@malloydata/malloy 0.0.177-dev240828173040 → 0.0.177-dev240829030921
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dialect/dialect.d.ts +23 -13
- package/dist/dialect/dialect.js +33 -27
- package/dist/dialect/duckdb/duckdb.d.ts +7 -11
- package/dist/dialect/duckdb/duckdb.js +34 -100
- package/dist/dialect/duckdb/functions/greatest_and_least.js +5 -12
- package/dist/dialect/functions/concat.js +1 -1
- package/dist/dialect/functions/greatest_and_least.js +1 -1
- package/dist/dialect/functions/simple_numeric_functions.js +1 -1
- package/dist/dialect/functions/sql.js +5 -15
- package/dist/dialect/functions/string_agg.js +2 -2
- package/dist/dialect/functions/trim_functions.js +2 -2
- package/dist/dialect/functions/util.d.ts +6 -9
- package/dist/dialect/functions/util.js +29 -38
- package/dist/dialect/index.d.ts +1 -1
- package/dist/dialect/index.js +1 -2
- package/dist/dialect/pg_impl.d.ts +15 -0
- package/dist/dialect/pg_impl.js +91 -0
- package/dist/dialect/postgres/functions/greatest_and_least.js +1 -3
- package/dist/dialect/postgres/functions/string_agg.js +2 -2
- package/dist/dialect/postgres/postgres.d.ts +7 -11
- package/dist/dialect/postgres/postgres.js +29 -92
- package/dist/dialect/snowflake/functions/string_agg.js +2 -2
- package/dist/dialect/snowflake/snowflake.d.ts +9 -9
- package/dist/dialect/snowflake/snowflake.js +41 -48
- package/dist/dialect/standardsql/functions/string_agg.js +4 -4
- package/dist/dialect/standardsql/standardsql.d.ts +9 -9
- package/dist/dialect/standardsql/standardsql.js +56 -51
- package/dist/dialect/trino/functions/concat.js +1 -1
- package/dist/dialect/trino/functions/string_agg.js +2 -2
- package/dist/dialect/trino/trino.d.ts +11 -12
- package/dist/dialect/trino/trino.js +59 -83
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -4
- package/dist/lang/ast/ast-utils.d.ts +1 -1
- package/dist/lang/ast/ast-utils.js +2 -2
- package/dist/lang/ast/expressions/apply.js +1 -2
- package/dist/lang/ast/expressions/binary-boolean.d.ts +2 -1
- package/dist/lang/ast/expressions/binary-boolean.js +6 -3
- package/dist/lang/ast/expressions/binary-numeric.d.ts +2 -1
- package/dist/lang/ast/expressions/boolean.js +1 -1
- package/dist/lang/ast/expressions/constant-expression.d.ts +3 -3
- package/dist/lang/ast/expressions/constant-expression.js +0 -23
- package/dist/lang/ast/expressions/expr-aggregate-function.js +24 -34
- package/dist/lang/ast/expressions/expr-alternation-tree.d.ts +6 -3
- package/dist/lang/ast/expressions/expr-alternation-tree.js +10 -5
- package/dist/lang/ast/expressions/expr-cast.js +1 -2
- package/dist/lang/ast/expressions/expr-coalesce.js +4 -1
- package/dist/lang/ast/expressions/expr-compare.d.ts +3 -3
- package/dist/lang/ast/expressions/expr-count-distinct.js +1 -1
- package/dist/lang/ast/expressions/expr-count.js +3 -3
- package/dist/lang/ast/expressions/expr-func.js +15 -18
- package/dist/lang/ast/expressions/expr-granular-time.js +8 -10
- package/dist/lang/ast/expressions/expr-id-reference.js +2 -2
- package/dist/lang/ast/expressions/expr-minus.js +5 -4
- package/dist/lang/ast/expressions/expr-not.js +1 -1
- package/dist/lang/ast/expressions/expr-now.js +1 -6
- package/dist/lang/ast/expressions/expr-null.js +1 -1
- package/dist/lang/ast/expressions/expr-number.js +1 -1
- package/dist/lang/ast/expressions/expr-parens.js +1 -1
- package/dist/lang/ast/expressions/expr-props.js +4 -7
- package/dist/lang/ast/expressions/expr-regex.js +1 -3
- package/dist/lang/ast/expressions/expr-string.js +1 -7
- package/dist/lang/ast/expressions/expr-time-extract.js +12 -16
- package/dist/lang/ast/expressions/expr-time.d.ts +2 -2
- package/dist/lang/ast/expressions/expr-time.js +4 -6
- package/dist/lang/ast/expressions/expr-ungroup.js +2 -2
- package/dist/lang/ast/expressions/for-range.d.ts +2 -1
- package/dist/lang/ast/expressions/function-ordering.js +5 -5
- package/dist/lang/ast/expressions/partial-compare.d.ts +3 -3
- package/dist/lang/ast/expressions/pick-when.js +24 -8
- package/dist/lang/ast/expressions/range.d.ts +2 -1
- package/dist/lang/ast/expressions/range.js +4 -2
- package/dist/lang/ast/expressions/time-literal.d.ts +4 -3
- package/dist/lang/ast/expressions/time-literal.js +5 -10
- package/dist/lang/ast/expressions/top-by.js +1 -2
- package/dist/lang/ast/expressions/utils.d.ts +3 -12
- package/dist/lang/ast/expressions/utils.js +8 -56
- package/dist/lang/ast/field-space/reference-field.js +1 -1
- package/dist/lang/ast/index.d.ts +1 -1
- package/dist/lang/ast/index.js +1 -1
- package/dist/lang/ast/query-builders/index-builder.d.ts +2 -2
- package/dist/lang/ast/query-builders/reduce-builder.d.ts +2 -2
- package/dist/lang/ast/query-items/field-declaration.js +1 -5
- package/dist/lang/ast/query-properties/filters.d.ts +3 -3
- package/dist/lang/ast/query-properties/filters.js +6 -5
- package/dist/lang/ast/query-properties/top.js +1 -2
- package/dist/lang/ast/source-elements/refined-source.js +1 -1
- package/dist/lang/ast/source-properties/joins.js +11 -10
- package/dist/lang/ast/time-utils.d.ts +5 -7
- package/dist/lang/ast/time-utils.js +17 -57
- package/dist/lang/ast/types/binary_operators.d.ts +9 -0
- package/dist/lang/ast/types/binary_operators.js +28 -0
- package/dist/lang/ast/types/expr-result.d.ts +3 -3
- package/dist/lang/ast/types/expression-def.d.ts +4 -3
- package/dist/lang/ast/types/expression-def.js +43 -50
- package/dist/lang/lib/Malloy/MalloyParser.d.ts +0 -11
- package/dist/lang/lib/Malloy/MalloyParser.js +803 -858
- package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +0 -13
- package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +0 -8
- package/dist/lang/malloy-to-ast.d.ts +0 -1
- package/dist/lang/malloy-to-ast.js +0 -4
- package/dist/lang/test/expressions.spec.js +42 -86
- package/dist/lang/test/field-symbols.spec.js +8 -6
- package/dist/lang/test/literals.spec.js +6 -6
- package/dist/lang/test/model_serialization.spec.js +5 -5
- package/dist/lang/test/test-translator.js +9 -7
- package/dist/malloy.d.ts +3 -3
- package/dist/malloy.js +1 -1
- package/dist/model/index.d.ts +1 -1
- package/dist/model/index.js +2 -1
- package/dist/model/malloy_query.d.ts +24 -19
- package/dist/model/malloy_query.js +272 -244
- package/dist/model/malloy_types.d.ts +224 -205
- package/dist/model/malloy_types.js +19 -98
- package/dist/model/utils.d.ts +10 -3
- package/dist/model/utils.js +84 -219
- package/package.json +1 -1
- package/dist/lang/ast/types/comparison.d.ts +0 -11
- package/dist/lang/ast/types/comparison.js +0 -41
- package/dist/lang/ast/types/equality.d.ts +0 -7
- package/dist/lang/ast/types/equality.js +0 -37
|
@@ -235,7 +235,7 @@ class QueryField extends QueryNode {
|
|
|
235
235
|
// find the structDef and return the path to the field...
|
|
236
236
|
const field = context.getFieldByName(expr.path);
|
|
237
237
|
if ((0, malloy_types_1.hasExpression)(field.fieldDef)) {
|
|
238
|
-
const ret = this.
|
|
238
|
+
const ret = this.exprToSQL(resultSet, field.parent, field.fieldDef.e, state);
|
|
239
239
|
// in order to avoid too many parens, there was some code here ..
|
|
240
240
|
// if (!ret.match(/^\(.*\)$/)) {
|
|
241
241
|
// ret = `(${ret})`;
|
|
@@ -253,8 +253,19 @@ class QueryField extends QueryNode {
|
|
|
253
253
|
generateOutputFieldFragment(resultSet, _context, frag, _state) {
|
|
254
254
|
return `(${resultSet.getField(frag.name).getAnalyticalSQL(false)})`;
|
|
255
255
|
}
|
|
256
|
-
|
|
257
|
-
|
|
256
|
+
*stringsFromSQLExpression(resultSet, context, e, state) {
|
|
257
|
+
/*
|
|
258
|
+
* Like template strings, the array of strings is paired with template insertions,
|
|
259
|
+
* each string is followed by at most one expression to be inserted
|
|
260
|
+
*/
|
|
261
|
+
const subExprList = [...e.kids.args];
|
|
262
|
+
for (const str of e.src) {
|
|
263
|
+
yield str;
|
|
264
|
+
const expr = subExprList.shift();
|
|
265
|
+
if (expr) {
|
|
266
|
+
yield this.exprToSQL(resultSet, context, expr, state);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
258
269
|
}
|
|
259
270
|
getParameterMap(overload, numArgs) {
|
|
260
271
|
return new Map(overload.params.map((param, paramIndex) => {
|
|
@@ -265,53 +276,61 @@ class QueryField extends QueryNode {
|
|
|
265
276
|
}));
|
|
266
277
|
}
|
|
267
278
|
expandFunctionCall(dialect, overload, args, orderBy, limit) {
|
|
279
|
+
function withCommas(es) {
|
|
280
|
+
const ret = [];
|
|
281
|
+
for (let i = 0; i < es.length;) {
|
|
282
|
+
ret.push(es[i]);
|
|
283
|
+
i += 1;
|
|
284
|
+
if (i < es.length) {
|
|
285
|
+
ret.push(',');
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return ret;
|
|
289
|
+
}
|
|
268
290
|
const paramMap = this.getParameterMap(overload, args.length);
|
|
269
291
|
if (overload.dialect[dialect] === undefined) {
|
|
270
|
-
throw new Error(`Function is not defined for
|
|
292
|
+
throw new Error(`Function is not defined for '${dialect}' dialect`);
|
|
271
293
|
}
|
|
272
|
-
|
|
294
|
+
const expanded = (0, utils_1.exprMap)(overload.dialect[dialect].e, fragment => {
|
|
273
295
|
var _a, _b;
|
|
274
|
-
if (
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
else if (fragment.type === 'spread') {
|
|
278
|
-
const param = fragment.e[0];
|
|
279
|
-
if (fragment.e.length !== 1 ||
|
|
280
|
-
typeof param === 'string' ||
|
|
281
|
-
param.type !== 'function_parameter') {
|
|
296
|
+
if (fragment.node === 'spread') {
|
|
297
|
+
const param = fragment.e;
|
|
298
|
+
if (param.node !== 'function_parameter') {
|
|
282
299
|
throw new Error('Invalid function definition. Argument to spread must be a function parameter.');
|
|
283
300
|
}
|
|
284
301
|
const entry = paramMap.get(param.name);
|
|
285
302
|
if (entry === undefined) {
|
|
286
|
-
return
|
|
287
|
-
}
|
|
288
|
-
else {
|
|
289
|
-
return (0, utils_1.joinWith)(entry.argIndexes.map(argIndex => args[argIndex]), ',');
|
|
303
|
+
return fragment;
|
|
290
304
|
}
|
|
305
|
+
const spread = entry.argIndexes.map(argIndex => args[argIndex]);
|
|
306
|
+
return (0, utils_1.composeSQLExpr)(withCommas(spread));
|
|
291
307
|
}
|
|
292
|
-
else if (fragment.
|
|
308
|
+
else if (fragment.node === 'function_parameter') {
|
|
293
309
|
const entry = paramMap.get(fragment.name);
|
|
294
310
|
if (entry === undefined) {
|
|
295
|
-
return
|
|
311
|
+
return fragment;
|
|
296
312
|
}
|
|
297
313
|
else if (entry.param.isVariadic) {
|
|
298
|
-
const spread =
|
|
299
|
-
return
|
|
314
|
+
const spread = entry.argIndexes.map(argIndex => args[argIndex]);
|
|
315
|
+
return (0, utils_1.composeSQLExpr)(withCommas(spread));
|
|
300
316
|
}
|
|
301
317
|
else {
|
|
302
318
|
return args[entry.argIndexes[0]];
|
|
303
319
|
}
|
|
304
320
|
}
|
|
305
|
-
else if (fragment.
|
|
321
|
+
else if (fragment.node === 'aggregate_order_by') {
|
|
306
322
|
return orderBy
|
|
307
|
-
?
|
|
308
|
-
|
|
323
|
+
? (0, utils_1.composeSQLExpr)([
|
|
324
|
+
` ${(_a = fragment.prefix) !== null && _a !== void 0 ? _a : ''}${orderBy}${(_b = fragment.suffix) !== null && _b !== void 0 ? _b : ''}`,
|
|
325
|
+
])
|
|
326
|
+
: { node: '' };
|
|
309
327
|
}
|
|
310
|
-
else if (fragment.
|
|
311
|
-
return limit ? [` ${limit}`] :
|
|
328
|
+
else if (fragment.node === 'aggregate_limit') {
|
|
329
|
+
return limit ? (0, utils_1.composeSQLExpr)([` ${limit}`]) : { node: '' };
|
|
312
330
|
}
|
|
313
|
-
return
|
|
331
|
+
return fragment;
|
|
314
332
|
});
|
|
333
|
+
return expanded;
|
|
315
334
|
}
|
|
316
335
|
getFunctionOrderBy(resultSet, context, state, orderBy, args, overload) {
|
|
317
336
|
if (orderBy.length === 0)
|
|
@@ -319,9 +338,9 @@ class QueryField extends QueryNode {
|
|
|
319
338
|
return ('ORDER BY ' +
|
|
320
339
|
orderBy
|
|
321
340
|
.map(ob => {
|
|
322
|
-
var _a
|
|
341
|
+
var _a;
|
|
323
342
|
const defaultOrderByArgIndex = (_a = overload.dialect[context.dialect.name].defaultOrderByArgIndex) !== null && _a !== void 0 ? _a : 0;
|
|
324
|
-
const expr =
|
|
343
|
+
const expr = ob.node === 'functionOrderBy' ? ob.e : args[defaultOrderByArgIndex];
|
|
325
344
|
const osql = this.generateDimFragment(resultSet, context, expr, state);
|
|
326
345
|
const dirsql = ob.dir === 'asc' ? ' ASC' : ob.dir === 'desc' ? ' DESC' : '';
|
|
327
346
|
return `${osql}${dirsql}`;
|
|
@@ -345,7 +364,7 @@ class QueryField extends QueryNode {
|
|
|
345
364
|
generateFunctionCallExpression(resultSet, context, frag, state) {
|
|
346
365
|
var _a, _b, _c;
|
|
347
366
|
const overload = frag.overload;
|
|
348
|
-
const args = frag.args;
|
|
367
|
+
const args = frag.kids.args;
|
|
349
368
|
const isSymmetric = (_a = frag.overload.isSymmetric) !== null && _a !== void 0 ? _a : false;
|
|
350
369
|
const distinctKey = (0, malloy_types_1.expressionIsAggregate)(overload.returnType.expressionType) &&
|
|
351
370
|
!isSymmetric &&
|
|
@@ -355,7 +374,7 @@ class QueryField extends QueryNode {
|
|
|
355
374
|
distinctKey &&
|
|
356
375
|
!context.dialect.supportsAggDistinct &&
|
|
357
376
|
context.dialect.name !== 'snowflake') {
|
|
358
|
-
return this.generateAsymmetricStringAggExpression(resultSet, context, args[0], args[1], distinctKey, frag.orderBy, context.dialect.name, state);
|
|
377
|
+
return this.generateAsymmetricStringAggExpression(resultSet, context, args[0], args[1], distinctKey, frag.kids.orderBy, context.dialect.name, state);
|
|
359
378
|
}
|
|
360
379
|
if (distinctKey) {
|
|
361
380
|
if (!context.dialect.supportsAggDistinct) {
|
|
@@ -364,11 +383,11 @@ class QueryField extends QueryNode {
|
|
|
364
383
|
const argsExpressions = args.map(arg => {
|
|
365
384
|
return this.generateDimFragment(resultSet, context, arg, state);
|
|
366
385
|
});
|
|
367
|
-
const orderBys = (_b = frag.orderBy) !== null && _b !== void 0 ? _b : [];
|
|
386
|
+
const orderBys = (_b = frag.kids.orderBy) !== null && _b !== void 0 ? _b : [];
|
|
368
387
|
const orderByExpressions = orderBys.map(ob => {
|
|
369
|
-
var _a
|
|
388
|
+
var _a;
|
|
370
389
|
const defaultOrderByArgIndex = (_a = overload.dialect[context.dialect.name].defaultOrderByArgIndex) !== null && _a !== void 0 ? _a : 0;
|
|
371
|
-
const expr =
|
|
390
|
+
const expr = ob.node === 'functionOrderBy' ? ob.e : args[defaultOrderByArgIndex];
|
|
372
391
|
return this.generateDimFragment(resultSet, context, expr, state);
|
|
373
392
|
});
|
|
374
393
|
return context.dialect.sqlAggDistinct(distinctKey, [...argsExpressions, ...orderByExpressions], valNames => {
|
|
@@ -382,17 +401,17 @@ class QueryField extends QueryNode {
|
|
|
382
401
|
return args[i];
|
|
383
402
|
}
|
|
384
403
|
}
|
|
385
|
-
return [v];
|
|
404
|
+
return (0, utils_1.composeSQLExpr)([v]);
|
|
386
405
|
});
|
|
387
406
|
const newArgs = vals.slice(0, argsExpressions.length);
|
|
388
407
|
const orderBy = vals
|
|
389
408
|
.slice(argsExpressions.length)
|
|
390
409
|
.map((e, i) => {
|
|
391
|
-
return { e, dir: orderBys[i].dir };
|
|
410
|
+
return { node: 'functionOrderBy', e, dir: orderBys[i].dir };
|
|
392
411
|
});
|
|
393
412
|
const orderBySQL = this.getFunctionOrderBy(resultSet, context, state, orderBy, newArgs, overload);
|
|
394
413
|
const funcCall = this.expandFunctionCall(context.dialect.name, overload, newArgs, orderBySQL, aggregateLimit);
|
|
395
|
-
return this.
|
|
414
|
+
return this.exprToSQL(resultSet, context, funcCall, state);
|
|
396
415
|
});
|
|
397
416
|
}
|
|
398
417
|
else {
|
|
@@ -413,11 +432,13 @@ class QueryField extends QueryNode {
|
|
|
413
432
|
// fragment.
|
|
414
433
|
return param.allowedTypes.every(t => (0, malloy_types_1.isLiteral)(t.evalSpace))
|
|
415
434
|
? arg
|
|
416
|
-
:
|
|
435
|
+
: (0, utils_1.composeSQLExpr)([
|
|
436
|
+
this.generateDimFragment(resultSet, context, arg, state),
|
|
437
|
+
]);
|
|
417
438
|
})
|
|
418
439
|
: args;
|
|
419
|
-
const orderBySql = frag.orderBy
|
|
420
|
-
? this.getFunctionOrderBy(resultSet, context, state, frag.orderBy, args, overload)
|
|
440
|
+
const orderBySql = frag.kids.orderBy
|
|
441
|
+
? this.getFunctionOrderBy(resultSet, context, state, frag.kids.orderBy, args, overload)
|
|
421
442
|
: '';
|
|
422
443
|
const funcCall = this.expandFunctionCall(context.dialect.name, overload, mappedArgs, orderBySql, aggregateLimit);
|
|
423
444
|
if ((0, malloy_types_1.expressionIsAnalytic)(overload.returnType.expressionType)) {
|
|
@@ -426,7 +447,7 @@ class QueryField extends QueryNode {
|
|
|
426
447
|
});
|
|
427
448
|
return this.generateAnalyticFragment(resultSet, context, funcCall, overload, state, args, extraPartitions, orderBySql);
|
|
428
449
|
}
|
|
429
|
-
return this.
|
|
450
|
+
return this.exprToSQL(resultSet, context, funcCall, state);
|
|
430
451
|
}
|
|
431
452
|
}
|
|
432
453
|
generateSpread(_resultSet, _context, _frag, _state) {
|
|
@@ -436,19 +457,19 @@ class QueryField extends QueryNode {
|
|
|
436
457
|
const name = expr.path[0];
|
|
437
458
|
const argument = context.arguments()[name];
|
|
438
459
|
if (argument.value) {
|
|
439
|
-
return this.
|
|
460
|
+
return this.exprToSQL(resultSet, context, argument.value, state);
|
|
440
461
|
}
|
|
441
462
|
throw new Error(`Can't generate SQL, no value for ${expr.path}`);
|
|
442
463
|
}
|
|
443
464
|
generateFilterFragment(resultSet, context, expr, state) {
|
|
444
465
|
const allWhere = new utils_1.AndChain(state.whereSQL);
|
|
445
|
-
for (const cond of expr.filterList) {
|
|
446
|
-
allWhere.add(this.
|
|
466
|
+
for (const cond of expr.kids.filterList) {
|
|
467
|
+
allWhere.add(this.exprToSQL(resultSet, context, cond.e, state.withWhere()));
|
|
447
468
|
}
|
|
448
|
-
return this.
|
|
469
|
+
return this.exprToSQL(resultSet, context, expr.kids.e, state.withWhere(allWhere.sql()));
|
|
449
470
|
}
|
|
450
471
|
generateDimFragment(resultSet, context, expr, state) {
|
|
451
|
-
let dim = this.
|
|
472
|
+
let dim = this.exprToSQL(resultSet, context, expr, state);
|
|
452
473
|
if (state.whereSQL) {
|
|
453
474
|
dim = `CASE WHEN ${state.whereSQL} THEN ${dim} END`;
|
|
454
475
|
}
|
|
@@ -461,7 +482,7 @@ class QueryField extends QueryNode {
|
|
|
461
482
|
let totalGroupSet;
|
|
462
483
|
let ungroupSet;
|
|
463
484
|
if (expr.fields && expr.fields.length > 0) {
|
|
464
|
-
const key = expr.fields.sort().join('|') + expr.
|
|
485
|
+
const key = expr.fields.sort().join('|') + expr.node;
|
|
465
486
|
ungroupSet = resultSet.ungroupedSets.get(key);
|
|
466
487
|
if (ungroupSet === undefined) {
|
|
467
488
|
throw new Error(`Internal Error, cannot find groupset with key ${key}`);
|
|
@@ -471,7 +492,7 @@ class QueryField extends QueryNode {
|
|
|
471
492
|
else {
|
|
472
493
|
totalGroupSet = resultSet.parent ? resultSet.parent.groupSet : 0;
|
|
473
494
|
}
|
|
474
|
-
const s = this.
|
|
495
|
+
const s = this.exprToSQL(resultSet, context, expr.e, state.withTotal(totalGroupSet));
|
|
475
496
|
const fields = resultSet.getUngroupPartitions(ungroupSet);
|
|
476
497
|
let partitionBy = '';
|
|
477
498
|
const fieldsString = fields.map(f => f.getAnalyticalSQL(true)).join(', ');
|
|
@@ -511,9 +532,7 @@ class QueryField extends QueryNode {
|
|
|
511
532
|
}
|
|
512
533
|
generateSymmetricFragment(resultSet, context, expr, state) {
|
|
513
534
|
const dimSQL = this.generateDimFragment(resultSet, context, expr.e, state);
|
|
514
|
-
const f = expr.function === '
|
|
515
|
-
? 'count(distinct '
|
|
516
|
-
: expr.function + '(';
|
|
535
|
+
const f = expr.function === 'distinct' ? 'count(distinct ' : expr.function + '(';
|
|
517
536
|
return `${f}${dimSQL})`;
|
|
518
537
|
}
|
|
519
538
|
generateAvgFragment(resultSet, context, expr, state) {
|
|
@@ -573,16 +592,6 @@ class QueryField extends QueryNode {
|
|
|
573
592
|
return `${func}${thing})`;
|
|
574
593
|
}
|
|
575
594
|
}
|
|
576
|
-
generateDialect(resultSet, context, expr, state) {
|
|
577
|
-
return this.generateExpressionFromExpr(resultSet, context, context.dialect.dialectExpr(resultSet.getQueryInfo(), expr), state);
|
|
578
|
-
}
|
|
579
|
-
generateSqlString(resultSet, context, expr, state) {
|
|
580
|
-
return expr.e
|
|
581
|
-
.map(part => typeof part === 'string'
|
|
582
|
-
? part
|
|
583
|
-
: this.generateExpressionFromExpr(resultSet, context, [part], state))
|
|
584
|
-
.join('');
|
|
585
|
-
}
|
|
586
595
|
generateSourceReference(resultSet, context, expr) {
|
|
587
596
|
if (expr.path === undefined) {
|
|
588
597
|
return context.getSQLIdentifier();
|
|
@@ -666,44 +675,85 @@ class QueryField extends QueryNode {
|
|
|
666
675
|
}
|
|
667
676
|
const argIndex = overload.params.findIndex(param => param.name === value);
|
|
668
677
|
const arg = args[argIndex];
|
|
669
|
-
if (arg.
|
|
670
|
-
typeof arg[0] === 'string' ||
|
|
671
|
-
arg[0].type !== 'dialect' ||
|
|
672
|
-
arg[0].function !== 'numberLiteral') {
|
|
678
|
+
if (arg.node !== 'numberLiteral') {
|
|
673
679
|
throw new Error('Invalid number of rows for window spec');
|
|
674
680
|
}
|
|
675
681
|
// TODO this does not handle float literals correctly
|
|
676
|
-
return arg
|
|
682
|
+
return arg.literal;
|
|
677
683
|
});
|
|
678
684
|
between = `ROWS BETWEEN ${preceding} PRECEDING AND ${following} FOLLOWING`;
|
|
679
685
|
}
|
|
680
|
-
const funcSQL = this.
|
|
686
|
+
const funcSQL = this.exprToSQL(resultStruct, context, expr, state);
|
|
681
687
|
let retExpr = `${funcSQL} OVER(${partitionBy} ${orderBy} ${between})`;
|
|
682
688
|
if (isComplex) {
|
|
683
689
|
retExpr = `CASE WHEN group_set=${resultStruct.groupSet} THEN ${retExpr} END`;
|
|
684
690
|
}
|
|
685
691
|
return retExpr;
|
|
686
692
|
}
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
for (
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
}
|
|
702
|
-
else if ((0, malloy_types_1.isUngroupFragment)(expr)) {
|
|
703
|
-
s += this.generateUngroupedFragment(resultSet, context, expr, state);
|
|
693
|
+
generatePickSQL(pf) {
|
|
694
|
+
const caseStmt = ['CASE'];
|
|
695
|
+
for (let i = 0; i < pf.kids.pickWhen.length; i += 1) {
|
|
696
|
+
caseStmt.push(`WHEN ${pf.kids.pickWhen[i].sql} THEN ${pf.kids.pickThen[i].sql}`);
|
|
697
|
+
}
|
|
698
|
+
caseStmt.push(`ELSE ${pf.kids.pickElse.sql}`, 'END');
|
|
699
|
+
return caseStmt.join(' ');
|
|
700
|
+
}
|
|
701
|
+
exprToSQL(resultSet, context, exprToTranslate, state = new GenerateState()) {
|
|
702
|
+
// Wrap non leaf sub expressions in parenthesis
|
|
703
|
+
const subExpr = function (qf, e) {
|
|
704
|
+
const sql = qf.exprToSQL(resultSet, context, e, state);
|
|
705
|
+
if ((0, malloy_types_1.exprHasKids)(e)) {
|
|
706
|
+
return `(${sql})`;
|
|
704
707
|
}
|
|
705
|
-
|
|
706
|
-
|
|
708
|
+
return sql;
|
|
709
|
+
};
|
|
710
|
+
/*
|
|
711
|
+
* Translate the children first, and stash the translation
|
|
712
|
+
* in the nodes themselves, so that if we call into the dialect
|
|
713
|
+
* it will have access to the translated children.
|
|
714
|
+
*/
|
|
715
|
+
let expr = exprToTranslate;
|
|
716
|
+
if ((0, malloy_types_1.exprHasE)(exprToTranslate)) {
|
|
717
|
+
expr = { ...exprToTranslate };
|
|
718
|
+
const eSql = subExpr(this, expr.e);
|
|
719
|
+
expr.e = { ...expr.e, sql: eSql };
|
|
720
|
+
}
|
|
721
|
+
else if ((0, malloy_types_1.exprHasKids)(exprToTranslate)) {
|
|
722
|
+
expr = { ...exprToTranslate };
|
|
723
|
+
const oldKids = exprToTranslate.kids;
|
|
724
|
+
for (const [name, kidExpr] of Object.entries(oldKids)) {
|
|
725
|
+
if (Array.isArray(kidExpr)) {
|
|
726
|
+
expr.kids[name] = kidExpr.map(e => {
|
|
727
|
+
return { ...e, sql: subExpr(this, e) };
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
else {
|
|
731
|
+
expr.kids[name] = { ...oldKids[name], sql: subExpr(this, kidExpr) };
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
/*
|
|
736
|
+
* Give the dialect a chance to translate this node
|
|
737
|
+
*/
|
|
738
|
+
const qi = resultSet.getQueryInfo();
|
|
739
|
+
const dialectSQL = this.parent.dialect.exprToSQL(qi, expr);
|
|
740
|
+
if (dialectSQL) {
|
|
741
|
+
return dialectSQL;
|
|
742
|
+
}
|
|
743
|
+
switch (expr.node) {
|
|
744
|
+
case 'field':
|
|
745
|
+
return this.generateFieldFragment(resultSet, context, expr, state);
|
|
746
|
+
case 'parameter':
|
|
747
|
+
return this.generateParameterFragment(resultSet, context, expr, state);
|
|
748
|
+
case 'filteredExpr':
|
|
749
|
+
return this.generateFilterFragment(resultSet, context, expr, state);
|
|
750
|
+
case 'all':
|
|
751
|
+
case 'exclude':
|
|
752
|
+
return this.generateUngroupedFragment(resultSet, context, expr, state);
|
|
753
|
+
case 'genericSQLExpr':
|
|
754
|
+
return Array.from(this.stringsFromSQLExpression(resultSet, context, expr, state)).join('');
|
|
755
|
+
case 'aggregate': {
|
|
756
|
+
let agg = '';
|
|
707
757
|
if (expr.function === 'sum') {
|
|
708
758
|
agg = this.generateSumFragment(resultSet, context, expr, state);
|
|
709
759
|
}
|
|
@@ -713,7 +763,9 @@ class QueryField extends QueryNode {
|
|
|
713
763
|
else if (expr.function === 'count') {
|
|
714
764
|
agg = this.generateCountFragment(resultSet, context, expr, state);
|
|
715
765
|
}
|
|
716
|
-
else if (
|
|
766
|
+
else if (expr.function === 'min' ||
|
|
767
|
+
expr.function === 'max' ||
|
|
768
|
+
expr.function === 'distinct') {
|
|
717
769
|
agg = this.generateSymmetricFragment(resultSet, context, expr, state);
|
|
718
770
|
}
|
|
719
771
|
else {
|
|
@@ -724,68 +776,92 @@ class QueryField extends QueryNode {
|
|
|
724
776
|
if (state.totalGroupSet !== -1) {
|
|
725
777
|
groupSet = state.totalGroupSet;
|
|
726
778
|
}
|
|
727
|
-
|
|
728
|
-
}
|
|
729
|
-
else {
|
|
730
|
-
s += agg;
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
else if ((0, malloy_types_1.isApplyFragment)(expr)) {
|
|
734
|
-
const applyVal = this.generateExpressionFromExpr(resultSet, context, expr.value, state);
|
|
735
|
-
s += this.generateExpressionFromExpr(resultSet, context, expr.to, state.withApply(applyVal));
|
|
736
|
-
}
|
|
737
|
-
else if ((0, malloy_types_1.isApplyValue)(expr)) {
|
|
738
|
-
if (state.applyValue) {
|
|
739
|
-
s += state.applyValue;
|
|
740
|
-
}
|
|
741
|
-
else {
|
|
742
|
-
throw new Error('Internal Error: Partial application value referenced but not provided');
|
|
779
|
+
return this.caseGroup([groupSet], agg);
|
|
743
780
|
}
|
|
781
|
+
return agg;
|
|
744
782
|
}
|
|
745
|
-
|
|
783
|
+
case 'function_parameter':
|
|
746
784
|
throw new Error('Internal Error: Function parameter fragment remaining during SQL generation');
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
785
|
+
case 'outputField':
|
|
786
|
+
return this.generateOutputFieldFragment(resultSet, context, expr, state);
|
|
787
|
+
case 'function_call':
|
|
788
|
+
return this.generateFunctionCallExpression(resultSet, context, expr, state);
|
|
789
|
+
case 'spread':
|
|
790
|
+
return this.generateSpread(resultSet, context, expr, state);
|
|
791
|
+
case 'source-reference':
|
|
792
|
+
return this.generateSourceReference(resultSet, context, expr);
|
|
793
|
+
case '+':
|
|
794
|
+
case '-':
|
|
795
|
+
case '*':
|
|
796
|
+
case '%':
|
|
797
|
+
case '/':
|
|
798
|
+
case '=':
|
|
799
|
+
case '!=':
|
|
800
|
+
case '>':
|
|
801
|
+
case '<':
|
|
802
|
+
case '>=':
|
|
803
|
+
case '<=':
|
|
804
|
+
return `${expr.kids.left.sql}${expr.node}${expr.kids.right.sql}`;
|
|
805
|
+
case 'and':
|
|
806
|
+
case 'or':
|
|
807
|
+
return `${expr.kids.left.sql} ${expr.node} ${expr.kids.right.sql}`;
|
|
808
|
+
case 'coalesce':
|
|
809
|
+
return `COALESCE(${expr.kids.left.sql},${expr.kids.right.sql})`;
|
|
810
|
+
case 'like':
|
|
811
|
+
return `${expr.kids.left.sql} LIKE ${expr.kids.right.sql}`;
|
|
812
|
+
case '!like':
|
|
813
|
+
return `${expr.kids.left.sql} NOT LIKE ${expr.kids.right.sql}`;
|
|
814
|
+
case '()':
|
|
815
|
+
return `(${expr.e.sql})`;
|
|
816
|
+
case 'not':
|
|
817
|
+
return `NOT ${expr.e.sql}`;
|
|
818
|
+
case 'unary-':
|
|
819
|
+
return `-${expr.e.sql}`;
|
|
820
|
+
case 'is-null':
|
|
821
|
+
return `${expr.e.sql} IS NULL`;
|
|
822
|
+
case 'is-not-null':
|
|
823
|
+
return `${expr.e.sql} IS NOT NULL`;
|
|
824
|
+
case 'true':
|
|
825
|
+
case 'false':
|
|
826
|
+
return expr.node;
|
|
827
|
+
case 'null':
|
|
828
|
+
return 'NULL';
|
|
829
|
+
case 'pick':
|
|
830
|
+
return this.generatePickSQL(expr);
|
|
831
|
+
case '':
|
|
832
|
+
return '';
|
|
833
|
+
case 'filterCondition':
|
|
834
|
+
// our child will be translated at the top of this function
|
|
835
|
+
if (expr.e.sql) {
|
|
836
|
+
expr.sql = expr.e.sql;
|
|
837
|
+
return expr.sql;
|
|
838
|
+
}
|
|
839
|
+
return '';
|
|
840
|
+
case 'functionDefaultOrderBy':
|
|
841
|
+
case 'functionOrderBy':
|
|
842
|
+
return '';
|
|
843
|
+
default:
|
|
844
|
+
throw new Error(`Internal Error: Unknown expression node '${expr.node}' ${JSON.stringify(expr, undefined, 2)}`);
|
|
772
845
|
}
|
|
773
|
-
return s;
|
|
774
846
|
}
|
|
775
847
|
getExpr() {
|
|
776
848
|
if ((0, malloy_types_1.hasExpression)(this.fieldDef)) {
|
|
777
849
|
return this.fieldDef.e;
|
|
778
850
|
}
|
|
779
|
-
return
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
851
|
+
return {
|
|
852
|
+
node: 'genericSQLExpr',
|
|
853
|
+
kids: { args: [] },
|
|
854
|
+
src: [
|
|
855
|
+
this.parent.dialect.sqlFieldReference(this.parent.getSQLIdentifier(), this.fieldDef.name, this.fieldDef.type, this.parent.fieldDef.structSource.type === 'nested' ||
|
|
856
|
+
this.parent.fieldDef.structSource.type === 'inline' ||
|
|
857
|
+
(this.parent.fieldDef.structSource.type === 'sql' &&
|
|
858
|
+
this.parent.fieldDef.structSource.method === 'nested'), this.parent.fieldDef.structRelationship.type === 'nested' &&
|
|
859
|
+
this.parent.fieldDef.structRelationship.isArray),
|
|
860
|
+
],
|
|
861
|
+
};
|
|
786
862
|
}
|
|
787
863
|
generateExpression(resultSet) {
|
|
788
|
-
return this.
|
|
864
|
+
return this.exprToSQL(resultSet, this.parent, this.getExpr());
|
|
789
865
|
}
|
|
790
866
|
}
|
|
791
867
|
function isCalculatedField(f) {
|
|
@@ -843,14 +919,13 @@ class QueryFieldStruct extends QueryAtomicField {
|
|
|
843
919
|
structRelationship: {
|
|
844
920
|
type: 'one',
|
|
845
921
|
matrixOperation: 'left',
|
|
846
|
-
onExpression:
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
path: [this.primaryKey],
|
|
922
|
+
onExpression: {
|
|
923
|
+
node: '=',
|
|
924
|
+
kids: {
|
|
925
|
+
left: { node: 'field', path: [this.primaryKey] },
|
|
926
|
+
right: { node: 'field', path: [foreignKeyName] },
|
|
850
927
|
},
|
|
851
|
-
|
|
852
|
-
{ type: 'field', path: [foreignKeyName] },
|
|
853
|
-
],
|
|
928
|
+
},
|
|
854
929
|
},
|
|
855
930
|
};
|
|
856
931
|
}
|
|
@@ -862,8 +937,12 @@ class QueryFieldDate extends QueryAtomicField {
|
|
|
862
937
|
return super.generateExpression(resultSet);
|
|
863
938
|
}
|
|
864
939
|
else {
|
|
865
|
-
const truncated =
|
|
866
|
-
|
|
940
|
+
const truncated = {
|
|
941
|
+
node: 'trunc',
|
|
942
|
+
e: { ...this.getExpr(), dataType: 'date' },
|
|
943
|
+
units: fd.timeframe,
|
|
944
|
+
};
|
|
945
|
+
return this.exprToSQL(resultSet, this.parent, truncated);
|
|
867
946
|
}
|
|
868
947
|
}
|
|
869
948
|
// clone ourselves on demand as a timeframe.
|
|
@@ -973,6 +1052,12 @@ class FieldInstanceResult {
|
|
|
973
1052
|
this.resultUsesUngrouped = false;
|
|
974
1053
|
this.firstSegment = turtleDef.pipeline[0];
|
|
975
1054
|
}
|
|
1055
|
+
/**
|
|
1056
|
+
* Information about the query containing this result set. Invented
|
|
1057
|
+
* to pass on timezone information, but maybe more things will
|
|
1058
|
+
* eventually go in here.
|
|
1059
|
+
* @returns QueryInfo
|
|
1060
|
+
*/
|
|
976
1061
|
getQueryInfo() {
|
|
977
1062
|
if (!(0, malloy_types_1.isIndexSegment)(this.firstSegment) &&
|
|
978
1063
|
!(0, malloy_types_1.isRawSegment)(this.firstSegment)) {
|
|
@@ -1371,7 +1456,7 @@ class JoinInstance {
|
|
|
1371
1456
|
const qf = new QueryFieldBoolean({
|
|
1372
1457
|
type: 'boolean',
|
|
1373
1458
|
name: 'ignoreme',
|
|
1374
|
-
e: filter.
|
|
1459
|
+
e: filter.e,
|
|
1375
1460
|
}, this.queryStruct);
|
|
1376
1461
|
this.joinFilterConditions.push(qf);
|
|
1377
1462
|
}
|
|
@@ -1528,31 +1613,46 @@ class QueryQuery extends QueryField {
|
|
|
1528
1613
|
}
|
|
1529
1614
|
addDependantExpr(resultStruct, context, e, joinStack) {
|
|
1530
1615
|
var _a;
|
|
1531
|
-
for (const expr of e) {
|
|
1532
|
-
if (
|
|
1533
|
-
(0, malloy_types_1.expressionIsAnalytic)(expr.overload.returnType.expressionType) &&
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1616
|
+
for (const expr of (0, utils_1.exprWalk)(e)) {
|
|
1617
|
+
if (expr.node === 'function_call') {
|
|
1618
|
+
if ((0, malloy_types_1.expressionIsAnalytic)(expr.overload.returnType.expressionType) &&
|
|
1619
|
+
this.parent.dialect.cantPartitionWindowFunctionsOnExpressions) {
|
|
1620
|
+
// force the use of a lateral_join_bag
|
|
1621
|
+
resultStruct.root().isComplexQuery = true;
|
|
1622
|
+
resultStruct.root().queryUsesPartitioning = true;
|
|
1623
|
+
}
|
|
1624
|
+
const isSymmetric = (_a = expr.overload.isSymmetric) !== null && _a !== void 0 ? _a : false;
|
|
1625
|
+
const isAggregate = (0, malloy_types_1.expressionIsAggregate)(expr.overload.returnType.expressionType);
|
|
1626
|
+
const isAsymmetricAggregate = isAggregate && !isSymmetric;
|
|
1627
|
+
const uniqueKeyPossibleUse = isAsymmetricAggregate
|
|
1628
|
+
? 'generic_asymmetric_aggregate'
|
|
1629
|
+
: undefined;
|
|
1630
|
+
if (expr.structPath) {
|
|
1631
|
+
this.addDependantPath(resultStruct, context, expr.structPath, uniqueKeyPossibleUse, joinStack);
|
|
1632
|
+
}
|
|
1633
|
+
else if (isAsymmetricAggregate) {
|
|
1634
|
+
resultStruct.addStructToJoin(context, this, uniqueKeyPossibleUse, joinStack);
|
|
1635
|
+
}
|
|
1636
|
+
if ((0, malloy_types_1.expressionIsAnalytic)(expr.overload.returnType.expressionType)) {
|
|
1637
|
+
resultStruct.root().queryUsesPartitioning = true;
|
|
1638
|
+
}
|
|
1538
1639
|
}
|
|
1539
|
-
if (
|
|
1640
|
+
else if (expr.node === 'all' || expr.node === 'exclude') {
|
|
1540
1641
|
resultStruct.resultUsesUngrouped = true;
|
|
1541
1642
|
resultStruct.root().isComplexQuery = true;
|
|
1542
1643
|
resultStruct.root().queryUsesPartitioning = true;
|
|
1543
1644
|
if (expr.fields && expr.fields.length > 0) {
|
|
1544
|
-
const key = expr.fields.sort().join('|') + expr.
|
|
1645
|
+
const key = expr.fields.sort().join('|') + expr.node;
|
|
1545
1646
|
if (resultStruct.ungroupedSets.get(key) === undefined) {
|
|
1546
1647
|
resultStruct.ungroupedSets.set(key, {
|
|
1547
|
-
type: expr.
|
|
1648
|
+
type: expr.node,
|
|
1548
1649
|
fields: expr.fields,
|
|
1549
1650
|
groupSet: -1,
|
|
1550
1651
|
});
|
|
1551
1652
|
}
|
|
1552
1653
|
}
|
|
1553
|
-
this.addDependantExpr(resultStruct, context, expr.e, joinStack);
|
|
1554
1654
|
}
|
|
1555
|
-
|
|
1655
|
+
if (expr.node === 'field') {
|
|
1556
1656
|
const field = context.getDimensionOrMeasureByName(expr.path);
|
|
1557
1657
|
if ((0, malloy_types_1.hasExpression)(field.fieldDef)) {
|
|
1558
1658
|
this.addDependantExpr(resultStruct, field.parent, field.fieldDef.e, joinStack);
|
|
@@ -1561,54 +1661,10 @@ class QueryQuery extends QueryField {
|
|
|
1561
1661
|
resultStruct
|
|
1562
1662
|
.root()
|
|
1563
1663
|
.addStructToJoin(field.parent.getJoinableParent(), this, undefined, joinStack);
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
for (const filterCond of expr.filterList) {
|
|
1569
|
-
this.addDependantExpr(resultStruct, context, filterCond.expression, joinStack);
|
|
1570
|
-
this.addDependantExpr(resultStruct, context, expr.e, joinStack);
|
|
1571
|
-
}
|
|
1572
|
-
this.addDependantExpr(resultStruct, context, expr.e, joinStack);
|
|
1573
|
-
}
|
|
1574
|
-
else if ((0, malloy_types_1.isDialectFragment)(expr)) {
|
|
1575
|
-
const expressions = [];
|
|
1576
|
-
switch (expr.function) {
|
|
1577
|
-
case 'now':
|
|
1578
|
-
break;
|
|
1579
|
-
case 'div':
|
|
1580
|
-
case 'mod':
|
|
1581
|
-
expressions.push(expr.denominator);
|
|
1582
|
-
expressions.push(expr.numerator);
|
|
1583
|
-
break;
|
|
1584
|
-
case 'numberLiteral':
|
|
1585
|
-
case 'timeLiteral':
|
|
1586
|
-
case 'stringLiteral':
|
|
1587
|
-
case 'regexpLiteral':
|
|
1588
|
-
break;
|
|
1589
|
-
case 'timeDiff':
|
|
1590
|
-
expressions.push(expr.left.value, expr.right.value);
|
|
1591
|
-
break;
|
|
1592
|
-
case 'delta':
|
|
1593
|
-
expressions.push(expr.base.value, expr.delta);
|
|
1594
|
-
break;
|
|
1595
|
-
case 'trunc':
|
|
1596
|
-
case 'extract':
|
|
1597
|
-
expressions.push(expr.expr.value);
|
|
1598
|
-
break;
|
|
1599
|
-
case 'regexpMatch':
|
|
1600
|
-
case 'cast':
|
|
1601
|
-
expressions.push(expr.expr);
|
|
1602
|
-
break;
|
|
1603
|
-
default:
|
|
1604
|
-
throw new Error("Unknown dialect Fragment type. Can't generate dependancies");
|
|
1605
|
-
}
|
|
1606
|
-
for (const e of expressions) {
|
|
1607
|
-
this.addDependantExpr(resultStruct, context, e, joinStack);
|
|
1608
|
-
}
|
|
1609
|
-
}
|
|
1610
|
-
else if ((0, malloy_types_1.isAggregateFragment)(expr)) {
|
|
1611
|
-
if ((0, malloy_types_1.isAsymmetricFragment)(expr)) {
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
else if (expr.node === 'aggregate') {
|
|
1667
|
+
if ((0, malloy_types_1.isAsymmetricExpr)(expr)) {
|
|
1612
1668
|
if (expr.structPath) {
|
|
1613
1669
|
this.addDependantPath(resultStruct, context, expr.structPath, expr.function, joinStack);
|
|
1614
1670
|
}
|
|
@@ -1617,34 +1673,6 @@ class QueryQuery extends QueryField {
|
|
|
1617
1673
|
resultStruct.addStructToJoin(context, this, expr.function, joinStack);
|
|
1618
1674
|
}
|
|
1619
1675
|
}
|
|
1620
|
-
this.addDependantExpr(resultStruct, context, expr.e, joinStack);
|
|
1621
|
-
}
|
|
1622
|
-
else if ((0, malloy_types_1.isFunctionCallFragment)(expr)) {
|
|
1623
|
-
const isSymmetric = (_a = expr.overload.isSymmetric) !== null && _a !== void 0 ? _a : false;
|
|
1624
|
-
const isAggregate = (0, malloy_types_1.expressionIsAggregate)(expr.overload.returnType.expressionType);
|
|
1625
|
-
const isAsymmetricAggregate = isAggregate && !isSymmetric;
|
|
1626
|
-
const uniqueKeyPossibleUse = isAsymmetricAggregate
|
|
1627
|
-
? 'generic_asymmetric_aggregate'
|
|
1628
|
-
: undefined;
|
|
1629
|
-
if (expr.structPath) {
|
|
1630
|
-
this.addDependantPath(resultStruct, context, expr.structPath, uniqueKeyPossibleUse, joinStack);
|
|
1631
|
-
}
|
|
1632
|
-
else if (isAsymmetricAggregate) {
|
|
1633
|
-
resultStruct.addStructToJoin(context, this, uniqueKeyPossibleUse, joinStack);
|
|
1634
|
-
}
|
|
1635
|
-
for (const e of expr.args) {
|
|
1636
|
-
this.addDependantExpr(resultStruct, context, e, joinStack);
|
|
1637
|
-
}
|
|
1638
|
-
if ((0, malloy_types_1.expressionIsAnalytic)(expr.overload.returnType.expressionType)) {
|
|
1639
|
-
resultStruct.root().queryUsesPartitioning = true;
|
|
1640
|
-
}
|
|
1641
|
-
if (expr.orderBy) {
|
|
1642
|
-
for (const ob of expr.orderBy) {
|
|
1643
|
-
if (ob.e) {
|
|
1644
|
-
this.addDependantExpr(resultStruct, context, ob.e, joinStack);
|
|
1645
|
-
}
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
1676
|
}
|
|
1649
1677
|
}
|
|
1650
1678
|
}
|
|
@@ -1716,7 +1744,7 @@ class QueryQuery extends QueryField {
|
|
|
1716
1744
|
// in the correct catgory.
|
|
1717
1745
|
for (const cond of resultStruct.firstSegment.filterList || []) {
|
|
1718
1746
|
const context = this.parent;
|
|
1719
|
-
this.addDependantExpr(resultStruct, context, cond.
|
|
1747
|
+
this.addDependantExpr(resultStruct, context, cond.e, []);
|
|
1720
1748
|
}
|
|
1721
1749
|
for (const join of resultStruct.root().joins.values() || []) {
|
|
1722
1750
|
for (const qf of join.joinFilterConditions || []) {
|
|
@@ -1726,9 +1754,11 @@ class QueryQuery extends QueryField {
|
|
|
1726
1754
|
}
|
|
1727
1755
|
}
|
|
1728
1756
|
}
|
|
1729
|
-
generateSQLFilters(resultStruct, which
|
|
1757
|
+
generateSQLFilters(resultStruct, which
|
|
1758
|
+
// filterList: FilterCondition[] | undefined = undefined
|
|
1759
|
+
) {
|
|
1730
1760
|
const resultFilters = new utils_1.AndChain();
|
|
1731
|
-
const list =
|
|
1761
|
+
const list = resultStruct.firstSegment.filterList;
|
|
1732
1762
|
if (list === undefined) {
|
|
1733
1763
|
return resultFilters;
|
|
1734
1764
|
}
|
|
@@ -1739,7 +1769,7 @@ class QueryQuery extends QueryField {
|
|
|
1739
1769
|
const context = this.parent;
|
|
1740
1770
|
if ((which === 'having' && (0, malloy_types_1.expressionIsCalculation)(cond.expressionType)) ||
|
|
1741
1771
|
(which === 'where' && (0, malloy_types_1.expressionIsScalar)(cond.expressionType))) {
|
|
1742
|
-
const sqlClause = this.
|
|
1772
|
+
const sqlClause = this.exprToSQL(resultStruct, context, cond.e, undefined);
|
|
1743
1773
|
resultFilters.add(sqlClause);
|
|
1744
1774
|
}
|
|
1745
1775
|
}
|
|
@@ -2935,9 +2965,7 @@ class QueryStruct extends QueryNode {
|
|
|
2935
2965
|
value: param.value === null
|
|
2936
2966
|
? null
|
|
2937
2967
|
: (0, utils_1.exprMap)(param.value, frag => {
|
|
2938
|
-
if (
|
|
2939
|
-
return [frag];
|
|
2940
|
-
if (frag.type === 'parameter') {
|
|
2968
|
+
if (frag.node === 'parameter') {
|
|
2941
2969
|
if (this.parent === undefined) {
|
|
2942
2970
|
throw new Error('No parent from which to retrieve parameter value');
|
|
2943
2971
|
}
|
|
@@ -2950,7 +2978,7 @@ class QueryStruct extends QueryNode {
|
|
|
2950
2978
|
return resolved2.value;
|
|
2951
2979
|
}
|
|
2952
2980
|
}
|
|
2953
|
-
return
|
|
2981
|
+
return frag;
|
|
2954
2982
|
}),
|
|
2955
2983
|
};
|
|
2956
2984
|
}
|