From cf4e49127722624c167f8a4e9a00ea79964d89ab Mon Sep 17 00:00:00 2001
From: Rafael <rpd17@inf.ufpr.br>
Date: Fri, 4 May 2018 11:55:56 -0300
Subject: [PATCH] Issue #67: Add dataType type check

Signed-off-by: Rafael <rpd17@inf.ufpr.br>
---
 config/ci_test.yaml.example         |   2 +-
 src/adapter/monet.ts                |   9 ++-
 src/adapter/postgres.ts             |   9 ++-
 src/adapter/sql.ts                  |   4 +-
 src/api/controllers/collect.spec.ts |  33 ++------
 src/api/controllers/collect.ts      |  14 ++--
 src/common/types.ts                 |  10 +++
 src/core/dimension.ts               |  15 ++--
 src/core/engine.ts                  |   4 +-
 src/core/enumType.ts                |  37 +++++++++
 src/core/filter.ts                  |   3 +-
 src/core/metric.ts                  |   9 ++-
 src/core/source.ts                  |  48 +++++++++++-
 src/util/configParser.spec.ts       | 115 ++++++++++++++++++++++++++--
 src/util/configParser.ts            |  65 ++++++++++++----
 src/util/graph.spec.ts              |  74 +++++++++---------
 src/util/graph.ts                   |   3 +-
 test/monet/fixture.ts               |  11 +--
 test/postgres/fixture.ts            |  13 ++--
 test/scenario.ts                    |  22 +++---
 20 files changed, 356 insertions(+), 144 deletions(-)

diff --git a/config/ci_test.yaml.example b/config/ci_test.yaml.example
index b319223d..260fa663 100644
--- a/config/ci_test.yaml.example
+++ b/config/ci_test.yaml.example
@@ -271,7 +271,7 @@ sources:
         -
             name: "fields:0"
             description: "first entry"
-            dataType: "notValid"
+            dataType: "string"
     -
         name: "source_3"
         description: "source with one entry and without description"
diff --git a/src/adapter/monet.ts b/src/adapter/monet.ts
index 321a3872..68d7ca31 100644
--- a/src/adapter/monet.ts
+++ b/src/adapter/monet.ts
@@ -22,6 +22,7 @@ import { SQLAdapter } from "./sql";
 import { View } from "../core/view";
 import { Source } from "../core/source";
 import { FilterOperator } from "../core/filter";
