Issue #100: Topological sort the query partial views in SQL adapter

Signed-off-by: Lucas Fernandes de Oliveira's avatarLucas Fernandes de Oliveira <lfoliveira@inf.ufpr.br>
parent 3b425558
Pipeline #18860 passed with stages
in 57 seconds
...@@ -27,6 +27,7 @@ import { Filter, FilterOperator } from "../core/filter"; ...@@ -27,6 +27,7 @@ import { Filter, FilterOperator } from "../core/filter";
import { AggregationType, RelationType, DataType } from "../common/types"; import { AggregationType, RelationType, DataType } from "../common/types";
import { Operation, Opcode } from "../common/expression"; import { Operation, Opcode } from "../common/expression";
import { View } from "../core/view"; import { View } from "../core/view";
import { Tsort } from "../util/tsort";
/** /**
* Information required to make a join clause. * Information required to make a join clause.
...@@ -62,6 +63,11 @@ interface QueryAndName { ...@@ -62,6 +63,11 @@ interface QueryAndName {
name: string; 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. * Two Dictionaries, both indexed with a dimension name.
* Used to get the views where a dimension is. * Used to get the views where a dimension is.
...@@ -90,7 +96,11 @@ export abstract class SQLAdapter extends Adapter { ...@@ -90,7 +96,11 @@ export abstract class SQLAdapter extends Adapter {
* @param view - View to be translated. * @param view - View to be translated.
*/ */
public getQueryFromView(view: View): string { 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 !== ""; return i.query !== "";
}).map((i) => { }).map((i) => {
return i.name + " AS (" + i.query + ")"; return i.name + " AS (" + i.query + ")";
...@@ -121,13 +131,14 @@ export abstract class SQLAdapter extends Adapter { ...@@ -121,13 +131,14 @@ export abstract class SQLAdapter extends Adapter {
* partials can only have one metric. * partials can only have one metric.
* @param view - View which the partial will be built. * @param view - View which the partial will be built.
*/ */
private buildPartials(view: View): QueryAndName[] { private buildPartials(view: View): QNMap {
let op = view.operation; let op = view.operation;
let queue: View[] = op.values.map((i) => i); let queue: View[] = op.values.map((i) => i);
const output: QueryAndName[] = [{ const output: QNMap = {};
output[view.name] = {
query: this.operation(op, view), query: this.operation(op, view),
name: view.name, name: view.name
}]; };
const map: {[key: string]: boolean } = {}; const map: {[key: string]: boolean } = {};
...@@ -137,10 +148,12 @@ export abstract class SQLAdapter extends Adapter { ...@@ -137,10 +148,12 @@ export abstract class SQLAdapter extends Adapter {
const query = this.operation(partial.operation, partial); const query = this.operation(partial.operation, partial);
if (query !== "") { if (query !== "") {
map[partial.id] = true; map[partial.id] = true;
output.unshift({ if (!output[partial.name]) {
query: query, output[partial.name] = {
name: partial.name query: query,
}); name: partial.name
};
}
queue = queue.concat(partial.operation.values); queue = queue.concat(partial.operation.values);
} }
} }
......
...@@ -22,6 +22,9 @@ ...@@ -22,6 +22,9 @@
* A representation of a dependency relation. * A representation of a dependency relation.
* Equivalent to a edge in a dependency graph. * Equivalent to a edge in a dependency graph.
*/ */
import { View } from "../core/view";
export interface TsortDep { export interface TsortDep {
/** The value (vertex). */ /** The value (vertex). */
value: string; value: string;
...@@ -60,6 +63,7 @@ export class Tsort { ...@@ -60,6 +63,7 @@ export class Tsort {
* dependency graph). * dependency graph).
*/ */
public static dependencies(deps: TsortDep[]): string[]{ public static dependencies(deps: TsortDep[]): string[]{
// Graph Creation
let graph: Graph = {}; let graph: Graph = {};
let mark: VertexMark = {}; let mark: VertexMark = {};
for (let i = 0; i < deps.length; ++i) { for (let i = 0; i < deps.length; ++i) {
...@@ -82,6 +86,57 @@ export class Tsort { ...@@ -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[] = []; let output: string[] = [];
for (let vertex of Object.keys(graph)) { for (let vertex of Object.keys(graph)) {
if (!mark[vertex]) { if (!mark[vertex]) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment