@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.
Files changed (121) hide show
  1. package/dist/dialect/dialect.d.ts +23 -13
  2. package/dist/dialect/dialect.js +33 -27
  3. package/dist/dialect/duckdb/duckdb.d.ts +7 -11
  4. package/dist/dialect/duckdb/duckdb.js +34 -100
  5. package/dist/dialect/duckdb/functions/greatest_and_least.js +5 -12
  6. package/dist/dialect/functions/concat.js +1 -1
  7. package/dist/dialect/functions/greatest_and_least.js +1 -1
  8. package/dist/dialect/functions/simple_numeric_functions.js +1 -1
  9. package/dist/dialect/functions/sql.js +5 -15
  10. package/dist/dialect/functions/string_agg.js +2 -2
  11. package/dist/dialect/functions/trim_functions.js +2 -2
  12. package/dist/dialect/functions/util.d.ts +6 -9
  13. package/dist/dialect/functions/util.js +29 -38
  14. package/dist/dialect/index.d.ts +1 -1
  15. package/dist/dialect/index.js +1 -2
  16. package/dist/dialect/pg_impl.d.ts +15 -0
  17. package/dist/dialect/pg_impl.js +91 -0
  18. package/dist/dialect/postgres/functions/greatest_and_least.js +1 -3
  19. package/dist/dialect/postgres/functions/string_agg.js +2 -2
  20. package/dist/dialect/postgres/postgres.d.ts +7 -11
  21. package/dist/dialect/postgres/postgres.js +29 -92
  22. package/dist/dialect/snowflake/functions/string_agg.js +2 -2
  23. package/dist/dialect/snowflake/snowflake.d.ts +9 -9
  24. package/dist/dialect/snowflake/snowflake.js +41 -48
  25. package/dist/dialect/standardsql/functions/string_agg.js +4 -4
  26. package/dist/dialect/standardsql/standardsql.d.ts +9 -9
  27. package/dist/dialect/standardsql/standardsql.js +56 -51
  28. package/dist/dialect/trino/functions/concat.js +1 -1
  29. package/dist/dialect/trino/functions/string_agg.js +2 -2
  30. package/dist/dialect/trino/trino.d.ts +11 -12
  31. package/dist/dialect/trino/trino.js +59 -83
  32. package/dist/index.d.ts +3 -3
  33. package/dist/index.js +3 -4
  34. package/dist/lang/ast/ast-utils.d.ts +1 -1
  35. package/dist/lang/ast/ast-utils.js +2 -2
  36. package/dist/lang/ast/expressions/apply.js +1 -2
  37. package/dist/lang/ast/expressions/binary-boolean.d.ts +2 -1
  38. package/dist/lang/ast/expressions/binary-boolean.js +6 -3
  39. package/dist/lang/ast/expressions/binary-numeric.d.ts +2 -1
  40. package/dist/lang/ast/expressions/boolean.js +1 -1
  41. package/dist/lang/ast/expressions/constant-expression.d.ts +3 -3
  42. package/dist/lang/ast/expressions/constant-expression.js +0 -23
  43. package/dist/lang/ast/expressions/expr-aggregate-function.js +24 -34
  44. package/dist/lang/ast/expressions/expr-alternation-tree.d.ts +6 -3
  45. package/dist/lang/ast/expressions/expr-alternation-tree.js +10 -5
  46. package/dist/lang/ast/expressions/expr-cast.js +1 -2
  47. package/dist/lang/ast/expressions/expr-coalesce.js +4 -1
  48. package/dist/lang/ast/expressions/expr-compare.d.ts +3 -3
  49. package/dist/lang/ast/expressions/expr-count-distinct.js +1 -1
  50. package/dist/lang/ast/expressions/expr-count.js +3 -3
  51. package/dist/lang/ast/expressions/expr-func.js +15 -18
  52. package/dist/lang/ast/expressions/expr-granular-time.js +8 -10
  53. package/dist/lang/ast/expressions/expr-id-reference.js +2 -2
  54. package/dist/lang/ast/expressions/expr-minus.js +5 -4
  55. package/dist/lang/ast/expressions/expr-not.js +1 -1
  56. package/dist/lang/ast/expressions/expr-now.js +1 -6
  57. package/dist/lang/ast/expressions/expr-null.js +1 -1
  58. package/dist/lang/ast/expressions/expr-number.js +1 -1
  59. package/dist/lang/ast/expressions/expr-parens.js +1 -1
  60. package/dist/lang/ast/expressions/expr-props.js +4 -7
  61. package/dist/lang/ast/expressions/expr-regex.js +1 -3
  62. package/dist/lang/ast/expressions/expr-string.js +1 -7
  63. package/dist/lang/ast/expressions/expr-time-extract.js +12 -16
  64. package/dist/lang/ast/expressions/expr-time.d.ts +2 -2
  65. package/dist/lang/ast/expressions/expr-time.js +4 -6
  66. package/dist/lang/ast/expressions/expr-ungroup.js +2 -2
  67. package/dist/lang/ast/expressions/for-range.d.ts +2 -1
  68. package/dist/lang/ast/expressions/function-ordering.js +5 -5
  69. package/dist/lang/ast/expressions/partial-compare.d.ts +3 -3
  70. package/dist/lang/ast/expressions/pick-when.js +24 -8
  71. package/dist/lang/ast/expressions/range.d.ts +2 -1
  72. package/dist/lang/ast/expressions/range.js +4 -2
  73. package/dist/lang/ast/expressions/time-literal.d.ts +4 -3
  74. package/dist/lang/ast/expressions/time-literal.js +5 -10
  75. package/dist/lang/ast/expressions/top-by.js +1 -2
  76. package/dist/lang/ast/expressions/utils.d.ts +3 -12
  77. package/dist/lang/ast/expressions/utils.js +8 -56
  78. package/dist/lang/ast/field-space/reference-field.js +1 -1
  79. package/dist/lang/ast/index.d.ts +1 -1
  80. package/dist/lang/ast/index.js +1 -1
  81. package/dist/lang/ast/query-builders/index-builder.d.ts +2 -2
  82. package/dist/lang/ast/query-builders/reduce-builder.d.ts +2 -2
  83. package/dist/lang/ast/query-items/field-declaration.js +1 -5
  84. package/dist/lang/ast/query-properties/filters.d.ts +3 -3
  85. package/dist/lang/ast/query-properties/filters.js +6 -5
  86. package/dist/lang/ast/query-properties/top.js +1 -2
  87. package/dist/lang/ast/source-elements/refined-source.js +1 -1
  88. package/dist/lang/ast/source-properties/joins.js +11 -10
  89. package/dist/lang/ast/time-utils.d.ts +5 -7
  90. package/dist/lang/ast/time-utils.js +17 -57
  91. package/dist/lang/ast/types/binary_operators.d.ts +9 -0
  92. package/dist/lang/ast/types/binary_operators.js +28 -0
  93. package/dist/lang/ast/types/expr-result.d.ts +3 -3
  94. package/dist/lang/ast/types/expression-def.d.ts +4 -3
  95. package/dist/lang/ast/types/expression-def.js +43 -50
  96. package/dist/lang/lib/Malloy/MalloyParser.d.ts +0 -11
  97. package/dist/lang/lib/Malloy/MalloyParser.js +803 -858
  98. package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +0 -13
  99. package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +0 -8
  100. package/dist/lang/malloy-to-ast.d.ts +0 -1
  101. package/dist/lang/malloy-to-ast.js +0 -4
  102. package/dist/lang/test/expressions.spec.js +42 -86
  103. package/dist/lang/test/field-symbols.spec.js +8 -6
  104. package/dist/lang/test/literals.spec.js +6 -6
  105. package/dist/lang/test/model_serialization.spec.js +5 -5
  106. package/dist/lang/test/test-translator.js +9 -7
  107. package/dist/malloy.d.ts +3 -3
  108. package/dist/malloy.js +1 -1
  109. package/dist/model/index.d.ts +1 -1
  110. package/dist/model/index.js +2 -1
  111. package/dist/model/malloy_query.d.ts +24 -19
  112. package/dist/model/malloy_query.js +272 -244
  113. package/dist/model/malloy_types.d.ts +224 -205
  114. package/dist/model/malloy_types.js +19 -98
  115. package/dist/model/utils.d.ts +10 -3
  116. package/dist/model/utils.js +84 -219
  117. package/package.json +1 -1
  118. package/dist/lang/ast/types/comparison.d.ts +0 -11
  119. package/dist/lang/ast/types/comparison.js +0 -41
  120. package/dist/lang/ast/types/equality.d.ts +0 -7
  121. package/dist/lang/ast/types/equality.js +0 -37
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.PostgresBase = exports.timeExtractMap = void 0;
10
+ const dialect_1 = require("./dialect");
11
+ exports.timeExtractMap = {
12
+ 'day_of_week': 'dow',
13
+ 'day_of_year': 'doy',
14
+ };
15
+ /**
16
+ * Many SQL implementations started with the PostGres source, and therefore can use the
17
+ * same implementations for the much of the SQL code generation
18
+ */
19
+ class PostgresBase extends dialect_1.Dialect {
20
+ sqlTruncExpr(qi, df) {
21
+ // adjusting for monday/sunday weeks
22
+ const week = df.units === 'week';
23
+ const truncThis = week ? `${df.e.sql} + INTERVAL '1' DAY` : df.e.sql;
24
+ if (df.e.dataType === 'timestamp') {
25
+ const tz = (0, dialect_1.qtz)(qi);
26
+ if (tz) {
27
+ const civilSource = `(${truncThis}::TIMESTAMPTZ AT TIME ZONE '${tz}')`;
28
+ let civilTrunc = `DATE_TRUNC('${df.units}', ${civilSource})`;
29
+ // MTOY todo ... only need to do this if this is a date ...
30
+ civilTrunc = `${civilTrunc}::TIMESTAMP`;
31
+ const truncTsTz = `${civilTrunc} AT TIME ZONE '${tz}'`;
32
+ return `(${truncTsTz})::TIMESTAMP`;
33
+ }
34
+ }
35
+ let result = `DATE_TRUNC('${df.units}', ${truncThis})`;
36
+ if (week) {
37
+ result = `(${result} - INTERVAL '1' DAY)`;
38
+ }
39
+ return result;
40
+ }
41
+ sqlNowExpr() {
42
+ return 'LOCALTIMESTAMP';
43
+ }
44
+ sqlTimeExtractExpr(qi, from) {
45
+ const units = exports.timeExtractMap[from.units] || from.units;
46
+ let extractFrom = from.e.sql;
47
+ if (from.e.dataType === 'timestamp') {
48
+ const tz = (0, dialect_1.qtz)(qi);
49
+ if (tz) {
50
+ extractFrom = `(${extractFrom}::TIMESTAMPTZ AT TIME ZONE '${tz}')`;
51
+ }
52
+ }
53
+ const extracted = `EXTRACT(${units} FROM ${extractFrom})`;
54
+ return from.units === 'day_of_week' ? `mod(${extracted}+1,7)` : extracted;
55
+ }
56
+ sqlCast(qi, cast) {
57
+ const expr = cast.e.sql || '';
58
+ const op = `${cast.srcType}::${cast.dstType}`;
59
+ const tz = (0, dialect_1.qtz)(qi);
60
+ if (op === 'timestamp::date' && tz) {
61
+ const tstz = `${expr}::TIMESTAMPTZ`;
62
+ return `CAST((${tstz}) AT TIME ZONE '${tz}' AS DATE)`;
63
+ }
64
+ else if (op === 'date::timestamp' && tz) {
65
+ return `CAST((${expr})::TIMESTAMP AT TIME ZONE '${tz}' AS TIMESTAMP)`;
66
+ }
67
+ if (cast.srcType !== cast.dstType) {
68
+ const dstType = typeof cast.dstType === 'string'
69
+ ? this.malloyTypeToSQLType({ type: cast.dstType })
70
+ : cast.dstType.raw;
71
+ const castFunc = cast.safe ? 'TRY_CAST' : 'CAST';
72
+ return `${castFunc}(${expr} AS ${dstType})`;
73
+ }
74
+ return expr;
75
+ }
76
+ sqlRegexpMatch(df) {
77
+ return `${df.kids.expr.sql} ~ ${df.kids.regex.sql}`;
78
+ }
79
+ sqlLiteralTime(qi, lt) {
80
+ if (lt.dataType === 'date') {
81
+ return `DATE '${lt.literal}'`;
82
+ }
83
+ const tz = lt.timezone || (0, dialect_1.qtz)(qi);
84
+ if (tz) {
85
+ return `TIMESTAMPTZ '${lt.literal} ${tz}'::TIMESTAMP`;
86
+ }
87
+ return `TIMESTAMP '${lt.literal}'`;
88
+ }
89
+ }
90
+ exports.PostgresBase = PostgresBase;
91
+ //# sourceMappingURL=pg_impl.js.map
@@ -34,9 +34,7 @@ const types = [
34
34
  function greatestOrLeast(fn) {
35
35
  return types.map(type => (0, util_1.overload)((0, util_1.minScalar)(type), [(0, util_1.params)('values', (0, util_1.anyExprType)(type))],
36
36
  // We match BigQuery null behavior here -- if any argument is null, return null
37
- [
38
- (0, util_1.sqlFragment)('CASE WHEN NUM_NULLS(', (0, util_1.spread)((0, util_1.arg)('values')), `) > 0 THEN NULL ELSE ${fn}(`, (0, util_1.spread)((0, util_1.arg)('values')), ') END'),
39
- ]));
37
+ (0, util_1.sql) `CASE WHEN NUM_NULLS(${(0, util_1.spread)((0, util_1.arg)('values'))}) > 0 THEN NULL ELSE ${fn}(${(0, util_1.spread)((0, util_1.arg)('values'))}) END`));
40
38
  }
41
39
  const fnGreatest = () => greatestOrLeast('GREATEST');
42
40
  exports.fnGreatest = fnGreatest;
@@ -27,7 +27,7 @@ const util_1 = require("../../functions/util");
27
27
  function fnStringAgg() {
28
28
  const value = (0, util_1.makeParam)('value', (0, util_1.maxScalar)('string'));
29
29
  const separator = (0, util_1.makeParam)('separator', (0, util_1.literal)((0, util_1.maxScalar)('string')));
30
- const orderBy = { type: 'aggregate_order_by' };
30
+ const orderBy = { node: 'aggregate_order_by' };
31
31
  return [
32
32
  (0, util_1.overload)((0, util_1.minAggregate)('string'), [value.param], (0, util_1.sql) `STRING_AGG(${value.arg}, ','${orderBy})`, { supportsOrderBy: true }),
33
33
  (0, util_1.overload)((0, util_1.minAggregate)('string'), [value.param, separator.param], (0, util_1.sql) `STRING_AGG(${value.arg}, ${separator.arg}${orderBy})`, { supportsOrderBy: true }),
@@ -37,7 +37,7 @@ exports.fnStringAgg = fnStringAgg;
37
37
  function fnStringAggDistinct() {
38
38
  const value = (0, util_1.makeParam)('value', (0, util_1.maxScalar)('string'));
39
39
  const separator = (0, util_1.makeParam)('separator', (0, util_1.literal)((0, util_1.maxScalar)('string')));
40
- const orderBy = { type: 'aggregate_order_by' };
40
+ const orderBy = { node: 'aggregate_order_by' };
41
41
  return [
42
42
  (0, util_1.overload)((0, util_1.minAggregate)('string'), [value.param], (0, util_1.sql) `STRING_AGG(DISTINCT ${value.arg}, ','${orderBy})`, {
43
43
  isSymmetric: true,
@@ -1,7 +1,8 @@
1
- import { DateUnit, Expr, ExtractUnit, Sampling, TimeFieldType, TimeValue, TimestampUnit, TypecastFragment, FieldAtomicTypeDef } from '../../model/malloy_types';
1
+ import { Sampling, FieldAtomicTypeDef, TimeDeltaExpr, TypecastExpr, MeasureTimeExpr } from '../../model/malloy_types';
2
2
  import { DialectFunctionOverloadDef } from '../functions';
3
- import { Dialect, DialectFieldList, QueryInfo } from '../dialect';
4
- export declare class PostgresDialect extends Dialect {
3
+ import { DialectFieldList, QueryInfo } from '../dialect';
4
+ import { PostgresBase } from '../pg_impl';
5
+ export declare class PostgresDialect extends PostgresBase {
5
6
  name: string;
6
7
  defaultNumberType: string;
7
8
  defaultDecimalType: string;
@@ -42,14 +43,9 @@ export declare class PostgresDialect extends Dialect {
42
43
  sqlSelectAliasAsStruct(alias: string): string;
43
44
  sqlMaybeQuoteIdentifier(identifier: string): string;
44
45
  sqlCreateTableAsSelect(_tableName: string, _sql: string): string;
45
- sqlNow(): Expr;
46
- sqlTrunc(qi: QueryInfo, sqlTime: TimeValue, units: TimestampUnit): Expr;
47
- sqlExtract(qi: QueryInfo, from: TimeValue, units: ExtractUnit): Expr;
48
- sqlAlterTime(op: '+' | '-', expr: TimeValue, n: Expr, timeframe: DateUnit): Expr;
49
- sqlCast(qi: QueryInfo, cast: TypecastFragment): Expr;
50
- sqlRegexpMatch(expr: Expr, regexp: Expr): Expr;
51
- sqlLiteralTime(qi: QueryInfo, timeString: string, type: TimeFieldType, timezone: string | undefined): string;
52
- sqlMeasureTime(from: TimeValue, to: TimeValue, units: string): Expr;
46
+ sqlAlterTimeExpr(df: TimeDeltaExpr): string;
47
+ sqlCast(qi: QueryInfo, cast: TypecastExpr): string;
48
+ sqlMeasureTimeExpr(df: MeasureTimeExpr): string;
53
49
  sqlSumDistinct(key: string, value: string, funcName: string): string;
54
50
  sqlAggDistinct(key: string, values: string[], func: (valNames: string[]) => string): string;
55
51
  sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
@@ -26,11 +26,7 @@ exports.PostgresDialect = void 0;
26
26
  const utils_1 = require("../../model/utils");
27
27
  const malloy_types_1 = require("../../model/malloy_types");
28
28
  const functions_1 = require("./functions");
29
- const dialect_1 = require("../dialect");
30
- const pgExtractionMap = {
31
- 'day_of_week': 'dow',
32
- 'day_of_year': 'doy',
33
- };
29
+ const pg_impl_1 = require("../pg_impl");
34
30
  const pgMakeIntervalMap = {
35
31
  'year': 'years',
36
32
  'month': 'months',
@@ -73,7 +69,7 @@ const postgresToMalloyTypes = {
73
69
  'pg_ndistinct': { type: 'number', numberType: 'integer' },
74
70
  'varchar': { type: 'string' },
75
71
  };
76
- class PostgresDialect extends dialect_1.Dialect {
72
+ class PostgresDialect extends pg_impl_1.PostgresBase {
77
73
  constructor() {
78
74
  super(...arguments);
79
75
  this.name = 'postgres';
@@ -243,99 +239,40 @@ class PostgresDialect extends dialect_1.Dialect {
243
239
  sqlCreateTableAsSelect(_tableName, _sql) {
244
240
  throw new Error('Not implemented Yet');
245
241
  }
246
- sqlNow() {
247
- return (0, malloy_types_1.mkExpr) `LOCALTIMESTAMP`;
248
- }
249
- sqlTrunc(qi, sqlTime, units) {
250
- // adjusting for monday/sunday weeks
251
- const week = units === 'week';
252
- const truncThis = week
253
- ? (0, malloy_types_1.mkExpr) `${sqlTime.value} + INTERVAL '1' DAY`
254
- : sqlTime.value;
255
- if (sqlTime.valueType === 'timestamp') {
256
- const tz = (0, dialect_1.qtz)(qi);
257
- if (tz) {
258
- const civilSource = (0, malloy_types_1.mkExpr) `(${truncThis}::TIMESTAMPTZ AT TIME ZONE '${tz}')`;
259
- let civilTrunc = (0, malloy_types_1.mkExpr) `DATE_TRUNC('${units}', ${civilSource})`;
260
- // MTOY todo ... only need to do this if this is a date ...
261
- civilTrunc = (0, malloy_types_1.mkExpr) `${civilTrunc}::TIMESTAMP`;
262
- const truncTsTz = (0, malloy_types_1.mkExpr) `${civilTrunc} AT TIME ZONE '${tz}'`;
263
- return (0, malloy_types_1.mkExpr) `(${truncTsTz})::TIMESTAMP`;
264
- }
265
- }
266
- let result = (0, malloy_types_1.mkExpr) `DATE_TRUNC('${units}', ${truncThis})`;
267
- if (week) {
268
- result = (0, malloy_types_1.mkExpr) `(${result} - INTERVAL '1' DAY)`;
269
- }
270
- return result;
271
- }
272
- sqlExtract(qi, from, units) {
273
- const pgUnits = pgExtractionMap[units] || units;
274
- let extractFrom = from.value;
275
- if (from.valueType === 'timestamp') {
276
- const tz = (0, dialect_1.qtz)(qi);
277
- if (tz) {
278
- extractFrom = (0, malloy_types_1.mkExpr) `(${extractFrom}::TIMESTAMPTZ AT TIME ZONE '${tz}')`;
279
- }
280
- }
281
- const extracted = (0, malloy_types_1.mkExpr) `EXTRACT(${pgUnits} FROM ${extractFrom})`;
282
- return units === 'day_of_week' ? (0, malloy_types_1.mkExpr) `(${extracted}+1)` : extracted;
283
- }
284
- sqlAlterTime(op, expr, n, timeframe) {
242
+ sqlAlterTimeExpr(df) {
243
+ let timeframe = df.units;
244
+ let n = df.kids.delta.sql;
285
245
  if (timeframe === 'quarter') {
286
246
  timeframe = 'month';
287
- n = (0, malloy_types_1.mkExpr) `${n}*3`;
247
+ n = `${n}*3`;
288
248
  }
289
- const interval = (0, malloy_types_1.mkExpr) `make_interval(${pgMakeIntervalMap[timeframe]}=>${n})`;
290
- return (0, malloy_types_1.mkExpr) `((${expr.value})${op}${interval})`;
291
- }
292
- sqlCast(qi, cast) {
293
- const op = `${cast.srcType}::${cast.dstType}`;
294
- const tz = (0, dialect_1.qtz)(qi);
295
- if (op === 'timestamp::date' && tz) {
296
- const tstz = (0, malloy_types_1.mkExpr) `${cast.expr}::TIMESTAMPTZ`;
297
- return (0, malloy_types_1.mkExpr) `CAST((${tstz}) AT TIME ZONE '${tz}' AS DATE)`;
298
- }
299
- else if (op === 'date::timestamp' && tz) {
300
- return (0, malloy_types_1.mkExpr) `CAST((${cast.expr})::TIMESTAMP AT TIME ZONE '${tz}' AS TIMESTAMP)`;
301
- }
302
- if (cast.srcType !== cast.dstType) {
303
- const dstType = typeof cast.dstType === 'string'
304
- ? this.malloyTypeToSQLType({ type: cast.dstType })
305
- : cast.dstType.raw;
306
- if (cast.safe) {
307
- throw new Error("Postgres dialect doesn't support Safe Cast");
308
- }
309
- const castFunc = 'CAST';
310
- return (0, malloy_types_1.mkExpr) `${castFunc}(${cast.expr} AS ${dstType})`;
249
+ else if (timeframe === 'week') {
250
+ timeframe = 'day';
251
+ n = `${n}*7`;
311
252
  }
312
- return cast.expr;
253
+ const interval = `make_interval(${pgMakeIntervalMap[timeframe]}=>${n})`;
254
+ return `(${df.kids.base.sql})${df.op}${interval}`;
313
255
  }
314
- sqlRegexpMatch(expr, regexp) {
315
- return (0, malloy_types_1.mkExpr) `(${expr} ~ ${regexp})`;
316
- }
317
- sqlLiteralTime(qi, timeString, type, timezone) {
318
- if (type === 'date') {
319
- return `DATE '${timeString}'`;
320
- }
321
- const tz = timezone || (0, dialect_1.qtz)(qi);
322
- if (tz) {
323
- return `TIMESTAMPTZ '${timeString} ${tz}'::TIMESTAMP`;
256
+ sqlCast(qi, cast) {
257
+ if (cast.safe) {
258
+ throw new Error("Postgres dialect doesn't support Safe Cast");
324
259
  }
325
- return `TIMESTAMP '${timeString}'`;
326
- }
327
- sqlMeasureTime(from, to, units) {
328
- let lVal = from.value;
329
- let rVal = to.value;
330
- if (inSeconds[units]) {
331
- lVal = (0, malloy_types_1.mkExpr) `EXTRACT(EPOCH FROM ${lVal})`;
332
- rVal = (0, malloy_types_1.mkExpr) `EXTRACT(EPOCH FROM ${rVal})`;
333
- const duration = (0, malloy_types_1.mkExpr) `${rVal}-${lVal}`;
334
- return units === 'second'
335
- ? (0, malloy_types_1.mkExpr) `FLOOR(${duration})`
336
- : (0, malloy_types_1.mkExpr) `FLOOR((${duration})/${inSeconds[units].toString()}.0)`;
260
+ return super.sqlCast(qi, cast);
261
+ }
262
+ sqlMeasureTimeExpr(df) {
263
+ const from = df.kids.left;
264
+ const to = df.kids.right;
265
+ let lVal = from.sql;
266
+ let rVal = to.sql;
267
+ if (inSeconds[df.units]) {
268
+ lVal = `EXTRACT(EPOCH FROM ${lVal})`;
269
+ rVal = `EXTRACT(EPOCH FROM ${rVal})`;
270
+ const duration = `${rVal}-${lVal}`;
271
+ return df.units === 'second'
272
+ ? `FLOOR(${duration})`
273
+ : `FLOOR((${duration})/${inSeconds[df.units].toString()}.0)`;
337
274
  }
338
- throw new Error(`Unknown or unhandled postgres time unit: ${units}`);
275
+ throw new Error(`Unknown or unhandled postgres time unit: ${df.units}`);
339
276
  }
340
277
  sqlSumDistinct(key, value, funcName) {
341
278
  // return `sum_distinct(list({key:${key}, val: ${value}}))`;
@@ -28,7 +28,7 @@ function fnStringAgg() {
28
28
  const value = (0, util_1.makeParam)('value', (0, util_1.maxScalar)('string'));
29
29
  const separator = (0, util_1.makeParam)('separator', (0, util_1.literal)((0, util_1.maxScalar)('string')));
30
30
  const orderBy = {
31
- type: 'aggregate_order_by',
31
+ node: 'aggregate_order_by',
32
32
  prefix: ' WITHIN GROUP(',
33
33
  suffix: ')',
34
34
  };
@@ -42,7 +42,7 @@ function fnStringAggDistinct() {
42
42
  const value = (0, util_1.makeParam)('value', (0, util_1.maxScalar)('string'));
43
43
  const separator = (0, util_1.makeParam)('separator', (0, util_1.literal)((0, util_1.maxScalar)('string')));
44
44
  const orderBy = {
45
- type: 'aggregate_order_by',
45
+ node: 'aggregate_order_by',
46
46
  prefix: ' WITHIN GROUP(',
47
47
  suffix: ')',
48
48
  };
@@ -1,4 +1,4 @@
1
- import { DateUnit, Expr, ExtractUnit, Sampling, TimeFieldType, TimeValue, TimestampUnit, TypecastFragment, FieldAtomicTypeDef } from '../../model/malloy_types';
1
+ import { Sampling, FieldAtomicTypeDef, TimeTruncExpr, TimeExtractExpr, TimeDeltaExpr, TypecastExpr, TimeLiteralNode, MeasureTimeExpr, RegexMatchExpr } from '../../model/malloy_types';
2
2
  import { DialectFunctionOverloadDef } from '../functions';
3
3
  import { Dialect, DialectFieldList, QueryInfo } from '../dialect';
4
4
  export declare class SnowflakeDialect extends Dialect {
@@ -43,15 +43,15 @@ export declare class SnowflakeDialect extends Dialect {
43
43
  sqlSelectAliasAsStruct(alias: string): string;
44
44
  sqlMaybeQuoteIdentifier(identifier: string): string;
45
45
  sqlCreateTableAsSelect(tableName: string, sql: string): string;
46
- sqlTrunc(qi: QueryInfo, sqlTime: TimeValue, units: TimestampUnit): Expr;
47
- sqlExtract(qi: QueryInfo, from: TimeValue, units: ExtractUnit): Expr;
48
- sqlAlterTime(op: '+' | '-', expr: TimeValue, n: Expr, timeframe: DateUnit): Expr;
46
+ sqlTruncExpr(qi: QueryInfo, te: TimeTruncExpr): string;
47
+ sqlTimeExtractExpr(qi: QueryInfo, from: TimeExtractExpr): string;
48
+ sqlAlterTimeExpr(df: TimeDeltaExpr): string;
49
49
  private atTz;
50
- sqlNow(): Expr;
51
- sqlCast(qi: QueryInfo, cast: TypecastFragment): Expr;
52
- sqlLiteralTime(qi: QueryInfo, timeString: string, type: TimeFieldType, timezone: string | undefined): string;
53
- sqlMeasureTime(from: TimeValue, to: TimeValue, units: string): Expr;
54
- sqlRegexpMatch(expr: Expr, regexp: Expr): Expr;
50
+ sqlNowExpr(): string;
51
+ sqlCast(qi: QueryInfo, cast: TypecastExpr): string;
52
+ sqlLiteralTime(qi: QueryInfo, lf: TimeLiteralNode): string;
53
+ sqlMeasureTimeExpr(df: MeasureTimeExpr): string;
54
+ sqlRegexpMatch(compare: RegexMatchExpr): string;
55
55
  sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
56
56
  sqlOrderBy(orderTerms: string[]): string;
57
57
  sqlLiteralString(literal: string): string;
@@ -141,20 +141,11 @@ class SnowflakeDialect extends dialect_1.Dialect {
141
141
  }
142
142
  sqlUnnestAlias(source, alias, _fieldList, _needDistinctKey, isArray, _isInNestedPipeline) {
143
143
  if (isArray) {
144
- // if (needDistinctKey) {
145
- // // return `LEFT JOIN UNNEST(ARRAY(( SELECT AS STRUCT row_number() over() as __row_id, value FROM UNNEST(${source}) value))) as ${alias}`;
146
- // } else {
147
- // return `LEFT JOIN UNNEST(ARRAY((SELECT AS STRUCT value FROM unnest(${source}) value))) as ${alias}`;
148
- // }
149
144
  return `,LATERAL FLATTEN(INPUT => ${source}) AS ${alias}_1, LATERAL (SELECT ${alias}_1.INDEX, object_construct('value', ${alias}_1.value) as value ) as ${alias}`;
150
145
  }
151
146
  else {
152
147
  // have to have a non empty row or it treats it like an inner join :barf-emoji:
153
148
  return `LEFT JOIN LATERAL FLATTEN(INPUT => ifnull(${source},[1])) AS ${alias}`;
154
- // return `LEFT JOIN UNNEST(ARRAY(( SELECT AS STRUCT row_number() over() as __row_id, * FROM UNNEST(${source})))) as ${alias}`;
155
- // } else {
156
- // return `LEFT JOIN UNNEST(${source}) as ${alias}`;
157
- // }
158
149
  }
159
150
  }
160
151
  /*
@@ -243,43 +234,43 @@ ${(0, utils_1.indent)(sql)}
243
234
  );
244
235
  `;
245
236
  }
246
- sqlTrunc(qi, sqlTime, units) {
237
+ sqlTruncExpr(qi, te) {
247
238
  const tz = (0, dialect_1.qtz)(qi);
248
- let truncThis = sqlTime.value;
249
- if (tz && sqlTime.valueType === 'timestamp') {
250
- truncThis = (0, malloy_types_1.mkExpr) `CONVERT_TIMEZONE('${tz}', ${truncThis})`;
239
+ let truncThis = te.e.sql;
240
+ if (tz && te.e.dataType === 'timestamp') {
241
+ truncThis = `CONVERT_TIMEZONE('${tz}',${truncThis})`;
251
242
  }
252
- return (0, malloy_types_1.mkExpr) `DATE_TRUNC('${units}', ${truncThis})`;
243
+ return `DATE_TRUNC('${te.units}',${truncThis})`;
253
244
  }
254
- sqlExtract(qi, from, units) {
255
- const extractUnits = extractionMap[units] || units;
256
- let extractFrom = from.value;
245
+ sqlTimeExtractExpr(qi, from) {
246
+ const extractUnits = extractionMap[from.units] || from.units;
247
+ let extractFrom = from.e.sql;
257
248
  const tz = (0, dialect_1.qtz)(qi);
258
- if (tz && from.valueType === 'timestamp') {
259
- extractFrom = (0, malloy_types_1.mkExpr) `CONVERT_TIMEZONE('${tz}', ${extractFrom})`;
249
+ if (tz && from.e.dataType === 'timestamp') {
250
+ extractFrom = `CONVERT_TIMEZONE('${tz}', ${extractFrom})`;
260
251
  }
261
- const extracted = (0, malloy_types_1.mkExpr) `EXTRACT(${extractUnits} FROM ${extractFrom})`;
262
- return extracted;
252
+ return `EXTRACT(${extractUnits} FROM ${extractFrom})`;
263
253
  }
264
- sqlAlterTime(op, expr, n, timeframe) {
265
- const interval = (0, malloy_types_1.mkExpr) `INTERVAL '${n} ${timeframe}'`;
266
- return (0, malloy_types_1.mkExpr) `((${expr.value})${op}${interval})`;
254
+ sqlAlterTimeExpr(df) {
255
+ const interval = `INTERVAL '${df.kids.delta.sql} ${df.units}'`;
256
+ return `(${df.kids.base.sql})${df.op}${interval}`;
267
257
  }
268
- atTz(expr, tz) {
258
+ atTz(sqlExpr, tz) {
269
259
  if (tz !== undefined) {
270
- return (0, malloy_types_1.mkExpr) `(
271
- TO_CHAR(${expr}::TIMESTAMP_NTZ, 'YYYY-MM-DD HH24:MI:SS.FF9') ||
260
+ return `(
261
+ TO_CHAR(${sqlExpr}::TIMESTAMP_NTZ, 'YYYY-MM-DD HH24:MI:SS.FF9') ||
272
262
  TO_CHAR(CONVERT_TIMEZONE('${tz}', '1970-01-01 00:00:00'), 'TZHTZM')
273
263
  )::TIMESTAMP_TZ`;
274
264
  }
275
- return (0, malloy_types_1.mkExpr) `${expr}::TIMESTAMP_NTZ`;
265
+ return `${sqlExpr}::TIMESTAMP_NTZ`;
276
266
  }
277
- sqlNow() {
278
- return (0, malloy_types_1.mkExpr) `CURRENT_TIMESTAMP()`;
267
+ sqlNowExpr() {
268
+ return 'CURRENT_TIMESTAMP()';
279
269
  }
280
270
  sqlCast(qi, cast) {
271
+ const src = cast.e.sql || '';
281
272
  if (cast.srcType === cast.dstType) {
282
- return cast.expr;
273
+ return src;
283
274
  }
284
275
  if (cast.safe && typeof cast.srcType !== 'string') {
285
276
  // safe cast is only supported for a few combinations of src -> dst types
@@ -291,35 +282,36 @@ ${(0, utils_1.indent)(sql)}
291
282
  const tz = (0, dialect_1.qtz)(qi);
292
283
  // casting timestamps and dates
293
284
  if (cast.dstType === 'date' && cast.srcType === 'timestamp') {
294
- let castExpr = cast.expr;
285
+ let castExpr = src;
295
286
  if (tz) {
296
- castExpr = (0, malloy_types_1.mkExpr) `CONVERT_TIMEZONE('${tz}', ${castExpr})`;
287
+ castExpr = `CONVERT_TIMEZONE('${tz}', ${castExpr})`;
297
288
  }
298
- return (0, malloy_types_1.mkExpr) `TO_DATE(${castExpr})`;
289
+ return `TO_DATE(${castExpr})`;
299
290
  }
300
291
  else if (cast.dstType === 'timestamp' && cast.srcType === 'date') {
301
- const retExpr = (0, malloy_types_1.mkExpr) `TO_TIMESTAMP(${cast.expr})`;
292
+ const retExpr = `TO_TIMESTAMP(${src})`;
302
293
  return this.atTz(retExpr, tz);
303
294
  }
304
295
  const dstType = typeof cast.dstType === 'string'
305
296
  ? this.malloyTypeToSQLType({ type: cast.dstType })
306
297
  : cast.dstType.raw;
307
298
  const castFunc = cast.safe ? 'TRY_CAST' : 'CAST';
308
- return (0, malloy_types_1.mkExpr) `${castFunc}(${cast.expr} AS ${dstType})`;
299
+ return `${castFunc}(${src} AS ${dstType})`;
309
300
  }
310
- sqlLiteralTime(qi, timeString, type, timezone) {
301
+ sqlLiteralTime(qi, lf) {
302
+ var _a;
311
303
  const tz = (0, dialect_1.qtz)(qi);
312
304
  // just making it explicit that timestring does not have timezone info
313
- let ret = `'${timeString}'::TIMESTAMP_NTZ`;
305
+ let ret = `'${lf.literal}'::TIMESTAMP_NTZ`;
314
306
  // now do the hack to add timezone to a timestamp ntz
315
- const targetTimeZone = timezone !== null && timezone !== void 0 ? timezone : tz;
307
+ const targetTimeZone = (_a = lf.timezone) !== null && _a !== void 0 ? _a : tz;
316
308
  if (targetTimeZone) {
317
309
  const targetTimeZoneSuffix = `TO_CHAR(CONVERT_TIMEZONE('${targetTimeZone}', '1970-01-01 00:00:00'), 'TZHTZM')`;
318
310
  const retTimeString = `TO_CHAR(${ret}, 'YYYY-MM-DD HH24:MI:SS.FF9')`;
319
311
  ret = `${retTimeString} || ${targetTimeZoneSuffix}`;
320
312
  ret = `(${ret})::TIMESTAMP_TZ`;
321
313
  }
322
- switch (type) {
314
+ switch (lf.dataType) {
323
315
  case 'date':
324
316
  return `TO_DATE(${ret})`;
325
317
  case 'timestamp': {
@@ -327,24 +319,25 @@ ${(0, utils_1.indent)(sql)}
327
319
  }
328
320
  }
329
321
  }
330
- sqlMeasureTime(from, to, units) {
322
+ sqlMeasureTimeExpr(df) {
323
+ const from = df.kids.left;
324
+ const to = df.kids.right;
331
325
  let extractUnits = 'nanoseconds';
332
- if (from.valueType === 'date' || to.valueType === 'date') {
326
+ if (from.dataType === 'date' || to.dataType === 'date') {
333
327
  extractUnits = 'seconds';
334
328
  }
335
- return (0, malloy_types_1.mkExpr) `TIMESTAMPDIFF(
336
- '${units}',
329
+ return `TIMESTAMPDIFF(
330
+ '${df.units}',
337
331
  '1970-01-01 00:00:00'::TIMESTAMP_NTZ,
338
332
  TIMESTAMPADD(
339
333
  '${extractUnits}',
340
- EXTRACT('epoch_${extractUnits}', ${to.value}) - EXTRACT('epoch_${extractUnits}', ${from.value}),
334
+ EXTRACT('epoch_${extractUnits}', ${to.sql}) - EXTRACT('epoch_${extractUnits}', ${from.sql}),
341
335
  '1970-01-01 00:00:00'::TIMESTAMP_NTZ
342
336
  )
343
337
  )`;
344
338
  }
345
- sqlRegexpMatch(expr, regexp) {
346
- // regexp_match captures any partial match
347
- return (0, malloy_types_1.mkExpr) `(REGEXP_INSTR(${expr}, ${regexp}) != 0)`;
339
+ sqlRegexpMatch(compare) {
340
+ return `REGEXP_INSTR(${compare.kids.expr.sql}, ${compare.kids.regex.sql}) != 0`;
348
341
  }
349
342
  sqlSampleTable(tableSQL, sample) {
350
343
  if (sample !== undefined) {
@@ -27,8 +27,8 @@ const util_1 = require("../../functions/util");
27
27
  function fnStringAgg() {
28
28
  const value = (0, util_1.makeParam)('value', (0, util_1.maxScalar)('string'));
29
29
  const separator = (0, util_1.makeParam)('separator', (0, util_1.literal)((0, util_1.maxScalar)('string')));
30
- const orderBy = { type: 'aggregate_order_by' };
31
- const limit = { type: 'aggregate_limit' };
30
+ const orderBy = { node: 'aggregate_order_by' };
31
+ const limit = { node: 'aggregate_limit' };
32
32
  return [
33
33
  (0, util_1.overload)((0, util_1.minAggregate)('string'), [value.param], (0, util_1.sql) `STRING_AGG(${value.arg}${orderBy}${limit})`, { supportsOrderBy: true, supportsLimit: true, defaultOrderByArgIndex: 0 }),
34
34
  (0, util_1.overload)((0, util_1.minAggregate)('string'), [value.param, separator.param], (0, util_1.sql) `STRING_AGG(${value.arg}, ${separator.arg}${orderBy}${limit})`, { supportsOrderBy: true, supportsLimit: true, defaultOrderByArgIndex: 0 }),
@@ -38,8 +38,8 @@ exports.fnStringAgg = fnStringAgg;
38
38
  function fnStringAggDistinct() {
39
39
  const value = (0, util_1.makeParam)('value', (0, util_1.maxScalar)('string'));
40
40
  const separator = (0, util_1.makeParam)('separator', (0, util_1.literal)((0, util_1.maxScalar)('string')));
41
- const orderBy = { type: 'aggregate_order_by' };
42
- const limit = { type: 'aggregate_limit' };
41
+ const orderBy = { node: 'aggregate_order_by' };
42
+ const limit = { node: 'aggregate_limit' };
43
43
  return [
44
44
  (0, util_1.overload)((0, util_1.minAggregate)('string'), [value.param], (0, util_1.sql) `STRING_AGG(DISTINCT ${value.arg}${orderBy}${limit})`, {
45
45
  isSymmetric: true,
@@ -1,4 +1,4 @@
1
- import { Expr, ExtractUnit, Sampling, TimeValue, TimestampUnit, TypecastFragment, FieldAtomicTypeDef } from '../../model/malloy_types';
1
+ import { Sampling, FieldAtomicTypeDef, TimeTruncExpr, TimeExtractExpr, TimeDeltaExpr, TypecastExpr, RegexMatchExpr, TimeLiteralNode, MeasureTimeExpr } from '../../model/malloy_types';
2
2
  import { DialectFunctionOverloadDef } from '../functions';
3
3
  import { Dialect, DialectFieldList, QueryInfo } from '../dialect';
4
4
  export declare class StandardSQLDialect extends Dialect {
@@ -41,15 +41,15 @@ export declare class StandardSQLDialect extends Dialect {
41
41
  sqlSelectAliasAsStruct(alias: string): string;
42
42
  keywords: string[];
43
43
  sqlMaybeQuoteIdentifier(identifier: string): string;
44
- sqlNow(): Expr;
45
- sqlTrunc(qi: QueryInfo, sqlTime: TimeValue, units: TimestampUnit): Expr;
46
- sqlExtract(qi: QueryInfo, expr: TimeValue, units: ExtractUnit): Expr;
47
- sqlAlterTime(op: '+' | '-', expr: TimeValue, n: Expr, timeframe: TimestampUnit): Expr;
44
+ sqlNowExpr(): string;
45
+ sqlTruncExpr(qi: QueryInfo, trunc: TimeTruncExpr): string;
46
+ sqlTimeExtractExpr(qi: QueryInfo, te: TimeExtractExpr): string;
47
+ sqlAlterTimeExpr(df: TimeDeltaExpr): string;
48
48
  ignoreInProject(fieldName: string): boolean;
49
- sqlCast(qi: QueryInfo, cast: TypecastFragment): Expr;
50
- sqlRegexpMatch(expr: Expr, regexp: Expr): Expr;
51
- sqlLiteralTime(qi: QueryInfo, timeString: string, type: 'date' | 'timestamp', timezone: string | undefined): string;
52
- sqlMeasureTime(from: TimeValue, to: TimeValue, units: string): Expr;
49
+ sqlCast(qi: QueryInfo, cast: TypecastExpr): string;
50
+ sqlRegexpMatch(match: RegexMatchExpr): string;
51
+ sqlLiteralTime(qi: QueryInfo, lit: TimeLiteralNode): string;
52
+ sqlMeasureTimeExpr(measure: MeasureTimeExpr): string;
53
53
  sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
54
54
  sqlLiteralString(literal: string): string;
55
55
  sqlLiteralRegexp(literal: string): string;