diff --git a/src/core/engine.spec.ts b/src/core/engine.spec.ts index a1dde4b77635165cbf237348538cdb94823813e6..4498640cdc9ea5825330de53875508747e0d4639 100644 --- a/src/core/engine.spec.ts +++ b/src/core/engine.spec.ts @@ -23,7 +23,8 @@ import { expect } from "chai"; import { Engine } from "./engine"; import { Metric } from "./metric"; import { Dimension } from "./dimension"; -import { FilterOperator } from "./filter"; +import { Filter, FilterOperator } from "./filter"; +import { Clause } from "./clause"; import { View } from "./view"; import { engineScenario } from "../../test/scenario"; @@ -119,6 +120,36 @@ describe("engine class", () => { expect(optimalView.id).to.be.equal(views[0].id); }); + it("should be create a fill that cover the query, that match perfectly with a existent view, with clauses", () => { + const clause = new Clause({ + filters: [new Filter({ + target: dim[2], + operator: FilterOperator.NOTEQUAL, + value: "1" + })] + }); + let query = { + metrics : [met[5], met[6], met[7]] + , dimensions : [dim[2]] + , clauses: [clause] + }; + let optimalView = engine.query(query); + expect(optimalView).to.be.an("object"); + expect(optimalView).to.have.property("metrics"); + expect(optimalView).to.have.property("dimensions"); + expect(optimalView).to.have.property("childViews"); + expect(optimalView).to.have.property("materialized"); + expect(optimalView.metrics).to.be.an("array"); + expect(optimalView.dimensions).to.be.an("array"); + expect(optimalView.childViews).to.be.an("array"); + expect(optimalView.metrics).to.have.length(3); + expect(optimalView.dimensions).to.have.length(1); + expect(optimalView.childViews).to.have.length(0); + expect(optimalView.materialized).to.be.true; + + expect(optimalView.id).to.be.equal(views[9].id); + }); + it("should be create a fill that cover the query, using sub dimensions", () => { let emptyMetrics: Metric[] = []; let query = { diff --git a/src/core/engine.ts b/src/core/engine.ts index a0209b5eb61de40f4969aa252dd9f2f78eecd729..3e39b7bbc37cc72175e7f57567278bc05d2412a5 100644 --- a/src/core/engine.ts +++ b/src/core/engine.ts @@ -152,18 +152,23 @@ export class Engine { // If all the metrics and dimensions are the same and only exist one child view // return this single child view + const metrics = q.metrics; + const dimensions = q.dimensions; + const clauses = ((q.clauses) ? q.clauses : []); if (optimalViews.length === 1 && - optimalViews[0].metrics.length === q.metrics.length && - optimalViews[0].dimensions.length === q.dimensions.length && - optimalViews[0].metrics.every((item) => q.metrics.indexOf(item) !== -1) && - optimalViews[0].dimensions.every((item) => q.dimensions.indexOf(item) !== -1)) { + optimalViews[0].metrics.length === metrics.length && + optimalViews[0].dimensions.length === dimensions.length && + optimalViews[0].clauses.length === clauses.length && + optimalViews[0].metrics.every((item) => metrics.indexOf(item) !== -1) && + optimalViews[0].dimensions.every((item) => dimensions.indexOf(item) !== -1) && + perfectMatch(optimalViews[0].clauses, clauses)) { return optimalViews[0]; } else { let options = { - metrics: q.metrics, - dimensions: q.dimensions, - clauses: ((q.clauses) ? q.clauses : []), + metrics: metrics, + dimensions: dimensions, + clauses: clauses, materialized: false, origin: false, // Never a dynamic generated view will be origin childViews: optimalViews @@ -175,3 +180,10 @@ export class Engine { } } } + +function perfectMatch (array1: Clause[], + array2: Clause[]) { + return array1.every((item: Clause) => { + return array2.some((otherItem: Clause) => item.id === otherItem.id); + }); +} diff --git a/src/util/graph.ts b/src/util/graph.ts index 881ce7df1f85a1955860cb1ac7d268be6e81cc42..359ac14c7895cb054ffd5602013760345863ed26 100644 --- a/src/util/graph.ts +++ b/src/util/graph.ts @@ -416,7 +416,8 @@ export class Graph { // Pick all views that contain the root vertex for (let i in root.neighbors) { views = views.concat(root.neighbors[i].filter((item) => { - return item.isView; + return item.isView && + this.passConstraints(clauses, item.view.clauses); }).map((item) => item.view)); } @@ -480,7 +481,7 @@ export class Graph { // Checks if the new option is better than the best until now let actualCover = actualCoverMet.length + actualCoverDim.length; - if (actualCover < bestCover || + if (actualCover > bestCover || (actualCover === bestCover && bestView.dimensions.length > actual.dimensions.length)) { bestCover = actualCover;