+import { DataType } from "../common/types";
 const MDB = require("monetdb")();
 
 export interface MonetConfig {
@@ -87,13 +88,13 @@ export class MonetAdapter extends SQLAdapter {
         this.executeQuery(query, cb);
     }
 
-    protected typeCast(quotedValue: string, dt: string): string {
+    protected typeCast(quotedValue: string, dt: DataType): string {
         switch (dt) {
-            case "date":
+            case DataType.DATE:
                 return "CAST(" + quotedValue + " AS TIMESTAMP)";
-            case "integer":
+            case DataType.INTEGER:
                 return "CAST(" + quotedValue + " AS INTEGER)";
-            case "boolean":
+            case DataType.BOOLEAN:
                 return "CAST(" + quotedValue + " AS BOOLEAN)";
             default:
                 return quotedValue;
diff --git a/src/adapter/postgres.ts b/src/adapter/postgres.ts
index e01b2bb3..ce0168bd 100644
--- a/src/adapter/postgres.ts
+++ b/src/adapter/postgres.ts
@@ -23,6 +23,7 @@ import { View } from "../core/view";
 import { Source } from "../core/source";
 import { FilterOperator } from "../core/filter";
 import { Pool, PoolConfig } from "pg";
+import { DataType } from "../common/types";
 
 export class PostgresAdapter extends SQLAdapter {
     private pool: Pool;
@@ -58,13 +59,13 @@ export class PostgresAdapter extends SQLAdapter {
         return false;
     }
 
-    protected typeCast(quotedValue: string, dt: string): string {
+    protected typeCast(quotedValue: string, dt: DataType): string {
         switch (dt) {
-            case "date":
+            case DataType.DATE:
                 return quotedValue + "::DATE";
-            case "integer":
+            case DataType.INTEGER:
                 return quotedValue + "::INTEGER";
-            case "boolean":
+            case DataType.BOOLEAN:
                 return quotedValue + "::BOOLEAN";
             default:
                 return quotedValue;
diff --git a/src/adapter/sql.ts b/src/adapter/sql.ts
index dc6c3cdc..e3b2d89c 100644
--- a/src/adapter/sql.ts
+++ b/src/adapter/sql.ts
@@ -24,7 +24,7 @@ import { Source } from "../core/source";
 import { Dimension } from "../core/dimension";
 import { Clause } from "../core/clause";
 import { Filter, FilterOperator } from "../core/filter";
-import { AggregationType, RelationType } from "../common/types";
+import { AggregationType, RelationType, DataType } from "../common/types";
 import { View } from "../core/view";
 
 interface ExpandedView {
@@ -793,7 +793,7 @@ export abstract class SQLAdapter extends Adapter {
 
     protected abstract applyOperator(leftSide: string, rightSide: string, op: FilterOperator): string;
 
-    protected abstract typeCast(quotedValue: string, dt: string): string;
+    protected abstract typeCast(quotedValue: string, dt: DataType): string;
 
     private compareKeys(a: Dimension[], b: Dimension[], blackList: string[]): number {
         /*
diff --git a/src/api/controllers/collect.spec.ts b/src/api/controllers/collect.spec.ts
index d4b57f0e..57d7cd37 100644
--- a/src/api/controllers/collect.spec.ts
+++ b/src/api/controllers/collect.spec.ts
@@ -76,7 +76,7 @@ describe("API collect controller", () => {
             .expect((res: any) => {
 
                 const message = "Query execution failed: " +
-                "Could not construct query with the paramters given.";
+                "Could not construct query with the parameters given.";
                 const error = "The source named 'thisisjustatest' was not found";
                 expect(res.body).to.be.an("object");
                 expect(res.body).to.have.property("message");
@@ -93,7 +93,7 @@ describe("API collect controller", () => {
             .expect(500)
             .expect((res: any) => {
                 const message = "Query execution failed: " +
-                "Could not construct query with the paramters given.";
+                "Could not construct query with the parameters given.";
                 const error = "The 'fields:0' wasn't informed on json";
                 expect(res.body).to.be.an("object");
                 expect(res.body).to.have.property("message");
@@ -124,7 +124,7 @@ describe("API collect controller", () => {
             .expect(500)
             .expect((res: any) => {
                 const message = "Query execution failed: " +
-                "Could not construct query with the paramters given.";
+                "Could not construct query with the parameters given.";
                 const error = "The value '1' from 'fields:0' isn't listed on enumtype:0";
                 expect(res.body).to.be.an("object");
                 expect(res.body).to.have.property("message");
@@ -157,7 +157,7 @@ describe("API collect controller", () => {
             .expect((res: any) => {
 
                 const message = "Query execution failed: " +
-                "Could not construct query with the paramters given.";
+                "Could not construct query with the parameters given.";
                 const error = "The value 'nope' from 'fields:0' isn't a type integer";
                 expect(res.body).to.be.an("object");
                 expect(res.body).to.have.property("message");
@@ -176,7 +176,7 @@ describe("API collect controller", () => {
             .expect((res: any) => {
 
                 const message = "Query execution failed: " +
-                "Could not construct query with the paramters given.";
+                "Could not construct query with the parameters given.";
                 const error = "The value 'notafloat' from 'fields:1' isn't a type float";
                 expect(res.body).to.be.an("object");
                 expect(res.body).to.have.property("message");
@@ -195,7 +195,7 @@ describe("API collect controller", () => {
             .expect((res: any) => {
 
                 const message = "Query execution failed: " +
-                "Could not construct query with the paramters given.";
+                "Could not construct query with the parameters given.";
                 const error = "The value '1' from 'fields:2' isn't a type string";
                 expect(res.body).to.be.an("object");
                 expect(res.body).to.have.property("message");
@@ -214,7 +214,7 @@ describe("API collect controller", () => {
             .expect((res: any) => {
 
                 const message = "Query execution failed: " +
-                "Could not construct query with the paramters given.";
+                "Could not construct query with the parameters given.";
                 const error = "The value 'notaboolean' from 'fields:3' isn't a type boolean";
                 expect(res.body).to.be.an("object");
                 expect(res.body).to.have.property("message");
@@ -233,7 +233,7 @@ describe("API collect controller", () => {
             .expect((res: any) => {
 
                 const message = "Query execution failed: " +
-                "Could not construct query with the paramters given.";
+                "Could not construct query with the parameters given.";
                 const error = "The value '1999-25-25' from 'fields:4' isn't a type date";
                 expect(res.body).to.be.an("object");
                 expect(res.body).to.have.property("message");
@@ -258,21 +258,4 @@ describe("API collect controller", () => {
             })
             .end(done);
     });
-    it("should respond 500 when dataType does not exist", (done) => {
-        request(server)
-        .post("/v1/collect/source_2")
-        .send({"fields:0" : 1 })
-        .expect(500)
-        .expect((res: any) => {
-            const message = "Query execution failed: " +
-            "Could not construct query with the paramters given.";
-            const error = "The dataType named 'notValid' was not found";
-            expect(res.body).to.be.an("object");
-            expect(res.body).to.have.property("message");
-            expect(res.body.message).to.be.eql(message);
-            expect(res.body.error).to.be.eql(error);
-
-        })
-        .end(done);
-    });
 });
diff --git a/src/api/controllers/collect.ts b/src/api/controllers/collect.ts
index 5fc3207e..8ac5b57f 100644
--- a/src/api/controllers/collect.ts
+++ b/src/api/controllers/collect.ts
@@ -22,6 +22,7 @@ import * as express from "express";
 import { Request } from "../types";
 import { Source, Field } from "../../core/source";
 import { EnumType } from "../../core/enumType";
+import { DataType } from "../../common/types";
 
 interface Valid{
     [key: string]: (value: any) => boolean;
@@ -114,17 +115,16 @@ export class CollectCtrl {
             }
 
             for (let i = 0; i < fields.length; i++){
-            if (validador[fields[i].dataType] !== undefined){
-                if (!validador[fields[i].dataType](data[i]) === true){
+            if (fields[i].dataType !== DataType.NONE){
+                if (!validador[EnumType.stringfyDataType(fields[i].dataType)](data[i]) === true){
                     throw new Error(
                         "The value '" +  data[i] + "' from '" + fields[i].name +
-                        "' isn't a type " + fields[i].dataType);
+                        "' isn't a type " + [EnumType.stringfyDataType(fields[i].dataType)]);
                 }
 
             }
             else {
-                    enumType = req.engine.getEnumTypeByName(fields[i].dataType);
-
+                    enumType = req.engine.getEnumTypeByName(fields[i].enumType);
                     types = enumType.values;
                     let found: boolean = false;
                     for (let j = 0; j < types.length; j++){
@@ -136,7 +136,7 @@ export class CollectCtrl {
                     if (!found) {
                         throw new Error(
                             "The value '" +  data[i] + "' from '" + fields[i].name +
-                            "' isn't listed on " + fields[i].dataType);
+                            "' isn't listed on " + fields[i].enumType);
                     }
                 }
             }
@@ -145,7 +145,7 @@ export class CollectCtrl {
         catch (e) {
             res.status(500).json({
                 message: "Query execution failed: " +
-                "Could not construct query with the paramters given.",
+                "Could not construct query with the parameters given.",
                 error: e.message
              });
             return;
diff --git a/src/common/types.ts b/src/common/types.ts
index 504dcd68..0bcf1498 100644
--- a/src/common/types.ts
+++ b/src/common/types.ts
@@ -33,3 +33,13 @@ export enum RelationType {
    MONTH,
    YEAR,
 };
+
+export enum DataType {
+    NONE,
+    INTEGER,
+    FLOAT,
+    STRING,
+    DATE,
+    BOOLEAN,
+    ENUMTYPE,
+};
diff --git a/src/core/dimension.ts b/src/core/dimension.ts
index 946bc43f..955ee443 100644
--- a/src/core/dimension.ts
+++ b/src/core/dimension.ts
@@ -18,14 +18,16 @@
  * along with blend.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-import { RelationType } from "../common/types";
+import { RelationType, DataType } from "../common/types";
+import { EnumType } from "./enumType";
 
 export interface DimensionOptions {
     name: string;
-    dataType: string;
+    dataType: DataType;
     parent?: Dimension;
     relation?: RelationType;
     description?: string;
+    enumType?: string;
 }
 
 export interface DimensionStrOptions {
@@ -38,10 +40,11 @@ export interface DimensionStrOptions {
 
 export class Dimension {
     public readonly name: string;
-    public readonly dataType: string;
+    public readonly dataType: DataType;
     public readonly parent: Dimension;
     public readonly relation: RelationType;
     public readonly description: string;
+    public readonly enumType: string;
 
     constructor(options: DimensionOptions) {
         this.name = options.name;
@@ -49,21 +52,21 @@ export class Dimension {
         this.relation = (options.relation) ? options.relation : RelationType.NONE;
         this.parent = (options.parent) ? options.parent : null;
         this.description = (options.description) ? options.description : "";
+        this.enumType = (options.enumType) ? (options.enumType) : "";
     }
 
     public strOptions(): DimensionStrOptions {
         if (this.relation === RelationType.NONE) {
             return {
                 name: this.name,
-                dataType: this.dataType,
+                dataType: (this.dataType !== DataType.NONE) ? EnumType.stringfyDataType(this.dataType) : this.enumType ,
                 description: this.description
             };
         }
-
         else {
             return {
                 name: this.name,
-                dataType: this.dataType,
+                dataType: (this.dataType !== DataType.NONE) ? EnumType.stringfyDataType(this.dataType) : this.enumType ,
                 parent: this.parent.name,
                 relation: Dimension.stringifyRelationType(this.relation),
                 description: this.description
diff --git a/src/core/engine.ts b/src/core/engine.ts
index 63331949..8058722d 100644
--- a/src/core/engine.ts
+++ b/src/core/engine.ts
@@ -26,7 +26,7 @@ import { View } from "./view";
 import { Query } from "../common/query";
 import { Graph } from "../util/graph";
 import { EnumType, EnumTypeOptions} from "./enumType";
-import { Source , SourceOptions } from "./source";
+import { Source , SourceStrOptions } from "./source";
 
 export class Engine {
     private views: View[] = [];
@@ -57,7 +57,7 @@ export class Engine {
         return this.enumTypes.map((i) => i.strOptions());
     }
 
-    public getSourcesDescription(): SourceOptions[] {
+    public getSourcesDescription(): SourceStrOptions[] {
         return this.sources.map((i) => i.strOptions());
     }
 
diff --git a/src/core/enumType.ts b/src/core/enumType.ts
index 039b8b4a..bfb5d975 100644
--- a/src/core/enumType.ts
+++ b/src/core/enumType.ts
@@ -18,6 +18,8 @@
  * along with blend.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+import { DataType } from "../common/types";
+
 export interface EnumTypeOptions {
     name: string;
     values: string[];
@@ -30,10 +32,45 @@ export class EnumType {
         this.name = options.name;
         this.values = options.values;
     }
+
     public strOptions(): EnumTypeOptions {
         return{
             name: this.name,
             values: this.values
         };
     }
+    public static stringfyDataType(a: DataType): string {
+        switch (a) {
+            case DataType.INTEGER:
+                return "integer";
+            case DataType.FLOAT:
+                return "float";
+            case DataType.STRING:
+                return "string";
+            case DataType.DATE:
+                return "date";
+            case DataType.BOOLEAN:
+                return "boolean";
+            default:
+                return  "";
+        }
+    }
+
+    public static parseDataType (str: string): DataType {
+        str = str.toLocaleLowerCase();
+        switch (str) {
+            case "integer":
+                return DataType.INTEGER;
+            case "float":
+                return DataType.FLOAT;
+            case "string":
+                return DataType.STRING;
+            case "date":
+                return DataType.DATE;
+            case "boolean":
+                return DataType.BOOLEAN;
+            default:
+                return  DataType.NONE;
+        }
+    }
 }
diff --git a/src/core/filter.ts b/src/core/filter.ts
index 29538096..47ec8e15 100644
--- a/src/core/filter.ts
+++ b/src/core/filter.ts
@@ -21,6 +21,7 @@
 import { Dimension } from "./dimension";
 import { Metric } from "./metric";
 import { Hash } from "../util/hash";
+import { DataType } from "../common/types";
 
 export interface FilterOptions {
     target: Metric|Dimension;
@@ -146,7 +147,7 @@ export class Filter {
             op.operator === FilterOperator.LOWER ||
             op.operator === FilterOperator.GREATEREQ ||
             op.operator === FilterOperator.LOWEREQ) {
-            if (op.target.dataType === "date" || op.target.dataType === "integer") {
+            if (op.target.dataType === DataType.DATE || op.target.dataType === DataType.INTEGER) {
                 return true;
             }
 
diff --git a/src/core/metric.ts b/src/core/metric.ts
index 7812a2c4..441b90cf 100644
--- a/src/core/metric.ts
+++ b/src/core/metric.ts
@@ -18,12 +18,13 @@
  * along with blend.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-import { AggregationType } from "../common/types";
+import { AggregationType, DataType } from "../common/types";
+import { EnumType } from "./enumType";
 
 export interface MetricOptions {
     name: string;
     aggregation: AggregationType;
-    dataType: string;
+    dataType: DataType;
     description?: string;
 }
 
@@ -37,7 +38,7 @@ export interface MetricStrOptions {
 export class Metric {
     public readonly name: string;
     public readonly aggregation: AggregationType;
-    public readonly dataType: string;
+    public readonly dataType: DataType;
     public readonly description: string;
 
     constructor(options: MetricOptions) {
@@ -51,7 +52,7 @@ export class Metric {
         return {
             name: this.name,
             aggregation: Metric.stringifyAggrType(this.aggregation),
-            dataType: this.dataType,
+            dataType: EnumType.stringfyDataType(this.dataType),
             description: this.description
         };
     }
diff --git a/src/core/source.ts b/src/core/source.ts
index 0fe15144..fcd55193 100644
--- a/src/core/source.ts
+++ b/src/core/source.ts
@@ -18,7 +18,17 @@
  * along with blendb.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+import { EnumType } from "./enumType";
+import { DataType } from "../common/types";
+
 export interface Field {
+    name: string;
+    description?: string;
+    dataType: DataType;
+    enumType?: string;
+}
+
+export interface FieldStr {
     name: string;
     description?: string;
     dataType: string;
@@ -30,6 +40,12 @@ export interface SourceOptions {
     fields: Field[];
 }
 
+export interface SourceStrOptions {
+    name: string;
+    description?: string;
+    fields: FieldStr[];
+}
+
 export class Source {
     public readonly name: string;
     public readonly description: string;
@@ -42,16 +58,42 @@ export class Source {
             return {
                 name: item.name,
                 description: (item.description) ? item.description : "",
-                dataType: item.dataType
+                dataType: item.dataType,
+                enumType: (item.enumType) ? item.enumType : ""
             };
         });
     }
 
-    public strOptions(): SourceOptions {
+    public strOptions(): SourceStrOptions {
         return {
             name: this.name,
             description: this.description,
-            fields: this.fields
+            fields: Source.stringfyFieldDataType(this.fields),
         };
     }
+
+    public static stringfyFieldDataType(opts: Field[]): FieldStr[] {
+        let str: FieldStr[];
+        str = opts.map((i) => {
+            return {
+                name : i.name,
+                description: i.description,
+                dataType: (i.dataType !== DataType.NONE) ? EnumType.stringfyDataType(i.dataType) : i.enumType
+            };
+        });
+        return str;
+    }
+
+    public static parseFieldDataType(opts: FieldStr[]): Field[] {
+        let str: Field[];
+        str = opts.map((i) => {
+            return {
+                name : i.name,
+                description: i.description,
+                dataType: EnumType.parseDataType(i.dataType),
+                enumType: (EnumType.parseDataType(i.dataType) === DataType.NONE) ? i.dataType : ""
+            };
+        });
+        return str;
+    }
 }
diff --git a/src/util/configParser.spec.ts b/src/util/configParser.spec.ts
index 389c6067..8c41cd00 100644
--- a/src/util/configParser.spec.ts
+++ b/src/util/configParser.spec.ts
@@ -22,7 +22,10 @@ import { expect } from "chai";
 
 import { ConfigParser, ViewParsingOptions } from "./configParser";
 import { Dimension, DimensionStrOptions } from "../core/dimension";
-import { RelationType } from "../common/types";
+import { RelationType , DataType} from "../common/types";
+import { EnumType } from "../core/enumType";
+import { MetricStrOptions } from "../core/metric";
+import { SourceStrOptions } from "../core/source";
 
 function strToRelationType (str: string): RelationType {
     switch (str) {
@@ -92,7 +95,7 @@ describe("configParser utility library", () => {
 
         let error: boolean = false;
         try {
-            ConfigParser.parseDimOpts(opts, dims);
+            ConfigParser.parseDimOpts(opts, dims, null);
         }
         catch (e) {
             error = true;
@@ -114,7 +117,7 @@ describe("configParser utility library", () => {
         };
 
         let dimMap: {[key: string]: Dimension} = {
-            "dim:0" : new Dimension({name: "dim:0", dataType: "integer"})
+            "dim:0" : new Dimension({name: "dim:0", dataType: DataType.INTEGER})
         };
 
         let error: boolean = false;
@@ -142,7 +145,7 @@ describe("configParser utility library", () => {
         };
 
         let dimMap: {[key: string]: Dimension} = {
-            "dim:0" : new Dimension({name: "dim:0", dataType: "integer"})
+            "dim:0" : new Dimension({name: "dim:0", dataType: DataType.INTEGER})
         };
 
         let error: boolean = false;
@@ -188,17 +191,113 @@ describe("configParser utility library", () => {
         ];
 
         let dims: Dimension[] = [
-            new Dimension({name: "dim:a", dataType: "date"}),
-            new Dimension({name: "dim:0", dataType: "date"})
+            new Dimension({name: "dim:a", dataType: DataType.DATE}),
+            new Dimension({name: "dim:0", dataType: DataType.DATE})
         ];
 
         for (let i = 0; i < opts.length; ++i) {
-            let parsed = ConfigParser.parseDimOpts(opts[i], dims);
+            let parsed = ConfigParser.parseDimOpts(opts[i], dims, null);
             expect(parsed.name).to.be.equal(opts[i].name);
-            expect(parsed.dataType).to.be.equal(opts[i].dataType);
+            expect(EnumType.stringfyDataType(parsed.dataType)).to.be.equal(opts[i].dataType);
             expect(parsed.parent).to.be.equal(dims[1]);
             expect(parsed.relation).to.be.equal(strToRelationType(opts[i].relation));
         }
     });
 
+    it("should parse correctly enumType with dimension", () => {
+
+        let opts: DimensionStrOptions =  {
+            name: "dim:day",
+            dataType: "enumtype:5",
+            parent: "dim:0",
+            relation: "day"
+        };
+        let dims: Dimension[] = [
+            new Dimension({name: "dim:0", dataType: DataType.DATE})
+        ];
+        let enumMap: {[key: string]: EnumType} = {
+            "enumtype:5" : new EnumType({name: "enumtype:5", values: ["nope", "test"]})
+        };
+        let parsed = ConfigParser.parseDimOpts(opts, dims, enumMap);
+
+        expect(parsed.enumType).to.be.equal(enumMap["enumtype:5"].name);
+    });
+
+    it("should fail to parse enumType with dimension", () => {
+
+        let opts: DimensionStrOptions =  {
+            name: "dim:day",
+            dataType: "enumtype:4",
+            parent: "dim:0",
+            relation: "day"
+        };
+        let dims: Dimension[] = [
+            new Dimension({name: "dim:0", dataType: DataType.INTEGER})
+        ];
+        let enumMap: {[key: string]: EnumType} = {
+            "enumtype:5" : new EnumType({name: "enumtype:5", values: ["nope", "test"]})
+        };
+        let error: boolean = false;
+        try {
+            ConfigParser.parseDimOpts(opts, dims, enumMap);
+        }
+        catch (e) {
+            error = true;
+            expect(e.message).to.be
+            .equal("[Parsing error] DataType: '" + opts.dataType + "' does not exist on Dimension");
+        }
+        expect(error).to.be.true;
+
+    });
+
+    it("should fail to parse dataType with Metrics", () => {
+        let met: MetricStrOptions;
+        met = {
+            name: "met:0",
+            aggregation: "sum",
+            dataType: "string",
+            description: "just for test"
+        };
+        let error: boolean = false;
+        try {
+            ConfigParser.parseMetOpts(met);
+        }
+        catch (e) {
+            error = true;
+            expect(e.message).to.be
+            .equal("[Parsing error] DataType: '" + met.dataType + "' does not exist on Metric");
+        }
+        expect(error).to.be.true;
+
+    });
+    it("should fail to parse enumType with Source", () => {
+        let sourc: SourceStrOptions;
+        sourc = {
+            name: "source_10",
+            description: "source used for test only",
+            fields: [
+                    {name: "fields:0",
+                    description: "first entry",
+                    dataType: "string"},
+                    {name: "fields:1",
+                    description: "second entry",
+                    dataType: "enumtype:10"}
+            ]
+        };
+        let enumMap: {[key: string]: EnumType} = {
+            "enumtype:5" : new EnumType({name: "enumtype:5", values: ["nope", "test"]})
+        };
+        let error: boolean = false;
+        try {
+            ConfigParser.parseSourceOpts(sourc, enumMap);
+        }
+        catch (e) {
+            error = true;
+            expect(e.message).to.be
+            .equal("[Parsing error] DataType: '" + sourc.fields[1].dataType + "' does not exist on Source");
+        }
+        expect(error).to.be.true;
+
+    });
+
 });
diff --git a/src/util/configParser.ts b/src/util/configParser.ts
index 6e15a86f..8ce6c352 100644
--- a/src/util/configParser.ts
+++ b/src/util/configParser.ts
@@ -22,10 +22,10 @@ import { Metric, MetricOptions, MetricStrOptions } from "../core/metric";
 import { Dimension, DimensionOptions, DimensionStrOptions } from "../core/dimension";
 import { View, ViewOptions, LoadView } from "../core/view";
 import { EnumType, EnumTypeOptions } from "../core/enumType";
-import { RelationType } from "../common/types";
+import { RelationType, DataType } from "../common/types";
 import { Filter } from "../core/filter";
 import { Clause } from "../core/clause";
-import { Source, SourceOptions} from "../core/source";
+import { Source, SourceOptions, SourceStrOptions} from "../core/source";
 import { Tsort, TsortDep } from "./tsort";
 import * as fs from "fs";
 import * as yaml from "js-yaml";
@@ -42,7 +42,7 @@ export interface ViewParsingOptions {
 }
 
 interface ConfigSchema {
-    sources: SourceOptions[];
+    sources: SourceStrOptions[];
     views: ViewParsingOptions[];
     metrics: MetricStrOptions[];
     dimensions: DimensionStrOptions[];
@@ -147,16 +147,16 @@ export class ConfigParser {
         let sourcMap: SourceMap = {};
         let dimOptsMap: DimensionOptsMap = {};
 
-        for (let i = 0; i < metricsOpts.length; ++i) {
-            let met = new Metric(this.parseMetOpts(metricsOpts[i]));
-            parsed.metrics.push(met);
-            metMap[met.name] = met;
-        }
         for (let i = 0; i < enumTypesOpts.length; i++) {
             let enumT = new EnumType((enumTypesOpts[i]));
             parsed.enumTypes.push(enumT);
             enumMap[enumT.name] = enumT;
         }
+        for (let i = 0; i < metricsOpts.length; ++i) {
+            let met = new Metric(this.parseMetOpts(metricsOpts[i]));
+            parsed.metrics.push(met);
+            metMap[met.name] = met;
+        }
 
         let toSort: TsortDep[] = [];
         for (let i = 0; i < dimensionsOpts.length; ++i) {
@@ -183,13 +183,13 @@ export class ConfigParser {
         });
 
         for (let i = 0; i < dimensionsOpts.length; ++i) {
-            let dim = new Dimension(this.parseDimOpts(dimensionsOpts[i], parsed.dimensions));
+            let dim = new Dimension(this.parseDimOpts(dimensionsOpts[i], parsed.dimensions, enumMap));
             parsed.dimensions.push(dim);
             dimMap[dim.name] = dim;
         }
 
         for (let i = 0; i < sourcesOpts.length; i++) {
-            let sourc = new Source((sourcesOpts[i]));
+            let sourc = new Source(this.parseSourceOpts(sourcesOpts[i], enumMap));
             parsed.sources.push(sourc);
             sourcMap[sourc.name] = sourc;
         }
@@ -277,16 +277,23 @@ export class ConfigParser {
         return viewOpt;
     }
 
-    public static parseDimOpts (opts: DimensionStrOptions, dims: Dimension[]): DimensionOptions {
+    public static parseDimOpts (opts: DimensionStrOptions, dims: Dimension[], map: EnumTypeMap): DimensionOptions {
+        let type = EnumType.parseDataType(opts.dataType);
+        if (type === DataType.NONE) {
+            if (!(map[opts.dataType])) {
+                throw new Error("[Parsing error] DataType: '" + opts.dataType + "' does not exist on Dimension");
+            }
+        }
         if (opts.parent || opts.relation) {
             for (let i = 0; i < dims.length; ++i) {
                 if (dims[i].name === opts.parent) {
                     return {
                         name: opts.name,
-                        dataType: opts.dataType,
+                        dataType: EnumType.parseDataType(opts.dataType),
                         description: opts.description,
                         parent: dims[i],
-                        relation: Dimension.parseRelationType(opts.relation)
+                        relation: Dimension.parseRelationType(opts.relation),
+                        enumType: (EnumType.parseDataType(opts.dataType) === DataType.NONE) ? opts.dataType : ""
                     };
                 }
             }
@@ -295,18 +302,25 @@ export class ConfigParser {
         }
         return {
             name: opts.name,
-            dataType: opts.dataType,
+            dataType: EnumType.parseDataType(opts.dataType),
             description: opts.description,
             parent: null,
-            relation: RelationType.NONE
+            relation: RelationType.NONE,
+            enumType: (EnumType.parseDataType(opts.dataType) === DataType.NONE) ? opts.dataType : ""
         };
     }
 
-    private static parseMetOpts (opts: MetricStrOptions): MetricOptions {
+    public static parseMetOpts (opts: MetricStrOptions): MetricOptions {
+        let type = EnumType.parseDataType(opts.dataType);
+        if (!(type === DataType.FLOAT || type === DataType.INTEGER)){
+
+            throw new Error("[Parsing error] DataType: '" + opts.dataType + "' does not exist on Metric");
+
+        }
         return {
             name: opts.name,
             aggregation: Metric.parseAggrType(opts.aggregation),
-            dataType : opts.dataType,
+            dataType : EnumType.parseDataType(opts.dataType),
             description: opts.description
         };
     }
@@ -326,6 +340,23 @@ export class ConfigParser {
         return new Clause ({filters: filters});
     }
 
+    public static parseSourceOpts (opts: SourceStrOptions , map: EnumTypeMap): SourceOptions {
+        for ( let k = 0; k  < opts.fields.length ; k++) {
+                    let type = EnumType.parseDataType(opts.fields[k].dataType);
+                    if (type === DataType.NONE) {
+                        if (!(map[opts.fields[k].dataType])){
+
+                                throw new Error("[Parsing error] DataType: '" + opts.fields[k].dataType + "' does not exist on Source");
+
+                        }
+                    }
+        }
+        return {
+            name: opts.name,
+            description: opts.description,
+            fields : Source.parseFieldDataType(opts.fields),
+        };
+    }
     private static parseFilter (opts: string, metMap: MetricMap, dimMap: DimensionMap): Filter {
         const strFilter = Filter.segment(opts);
         if (!strFilter) {
diff --git a/src/util/graph.spec.ts b/src/util/graph.spec.ts
index 464dd1dc..72e372e0 100644
--- a/src/util/graph.spec.ts
+++ b/src/util/graph.spec.ts
@@ -26,14 +26,14 @@ import { View } from "../core/view";
 import { Filter, FilterOperator } from "../core/filter";
 import { Clause } from "../core/clause";
 import { Graph } from "./graph";
-import { AggregationType, RelationType } from "../common/types";
+import { AggregationType, RelationType, DataType } from "../common/types";
 import { Query } from "../common/query";
 
 describe("graph class", () => {
 
     it("should not create 2 vertices with the same dimension", () => {
         let g = new Graph();
-        let dim = new Dimension({name: "dim:test", dataType: "string"});
+        let dim = new Dimension({name: "dim:test", dataType: DataType.STRING});
 
         expect(g.addDimension(dim)).to.be.true;
         expect(g.addDimension(dim)).to.be.false;
@@ -44,7 +44,7 @@ describe("graph class", () => {
         let met = new Metric({
             name: "met:test",
             aggregation: AggregationType.SUM,
-            dataType: "string"
+            dataType: DataType.STRING
         });
 
         expect(g.addMetric(met)).to.be.true;
@@ -67,10 +67,10 @@ describe("graph class", () => {
 
     it("should not create a vertex with a subdimension when parent is not a vertex", () => {
         let g = new Graph();
-        let dim = new Dimension({name: "dim:test", dataType: "string"});
+        let dim = new Dimension({name: "dim:test", dataType: DataType.STRING});
         let subdim = new Dimension({
             name: "dim:sub_test",
-            dataType: "string",
+            dataType: DataType.STRING,
             relation: RelationType.MONTH,
             parent: dim
         });
@@ -80,10 +80,10 @@ describe("graph class", () => {
 
     it("should add a set of views", () => {
         let dims = [
-            new Dimension({name: "dim:0", dataType: "string"}),
-            new Dimension({name: "dim:1", dataType: "string"}),
-            new Dimension({name: "dim:2", dataType: "string"}),
-            new Dimension({name: "dim:3", dataType: "string"})
+            new Dimension({name: "dim:0", dataType: DataType.STRING}),
+            new Dimension({name: "dim:1", dataType: DataType.STRING}),
+            new Dimension({name: "dim:2", dataType: DataType.STRING}),
+            new Dimension({name: "dim:3", dataType: DataType.STRING})
         ];
 
         let g = new Graph();
@@ -120,8 +120,8 @@ describe("graph class", () => {
 
     it("should not add a view twice", () => {
         let dims = [
-            new Dimension({name: "dim:0", dataType: "string"}),
-            new Dimension({name: "dim:1", dataType: "string"}),
+            new Dimension({name: "dim:0", dataType: DataType.STRING}),
+            new Dimension({name: "dim:1", dataType: DataType.STRING}),
         ];
 
         let g = new Graph();
@@ -143,9 +143,9 @@ describe("graph class", () => {
 
     it("should not add views when metrics and dimensions are not vertices", () => {
         let dims = [
-            new Dimension({name: "dim:0", dataType: "string"}),
-            new Dimension({name: "dim:1", dataType: "string"}),
-            new Dimension({name: "dim:2", dataType: "string"})
+            new Dimension({name: "dim:0", dataType: DataType.STRING}),
+            new Dimension({name: "dim:1", dataType: DataType.STRING}),
+            new Dimension({name: "dim:2", dataType: DataType.STRING})
         ];
 
         let g = new Graph();
@@ -168,7 +168,7 @@ describe("graph class", () => {
     });
 
     it("should add only once a view with only one vertex", () => {
-        let dim = new Dimension({name: "dim:0", dataType: "string"});
+        let dim = new Dimension({name: "dim:0", dataType: DataType.STRING});
 
         let g = new Graph();
 
@@ -186,7 +186,7 @@ describe("graph class", () => {
     });
 
     it("should create a cover for a single vertex", () => {
-        let dim = new Dimension({name: "dim:0", dataType: "string"});
+        let dim = new Dimension({name: "dim:0", dataType: DataType.STRING});
 
         let g = new Graph();
 
@@ -209,15 +209,15 @@ describe("graph class", () => {
 
     it("should create a cover for several vertices", () => {
         let dims = [
-            new Dimension({name: "dim:0", dataType: "string"}),
-            new Dimension({name: "dim:1", dataType: "string"}),
-            new Dimension({name: "dim:2", dataType: "string"})
+            new Dimension({name: "dim:0", dataType: DataType.STRING}),
+            new Dimension({name: "dim:1", dataType: DataType.STRING}),
+            new Dimension({name: "dim:2", dataType: DataType.STRING})
         ];
 
         let mets = [
-            new Metric({name: "met:0", dataType: "integer", aggregation: AggregationType.SUM}),
-            new Metric({name: "met:1", dataType: "integer", aggregation: AggregationType.AVG}),
-            new Metric({name: "met:2", dataType: "integer", aggregation: AggregationType.AVG})
+            new Metric({name: "met:0", dataType: DataType.INTEGER, aggregation: AggregationType.SUM}),
+            new Metric({name: "met:1", dataType: DataType.INTEGER, aggregation: AggregationType.AVG}),
+            new Metric({name: "met:2", dataType: DataType.INTEGER, aggregation: AggregationType.AVG})
         ];
 
         let g = new Graph();
@@ -278,18 +278,18 @@ describe("graph class", () => {
     });
 
     it("should create a cover with sub dimensions", () => {
-        let dim = new Dimension({name: "dim:0", dataType: "date"});
+        let dim = new Dimension({name: "dim:0", dataType: DataType.DATE});
         let dims = [
             dim,
             new Dimension({
                 name: "subdim:0",
-                dataType: "string",
+                dataType: DataType.STRING,
                 parent: dim,
                 relation: RelationType.MONTH
             }),
             new Dimension({
                 name: "subdim:1",
-                dataType: "string",
+                dataType: DataType.STRING,
                 parent: dim,
                 relation: RelationType.DAY
             }),
@@ -318,18 +318,18 @@ describe("graph class", () => {
     });
 
     it("should return empty when try to cover a empty list", () => {
-        let dim = new Dimension({name: "dim:0", dataType: "date"});
+        let dim = new Dimension({name: "dim:0", dataType: DataType.DATE});
         let dims = [
             dim,
             new Dimension({
                 name: "subdim:0",
-                dataType: "string",
+                dataType: DataType.STRING,
                 parent: dim,
                 relation: RelationType.MONTH
             }),
             new Dimension({
                 name: "subdim:1",
-                dataType: "string",
+                dataType: DataType.STRING,
                 parent: dim,
                 relation: RelationType.DAY
             }),
@@ -358,9 +358,9 @@ describe("graph class", () => {
 
     it("should cover the graph, even when a constraint edge can not be used", () => {
         let dims = [
-            new Dimension({name: "dim:0", dataType: "date"}),
-            new Dimension({name: "dim:1", dataType: "date"}),
-            new Dimension({name: "dim:2", dataType: "date"}),
+            new Dimension({name: "dim:0", dataType: DataType.DATE}),
+            new Dimension({name: "dim:1", dataType: DataType.DATE}),
+            new Dimension({name: "dim:2", dataType: DataType.DATE}),
         ];
 
         let filter1 = new Filter({
@@ -418,9 +418,9 @@ describe("graph class", () => {
 
     it("should cover the query, using filters of intervals", () => {
         let dims = [
-            new Dimension({name: "dim:0", dataType: "float"}),
-            new Dimension({name: "dim:1", dataType: "float"}),
-            new Dimension({name: "dim:2", dataType: "date"}),
+            new Dimension({name: "dim:0", dataType: DataType.FLOAT}),
+            new Dimension({name: "dim:1", dataType: DataType.FLOAT}),
+            new Dimension({name: "dim:2", dataType: DataType.DATE}),
         ];
 
         const filters = [
@@ -531,9 +531,9 @@ describe("graph class", () => {
 
     it("should cover the query, not using filters of intervals", () => {
         let dims = [
-            new Dimension({name: "dim:0", dataType: "float"}),
-            new Dimension({name: "dim:1", dataType: "float"}),
-            new Dimension({name: "dim:2", dataType: "date"}),
+            new Dimension({name: "dim:0", dataType: DataType.FLOAT}),
+            new Dimension({name: "dim:1", dataType: DataType.FLOAT}),
+            new Dimension({name: "dim:2", dataType: DataType.DATE}),
         ];
 
         const filters = [
diff --git a/src/util/graph.ts b/src/util/graph.ts
index 145b2228..ad654a93 100644
--- a/src/util/graph.ts
+++ b/src/util/graph.ts
@@ -24,6 +24,7 @@ import { Dimension } from "../core/dimension";
 import { Query } from "../common/query";
 import { Clause } from "../core/clause";
 import { FilterOperator } from "../core/filter";
+import { DataType } from "../common/types";
 
 enum State {
     UNVISITED,
@@ -548,7 +549,7 @@ export class Graph {
 
                 let queryValue: number;
                 let viewValue: number;
-                if (queryFilter.target.dataType === "date") {
+                if (queryFilter.target.dataType === DataType.DATE) {
                     queryValue = new Date(queryFilter.value).getTime();
                     viewValue = new Date(viewFilter.value).getTime();
                 }
diff --git a/test/monet/fixture.ts b/test/monet/fixture.ts
index 2ff73091..c0cbee72 100644
--- a/test/monet/fixture.ts
+++ b/test/monet/fixture.ts
@@ -23,6 +23,7 @@ import { View, LoadView } from "../../src/core/view";
 import { each, series } from "async";
 import { Connection } from "../../src/util/configParser";
 import * as fs from "fs";
+import { DataType } from "../../src/common/types";
 
 interface TransSet {
     init: string;
@@ -93,15 +94,15 @@ export class Fixture {
         });
     }
 
-    private typeConvertion(t: string): string {
+    private typeConvertion(t: DataType): string {
         switch (t) {
-            case "integer":
+            case DataType.INTEGER:
                 return "INTEGER";
-            case "date":
+            case DataType.DATE:
                 return "TIMESTAMP";
-            case "string":
+            case DataType.STRING:
                 return "TEXT";
-            case "boolean":
+            case DataType.BOOLEAN:
                 return "BOOLEAN";
             default:
                 return "";
diff --git a/test/postgres/fixture.ts b/test/postgres/fixture.ts
index 3233453e..d560d7eb 100644
--- a/test/postgres/fixture.ts
+++ b/test/postgres/fixture.ts
@@ -23,6 +23,7 @@ import { View, LoadView } from "../../src/core/view";
 import { Source } from "../../src/core/source";
 import { each, series } from "async";
 import * as fs from "fs";
+import { DataType } from "../../src/common/types";
 
 interface TransSet {
     init: string;
@@ -103,15 +104,15 @@ export class Fixture {
         });
     }
 
-    private typeConvertion(t: string): string {
+    private typeConvertion(t: DataType): string {
         switch (t) {
-            case "integer":
+            case DataType.INTEGER:
                 return "INTEGER";
-            case "date":
+            case DataType.DATE:
                 return "DATE";
-            case "string":
+            case DataType.STRING:
                 return "TEXT";
-            case "boolean":
+            case DataType.BOOLEAN:
                 return "BOOLEAN";
             default:
                 return "TEXT";
@@ -188,7 +189,7 @@ export class Fixture {
     }
     private ExtractData(data: Source , create: boolean): string{
         let name: string;
-        let type: string[];
+        let type: DataType[];
         let fields: string[];
         let consult: string;
 
diff --git a/test/scenario.ts b/test/scenario.ts
index 9abe77b2..2e1bd1b8 100644
--- a/test/scenario.ts
+++ b/test/scenario.ts
@@ -24,7 +24,7 @@ import { Dimension } from "../src/core/dimension";
 import { View } from "../src/core/view";
 import { Filter, FilterOperator } from "../src/core/filter";
 import { Clause } from "../src/core/clause";
-import { AggregationType, RelationType } from "../src/common/types";
+import { AggregationType, RelationType , DataType} from "../src/common/types";
 import { Query} from "../src/common/query";
 
 interface EngineScenario {
@@ -151,13 +151,13 @@ const clauses: { [key: string]: Clause }  = {
 const wrongMet = new Metric({
     name: "met:-1",
     aggregation: AggregationType.COUNT,
-    dataType: "integer"
+    dataType: DataType.INTEGER
 });
-const wrongDim = new Dimension({ name: "dim:-1", dataType: "integer" });
+const wrongDim = new Dimension({ name: "dim:-1", dataType: DataType.INTEGER });
 
 const subdimAux = new Dimension({
     name: "sub:0",
-    dataType: "integer",
+    dataType: DataType.INTEGER,
     parent: dims[0],
     relation: RelationType.DAY
 });
@@ -166,25 +166,25 @@ const subdims = [
     subdimAux,
     new Dimension({
         name: "sub:1",
-        dataType: "integer",
+        dataType: DataType.INTEGER,
         parent: dims[1],
         relation: RelationType.DAY
     }),
     new Dimension({
         name: "sub:2",
-        dataType: "integer",
+        dataType: DataType.INTEGER,
         parent: subdimAux,
         relation: RelationType.DAY
     }),
     new Dimension({
         name: "sub:3",
-        dataType: "integer",
+        dataType: DataType.INTEGER,
         parent: null,
         relation: RelationType.DAY
     }),
     new Dimension({
         name: "sub:4",
-        dataType: "integer",
+        dataType: DataType.INTEGER,
         parent: dims[1],
         relation: RelationType.DAY
     })
@@ -197,19 +197,19 @@ const subdims = [
 const dateSubDim = [
     new Dimension ({
         name: "dim:0:month",
-        dataType: "integer",
+        dataType: DataType.INTEGER,
         parent: dims[0],
         relation: RelationType.MONTH
     }),
     new Dimension ({
         name: "dim:0:day",
-        dataType: "integer",
+        dataType: DataType.INTEGER,
         parent: dims[0],
         relation: RelationType.DAY
     }),
     new Dimension ({
         name: "dim:0:year",
-        dataType: "integer",
+        dataType: DataType.INTEGER,
         parent: dims[0],
         relation: RelationType.YEAR
     })
-- 
GitLab