diff --git a/src/util/configParser.ts b/src/util/configParser.ts index c4abac077eff6b79594ef40d19f723f9be037756..83631da0050fbd61b9957de451a0533695a9035f 100644 --- a/src/util/configParser.ts +++ b/src/util/configParser.ts @@ -24,6 +24,7 @@ import { View, ViewOptions, LoadView } from "../core/view"; import { RelationType } from "../common/types"; import { Filter } from "../core/filter"; import { Clause } from "../core/clause"; +import { Tsort, TsortDep } from "./tsort"; import * as fs from "fs"; import * as yaml from "js-yaml"; @@ -78,6 +79,10 @@ interface DimensionMap { [key: string]: Dimension; } +interface DimensionOptsMap { + [key: string]: DimensionStrOptions; +} + interface MetricMap { [key: string]: Metric; } @@ -120,6 +125,7 @@ export class ConfigParser { let metMap: MetricMap = {}; let dimMap: DimensionMap = {}; + let dimOptsMap: DimensionOptsMap = {}; for (let i = 0; i < metricsOpts.length; ++i) { let met = new Metric(this.parseMetOpts(metricsOpts[i])); @@ -127,6 +133,30 @@ export class ConfigParser { metMap[met.name] = met; } + let toSort: TsortDep[] = []; + for (let i = 0; i < dimensionsOpts.length; ++i) { + if (dimensionsOpts[i].parent) { + toSort.push({ + value: dimensionsOpts[i].name, + dependOf: dimensionsOpts[i].parent + }); + } + + else { + toSort.push({ + value: dimensionsOpts[i].name + }); + } + + dimOptsMap[dimensionsOpts[i].name] = dimensionsOpts[i]; + } + + dimensionsOpts = Tsort.dependencies(toSort).filter((name) => { + return (dimOptsMap[name]) ? true : false; + }).map((name) => { + return dimOptsMap[name]; + }); + for (let i = 0; i < dimensionsOpts.length; ++i) { let dim = new Dimension(this.parseDimOpts(dimensionsOpts[i], parsed.dimensions)); parsed.dimensions.push(dim); diff --git a/src/util/tsort.spec.ts b/src/util/tsort.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..cbb268c47a198de482461745a3b9a85487556980 --- /dev/null +++ b/src/util/tsort.spec.ts @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 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 { Tsort, TsortDep } from "./tsort"; + +describe("topological sorting utility library", () => { + it("should sort the dependencies", () => { + let deps: TsortDep[] = [ + {value: "dim:1", dependOf: "dim:0"}, + {value: "dim:2", dependOf: "dim:0"}, + {value: "dim:3", dependOf: "dim:1"}, + {value: "dim:4", dependOf: "dim:2"}, + {value: "dim:5", dependOf: "dim:3"}, + {value: "dim:5", dependOf: "dim:2"}, + ]; + let sorted = Tsort.dependencies(deps); + let res: string[] = ["dim:0", "dim:2", "dim:4", "dim:1", "dim:3", "dim:5"]; + + expect(res).to.be.a("array"); + expect(res).to.not.be.empty; + for (let i = 0; i < sorted.length; ++i) { + expect(sorted[i]).to.be.a("string"); + expect(sorted[i]).to.be.eql(res[i]); + } + }); +}); diff --git a/src/util/tsort.ts b/src/util/tsort.ts new file mode 100644 index 0000000000000000000000000000000000000000..273c7ea1b07cc2bd06b0b7b6bdb26cd4e1f73abb --- /dev/null +++ b/src/util/tsort.ts @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2018 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/>. + */ + +export interface TsortDep { + value: string; + dependOf?: string; +} + +interface Graph { + [key: string]: string[]; +} + +interface VertexMark { + [key: string]: boolean; +} + +export class Tsort { + public static dependencies(deps: TsortDep[]): string[]{ + let graph: Graph = {}; + let mark: VertexMark = {}; + for (let i = 0; i < deps.length; ++i) { + let vertex = deps[i].dependOf; + if (!graph[deps[i].value]) { + graph[deps[i].value] = []; + mark[deps[i].value] = false; + } + + if (vertex) { + if (!graph[vertex]) { + graph[vertex] = [deps[i].value]; + mark[vertex] = false; + } + + else { + graph[vertex].push(deps[i].value); + } + } + + } + + let output: string[] = []; + for (let vertex of Object.keys(graph)) { + if (!mark[vertex]) { + Tsort.markVertex(vertex, graph, mark, output); + } + } + return output; + } + + private static markVertex(vertex: string, graph: Graph, + mark: VertexMark, output: string[]): void { + if (mark[vertex]) { + return; + } + + mark[vertex] = true; + for (let i = 0; i < graph[vertex].length; ++i) { + Tsort.markVertex(graph[vertex][i], graph, mark, output); + } + output.unshift(vertex); + return; + } +}