diff --git a/src/common/query.ts b/src/common/query.ts index 4cb0a9e986b6e183287d5bb2e279637080a1095a..85f158d85cf48286d4dc2df7ed1ac7996f3784c8 100644 --- a/src/common/query.ts +++ b/src/common/query.ts @@ -25,7 +25,7 @@ import { Clause } from "../core/clause"; /** * Internal representation of a query in BlenDB perspective. */ -export interface Query { +export interface queryOpts { /** Set of metrics of the query. */ metrics: Metric[]; /** Set of dimensions of the query. */ @@ -35,3 +35,24 @@ export interface Query { /** List of metrics and dimensions to sort the query. */ sort?: (Metric|Dimension)[]; } + +export class Query { + /** Set of metrics of the query. */ + public metrics: Metric[]; + /** Set of dimensions of the query. */ + public dimensions: Dimension[]; + /** Set of clauses of the query. */ + public clauses: Clause[]; + /** List of metrics and dimensions to sort the query. */ + public sort: (Metric|Dimension)[]; + /** + * Create Query + * @param opts - Parameters required to create a query. + */ + constructor(opts: queryOpts){ + this.metrics = opts.metrics; + this.dimensions = opts.dimensions; + this.clauses = (opts.clauses) ? opts.clauses : []; + this.sort = (opts.sort) ? opts.sort : []; + } +} diff --git a/src/core/engine.ts b/src/core/engine.ts index 712d722082d99f418a587f9dff24baf6b93da6af..fd7ae68a7d0a0082806fc10245e73e33f458a573 100644 --- a/src/core/engine.ts +++ b/src/core/engine.ts @@ -283,8 +283,8 @@ export class Engine { queries.push({ metrics: [q.metrics[i]], dimensions: q.dimensions, - clauses: (q.clauses) ? q.clauses : [], - sort: (q.sort) ? q.sort : [] + clauses: q.clauses, + sort: q.sort, }); } const views = queries.map((query) => { @@ -295,11 +295,11 @@ export class Engine { } else { - let query = { + let query: Query = { metrics: q.metrics, dimensions: q.dimensions, - clauses: (q.clauses) ? q.clauses : [], - sort: (q.sort) ? q.sort : [] + clauses: q.clauses, + sort: q.sort }; return ViewHandler.growView(query, this.getCover(query)); } diff --git a/src/util/graph.spec.ts b/src/util/graph.spec.ts index 8dc8ea982468a6e32235da45507d7dae24220dc8..b6621fedfb5772676948e5ca7e32eb20473fc1d6 100644 --- a/src/util/graph.spec.ts +++ b/src/util/graph.spec.ts @@ -193,7 +193,7 @@ describe("graph class", () => { }); expect(g.addView(view)).to.be.true; - const query: Query = { metrics: [], dimensions: [dim] }; + const query: Query = { metrics: [], dimensions: [dim], sort: [], clauses: []}; let children = g.cover(query); expect(children).to.be.an("array"); expect(children).to.have.length(1); @@ -257,7 +257,8 @@ describe("graph class", () => { expect(g.addView(views[i])).to.be.true; } - const query: Query = { metrics: [mets[0], mets[1]], dimensions: [dims[0], dims[1]] }; + const query: Query = { metrics: [mets[0], mets[1]], dimensions: [dims[0], dims[1]], + sort: [], clauses: [] }; let children = g.cover(query); expect(children).to.be.an("array"); expect(children).to.have.length(1); @@ -296,7 +297,8 @@ describe("graph class", () => { expect(g.addView(view)).to.be.true; - const query: Query = { metrics: [], dimensions: [dims[1], dims[2]] }; + const query: Query = { metrics: [], dimensions: [dims[1], dims[2]], + sort: [], clauses: [] }; let children = g.cover(query); expect(children).to.be.an("array"); expect(children).to.have.length(1); @@ -335,7 +337,8 @@ describe("graph class", () => { expect(g.addView(view)).to.be.true; - const query: Query = { metrics: [], dimensions: [] }; + const query: Query = { metrics: [], dimensions: [], + sort: [], clauses: [] }; let children = g.cover(query); expect(children).to.be.an("array"); expect(children).to.be.empty; @@ -390,7 +393,8 @@ describe("graph class", () => { expect(g.addView(view2)).to.be.true; expect(g.addView(view3)).to.be.true; - const query: Query = { metrics: [], dimensions: dims, clauses: [clause2] }; + const query: Query = { metrics: [], dimensions: dims, clauses: [clause2], + sort: []}; let children = g.cover(query); expect(children).to.be.an("array"); expect(children).to.have.length(2); @@ -503,7 +507,8 @@ describe("graph class", () => { expect(g.addView(view0)).to.be.true; - const query: Query = { metrics: [], dimensions: dims, clauses: testClauses }; + const query: Query = { metrics: [], dimensions: dims, clauses: testClauses, + sort: []}; let children = g.cover(query); expect(children).to.have.length(1); expect(children[0].id === view0.id).to.be.true; @@ -627,7 +632,8 @@ describe("graph class", () => { expect(g.addView(views[i])).to.be.true; } - const query: Query = { metrics: [], dimensions: dims, clauses: testClauses }; + const query: Query = { metrics: [], dimensions: dims, clauses: testClauses, + sort: []}; let children = g.cover(query); expect(children).to.have.length(1); expect(children[0].id === views[0].id).to.be.true; diff --git a/src/util/graph.ts b/src/util/graph.ts index 36a5ea1070d368b1b145ba7c9a37393b32b74ddc..3eb989b786abbec3a48846999b307484e6fdb3ee 100644 --- a/src/util/graph.ts +++ b/src/util/graph.ts @@ -321,7 +321,7 @@ export class Graph { public cover(q: Query): View[] { const metrics = q.metrics; const dimensions = q.dimensions; - const clauses = (q.clauses) ? q.clauses : []; + const clauses = q.clauses let output: View[] = []; let verticesIds = this.verticesInQuery(q); @@ -621,7 +621,7 @@ export class Graph { private verticesInQuery(q: Query): string[] { const metrics = q.metrics; const dimensions = q.dimensions; - const clauses = (q.clauses) ? q.clauses : []; + const clauses = q.clauses; let verticesIds = metrics.map((met) => met.name); verticesIds = verticesIds.concat(dimensions.map((dim) => dim.name)); for (let i = 0; i < clauses.length; ++i) { diff --git a/src/util/viewHandler.ts b/src/util/viewHandler.ts index 6ecc43f06fbb1eeb2888319080fb4a79e80ddf91..72914f8e941859b228696d2fb615f11f7dcf8a05 100644 --- a/src/util/viewHandler.ts +++ b/src/util/viewHandler.ts @@ -60,8 +60,8 @@ export class ViewHandler { metrics: q.metrics, dimensions: q.dimensions, origin: false, - clauses: (q.clauses) ? q.clauses : [], - sort: (q.sort) ? q.sort : [], + clauses: q.clauses, + sort: q.sort, operation: { opcode: Opcode.JOIN, values: views.map((i) => i) @@ -85,8 +85,8 @@ export class ViewHandler { metrics: q.metrics, dimensions: q.dimensions, origin: false, - clauses: (q.clauses) ? q.clauses : [], - sort: (q.sort) ? q.sort : [], + clauses: q.clauses, + sort: q.sort, operation: { opcode: Opcode.REDUCE, values: [view] @@ -358,7 +358,8 @@ export class ViewHandler { const partialQuery: Query = { metrics: mets, dimensions: dims, - clauses: clauses + clauses: clauses, + sort: [] }; const partial = ViewHandler.queryJoin(partialQuery, [partial0, partial1]); diff --git a/test/scenario.ts b/test/scenario.ts index 570d6ef8d5c25c70a02e451e5e4517700a4ea9ae..6f72da335cd4ed6e9427ec8deaeff794c7072607 100644 --- a/test/scenario.ts +++ b/test/scenario.ts @@ -27,6 +27,7 @@ import { Clause } from "../src/core/clause"; import { AggregationType, RelationType , DataType} from "../src/common/types"; import { ViewHandler } from "../src/util/viewHandler"; import { EngineScenario, AdapterScenario, DataCtrlScenario } from "../src/util/scenarioHandler"; +import { Query } from "../src/common/query"; const configPath = process.env.BLENDB_SCHEMA_FILE; const config = ConfigParser.parse(configPath); @@ -50,8 +51,15 @@ for (let i in config.buildViews){ views[view.alias] = view.view; } +let emptyQuery: Query = { + metrics: [], + dimensions: [], + sort: [], + clauses: [] +}; + /** - * Create new filters to use in clause and test + * Create new filters to use in clause and test * the clauses */ const filters: { [key: string]: Filter } = { @@ -133,7 +141,7 @@ const subdims : {[key:string]: Dimension} = { // Clauses -const clauses: { [key: string]: Clause } = { +const clauses: { [key: string]: Clause } = { "lastDay": new Clause({filters: [filters["equal"]]}), "undefined": @@ -162,19 +170,22 @@ const clauses: { [key: string]: Clause } = { const JoinWithAncestors = ViewHandler.growView({ metrics: [mets["met:sell:count:quantity"]], dimensions: [dims["dim:seller:id"],dims["dim:provider:id"]], - clauses: [] + clauses: [], + sort: [] },[views["Sell"]]); const joinWithNoMetrics = ViewHandler.growView({ - metrics: [], + metrics: emptyQuery.metrics, dimensions: [dims["dim:product:name"],dims["dim:seller:name"]], - clauses: [] + clauses: [], + sort: [] }, [views["Product"],views["Sell"],views["Seller"]]); const growOneView = ViewHandler.growView({ metrics: [mets["met:seller:min:age"]], dimensions: [dims["dim:seller:name"],dims["dim:seller:sex"]], - clauses: [] + clauses: [], + sort: [] }, [views["Seller"]]); const multipleClause = ViewHandler.growView({ @@ -182,44 +193,56 @@ const multipleClause = ViewHandler.growView({ dimensions: [dims["dim:sell:datein"],dims["dim:seller:name"], dims["dim:client:name"]], // and between filters => (A) and (B) - clauses: [clauses["expired"],clauses["averageBought"]] + clauses: [clauses["expired"],clauses["averageBought"]], + sort: [] }, [views["Sell"],views["Seller"],views["Client"],views["Product"]]); const singleClause = ViewHandler.growView({ metrics: [mets["met:sell:avg:quantity"]], dimensions: [dims["dim:sell:datein"],dims["dim:seller:name"], dims["dim:client:name"]], - clauses: [clauses["expiredAndAverage"]] + clauses: [clauses["expiredAndAverage"]], + sort: [] }, [views["Sell"],views["Seller"],views["Client"],views["Product"]]); const equalfilter = ViewHandler.queryJoin({ - metrics: [], + metrics: emptyQuery.metrics, dimensions: [dims["dim:client:name"],dims["dim:product:validity"]], - clauses: [clauses["lastDay"]] + clauses: [clauses["lastDay"]], + sort: [] },[views["Sell"],views["Client"],views["Product"]]); const withSortView = ViewHandler.queryJoin({ metrics: [mets["met:sell:sum:quantity"]], dimensions: [dims["dim:client:name"]], + clauses: [], sort: [mets["met:sell:sum:quantity"]] },[ViewHandler.queryReduce({ metrics: [mets["met:sell:sum:quantity"]], - dimensions: [dims["dim:client:id"]] + dimensions: [dims["dim:client:id"]], + clauses: [], + sort: [], },views["Sell"]),views["Client"]]); const subDimView = ViewHandler.queryJoin({ - metrics : [], + metrics: emptyQuery.metrics, dimensions : [dims["dim:sell:datein"],subdims["subdims_day"], - subdims["subdims_month"],subdims["subdims_year"]]}, + subdims["subdims_month"],subdims["subdims_year"]], + clauses: [], + sort: []}, [ViewHandler.queryReduce({ - metrics: [], - dimensions: [dims["dim:sell:datein"]] + metrics: emptyQuery.metrics, + dimensions: [dims["dim:sell:datein"]], + clauses: [], + sort: [] },views["Sell"]),views["Sell"]]); const joinOneView = ViewHandler.queryJoin({ metrics: [mets["met:product:avg:pricein"]], - dimensions: [] + dimensions: emptyQuery.dimensions, + clauses: [], + sort: [] },[views["Product"]]); const reduceAsView = ViewHandler.queryReduce({ @@ -227,16 +250,20 @@ const reduceAsView = ViewHandler.queryReduce({ mets["met:sell:count:quantity"]], dimensions: [dims["dim:sell:registered"], dims["dim:product:id"], dims["dim:seller:id"], dims["dim:client:id"],dims["dim:sell:datein"]], +clauses: [], sort: [mets["met:sell:sum:quantity"]] },views["Sell"]); const clientAverageBought = ViewHandler.queryReduce({ metrics: [mets["met:sell:avg:quantity"]], dimensions: [dims["dim:client:name"]], - clauses: [clauses["averageBought"]] + clauses: [clauses["averageBought"]], + sort: [] },ViewHandler.queryJoin({ metrics: [mets["met:sell:avg:quantity"]], - dimensions: [dims["dim:client:name"], dims["dim:seller:id"]] + dimensions: [dims["dim:client:name"], dims["dim:seller:id"]], + clauses: [], + sort: [] },[views["Sell"],views["Client"]])); @@ -257,44 +284,56 @@ const wrongDim = new Dimension({ name: "dim:this:is:just:a:test", dataType: Data // Queries const queryNoParent = { - metrics: [mets["met:sell:count:quantity"]], - dimensions: [subdims["subdims_none"]] + metrics: [mets["met:sell:count:quantity"]], + dimensions: [subdims["subdims_none"]], + clauses: emptyQuery.clauses, + sort: emptyQuery.sort } const queryMetsDims = { metrics : Object.keys(mets).map((key) => mets[key]), - dimensions : Object.keys(dims).map((key) => dims[key]) + dimensions : Object.keys(dims).map((key) => dims[key]), + clauses: emptyQuery.clauses, + sort: emptyQuery.sort }; const queryNoMets = { - metrics: [wrongMet], - dimensions: [dims["dim:product:name"]] + metrics: [wrongMet], + dimensions: [dims["dim:product:name"]], + clauses: emptyQuery.clauses, + sort: emptyQuery.sort }; -const queryNoDims = { +const queryNoDims = { metrics: [mets["met:buyout:min:quantity"]], - dimensions: [wrongDim] + dimensions: [wrongDim], + clauses: emptyQuery.clauses, + sort: emptyQuery.sort } const queryProduct = { metrics: [mets["met:product:avg:pricein"], mets["met:product:max:pricein"], mets["met:product:min:pricein"], mets["met:product:avg:priceout"],mets["met:product:max:priceout"],mets["met:product:min:priceout"]], - dimensions: [dims["dim:product:name"], dims["dim:product:validity"],dims["dim:product:id"]] + dimensions: [dims["dim:product:name"], dims["dim:product:validity"],dims["dim:product:id"]], + clauses: emptyQuery.clauses, + sort: emptyQuery.sort }; const queryActive = { metrics: [mets["met:seller:max:age"]], dimensions: [dims["dim:seller:name"],dims["dim:seller:status"]], - clauses: [clauses["equalClauseView"]] + clauses: [clauses["equalClauseView"]], + sort: emptyQuery.sort } // Metrics -let emptyMetrics: Metric[] = []; -const querySubDim = { - metrics : emptyMetrics - , dimensions : [subdims["subdims_day"],subdims["subdims_month"]] +const querySubDim = { + metrics : emptyQuery.metrics + , dimensions : [subdims["subdims_day"],subdims["subdims_month"]], + clauses: emptyQuery.clauses, + sort: emptyQuery.sort } // Exports @@ -335,18 +374,26 @@ export const adapterScenario: AdapterScenario = { export const dataCtrlScenario: DataCtrlScenario = { wrongMet: { metrics: [wrongMet], - dimensions: [dims["dim:product:id"]] + dimensions: [dims["dim:product:id"]], + clauses: [], + sort: [] }, wrongDim: { metrics: [mets["met:sell:avg:quantity"]], - dimensions: [wrongDim] }, + dimensions: [wrongDim], + clauses: [], + sort: [] }, correct: { metrics: [mets["met:buyout:avg:quantity"]], - dimensions: [dims["dim:provider:id"]] + dimensions: [dims["dim:provider:id"]], + clauses: [], + sort: [] }, clausal: { metrics: [mets["met:product:avg:pricein"]], dimensions: [dims["dim:product:name"], - dims["dim:product:id"]] - } + dims["dim:product:id"]], + clauses: [], + sort: [] + } };