From a3e4638c84ec41f5042ec69d5bf4d49e7945d8e1 Mon Sep 17 00:00:00 2001
From: Lucas Fernandes de Oliveira <lfo14@inf.ufpr.br>
Date: Wed, 19 Oct 2016 10:19:15 -0200
Subject: [PATCH] Partial query

Signed-off-by: Lucas Fernandes de Oliveira <lfo14@inf.ufpr.br>
---
 src/core/query.spec.ts | 70 +++++++++++++++++++++++++++++++++
 src/core/query.ts      | 87 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 157 insertions(+)
 create mode 100644 src/core/query.spec.ts
 create mode 100644 src/core/query.ts

diff --git a/src/core/query.spec.ts b/src/core/query.spec.ts
new file mode 100644
index 00000000..f82e3991
--- /dev/null
+++ b/src/core/query.spec.ts
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre
+ * Departamento de Informatica - Universidade Federal do Parana
+ *
+ * This file is part of blendb.
+ *
+ * blendb is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * blendb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with blendb.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import { expect } from "chai";
+
+import { sqlGenerator, IViewData } from "./query";
+
+describe("SQL Generator", () => {
+    let sql = "";
+    it("should be able to create a sql query", () => {
+
+        const testViews: IViewData[] = [
+            {
+                name: "view 0",
+                metrics : ["met 1", "met 2"],
+                dimensions: ["dim 1", "dim 2", "dim 3"]
+            },
+
+            {
+                name: "view 1",
+                metrics : ["met 2", "met 3"],
+                dimensions: ["dim 2", "dim 3", "dim 4"]
+            },
+
+            {
+                name: "view 2",
+                metrics : ["met 4", "met 5"],
+                dimensions: ["dim 1", "dim 4", "dim 5"]
+            },
+
+            {
+                name: "view 3",
+                metrics : ["met 1", "met 6"],
+                dimensions: ["dim 5"]
+            }
+        ];
+
+        const testQuery: IViewData = {
+            name: "Query 1",
+            metrics : ["met1", "met2", "met3", "met4", "met5"],
+            dimensions : ["dim1", "dim2", "dim3", "dim4", "dim5"]
+        };
+
+        sql = sqlGenerator(testQuery, testViews);
+
+        expect(sql).to.be.an("string");
+
+    });
+
+    it(sql, () => {
+        expect(sql).to.be.an("string");
+    });
+});
diff --git a/src/core/query.ts b/src/core/query.ts
new file mode 100644
index 00000000..eceaa5e0
--- /dev/null
+++ b/src/core/query.ts
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre
+ * Departamento de Informatica - Universidade Federal do Parana
+ *
+ * This file is part of blend.
+ *
+ * blend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * blend is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with blend.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+export interface IViewData {
+    name: string;
+    metrics: string[];
+    dimensions: string[];
+};
+
+export function sqlGenerator (query: IViewData, views: IViewData[]) {
+    let objective: string[] = query.dimensions;
+    let aliasPrefix: string = "v";
+    let fromClause: IViewData[] = [];
+    let activeViews: IViewData[] = views;
+    let whereClause: Map<string, string[]> = new Map();
+    objective.forEach((item: string) =>  whereClause.set(item, []) );
+
+    while (objective.length  > 0) {
+        let actual: IViewData;
+        let actualDistance: number = objective.length + 1;
+        activeViews = activeViews.filter((view: IViewData) => {
+            let intersection: string[] = [];
+            let dims: string[] = view.dimensions;
+            intersection = dims.filter((item: string) => {
+                return objective.indexOf(item) !== -1;
+            });
+
+            if (intersection.length > 0) {
+                let distance: number = objective.length - intersection.length;
+
+                if (distance < actualDistance) {
+                    actual = view;
+                    actualDistance = distance;
+                }
+                return true;
+            }
+
+            return false;
+        });
+        if (activeViews.length  === objective.length + 1) {
+            // Erro as views fornecisdas não atemdem a query
+            return "";
+        }
+        let viewAlias: number = fromClause.push(actual) - 1;
+        actual.dimensions.forEach((item: string) => {
+            whereClause.get(item).push(aliasPrefix + viewAlias);
+        });
+        objective = objective.filter((item: string) => {
+            return actual.dimensions.indexOf(item) === -1;
+        });
+    }
+
+    let sql: string = "";
+    // SELECT CLAUSE
+    sql += "FROM ";
+    let aliases = fromClause.map((item: IViewData, idx: number) => {
+        return item.name + " " + aliasPrefix + idx;
+    });
+    sql += aliases.join(", ") + "\n";
+    sql += "WHERE ";
+    whereClause.forEach((items: string[]) => {
+        let last: string = items.pop();
+        sql += items.reduce((total: string, item: string) => {
+            return total + ", " + item + " = " + last;
+        });
+    });
+    // group by
+
+    return sql;
+}
-- 
GitLab