Skip to content
Snippets Groups Projects

Issue #6: Create selector of optimal View and sql query generator for Postgres adpter

Merged Issue #6: Create selector of optimal View and sql query generator for Postgres adpter
11 unresolved threads
Merged Lucas Fernandes de Oliveira requested to merge issue/6 into master
11 unresolved threads
Files
7
+ 150
0
/*
Please register or sign in to reply
* Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre
* Departamento de Informatica - Universidade Federal do Parana
*
* This file is part of blend.
*
* blend 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.
*
* blend 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 blend. If not, see <http://www.gnu.org/licenses/>.
*/
import { View } from "../core/view";
import { Adapter } from "../core/adapter";
import { AggregationType } from "../common/aggregationType";
interface ParsedView {
query: string;
view: View;
alias: string;
};
export class PostGresAdapter extends Adapter{
Please register or sign in to reply
public getDataFromView(view: View): string {
// queryfyView does not put the final ;, it need to be put apart
return this.queryfyView(view, "v0") + ";\n";
}
public materializeView(view: View): string {
return null;
}
private queryfyView (view: View, alias: string, degree: number = 0): string {
Please register or sign in to reply
let ident = " ".repeat(degree + 1);
let lessIdent = " ".repeat(degree);
let sql: string = lessIdent + "(\n";
    • Acho que não precisa definir tipos nessas variáveis, porque o tipo é inferido a partir da definição. Ou seja, como lessIdent é uma string, lessIdent + "(\n)" também é uma string e o typescript automaticamente infere que a variavel sql tem que ser do tipo string. Ver Type Inference.

      Sem essas definições de tipos em variáveis locais triviais, acho que o código fica mais limpo. A definição de tipos faz mais sentido e é mais importante em variáveis que não são locais (parâmetros de funções, atributos de classes, etc.)

Please register or sign in to reply
let metrics: string[] = view.metrics.map((metric: string) => {
let func: string = this.metricFunction(view, metric);
let extMetric: string = func + "(" + metric + ")";
return extMetric;
});
let dimensions: string[] = view.dimensions.map((item: string) => {
return alias + "." + item;
});
if (view.materialized) {
sql += ident + "SELECT " + metrics.join(", ") + ", " + dimensions.join(", ") + "\n";
sql += ident + "FROM " + view.id + "\n";
sql += ident + "GROUP BY " + dimensions.join(", ") + "\n";
sql += lessIdent + ") AS " + alias + "\n";
}
else {
let children: ParsedView[] = view.childViews.map((item: View, idx: number) => {
    • Essa parte aqui ficou meio difícil de entender.

      Primeiramente, cada view tem um id único que é uma string hexadecimal, tipo c2beff2aff88. Então acho que não precisa do alias. Podemos só utilizar o próprio nome da view direto, sacou?

      "Segundamente", o degree também acho que não precisa. Claro que fica legal pra ver a query num console.log, mas acho que isso pode ser feito depois (um identador de SQL). A saída desse método tem que ser a query sem quebra de linhas, sem identação, sem nada. Depois pode usar uma coisa tipo essa pra visualizar a sua query melhor.

      Tudo isso para eliminar os parâmetros alias e degree, e dá pra colocar a chamada nessa queryfyView pra dentro do outro loop ali em baixo, não?

      Bom, vou tentar entender melhor o código aqui, depois agente pensa numa solução junto.

Please register or sign in to reply
let childAlias: string = "v" + idx;
return {
query: this.queryfyView(item, childAlias, degree + 1),
view: item,
alias: childAlias
};
});
let covered: Map<string, string> = new Map();
view.dimensions.forEach((item: string) => covered.set(item, ""));
view.metrics.forEach((item: string) => covered.set(item, ""));
let projection: string = ident + "SELECT ";
let viewsFrom: string = ident + "FROM";
let selection: string = ident + "WHERE ";
let grouping: string = ident + "GROUP BY ";
let elements: string[] = [];
let group: string[] = [];
children.forEach((child: ParsedView) => {
let selected: string[] = [];
child.view.dimensions.forEach((dimension: string) => {
let first: string = covered.get(dimension);
let extDimension = child.alias + "." + dimension;
if (first === "") {
covered.set(dimension, child.alias);
elements.push(extDimension);
group.push(extDimension);
}
else {
let extFirst = first + "." + dimension;
selected.push(extDimension + " = " + extFirst);
}
});
child.view.metrics.forEach((metric: string) => {
let first: string = covered.get(metric);
let func: string = this.metricFunction(child.view, metric);
    • Para desacoplar melhor as coisas, acho que poderia ser assim:

      aggrType = child.view.getAggregationType(metric);
      this.getAggregateFunction(aggrType);

      E no enum AggregationType , adicionar o tipo NONE (pra que o método getAggregationType retorne quando não estiver definido nenhuma agregação para a métrica).

Please register or sign in to reply
let extMetric: string = func + "(" + child.alias + "." + metric + ")";
if (first === "") {
covered.set(metric, child.alias);
elements.push(extMetric);
}
});
viewsFrom += "\n" + child.query;
if (selected.length > 0) {
selection += selected.join(" AND ");
}
});
projection += elements.join(", ") + "\n";
selection += "\n";
grouping += group.join(", ") + "\n";
alias += "\n";
sql += projection + viewsFrom + selection + grouping + lessIdent + ") AS " + alias;
}
return sql;
}
private metricFunction(view: View, metric: string): string{
Please register or sign in to reply
let map: Map<string, AggregationType> = view.aggregationMap;
Please register or sign in to reply
let func: string = "";
if (map.has(metric)) {
Please register or sign in to reply
switch (map.get(metric)) {
case AggregationType.SUM:
func = "SUM";
    • Ao invés de func = "XXX" e um return func no final, dá pra trocar isso por um return "XXX";. Até o break dá pra tirar daí.

      switch (map.get(metric)) {
          case AggregationType.SUM:
              return  "SUM";
          case AggregationType.AVG:
              ...
Please register or sign in to reply
break;
case AggregationType.AVG:
func = "AVG";
break;
case AggregationType.COUNT:
func = "COUNT";
break;
default:
func = "";
break;
}
}
return func;
}
}
Loading