Skip to content

Commit

Permalink
feat: Basic query rewrites
Browse files Browse the repository at this point in the history
  • Loading branch information
paveltiunov committed Apr 2, 2020
1 parent af92970 commit af07865
Show file tree
Hide file tree
Showing 17 changed files with 2,507 additions and 6 deletions.
40 changes: 36 additions & 4 deletions packages/cubejs-schema-compiler/adapter/BaseQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const BaseFilter = require('./BaseFilter');
const BaseTimeDimension = require('./BaseTimeDimension');
const ParamAllocator = require('./ParamAllocator');
const PreAggregations = require('./PreAggregations');
const SqlParser = require('../parser/SqlParser');

const DEFAULT_PREAGGREGATIONS_SCHEMA = `stb_pre_aggregations`;

Expand Down Expand Up @@ -335,7 +336,10 @@ class BaseQuery {

simpleQuery() {
// eslint-disable-next-line prefer-template
return `${this.commonQuery()} ${this.baseWhere(this.allFilters)}` +
const inlineWhereConditions = [];
const commonQuery = this.rewriteInlineWhere(() => this.commonQuery(), inlineWhereConditions);
const inlineFilters = inlineWhereConditions.map(f => ({ filterToWhere: () => f }));
return `${commonQuery} ${this.baseWhere(this.allFilters.concat(inlineFilters))}` +
this.groupByClause() +
this.baseHaving(this.measureFilters) +
this.orderBy() +
Expand Down Expand Up @@ -619,13 +623,33 @@ class BaseQuery {
return this.joinQuery(this.join, this.collectFromMembers(false, this.collectSubQueryDimensionsFor.bind(this)));
}

rewriteInlineCubeSql(cube) {
const sql = this.cubeSql(cube);
const parser = new SqlParser(sql);
const cubeAlias = this.cubeAlias(cube);
if (
this.safeEvaluateSymbolContext().inlineWhereConditions &&
this.cubeEvaluator.cubeFromPath(cube).rewriteQueries &&
parser.isSimpleAsteriskQuery()
) {
this.safeEvaluateSymbolContext().inlineWhereConditions.push(parser.extractWhereConditions(cubeAlias));
return [parser.extractTableFrom(), cubeAlias];
} else {
return [sql, cubeAlias];
}
}

joinQuery(join, subQueryDimensions) {
const joins = join.joins.map(
j => `LEFT JOIN ${this.cubeSql(j.originalTo)} ${this.asSyntaxJoin} ${this.cubeAlias(j.originalTo)}
ON ${this.evaluateSql(j.originalFrom, j.join.sql)}`
j => {
const [cubeSql, cubeAlias] = this.rewriteInlineCubeSql(j.originalTo);
return `LEFT JOIN ${cubeSql} ${this.asSyntaxJoin} ${cubeAlias}
ON ${this.evaluateSql(j.originalFrom, j.join.sql)}`;
}
).concat(subQueryDimensions.map(d => this.subQueryJoin(d)));

return `${this.cubeSql(join.root)} ${this.asSyntaxJoin} ${this.cubeAlias(join.root)}\n${joins.join("\n")}`;
const [cubeSql, cubeAlias] = this.rewriteInlineCubeSql(join.root);
return `${cubeSql} ${this.asSyntaxJoin} ${cubeAlias}\n${joins.join("\n")}`;
}

subQueryJoin(dimension) {
Expand Down Expand Up @@ -877,6 +901,14 @@ class BaseQuery {
return R.uniq(context.subQueryDimensions);
}

rewriteInlineWhere(fn, inlineWhereConditions) {
const context = { inlineWhereConditions };
return this.evaluateSymbolSqlWithContext(
fn,
context
);
}

groupByClause() {
if (this.ungrouped) {
return '';
Expand Down
1 change: 1 addition & 0 deletions packages/cubejs-schema-compiler/compiler/CubeValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ const cubeSchema = Joi.object().keys({
sqlAlias: Joi.string(),
dataSource: Joi.string(),
description: Joi.string(),
rewriteQueries: Joi.boolean(),
joins: Joi.object().pattern(identifierRegex, Joi.object().keys({
sql: Joi.func().required(),
relationship: Joi.any().valid('hasMany', 'belongsTo', 'hasOne').required()
Expand Down
3 changes: 3 additions & 0 deletions packages/cubejs-schema-compiler/generate-parser.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

cd parser && antlr -Dlanguage=JavaScript GenericSql.g4
3 changes: 2 additions & 1 deletion packages/cubejs-schema-compiler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
},
"scripts": {
"test": "mocha",
"lint": "eslint adapter/*.js compiler/*.js extensions/*.js scaffolding/*.js"
"lint": "eslint adapter/*.js compiler/*.js extensions/*.js scaffolding/*.js parser/SqlParser.js"
},
"dependencies": {
"@babel/generator": "^7.4.0",
Expand All @@ -23,6 +23,7 @@
"@babel/traverse": "^7.4.0",
"@babel/types": "^7.4.0",
"@hapi/joi": "^15.1.1",
"antlr4": "^4.8.0",
"humps": "^2.0.1",
"inflection": "^1.12.0",
"moment-range": "^4.0.1",
Expand Down
85 changes: 85 additions & 0 deletions packages/cubejs-schema-compiler/parser/GenericSql.g4
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
grammar GenericSql;

statement:
query EOF | '(' query ')' EOF;

query:
SELECT selectFields
FROM from=fromTables
(WHERE where=boolExp)?;

fromTables:
aliasField;

selectFields:
(field (',' field)*);

field:
aliasField | ASTERISK;

aliasField:
idPath (AS? identifier)?;

boolExp:
exp |
exp AND exp |
exp OR exp |
NOT exp
;

exp:
exp binaryOperator exp |
exp unaryOperator |
idPath |
identifier '(' (exp (',' exp)*) ')' |
CAST '(' exp AS identifier ')' |
STRING |
numeric |
identifier |
INDEXED_PARAM |
'(' exp ')'
;

numeric:
DIGIT+ ('.' DIGIT+)? |
'.' DIGIT+;

binaryOperator:
LT | LTE | GT | GTE | EQUALS | NOT_EQUALS;

unaryOperator:
IS NULL | IS NOT NULL;

idPath:
identifier ('.' identifier)*;

identifier:
ID |
QUOTED_ID;

SELECT: 'SELECT';
ASTERISK: '*';
FROM: 'FROM';
WHERE: 'WHERE';
AND: 'AND';
OR: 'OR';
NOT: 'NOT';
AS: 'AS';
LT: '<';
LTE: '<=';
GT: '>';
GTE: '>=';
EQUALS: '=';
NOT_EQUALS: '<>' | '!=';
IS: 'IS';
NULL: 'NULL';
CAST: 'CAST';

INDEXED_PARAM: '$' [0-9]+ '$';
ID: [A-Z_@] [A-Z_@0-9]*;
DIGIT: [0-9];
QUOTED_ID: ('"' (~'"')* '"') | ('`' (~'`')* '`');
STRING: ('\'' (~ '\'' | '\'\'')* '\'');


WHITESPACE: [ \t\r\n] -> channel(HIDDEN);
78 changes: 78 additions & 0 deletions packages/cubejs-schema-compiler/parser/GenericSql.interp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
token literal names:
null
'('
')'
','
'.'
'SELECT'
'*'
'FROM'
'WHERE'
'AND'
'OR'
'NOT'
'AS'
'<'
'<='
'>'
'>='
'='
null
'IS'
'NULL'
'CAST'
null
null
null
null
null
null

token symbolic names:
null
null
null
null
null
SELECT
ASTERISK
FROM
WHERE
AND
OR
NOT
AS
LT
LTE
GT
GTE
EQUALS
NOT_EQUALS
IS
NULL
CAST
INDEXED_PARAM
ID
DIGIT
QUOTED_ID
STRING
WHITESPACE

rule names:
statement
query
fromTables
selectFields
field
aliasField
boolExp
exp
numeric
binaryOperator
unaryOperator
idPath
identifier


atn:
[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 29, 163, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 5, 2, 37, 10, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 45, 10, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 7, 5, 52, 10, 5, 12, 5, 14, 5, 55, 11, 5, 3, 6, 3, 6, 5, 6, 59, 10, 6, 3, 7, 3, 7, 5, 7, 63, 10, 7, 3, 7, 5, 7, 66, 10, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 5, 8, 79, 10, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 7, 9, 88, 10, 9, 12, 9, 14, 9, 91, 11, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 5, 9, 110, 10, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 7, 9, 118, 10, 9, 12, 9, 14, 9, 121, 11, 9, 3, 10, 6, 10, 124, 10, 10, 13, 10, 14, 10, 125, 3, 10, 3, 10, 6, 10, 130, 10, 10, 13, 10, 14, 10, 131, 5, 10, 134, 10, 10, 3, 10, 3, 10, 6, 10, 138, 10, 10, 13, 10, 14, 10, 139, 5, 10, 142, 10, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 5, 12, 151, 10, 12, 3, 13, 3, 13, 3, 13, 7, 13, 156, 10, 13, 12, 13, 14, 13, 159, 11, 13, 3, 14, 3, 14, 3, 14, 2, 3, 16, 15, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 2, 4, 3, 2, 15, 20, 4, 2, 25, 25, 27, 27, 2, 175, 2, 36, 3, 2, 2, 2, 4, 38, 3, 2, 2, 2, 6, 46, 3, 2, 2, 2, 8, 48, 3, 2, 2, 2, 10, 58, 3, 2, 2, 2, 12, 60, 3, 2, 2, 2, 14, 78, 3, 2, 2, 2, 16, 109, 3, 2, 2, 2, 18, 141, 3, 2, 2, 2, 20, 143, 3, 2, 2, 2, 22, 150, 3, 2, 2, 2, 24, 152, 3, 2, 2, 2, 26, 160, 3, 2, 2, 2, 28, 29, 5, 4, 3, 2, 29, 30, 7, 2, 2, 3, 30, 37, 3, 2, 2, 2, 31, 32, 7, 3, 2, 2, 32, 33, 5, 4, 3, 2, 33, 34, 7, 4, 2, 2, 34, 35, 7, 2, 2, 3, 35, 37, 3, 2, 2, 2, 36, 28, 3, 2, 2, 2, 36, 31, 3, 2, 2, 2, 37, 3, 3, 2, 2, 2, 38, 39, 7, 7, 2, 2, 39, 40, 5, 8, 5, 2, 40, 41, 7, 9, 2, 2, 41, 44, 5, 6, 4, 2, 42, 43, 7, 10, 2, 2, 43, 45, 5, 14, 8, 2, 44, 42, 3, 2, 2, 2, 44, 45, 3, 2, 2, 2, 45, 5, 3, 2, 2, 2, 46, 47, 5, 12, 7, 2, 47, 7, 3, 2, 2, 2, 48, 53, 5, 10, 6, 2, 49, 50, 7, 5, 2, 2, 50, 52, 5, 10, 6, 2, 51, 49, 3, 2, 2, 2, 52, 55, 3, 2, 2, 2, 53, 51, 3, 2, 2, 2, 53, 54, 3, 2, 2, 2, 54, 9, 3, 2, 2, 2, 55, 53, 3, 2, 2, 2, 56, 59, 5, 12, 7, 2, 57, 59, 7, 8, 2, 2, 58, 56, 3, 2, 2, 2, 58, 57, 3, 2, 2, 2, 59, 11, 3, 2, 2, 2, 60, 65, 5, 24, 13, 2, 61, 63, 7, 14, 2, 2, 62, 61, 3, 2, 2, 2, 62, 63, 3, 2, 2, 2, 63, 64, 3, 2, 2, 2, 64, 66, 5, 26, 14, 2, 65, 62, 3, 2, 2, 2, 65, 66, 3, 2, 2, 2, 66, 13, 3, 2, 2, 2, 67, 79, 5, 16, 9, 2, 68, 69, 5, 16, 9, 2, 69, 70, 7, 11, 2, 2, 70, 71, 5, 16, 9, 2, 71, 79, 3, 2, 2, 2, 72, 73, 5, 16, 9, 2, 73, 74, 7, 12, 2, 2, 74, 75, 5, 16, 9, 2, 75, 79, 3, 2, 2, 2, 76, 77, 7, 13, 2, 2, 77, 79, 5, 16, 9, 2, 78, 67, 3, 2, 2, 2, 78, 68, 3, 2, 2, 2, 78, 72, 3, 2, 2, 2, 78, 76, 3, 2, 2, 2, 79, 15, 3, 2, 2, 2, 80, 81, 8, 9, 1, 2, 81, 110, 5, 24, 13, 2, 82, 83, 5, 26, 14, 2, 83, 84, 7, 3, 2, 2, 84, 89, 5, 16, 9, 2, 85, 86, 7, 5, 2, 2, 86, 88, 5, 16, 9, 2, 87, 85, 3, 2, 2, 2, 88, 91, 3, 2, 2, 2, 89, 87, 3, 2, 2, 2, 89, 90, 3, 2, 2, 2, 90, 92, 3, 2, 2, 2, 91, 89, 3, 2, 2, 2, 92, 93, 7, 4, 2, 2, 93, 110, 3, 2, 2, 2, 94, 95, 7, 23, 2, 2, 95, 96, 7, 3, 2, 2, 96, 97, 5, 16, 9, 2, 97, 98, 7, 14, 2, 2, 98, 99, 5, 26, 14, 2, 99, 100, 7, 4, 2, 2, 100, 110, 3, 2, 2, 2, 101, 110, 7, 28, 2, 2, 102, 110, 5, 18, 10, 2, 103, 110, 5, 26, 14, 2, 104, 110, 7, 24, 2, 2, 105, 106, 7, 3, 2, 2, 106, 107, 5, 16, 9, 2, 107, 108, 7, 4, 2, 2, 108, 110, 3, 2, 2, 2, 109, 80, 3, 2, 2, 2, 109, 82, 3, 2, 2, 2, 109, 94, 3, 2, 2, 2, 109, 101, 3, 2, 2, 2, 109, 102, 3, 2, 2, 2, 109, 103, 3, 2, 2, 2, 109, 104, 3, 2, 2, 2, 109, 105, 3, 2, 2, 2, 110, 119, 3, 2, 2, 2, 111, 112, 12, 12, 2, 2, 112, 113, 5, 20, 11, 2, 113, 114, 5, 16, 9, 13, 114, 118, 3, 2, 2, 2, 115, 116, 12, 11, 2, 2, 116, 118, 5, 22, 12, 2, 117, 111, 3, 2, 2, 2, 117, 115, 3, 2, 2, 2, 118, 121, 3, 2, 2, 2, 119, 117, 3, 2, 2, 2, 119, 120, 3, 2, 2, 2, 120, 17, 3, 2, 2, 2, 121, 119, 3, 2, 2, 2, 122, 124, 7, 26, 2, 2, 123, 122, 3, 2, 2, 2, 124, 125, 3, 2, 2, 2, 125, 123, 3, 2, 2, 2, 125, 126, 3, 2, 2, 2, 126, 133, 3, 2, 2, 2, 127, 129, 7, 6, 2, 2, 128, 130, 7, 26, 2, 2, 129, 128, 3, 2, 2, 2, 130, 131, 3, 2, 2, 2, 131, 129, 3, 2, 2, 2, 131, 132, 3, 2, 2, 2, 132, 134, 3, 2, 2, 2, 133, 127, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 142, 3, 2, 2, 2, 135, 137, 7, 6, 2, 2, 136, 138, 7, 26, 2, 2, 137, 136, 3, 2, 2, 2, 138, 139, 3, 2, 2, 2, 139, 137, 3, 2, 2, 2, 139, 140, 3, 2, 2, 2, 140, 142, 3, 2, 2, 2, 141, 123, 3, 2, 2, 2, 141, 135, 3, 2, 2, 2, 142, 19, 3, 2, 2, 2, 143, 144, 9, 2, 2, 2, 144, 21, 3, 2, 2, 2, 145, 146, 7, 21, 2, 2, 146, 151, 7, 22, 2, 2, 147, 148, 7, 21, 2, 2, 148, 149, 7, 13, 2, 2, 149, 151, 7, 22, 2, 2, 150, 145, 3, 2, 2, 2, 150, 147, 3, 2, 2, 2, 151, 23, 3, 2, 2, 2, 152, 157, 5, 26, 14, 2, 153, 154, 7, 6, 2, 2, 154, 156, 5, 26, 14, 2, 155, 153, 3, 2, 2, 2, 156, 159, 3, 2, 2, 2, 157, 155, 3, 2, 2, 2, 157, 158, 3, 2, 2, 2, 158, 25, 3, 2, 2, 2, 159, 157, 3, 2, 2, 2, 160, 161, 9, 3, 2, 2, 161, 27, 3, 2, 2, 2, 20, 36, 44, 53, 58, 62, 65, 78, 89, 109, 117, 119, 125, 131, 133, 139, 141, 150, 157]
47 changes: 47 additions & 0 deletions packages/cubejs-schema-compiler/parser/GenericSql.tokens
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
T__0=1
T__1=2
T__2=3
T__3=4
SELECT=5
ASTERISK=6
FROM=7
WHERE=8
AND=9
OR=10
NOT=11
AS=12
LT=13
LTE=14
GT=15
GTE=16
EQUALS=17
NOT_EQUALS=18
IS=19
NULL=20
CAST=21
INDEXED_PARAM=22
ID=23
DIGIT=24
QUOTED_ID=25
STRING=26
WHITESPACE=27
'('=1
')'=2
','=3
'.'=4
'SELECT'=5
'*'=6
'FROM'=7
'WHERE'=8
'AND'=9
'OR'=10
'NOT'=11
'AS'=12
'<'=13
'<='=14
'>'=15
'>='=16
'='=17
'IS'=19
'NULL'=20
'CAST'=21
Loading

0 comments on commit af07865

Please sign in to comment.