From 44480c5ea986673b098fddd1ca74c23bc2b7e5e1 Mon Sep 17 00:00:00 2001 From: Lucas Fernandes de Oliveira <lfoliveira@inf.ufpr.br> Date: Wed, 12 Dec 2018 09:23:49 -0200 Subject: [PATCH] Issue #100: Topological sort the query partial views in SQL adapter Signed-off-by: Lucas Fernandes de Oliveira <lfoliveira@inf.ufpr.br> --- src/adapter/sql.ts | 31 ++++++++++++++++++-------- src/util/tsort.ts | 55 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 9 deletions(-) diff --git a/src/adapter/sql.ts b/src/adapter/sql.ts index 6bf00505..93c3bb96 100644 --- a/src/adapter/sql.ts +++ b/src/adapter/sql.ts @@ -27,6 +27,7 @@ import { Filter, FilterOperator } from "../core/filter"; import { AggregationType, RelationType, DataType } from "../common/types"; import { Operation, Opcode } from "../common/expression"; import { View } from "../core/view"; +import { Tsort } from "../util/tsort"; /** * Information required to make a join clause. @@ -62,6 +63,11 @@ interface QueryAndName { name: string; } +/** Dictonary indexed by view name, that returns the QueryAndName object. */ +interface QNMap { + [key: string]: QueryAndName; +} + /** * Two Dictionaries, both indexed with a dimension name. * Used to get the views where a dimension is. @@ -90,7 +96,11 @@ export abstract class SQLAdapter extends Adapter { * @param view - View to be translated. */ public getQueryFromView(view: View): string { - const partials = this.buildPartials(view).filter((i) => { + const map = this.buildPartials(view); + const topSort = Tsort.view(view); + const partials = topSort.map((i) => { + return (map[i]) ? map[i] : {query : "", name: i}; + }).filter((i) => { return i.query !== ""; }).map((i) => { return i.name + " AS (" + i.query + ")"; @@ -121,13 +131,14 @@ export abstract class SQLAdapter extends Adapter { * partials can only have one metric. * @param view - View which the partial will be built. */ - private buildPartials(view: View): QueryAndName[] { + private buildPartials(view: View): QNMap { let op = view.operation; let queue: View[] = op.values.map((i) => i); - const output: QueryAndName[] = [{ + const output: QNMap = {}; + output[view.name] = { query: this.operation(op, view), - name: view.name, - }]; + name: view.name + }; const map: {[key: string]: boolean } = {}; @@ -137,10 +148,12 @@ export abstract class SQLAdapter extends Adapter { const query = this.operation(partial.operation, partial); if (query !== "") { map[partial.id] = true; - output.unshift({ - query: query, - name: partial.name - }); + if (!output[partial.name]) { + output[partial.name] = { + query: query, + name: partial.name + }; + } queue = queue.concat(partial.operation.values); } } diff --git a/src/util/tsort.ts b/src/util/tsort.ts index a97f7f4b..2bff0690 100644 --- a/src/util/tsort.ts +++ b/src/util/tsort.ts @@ -22,6 +22,9 @@ * A representation of a dependency relation. * Equivalent to a edge in a dependency graph. */ + +import { View } from "../core/view"; + export interface TsortDep { /** The value (vertex). */ value: string; @@ -60,6 +63,7 @@ export class Tsort { * dependency graph). */ public static dependencies(deps: TsortDep[]): string[]{ + // Graph Creation let graph: Graph = {}; let mark: VertexMark = {}; for (let i = 0; i < deps.length; ++i) { @@ -82,6 +86,57 @@ export class Tsort { } + // Topological Sort + let output: string[] = []; + for (let vertex of Object.keys(graph)) { + if (!mark[vertex]) { + Tsort.markVertex(vertex, graph, mark, output); + } + } + return output; + } + + /** + * Topologicaly sort view descendents names. + * @param view - View to construct dependency tree(graph) and sort it + */ + public static view(view: View): string[] { + // Graph creation + const graph: Graph = {}; + const mark: VertexMark = {}; + + let queue = [view]; + + while (queue.length > 0) { + const partial = queue.shift(); + + // If the dependent vertex does not exist, create it + // with a empty dependent list + if (!graph[partial.name]) { + graph[partial.name] = []; + mark[partial.name] = false; + } + for (let i = 0; i < partial.operation.values.length; ++i) { + const dep = partial.operation.values[i]; + + // If the required vertex does not exists create it + // and put the dependent vertex in the dependent list + if (!graph[dep.name]) { + graph[dep.name] = [partial.name]; + mark[dep.name] = false; + } + + // If the vertex already exists, add it in the dependent list + else { + graph[dep.name].push(partial.name); + } + + // Add the other view. Could create replicated edges. + queue = queue.concat(partial.operation.values); + } + } + + // Topological Sort let output: string[] = []; for (let vertex of Object.keys(graph)) { if (!mark[vertex]) { -- GitLab