@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
@@ -1,4 +1,4 @@
1
- import { DialectFragment, Expr, ExtractUnit, Sampling, TimeFieldType, TimeValue, TimestampUnit, TypecastFragment, FieldAtomicTypeDef } from '../model/malloy_types';
1
+ import { Expr, Sampling, FieldAtomicTypeDef, MeasureTimeExpr, TimeTruncExpr, TimeExtractExpr, TimeDeltaExpr, TypecastExpr, RegexMatchExpr, TimeLiteralNode } from '../model/malloy_types';
2
2
  import { DialectFunctionOverloadDef } from './functions';
3
3
  type DialectFieldTypes = string | 'struct';
4
4
  interface DialectField {
@@ -79,21 +79,31 @@ export declare abstract class Dialect {
79
79
  sqlFinalStage(_lastStageName: string, _fields: string[]): string;
80
80
  sqlDateToString(sqlDateExp: string): string;
81
81
  abstract sqlMaybeQuoteIdentifier(identifier: string): string;
82
- abstract sqlNow(): Expr;
83
- abstract sqlTrunc(qi: QueryInfo, sqlTime: TimeValue, units: TimestampUnit): Expr;
84
- abstract sqlExtract(qi: QueryInfo, sqlTime: TimeValue, units: ExtractUnit): Expr;
85
- abstract sqlMeasureTime(from: TimeValue, to: TimeValue, units: TimestampUnit): Expr;
86
- abstract sqlAlterTime(op: '+' | '-', expr: TimeValue, n: Expr, timeframe: TimestampUnit): Expr;
87
- ignoreInProject(_fieldName: string): boolean;
88
- abstract sqlCast(qi: QueryInfo, cast: TypecastFragment): Expr;
89
- abstract sqlLiteralTime(qi: QueryInfo, timeString: string, type: TimeFieldType, timezone?: string): string;
90
- abstract sqlLiteralString(literal: string): string;
91
- abstract sqlLiteralRegexp(literal: string): string;
92
- abstract sqlRegexpMatch(expr: Expr, regex: Expr): Expr;
93
82
  abstract castToString(expression: string): string;
94
83
  abstract concat(...values: string[]): string;
95
84
  sqlLiteralNumber(literal: string): string;
96
- dialectExpr(qi: QueryInfo, df: DialectFragment): Expr;
85
+ ignoreInProject(_fieldName: string): boolean;
86
+ abstract sqlNowExpr(): string;
87
+ abstract sqlTruncExpr(qi: QueryInfo, toTrunc: TimeTruncExpr): string;
88
+ abstract sqlTimeExtractExpr(qi: QueryInfo, xFrom: TimeExtractExpr): string;
89
+ abstract sqlMeasureTimeExpr(e: MeasureTimeExpr): string;
90
+ abstract sqlAlterTimeExpr(df: TimeDeltaExpr): string;
91
+ abstract sqlCast(qi: QueryInfo, cast: TypecastExpr): string;
92
+ abstract sqlLiteralTime(qi: QueryInfo, df: TimeLiteralNode): string;
93
+ abstract sqlLiteralString(literal: string): string;
94
+ abstract sqlLiteralRegexp(literal: string): string;
95
+ abstract sqlRegexpMatch(df: RegexMatchExpr): string;
96
+ /**
97
+ * The dialect has a chance to over-ride how expressions are translated. If
98
+ * "undefined" is returned then the translation is left to the query translator.
99
+ *
100
+ * Any child nodes of the expression will already have been translated, and
101
+ * the translated value will be in the ".sql" fields for those nodes
102
+ * @param qi Info from the query containing this expression
103
+ * @param df The expression being translated
104
+ * @returns The SQL translation of the expression, or undefined
105
+ */
106
+ exprToSQL(qi: QueryInfo, df: Expr): string | undefined;
97
107
  sqlSumDistinct(_key: string, _value: string, _funcName: string): string;
98
108
  sqlAggDistinct(_key: string, _values: string[], _func: (valNames: string[]) => string): string;
99
109
  sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
@@ -23,7 +23,6 @@
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.Dialect = exports.qtz = exports.inDays = exports.dayIndex = exports.isDialectFieldStruct = void 0;
26
- const malloy_types_1 = require("../model/malloy_types");
27
26
  function isDialectFieldStruct(d) {
28
27
  return d.type === 'struct';
29
28
  }
@@ -90,53 +89,60 @@ class Dialect {
90
89
  sqlDateToString(sqlDateExp) {
91
90
  return this.castToString(`DATE(${sqlDateExp})`);
92
91
  }
92
+ sqlLiteralNumber(literal) {
93
+ return literal;
94
+ }
93
95
  // BigQuery has some fieldNames that are Pseudo Fields and shouldn't be
94
96
  // included in projections.
95
97
  ignoreInProject(_fieldName) {
96
98
  return false;
97
99
  }
98
- sqlLiteralNumber(literal) {
99
- return literal;
100
- }
101
- dialectExpr(qi, df) {
102
- switch (df.function) {
100
+ /**
101
+ * The dialect has a chance to over-ride how expressions are translated. If
102
+ * "undefined" is returned then the translation is left to the query translator.
103
+ *
104
+ * Any child nodes of the expression will already have been translated, and
105
+ * the translated value will be in the ".sql" fields for those nodes
106
+ * @param qi Info from the query containing this expression
107
+ * @param df The expression being translated
108
+ * @returns The SQL translation of the expression, or undefined
109
+ */
110
+ exprToSQL(qi, df) {
111
+ switch (df.node) {
103
112
  case 'now':
104
- return this.sqlNow();
113
+ return this.sqlNowExpr();
105
114
  case 'timeDiff':
106
- return this.sqlMeasureTime(df.left, df.right, df.units);
115
+ return this.sqlMeasureTimeExpr(df);
107
116
  case 'delta':
108
- return this.sqlAlterTime(df.op, df.base, df.delta, df.units);
117
+ return this.sqlAlterTimeExpr(df);
109
118
  case 'trunc':
110
- return this.sqlTrunc(qi, df.expr, df.units);
119
+ return this.sqlTruncExpr(qi, df);
111
120
  case 'extract':
112
- return this.sqlExtract(qi, df.expr, df.units);
121
+ return this.sqlTimeExtractExpr(qi, df);
113
122
  case 'cast':
114
123
  return this.sqlCast(qi, df);
115
124
  case 'regexpMatch':
116
- return this.sqlRegexpMatch(df.expr, df.regexp);
117
- case 'div': {
125
+ return this.sqlRegexpMatch(df);
126
+ case '/': {
118
127
  if (this.divisionIsInteger) {
119
- return (0, malloy_types_1.mkExpr) `${df.numerator}*1.0/${df.denominator}`;
128
+ return `${df.kids.left.sql}*1.0/${df.kids.right.sql}`;
120
129
  }
121
- return (0, malloy_types_1.mkExpr) `${df.numerator}/${df.denominator}`;
130
+ return;
122
131
  }
123
- case 'mod': {
124
- if (this.hasModOperator) {
125
- return (0, malloy_types_1.mkExpr) `${df.numerator}%${df.denominator}`;
132
+ case '%': {
133
+ if (!this.hasModOperator) {
134
+ return `MOD(${df.kids.left.sql},${df.kids.right.sql})`;
126
135
  }
127
- return (0, malloy_types_1.mkExpr) `mod(${df.numerator},${df.denominator})`;
128
- }
129
- case 'timeLiteral': {
130
- return [
131
- this.sqlLiteralTime(qi, df.literal, df.literalType, df.timezone),
132
- ];
136
+ return;
133
137
  }
138
+ case 'timeLiteral':
139
+ return this.sqlLiteralTime(qi, df);
134
140
  case 'stringLiteral':
135
- return [this.sqlLiteralString(df.literal)];
141
+ return this.sqlLiteralString(df.literal);
136
142
  case 'numberLiteral':
137
- return [this.sqlLiteralNumber(df.literal)];
143
+ return this.sqlLiteralNumber(df.literal);
138
144
  case 'regexpLiteral':
139
- return [this.sqlLiteralRegexp(df.literal)];
145
+ return this.sqlLiteralRegexp(df.literal);
140
146
  }
141
147
  }
142
148
  sqlSumDistinct(_key, _value, _funcName) {
@@ -1,7 +1,8 @@
1
- import { DateUnit, Expr, ExtractUnit, Sampling, TimeFieldType, TimeValue, TimestampUnit, TypecastFragment, FieldAtomicTypeDef } from '../../model/malloy_types';
1
+ import { Sampling, FieldAtomicTypeDef, TimeDeltaExpr, RegexMatchExpr, MeasureTimeExpr } from '../../model/malloy_types';
2
2
  import { DialectFunctionOverloadDef } from '../functions';
3
- import { Dialect, DialectFieldList, QueryInfo } from '../dialect';
4
- export declare class DuckDBDialect extends Dialect {
3
+ import { DialectFieldList } from '../dialect';
4
+ import { PostgresBase } from '../pg_impl';
5
+ export declare class DuckDBDialect extends PostgresBase {
5
6
  name: string;
6
7
  experimental: boolean;
7
8
  defaultNumberType: string;
@@ -42,14 +43,6 @@ export declare class DuckDBDialect extends Dialect {
42
43
  sqlSelectAliasAsStruct(alias: string, dialectFieldList: DialectFieldList): string;
43
44
  sqlMaybeQuoteIdentifier(identifier: string): string;
44
45
  sqlCreateTableAsSelect(_tableName: string, _sql: string): string;
45
- sqlMeasureTime(from: TimeValue, to: TimeValue, units: string): Expr;
46
- sqlNow(): Expr;
47
- sqlTrunc(qi: QueryInfo, sqlTime: TimeValue, units: TimestampUnit): Expr;
48
- sqlExtract(qi: QueryInfo, from: TimeValue, units: ExtractUnit): Expr;
49
- sqlAlterTime(op: '+' | '-', expr: TimeValue, n: Expr, timeframe: DateUnit): Expr;
50
- sqlCast(qi: QueryInfo, cast: TypecastFragment): Expr;
51
- sqlRegexpMatch(expr: Expr, regexp: Expr): Expr;
52
- sqlLiteralTime(qi: QueryInfo, timeString: string, type: TimeFieldType, timezone: string | undefined): string;
53
46
  sqlSumDistinct(key: string, value: string, funcName: string): string;
54
47
  sqlAggDistinct(key: string, values: string[], func: (valNames: string[]) => string): string;
55
48
  sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
@@ -62,4 +55,7 @@ export declare class DuckDBDialect extends Dialect {
62
55
  castToString(expression: string): string;
63
56
  concat(...values: string[]): string;
64
57
  validateTypeName(sqlType: string): boolean;
58
+ sqlAlterTimeExpr(df: TimeDeltaExpr): string;
59
+ sqlRegexpMatch(df: RegexMatchExpr): string;
60
+ sqlMeasureTimeExpr(df: MeasureTimeExpr): string;
65
61
  }
@@ -27,12 +27,9 @@ const malloy_types_1 = require("../../model/malloy_types");
27
27
  const utils_1 = require("../../model/utils");
28
28
  const functions_1 = require("./functions");
29
29
  const dialect_1 = require("../dialect");
30
+ const pg_impl_1 = require("../pg_impl");
30
31
  // need to refactor runSQL to take a SQLBlock instead of just a sql string.
31
32
  const hackSplitComment = '-- hack: split on this';
32
- const pgExtractionMap = {
33
- 'day_of_week': 'dow',
34
- 'day_of_year': 'doy',
35
- };
36
33
  const duckDBToMalloyTypes = {
37
34
  'BIGINT': { type: 'number', numberType: 'integer' },
38
35
  'INTEGER': { type: 'number', numberType: 'integer' },
@@ -52,7 +49,7 @@ const duckDBToMalloyTypes = {
52
49
  'DECIMAL': { type: 'number', numberType: 'float' },
53
50
  'BOOLEAN': { type: 'boolean' },
54
51
  };
55
- class DuckDBDialect extends dialect_1.Dialect {
52
+ class DuckDBDialect extends pg_impl_1.PostgresBase {
56
53
  constructor() {
57
54
  super(...arguments);
58
55
  this.name = 'duckdb';
@@ -212,101 +209,6 @@ class DuckDBDialect extends dialect_1.Dialect {
212
209
  sqlCreateTableAsSelect(_tableName, _sql) {
213
210
  throw new Error('Not implemented Yet');
214
211
  }
215
- sqlMeasureTime(from, to, units) {
216
- let lVal = from.value;
217
- let rVal = to.value;
218
- if (!(0, dialect_1.inDays)(units)) {
219
- if (from.valueType === 'date') {
220
- lVal = (0, malloy_types_1.mkExpr) `(${lVal})::TIMESTAMP`;
221
- }
222
- if (to.valueType === 'date') {
223
- rVal = (0, malloy_types_1.mkExpr) `(${rVal})::TIMESTAMP`;
224
- }
225
- }
226
- return (0, malloy_types_1.mkExpr) `DATE_SUB('${units}',${lVal},${rVal})`;
227
- }
228
- sqlNow() {
229
- return (0, malloy_types_1.mkExpr) `LOCALTIMESTAMP`;
230
- }
231
- sqlTrunc(qi, sqlTime, units) {
232
- // adjusting for monday/sunday weeks
233
- const week = units === 'week';
234
- const truncThis = week
235
- ? (0, malloy_types_1.mkExpr) `${sqlTime.value} + INTERVAL 1 DAY`
236
- : sqlTime.value;
237
- if (sqlTime.valueType === 'timestamp') {
238
- const tz = (0, dialect_1.qtz)(qi);
239
- if (tz) {
240
- const civilSource = (0, malloy_types_1.mkExpr) `(${truncThis}::TIMESTAMPTZ AT TIME ZONE '${tz}')`;
241
- let civilTrunc = (0, malloy_types_1.mkExpr) `DATE_TRUNC('${units}', ${civilSource})`;
242
- // MTOY todo ... only need to do this if this is a date ...
243
- civilTrunc = (0, malloy_types_1.mkExpr) `${civilTrunc}::TIMESTAMP`;
244
- const truncTsTz = (0, malloy_types_1.mkExpr) `${civilTrunc} AT TIME ZONE '${tz}'`;
245
- return (0, malloy_types_1.mkExpr) `(${truncTsTz})::TIMESTAMP`;
246
- }
247
- }
248
- let result = (0, malloy_types_1.mkExpr) `DATE_TRUNC('${units}', ${truncThis})`;
249
- if (week) {
250
- result = (0, malloy_types_1.mkExpr) `(${result} - INTERVAL 1 DAY)`;
251
- }
252
- return result;
253
- }
254
- sqlExtract(qi, from, units) {
255
- const pgUnits = pgExtractionMap[units] || units;
256
- let extractFrom = from.value;
257
- if (from.valueType === 'timestamp') {
258
- const tz = (0, dialect_1.qtz)(qi);
259
- if (tz) {
260
- extractFrom = (0, malloy_types_1.mkExpr) `(${extractFrom}::TIMESTAMPTZ AT TIME ZONE '${tz}')`;
261
- }
262
- }
263
- const extracted = (0, malloy_types_1.mkExpr) `EXTRACT(${pgUnits} FROM ${extractFrom})`;
264
- return units === 'day_of_week' ? (0, malloy_types_1.mkExpr) `(${extracted}+1)` : extracted;
265
- }
266
- sqlAlterTime(op, expr, n, timeframe) {
267
- if (timeframe === 'quarter') {
268
- timeframe = 'month';
269
- n = (0, malloy_types_1.mkExpr) `${n}*3`;
270
- }
271
- if (timeframe === 'week') {
272
- timeframe = 'day';
273
- n = (0, malloy_types_1.mkExpr) `${n}*7`;
274
- }
275
- const interval = (0, malloy_types_1.mkExpr) `INTERVAL (${n}) ${timeframe}`;
276
- return (0, malloy_types_1.mkExpr) `${expr.value} ${op} ${interval}`;
277
- }
278
- sqlCast(qi, cast) {
279
- const op = `${cast.srcType}::${cast.dstType}`;
280
- const tz = (0, dialect_1.qtz)(qi);
281
- if (op === 'timestamp::date' && tz) {
282
- const tstz = (0, malloy_types_1.mkExpr) `${cast.expr}::TIMESTAMPTZ`;
283
- return (0, malloy_types_1.mkExpr) `CAST((${tstz}) AT TIME ZONE '${tz}' AS DATE)`;
284
- }
285
- else if (op === 'date::timestamp' && tz) {
286
- return (0, malloy_types_1.mkExpr) `CAST((${cast.expr})::TIMESTAMP AT TIME ZONE '${tz}' AS TIMESTAMP)`;
287
- }
288
- if (cast.srcType !== cast.dstType) {
289
- const dstType = typeof cast.dstType === 'string'
290
- ? this.malloyTypeToSQLType({ type: cast.dstType })
291
- : cast.dstType.raw;
292
- const castFunc = cast.safe ? 'TRY_CAST' : 'CAST';
293
- return (0, malloy_types_1.mkExpr) `${castFunc}(${cast.expr} AS ${dstType})`;
294
- }
295
- return cast.expr;
296
- }
297
- sqlRegexpMatch(expr, regexp) {
298
- return (0, malloy_types_1.mkExpr) `REGEXP_MATCHES(${expr}, ${regexp})`;
299
- }
300
- sqlLiteralTime(qi, timeString, type, timezone) {
301
- if (type === 'date') {
302
- return `DATE '${timeString}'`;
303
- }
304
- const tz = timezone || (0, dialect_1.qtz)(qi);
305
- if (tz) {
306
- return `TIMESTAMPTZ '${timeString} ${tz}'::TIMESTAMP`;
307
- }
308
- return `TIMESTAMP '${timeString}'`;
309
- }
310
212
  sqlSumDistinct(key, value, funcName) {
311
213
  // return `sum_distinct(list({key:${key}, val: ${value}}))`;
312
214
  return `(
@@ -395,6 +297,38 @@ class DuckDBDialect extends dialect_1.Dialect {
395
297
  // Brackets: INT[ ]
396
298
  return sqlType.match(/^[A-Za-z\s(),[\]0-9]*$/) !== null;
397
299
  }
300
+ sqlAlterTimeExpr(df) {
301
+ let timeframe = df.units;
302
+ let n = df.kids.delta.sql;
303
+ if (timeframe === 'quarter') {
304
+ timeframe = 'month';
305
+ n = `${n}*3`;
306
+ }
307
+ else if (timeframe === 'week') {
308
+ timeframe = 'day';
309
+ n = `${n}*7`;
310
+ }
311
+ const interval = `INTERVAL (${n}) ${timeframe}`;
312
+ return `${df.kids.base.sql} ${df.op} ${interval}`;
313
+ }
314
+ sqlRegexpMatch(df) {
315
+ return `REGEXP_MATCHES(${df.kids.expr.sql},${df.kids.regex.sql})`;
316
+ }
317
+ sqlMeasureTimeExpr(df) {
318
+ const from = df.kids.left;
319
+ const to = df.kids.right;
320
+ let lVal = from.sql || '';
321
+ let rVal = to.sql || '';
322
+ if (!(0, dialect_1.inDays)(df.units)) {
323
+ if (from.dataType === 'date') {
324
+ lVal = `${lVal}::TIMESTAMP`;
325
+ }
326
+ if (to.dataType === 'date') {
327
+ rVal = `${rVal}::TIMESTAMP`;
328
+ }
329
+ }
330
+ return `DATE_SUB('${df.units}', ${lVal}, ${rVal})`;
331
+ }
398
332
  }
399
333
  exports.DuckDBDialect = DuckDBDialect;
400
334
  //# sourceMappingURL=duckdb.js.map
@@ -38,18 +38,11 @@ function greatestOrLeast(fn) {
38
38
  // CASE WHEN arg1 IS NULL OR arg2 is NULL ... OR argN is NULL THEN NULL ELSE GREATEST(arg1, arg2, ..., argN) END
39
39
  // But we can't do that with today's function spec.
40
40
  // That might look someday like
41
- /*
42
- sqlFragment(
43
- 'CASE WHEN ',
44
- spread(map(arg('values'), '$ARG IS NULL'), ' OR '),
45
- `THEN NULL ELSE ${fn}(`,
46
- spread(arg('values')),
47
- ') END'
48
- ),
49
- */
50
- [
51
- (0, util_1.sqlFragment)('CASE WHEN LEN(LIST_FILTER([', (0, util_1.spread)((0, util_1.arg)('values')), `], x -> x is null)) > 0 THEN NULL ELSE ${fn}(`, (0, util_1.spread)((0, util_1.arg)('values')), ') END'),
52
- ]));
41
+ (0, util_1.sql) `CASE
42
+ WHEN LEN(LIST_FILTER([${(0, util_1.spread)((0, util_1.arg)('values'))}], x -> x is null)) > 0
43
+ THEN NULL
44
+ ELSE ${fn}(${(0, util_1.spread)((0, util_1.arg)('values'))})
45
+ END`));
53
46
  }
54
47
  const fnGreatest = () => greatestOrLeast('GREATEST');
55
48
  exports.fnGreatest = fnGreatest;
@@ -28,7 +28,7 @@ function fnConcat() {
28
28
  return [
29
29
  // TODO: in DuckDB and Postgres, nulls are treated like "",
30
30
  // but in BigQuery and Snowflake, nulls propagate and the result becomes null
31
- (0, util_1.overload)((0, util_1.minScalar)('string'), [], [{ type: 'dialect', function: 'stringLiteral', literal: '' }]),
31
+ (0, util_1.overload)((0, util_1.minScalar)('string'), [], { node: 'stringLiteral', literal: '' }),
32
32
  (0, util_1.overload)((0, util_1.minScalar)('string'), [
33
33
  (0, util_1.params)('values', (0, util_1.anyExprType)('string'), (0, util_1.anyExprType)('number'), (0, util_1.anyExprType)('date'), (0, util_1.anyExprType)('timestamp'), (0, util_1.anyExprType)('boolean')),
34
34
  ], (0, util_1.sql) `CONCAT(${(0, util_1.spread)((0, util_1.arg)('values'))})`),
@@ -35,7 +35,7 @@ const types = [
35
35
  // directly, and in BigQuery we add a wrapper to ensure that the null behavior is consistent.
36
36
  // It should be that nulls are ignored, rather than propagated.
37
37
  function greatestOrLeast(fn) {
38
- return types.map(type => (0, util_1.overload)((0, util_1.minScalar)(type), [(0, util_1.params)('values', (0, util_1.anyExprType)(type))], [(0, util_1.sqlFragment)(`${fn}(`, (0, util_1.spread)((0, util_1.arg)('values')), ')')]));
38
+ return types.map(type => (0, util_1.overload)((0, util_1.minScalar)(type), [(0, util_1.params)('values', (0, util_1.anyExprType)(type))], (0, util_1.sql) `${fn}(${(0, util_1.spread)((0, util_1.arg)('values'))})`));
39
39
  }
40
40
  const fnGreatest = () => greatestOrLeast('GREATEST');
41
41
  exports.fnGreatest = fnGreatest;
@@ -26,7 +26,7 @@ exports.fnExp = exports.fnLn = exports.fnSqrt = exports.fnAbs = exports.fnFloor
26
26
  const util_1 = require("./util");
27
27
  function simple(fn) {
28
28
  return [
29
- (0, util_1.overload)((0, util_1.minScalar)('number'), [(0, util_1.param)('value', (0, util_1.anyExprType)('number'))], [(0, util_1.sqlFragment)(`${fn}(`, (0, util_1.arg)('value'), ')')]),
29
+ (0, util_1.overload)((0, util_1.minScalar)('number'), [(0, util_1.param)('value', (0, util_1.anyExprType)('number'))], (0, util_1.sql) `${fn}(${(0, util_1.arg)('value')})`),
30
30
  ];
31
31
  }
32
32
  exports.simple = simple;
@@ -26,37 +26,27 @@ exports.fnSqlBoolean = exports.fnSqlTimestamp = exports.fnSqlDate = exports.fnSq
26
26
  const util_1 = require("./util");
27
27
  function fnSqlNumber() {
28
28
  const value = (0, util_1.makeParam)('value', (0, util_1.literal)((0, util_1.maxScalar)('string')));
29
- return [
30
- (0, util_1.overload)((0, util_1.minScalar)('number'), [value.param], [{ type: 'sql-string', e: [value.arg] }]),
31
- ];
29
+ return [(0, util_1.overload)((0, util_1.minScalar)('number'), [value.param], value.arg)];
32
30
  }
33
31
  exports.fnSqlNumber = fnSqlNumber;
34
32
  function fnSqlString() {
35
33
  const value = (0, util_1.makeParam)('value', (0, util_1.literal)((0, util_1.maxScalar)('string')));
36
- return [
37
- (0, util_1.overload)((0, util_1.minScalar)('string'), [value.param], [{ type: 'sql-string', e: [value.arg] }]),
38
- ];
34
+ return [(0, util_1.overload)((0, util_1.minScalar)('string'), [value.param], value.arg)];
39
35
  }
40
36
  exports.fnSqlString = fnSqlString;
41
37
  function fnSqlDate() {
42
38
  const value = (0, util_1.makeParam)('value', (0, util_1.literal)((0, util_1.maxScalar)('string')));
43
- return [
44
- (0, util_1.overload)((0, util_1.minScalar)('date'), [value.param], [{ type: 'sql-string', e: [value.arg] }]),
45
- ];
39
+ return [(0, util_1.overload)((0, util_1.minScalar)('date'), [value.param], value.arg)];
46
40
  }
47
41
  exports.fnSqlDate = fnSqlDate;
48
42
  function fnSqlTimestamp() {
49
43
  const value = (0, util_1.makeParam)('value', (0, util_1.literal)((0, util_1.maxScalar)('string')));
50
- return [
51
- (0, util_1.overload)((0, util_1.minScalar)('timestamp'), [value.param], [{ type: 'sql-string', e: [value.arg] }]),
52
- ];
44
+ return [(0, util_1.overload)((0, util_1.minScalar)('timestamp'), [value.param], value.arg)];
53
45
  }
54
46
  exports.fnSqlTimestamp = fnSqlTimestamp;
55
47
  function fnSqlBoolean() {
56
48
  const value = (0, util_1.makeParam)('value', (0, util_1.literal)((0, util_1.maxScalar)('string')));
57
- return [
58
- (0, util_1.overload)((0, util_1.minScalar)('boolean'), [value.param], [{ type: 'sql-string', e: [value.arg] }]),
59
- ];
49
+ return [(0, util_1.overload)((0, util_1.minScalar)('boolean'), [value.param], value.arg)];
60
50
  }
61
51
  exports.fnSqlBoolean = fnSqlBoolean;
62
52
  //# sourceMappingURL=sql.js.map
@@ -27,7 +27,7 @@ const util_1 = require("./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, defaultOrderByArgIndex: 0 }),
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, defaultOrderByArgIndex: 0 }),
@@ -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,
@@ -26,11 +26,11 @@ exports.fnRtrim = exports.fnLtrim = exports.fnTrim = void 0;
26
26
  const util_1 = require("./util");
27
27
  function trimFn(fn) {
28
28
  return [
29
- (0, util_1.overload)((0, util_1.minScalar)('string'), [(0, util_1.param)('value', (0, util_1.anyExprType)('string'))], [(0, util_1.sqlFragment)(`${fn}(`, (0, util_1.arg)('value'), ')')]),
29
+ (0, util_1.overload)((0, util_1.minScalar)('string'), [(0, util_1.param)('value', (0, util_1.anyExprType)('string'))], (0, util_1.sql) `${fn}(${(0, util_1.arg)('value')})`),
30
30
  (0, util_1.overload)((0, util_1.minScalar)('string'), [
31
31
  (0, util_1.param)('value', (0, util_1.anyExprType)('string')),
32
32
  (0, util_1.param)('trim_characters', (0, util_1.anyExprType)('string')),
33
- ], [(0, util_1.sqlFragment)(`${fn}(`, (0, util_1.arg)('value'), ',', (0, util_1.arg)('trim_characters'), ')')]),
33
+ ], (0, util_1.sql) `${fn}(${(0, util_1.arg)('value')},${(0, util_1.arg)('trim_characters')})`),
34
34
  ];
35
35
  }
36
36
  const fnTrim = () => trimFn('TRIM');
@@ -1,4 +1,5 @@
1
- import { FunctionParameterDef, Fragment, FieldValueType, TypeDesc, Expr, FunctionParamTypeDesc } from '../../model/malloy_types';
1
+ import { FunctionParameterDef, FieldValueType, TypeDesc, Expr, FunctionParamTypeDesc } from '../../model/malloy_types';
2
+ import { SQLExprElement } from '../../model/utils';
2
3
  export interface DialectFunctionOverloadDef {
3
4
  returnType: TypeDesc;
4
5
  params: FunctionParameterDef[];
@@ -13,13 +14,9 @@ export interface DialectFunctionOverloadDef {
13
14
  following: number | string;
14
15
  } | undefined;
15
16
  }
16
- export declare function arg(name: string): Fragment;
17
- export declare function spread(f: Fragment, prefix?: string | undefined, suffix?: string | undefined): Fragment;
18
- /**
19
- * Prefer `sql` when possible.
20
- */
21
- export declare function sqlFragment(...e: Expr): Fragment;
22
- export declare function sql(strings: TemplateStringsArray, ...expr: (Fragment | string)[]): Expr;
17
+ export declare function arg(name: string): Expr;
18
+ export declare function spread(e: Expr, prefix?: string | undefined, suffix?: string | undefined): Expr;
19
+ export declare function sql(strings: TemplateStringsArray, ...subExprs: SQLExprElement[]): Expr;
23
20
  export declare function constant(type: TypeDesc): TypeDesc;
24
21
  export declare function output(type: TypeDesc): TypeDesc;
25
22
  export declare function literal(type: TypeDesc): TypeDesc;
@@ -30,7 +27,7 @@ export declare function params(name: string, ...allowedTypes: FunctionParamTypeD
30
27
  export declare function param(name: string, ...allowedTypes: FunctionParamTypeDesc[]): FunctionParameterDef;
31
28
  export declare function makeParam(name: string, ...allowedTypes: FunctionParamTypeDesc[]): {
32
29
  param: FunctionParameterDef;
33
- arg: Fragment;
30
+ arg: Expr;
34
31
  };
35
32
  export declare function maxScalar(dataType: FieldValueType): TypeDesc;
36
33
  export declare function maxAggregate(dataType: FieldValueType): TypeDesc;
@@ -22,52 +22,43 @@
22
22
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.overload = exports.minAnalytic = exports.minAggregate = exports.minScalar = exports.maxAnalytic = exports.maxUngroupedAggregate = exports.anyExprType = exports.maxAggregate = exports.maxScalar = exports.makeParam = exports.param = exports.params = exports.literal = exports.output = exports.constant = exports.sql = exports.sqlFragment = exports.spread = exports.arg = void 0;
25
+ exports.overload = exports.minAnalytic = exports.minAggregate = exports.minScalar = exports.maxAnalytic = exports.maxUngroupedAggregate = exports.anyExprType = exports.maxAggregate = exports.maxScalar = exports.makeParam = exports.param = exports.params = exports.literal = exports.output = exports.constant = exports.sql = exports.spread = exports.arg = void 0;
26
26
  function arg(name) {
27
- return {
28
- type: 'function_parameter',
29
- name,
30
- };
27
+ return { node: 'function_parameter', name };
31
28
  }
32
29
  exports.arg = arg;
33
- function spread(f, prefix = undefined, suffix = undefined) {
34
- return {
35
- type: 'spread',
36
- e: [f],
37
- prefix,
38
- suffix,
39
- };
30
+ function spread(e, prefix = undefined, suffix = undefined) {
31
+ return { node: 'spread', e, prefix, suffix };
40
32
  }
41
33
  exports.spread = spread;
42
- /**
43
- * Prefer `sql` when possible.
44
- */
45
- function sqlFragment(...e) {
46
- return {
47
- type: 'sql_expression',
48
- e,
49
- };
50
- }
51
- exports.sqlFragment = sqlFragment;
52
- function sql(strings, ...expr) {
53
- return [
54
- {
55
- type: 'sql_expression',
56
- e: interpolate([...strings], expr),
57
- },
58
- ];
59
- }
60
- exports.sql = sql;
61
- function interpolate(outer, inner) {
62
- const result = [];
63
- for (let i = 0; i < outer.length; i++) {
64
- result.push(outer[i]);
65
- if (i < inner.length) {
66
- result.push(inner[i]);
34
+ function sql(strings, ...subExprs) {
35
+ const ret = {
36
+ node: 'genericSQLExpr',
37
+ kids: { args: [] },
38
+ src: [],
39
+ };
40
+ const safeExprs = [...subExprs];
41
+ let srcToPush = '';
42
+ for (const str of strings) {
43
+ srcToPush += str;
44
+ const arg = safeExprs.shift();
45
+ if (arg !== undefined) {
46
+ if (typeof arg === 'string') {
47
+ srcToPush += arg;
48
+ }
49
+ else {
50
+ ret.src.push(srcToPush);
51
+ ret.kids.args.push(arg);
52
+ srcToPush = '';
53
+ }
67
54
  }
68
55
  }
69
- return result;
56
+ if (srcToPush.length > 0) {
57
+ ret.src.push(srcToPush);
58
+ }
59
+ return ret;
70
60
  }
61
+ exports.sql = sql;
71
62
  function constant(type) {
72
63
  return {
73
64
  ...type,
@@ -1,5 +1,5 @@
1
1
  export type { DialectFunctionOverloadDef } from './functions/util';
2
- export { arg, anyExprType, makeParam, overload, minScalar, minAggregate, maxScalar, spread, sqlFragment, param, params, literal, sql, } from './functions/util';
2
+ export { arg, anyExprType, makeParam, overload, minScalar, minAggregate, maxScalar, spread, param, params, literal, sql, } from './functions/util';
3
3
  export { Dialect, qtz } from './dialect';
4
4
  export type { DialectFieldList, QueryInfo } from './dialect';
5
5
  export { StandardSQLDialect } from './standardsql';
@@ -22,7 +22,7 @@
22
22
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.FUNCTIONS = exports.getDialectFunction = exports.registerDialect = exports.getDialect = exports.TrinoDialect = exports.SnowflakeDialect = exports.DuckDBDialect = exports.PostgresDialect = exports.StandardSQLDialect = exports.qtz = exports.Dialect = exports.sql = exports.literal = exports.params = exports.param = exports.sqlFragment = exports.spread = exports.maxScalar = exports.minAggregate = exports.minScalar = exports.overload = exports.makeParam = exports.anyExprType = exports.arg = void 0;
25
+ exports.FUNCTIONS = exports.getDialectFunction = exports.registerDialect = exports.getDialect = exports.TrinoDialect = exports.SnowflakeDialect = exports.DuckDBDialect = exports.PostgresDialect = exports.StandardSQLDialect = exports.qtz = exports.Dialect = exports.sql = exports.literal = exports.params = exports.param = exports.spread = exports.maxScalar = exports.minAggregate = exports.minScalar = exports.overload = exports.makeParam = exports.anyExprType = exports.arg = void 0;
26
26
  var util_1 = require("./functions/util");
27
27
  Object.defineProperty(exports, "arg", { enumerable: true, get: function () { return util_1.arg; } });
28
28
  Object.defineProperty(exports, "anyExprType", { enumerable: true, get: function () { return util_1.anyExprType; } });
@@ -32,7 +32,6 @@ Object.defineProperty(exports, "minScalar", { enumerable: true, get: function ()
32
32
  Object.defineProperty(exports, "minAggregate", { enumerable: true, get: function () { return util_1.minAggregate; } });
33
33
  Object.defineProperty(exports, "maxScalar", { enumerable: true, get: function () { return util_1.maxScalar; } });
34
34
  Object.defineProperty(exports, "spread", { enumerable: true, get: function () { return util_1.spread; } });
35
- Object.defineProperty(exports, "sqlFragment", { enumerable: true, get: function () { return util_1.sqlFragment; } });
36
35
  Object.defineProperty(exports, "param", { enumerable: true, get: function () { return util_1.param; } });
37
36
  Object.defineProperty(exports, "params", { enumerable: true, get: function () { return util_1.params; } });
38
37
  Object.defineProperty(exports, "literal", { enumerable: true, get: function () { return util_1.literal; } });
@@ -0,0 +1,15 @@
1
+ import { RegexMatchExpr, TimeExtractExpr, TimeLiteralNode, TimeTruncExpr, TypecastExpr } from '../model/malloy_types';
2
+ import { Dialect, QueryInfo } from './dialect';
3
+ export declare const timeExtractMap: Record<string, string>;
4
+ /**
5
+ * Many SQL implementations started with the PostGres source, and therefore can use the
6
+ * same implementations for the much of the SQL code generation
7
+ */
8
+ export declare abstract class PostgresBase extends Dialect {
9
+ sqlTruncExpr(qi: QueryInfo, df: TimeTruncExpr): string;
10
+ sqlNowExpr(): string;
11
+ sqlTimeExtractExpr(qi: QueryInfo, from: TimeExtractExpr): string;
12
+ sqlCast(qi: QueryInfo, cast: TypecastExpr): string;
13
+ sqlRegexpMatch(df: RegexMatchExpr): string;
14
+ sqlLiteralTime(qi: QueryInfo, lt: TimeLiteralNode): string;
15
+ }