diff --git a/config/ci_test.yaml.example b/config/ci_test.yaml.example index eed9cb2bd5d5ada6b33700bfcee60cd13ef22d90..458dec196eed6805e077a641ff94497a63d71683 100644 --- a/config/ci_test.yaml.example +++ b/config/ci_test.yaml.example @@ -6,9 +6,10 @@ views: - config/market_views.yaml.example obj: - - alias: "Seller" + alias: "view:Seller" data: "test/postgres/fixtures/seller.json" origin: true + aliasAsName: true dimensions: - "dim:seller:name" - "dim:seller:sex" diff --git a/config/config.yaml.example b/config/config.yaml.example index eed9cb2bd5d5ada6b33700bfcee60cd13ef22d90..11c7451116e1aa6122386c012f6d9147940e402e 100644 --- a/config/config.yaml.example +++ b/config/config.yaml.example @@ -6,7 +6,7 @@ views: - config/market_views.yaml.example obj: - - alias: "Seller" + alias: "view:Seller" data: "test/postgres/fixtures/seller.json" origin: true dimensions: diff --git a/config/market_main.yaml.example b/config/market_main.yaml.example index 36893eba1fb0610e0d08079d0031b2aa09e4b1e3..32db12921d05daee820913e0587e4093999ed2b4 100644 --- a/config/market_main.yaml.example +++ b/config/market_main.yaml.example @@ -3,7 +3,7 @@ views: - config/market_views.yaml.example obj: - - alias: "Seller" + alias: "view:Seller" data: "test/postgres/fixtures/seller.json" origin: true dimensions: diff --git a/config/market_views.yaml.example b/config/market_views.yaml.example index 5c3580db3ab4f7b8bbba40431f6916d6d1e70a0d..f9d9ef2c290d7a30a40f1f1859af914ecd2609e4 100644 --- a/config/market_views.yaml.example +++ b/config/market_views.yaml.example @@ -1,7 +1,8 @@ - - alias: "Product" + alias: "view:Product" data: "test/postgres/fixtures/product.json" origin: true + aliasAsName: true dimensions: - "dim:product:name" - "dim:product:validity" @@ -14,17 +15,19 @@ - "met:product:max:priceout" - "met:product:min:priceout" - - alias: "Client" + alias: "view:Client" data: "test/postgres/fixtures/client.json" origin: true + aliasAsName: true dimensions: - "dim:client:name" - "dim:client:cpf" - "dim:client:id" - - alias: "Sell" + alias: "view:Sell" data: "test/postgres/fixtures/sell.json" origin: true + aliasAsName: true dimensions: - "dim:sell:registered" - "dim:product:id" @@ -36,9 +39,10 @@ - "met:sell:avg:quantity" - "met:sell:count:quantity" - - alias: "Buyout" + alias: "view:Buyout" data: "test/postgres/fixtures/buyout.json" origin: true + aliasAsName: true dimensions: - "dim:buyout:datein" - "dim:provider:id" @@ -48,23 +52,26 @@ - "met:buyout:max:quantity" - "met:buyout:min:quantity" - - alias: "Provider" + alias: "view:Provider" data: "test/postgres/fixtures/provider.json" origin: true + aliasAsName: true dimensions: - "dim:provider:name" - "dim:provider:id" - - alias: "Distribute" + alias: "view:Distribute" data: "test/postgres/fixtures/distribute.json" origin: true + aliasAsName: true dimensions: - "dim:provider:id" - "dim:product:id" - - alias: "ActiveSeller" + alias: "view:ActiveSeller" data: "test/postgres/fixtures/activeseller.json" origin: true + aliasAsName: true dimensions: - "dim:seller:name" - "dim:seller:status" diff --git a/scripts/schema.ts b/scripts/schema.ts index 07da0525a2e6aec2e7d1fa3de4aaceedc11beed7..1a8ced75b1fadc8e461afd1d436addc168035dd1 100755 --- a/scripts/schema.ts +++ b/scripts/schema.ts @@ -53,13 +53,13 @@ for (let i = 0; i < config.buildViews.length; ++i) { // Cria uma tabela let output = "-- View: " + alias + "\n"; if (process.env.BLENDB_ADAPTER === "postgres") { - output += "DROP VIEW IF EXISTS view_" + view.id + " CASCADE;\n"; - output += "CREATE OR REPLACE VIEW view_" + view.id + " AS\n"; + output += "DROP VIEW IF EXISTS " + view.name + " CASCADE;\n"; + output += "CREATE OR REPLACE VIEW " + view.name + " AS\n"; } else if (process.env.BLENDB_ADAPTER === "monet") { - output += "DROP VIEW view_" + view.id + " CASCADE;\n"; - output += "CREATE VIEW view_" + view.id + " AS\n"; + output += "DROP VIEW " + view.name + " CASCADE;\n"; + output += "CREATE VIEW " + view.name + " AS\n"; } else { diff --git a/src/adapter/postgres.spec.ts b/src/adapter/postgres.spec.ts index 7bd2ca34d1422cc7c010ec2f6defbaa222ab0a24..acdd1a4f31e1532028f58a4b338848aed4a787f1 100644 --- a/src/adapter/postgres.spec.ts +++ b/src/adapter/postgres.spec.ts @@ -37,7 +37,6 @@ describe("Sql adapter", () => { // Arrow function not used to get acces to this and skip the test const configPath = process.env.BLENDB_SCHEMA_FILE; config = ConfigParser.parse(configPath); - if (config.adapter === "postgres") { fixture = new FixPostgres(config.connection); fixture.load(config.loadViews, (err) => { diff --git a/src/adapter/sql.ts b/src/adapter/sql.ts index 8958805c978b594bb02a148965f025c2b25b19d8..6bf00505524ba3f0f160a4ee158c8bece2d8e298 100644 --- a/src/adapter/sql.ts +++ b/src/adapter/sql.ts @@ -111,7 +111,7 @@ export abstract class SQLAdapter extends Adapter { sort = " ORDER BY " + order; } - return withClause + "SELECT * FROM " + this.viewName(view) + sort + ";"; + return withClause + "SELECT * FROM " + view.name + sort + ";"; } /** @@ -126,7 +126,7 @@ export abstract class SQLAdapter extends Adapter { let queue: View[] = op.values.map((i) => i); const output: QueryAndName[] = [{ query: this.operation(op, view), - name: this.viewName(view) + name: view.name, }]; const map: {[key: string]: boolean } = {}; @@ -139,7 +139,7 @@ export abstract class SQLAdapter extends Adapter { map[partial.id] = true; output.unshift({ query: query, - name: this.viewName(partial) + name: partial.name }); queue = queue.concat(partial.operation.values); } @@ -149,14 +149,6 @@ export abstract class SQLAdapter extends Adapter { return output; } - /** - * The translated name of a view into SQL databases. - * @param view - View which the name will be built. - */ - protected viewName(view: View): string { - return "view_" + view.id; - } - /** * Constructs a query from a view based in a given operation * @param op - Operation used to construct the view. @@ -221,9 +213,9 @@ export abstract class SQLAdapter extends Adapter { if (dimMap[i].views.length > 1) { const views = dimMap[i].views; const dim = dimMap[i].dim; - const leftSide = this.buildColumn(dim, views.shift().id); + const leftSide = this.buildColumn(dim, views.shift().name); while (views.length > 0) { - const rightSide = this.buildColumn(dim, views.shift().id); + const rightSide = this.buildColumn(dim, views.shift().name); conds.push("(" + leftSide + "=" + rightSide + ")"); } } @@ -232,7 +224,7 @@ export abstract class SQLAdapter extends Adapter { // Assembly const projection = "SELECT " + projElem.join(", "); - const sources = "FROM " + partials.map((i) => this.viewName(i)).join(", "); + const sources = "FROM " + partials.map((i) => (i.name)).join(", "); const selection = (conds.length > 0) ? " WHERE " + conds.join(" AND ") : ""; let grouping = ""; @@ -371,11 +363,11 @@ export abstract class SQLAdapter extends Adapter { /** * Add quotes and the proper view name to a attribute in a SQL query. * @param item - Attribute to get the name quoted. - * @param id - View id used to build the view name. + * @param viewName - View name used to build the view name. */ - private buildColumn (item: Metric|Dimension, id: string): string { + private buildColumn (item: Metric|Dimension, viewName: string): string { const quotedName = "\"" + item.name + "\""; - return "view_" + id + "." + quotedName; + return viewName + "." + quotedName; } /** @@ -404,8 +396,8 @@ export abstract class SQLAdapter extends Adapter { return ""; } - const viewId = map[filter.target.name].id; - const leftSide = this.buildColumn(filter.target, viewId); + const viewName = map[filter.target.name].name; + const leftSide = this.buildColumn(filter.target, viewName); const quotedValue = "'" + filter.value + "'"; const castedValue = this.typeCast(quotedValue, filter.target.dataType); return this.applyOperator(leftSide, castedValue, filter.operator); @@ -419,7 +411,7 @@ export abstract class SQLAdapter extends Adapter { private translateMetric(metric: Metric, view: View): string { const func = this.getAggregateFunction(metric.aggregation, view.origin); const quotedName = "\"" + metric.name + "\""; - const extMetric = func + "(" + this.buildColumn(metric, view.id) + ")"; + const extMetric = func + "(" + this.buildColumn(metric, view.name) + ")"; return extMetric + " AS " + quotedName; } @@ -434,7 +426,7 @@ export abstract class SQLAdapter extends Adapter { ancestor: Dimension, view: View): DimTranslation { const quotedName = "\"" + dimension.name + "\""; - let extDimension = this.buildColumn(ancestor, view.id); + let extDimension = this.buildColumn(ancestor, view.name); let aux = dimension; let expanded = false; while (aux.name !== ancestor.name) { diff --git a/src/core/view.ts b/src/core/view.ts index 6d15a1dbe9fe4b75fb19a181b09478dbd423e202..4f54013d24ad0bd2ee823cabd1f4ad4473b7da73 100644 --- a/src/core/view.ts +++ b/src/core/view.ts @@ -46,6 +46,10 @@ export interface ViewOptions { sort?: (Metric|Dimension)[]; /** Definition of how to create this view using other views. */ operation?: Operation; + /** Defines if views's name will be its alias or automatically generated. */ + aliasAsName?: boolean; + /** Fake identifier (human understandable) of the view. */ + alias?: string; } /** @@ -54,7 +58,7 @@ export interface ViewOptions { * these objects can only be found in views. */ export class View { - /** Hash of components that unique identify the clause. */ + /** Hash of components that unique identify the view. */ public readonly id: string; /** Set of metrics contained into the view. */ public readonly metrics: Metric[]; @@ -68,6 +72,8 @@ export class View { public readonly origin: boolean; /** Definition of how to create this view using other views. */ public readonly operation: Operation; + /** View identifier, used on query generation as "table" name */ + public readonly name: string; /** * Create a view. @@ -96,5 +102,13 @@ export class View { const clausesIds = this.clauses.map((clause) => clause.id); const join = metNames.concat(dimNames).concat(clausesIds).sort(); this.id = Hash.sha1(join); + + if ( options.aliasAsName ) { + this.name = "\"" + options.alias + "\""; + } else { + this.name = "view_" + this.id; + } + } + } diff --git a/src/util/configParser.ts b/src/util/configParser.ts index 6ebf9d67e4972eedaea42cf8d2200f0b04dbf81c..80b3041e086e2a5350e7be2a195a3f2cac083b57 100644 --- a/src/util/configParser.ts +++ b/src/util/configParser.ts @@ -50,6 +50,8 @@ export interface ViewParsingOptions { metrics: string[]; /** Set of (stringified) clauses applied to the view. */ clauses?: string[]; + /** Inform if the view's name will be it's alias or id */ + aliasAsName?: boolean; } /** @@ -300,7 +302,9 @@ export class ConfigParser { metrics: [], dimensions: [], origin: opts.origin, + alias: (opts.alias) ? opts.alias : "", clauses: [], + aliasAsName: (opts.aliasAsName) ? opts.aliasAsName : false, operation: { opcode: Opcode.PUSH, values: [] diff --git a/test/monet/fixture.ts b/test/monet/fixture.ts index bf6e7eabb00f42b42b427feb9871b03c67934d77..835763bf4b33cf6197830dcd325f24edabcb2bf4 100644 --- a/test/monet/fixture.ts +++ b/test/monet/fixture.ts @@ -112,7 +112,7 @@ export class Fixture { } private extractDataView(view: View, filePath: string): string[]{ - let name = "view_" + view.id; + let name = view.name; let data: string[] = []; let rows = JSON.parse(fs.readFileSync(filePath, {encoding : "utf8"})); for (let i = 0; i < rows.length; ++i) { @@ -132,7 +132,7 @@ export class Fixture { } private createTransSet(view: View, filePath: string, create: boolean): string { - let name = "view_" + view.id; + let name = view.name; let init: string = ""; let props = []; for (let i = 0; i < view.metrics.length; ++i) { diff --git a/test/postgres/fixture.ts b/test/postgres/fixture.ts index 1142f062e9f9a137ca34be7807c8ae6bea8ac0a4..57e761a4d026c0c8551f94b5148c5493ab689c77 100644 --- a/test/postgres/fixture.ts +++ b/test/postgres/fixture.ts @@ -122,7 +122,7 @@ export class Fixture { } private extractDataView(view: View, filePath: string): string[]{ - let name = "view_" + view.id; + let name = view.name; let data: string[] = []; let rows = JSON.parse(fs.readFileSync(filePath, {encoding : "utf8"})); for (let i = 0; i < rows.length; ++i) { @@ -142,7 +142,7 @@ export class Fixture { } private createTransSet(view: View, filePath: string, create: boolean): string { - let name = "view_" + view.id; + let name = view.name; let init: string = ""; let props = []; for (let i = 0; i < view.metrics.length; ++i) { diff --git a/test/scenario.ts b/test/scenario.ts index 570d6ef8d5c25c70a02e451e5e4517700a4ea9ae..71c10136ed977625cc3ac545ed5febac17724697 100644 --- a/test/scenario.ts +++ b/test/scenario.ts @@ -163,19 +163,19 @@ const JoinWithAncestors = ViewHandler.growView({ metrics: [mets["met:sell:count:quantity"]], dimensions: [dims["dim:seller:id"],dims["dim:provider:id"]], clauses: [] -},[views["Sell"]]); +},[views["view:Sell"]]); const joinWithNoMetrics = ViewHandler.growView({ metrics: [], dimensions: [dims["dim:product:name"],dims["dim:seller:name"]], clauses: [] -}, [views["Product"],views["Sell"],views["Seller"]]); +}, [views["view:Product"],views["view:Sell"],views["view:Seller"]]); const growOneView = ViewHandler.growView({ metrics: [mets["met:seller:min:age"]], dimensions: [dims["dim:seller:name"],dims["dim:seller:sex"]], clauses: [] -}, [views["Seller"]]); +}, [views["view:Seller"]]); const multipleClause = ViewHandler.growView({ metrics: [mets["met:sell:avg:quantity"]], @@ -183,20 +183,20 @@ const multipleClause = ViewHandler.growView({ dims["dim:client:name"]], // and between filters => (A) and (B) clauses: [clauses["expired"],clauses["averageBought"]] -}, [views["Sell"],views["Seller"],views["Client"],views["Product"]]); +}, [views["view:Sell"],views["view:Seller"],views["view:Client"],views["view: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"]] -}, [views["Sell"],views["Seller"],views["Client"],views["Product"]]); +}, [views["view:Sell"],views["view:Seller"],views["view:Client"],views["view:Product"]]); const equalfilter = ViewHandler.queryJoin({ metrics: [], dimensions: [dims["dim:client:name"],dims["dim:product:validity"]], clauses: [clauses["lastDay"]] -},[views["Sell"],views["Client"],views["Product"]]); +},[views["view:Sell"],views["view:Client"],views["view:Product"]]); const withSortView = ViewHandler.queryJoin({ metrics: [mets["met:sell:sum:quantity"]], @@ -205,7 +205,7 @@ const withSortView = ViewHandler.queryJoin({ },[ViewHandler.queryReduce({ metrics: [mets["met:sell:sum:quantity"]], dimensions: [dims["dim:client:id"]] - },views["Sell"]),views["Client"]]); + },views["view:Sell"]),views["view:Client"]]); const subDimView = ViewHandler.queryJoin({ metrics : [], @@ -214,13 +214,13 @@ const subDimView = ViewHandler.queryJoin({ [ViewHandler.queryReduce({ metrics: [], dimensions: [dims["dim:sell:datein"]] -},views["Sell"]),views["Sell"]]); +},views["view:Sell"]),views["view:Sell"]]); const joinOneView = ViewHandler.queryJoin({ metrics: [mets["met:product:avg:pricein"]], dimensions: [] -},[views["Product"]]); +},[views["view:Product"]]); const reduceAsView = ViewHandler.queryReduce({ metrics: [mets["met:sell:sum:quantity"],mets["met:sell:avg:quantity"], @@ -228,7 +228,7 @@ 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"]], sort: [mets["met:sell:sum:quantity"]] -},views["Sell"]); +},views["view:Sell"]); const clientAverageBought = ViewHandler.queryReduce({ metrics: [mets["met:sell:avg:quantity"]], @@ -237,12 +237,12 @@ const clientAverageBought = ViewHandler.queryReduce({ },ViewHandler.queryJoin({ metrics: [mets["met:sell:avg:quantity"]], dimensions: [dims["dim:client:name"], dims["dim:seller:id"]] -},[views["Sell"],views["Client"]])); +},[views["view:Sell"],views["view:Client"]])); -const viewProduct = views["Product"]; +const viewProduct = views["view:Product"]; -const viewActiveSeller = views["ActiveSeller"]; +const viewActiveSeller = views["view:ActiveSeller"]; const wrongMet = new Metric({ name: "met:this:is:just:a:test", @@ -318,7 +318,7 @@ export const engineScenario: EngineScenario = { }; export const adapterScenario: AdapterScenario = { - materializedView: views["Product"], + materializedView: views["view:Product"], sortView: withSortView, joinWithOneView: joinOneView, singleClause: singleClause,