@malloydata/malloy 0.0.435 → 0.0.436

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 (76) hide show
  1. package/dist/api/foundation/build_targets.d.ts +5 -6
  2. package/dist/api/foundation/build_targets.js +74 -6
  3. package/dist/api/foundation/core.d.ts +16 -4
  4. package/dist/api/foundation/core.js +23 -23
  5. package/dist/api/foundation/index.d.ts +1 -1
  6. package/dist/api/foundation/runtime.d.ts +21 -2
  7. package/dist/api/foundation/runtime.js +44 -31
  8. package/dist/api/foundation/types.d.ts +43 -3
  9. package/dist/connection/dbmeta.d.ts +29 -0
  10. package/dist/connection/dbmeta.js +46 -0
  11. package/dist/connection/index.d.ts +1 -0
  12. package/dist/connection/index.js +1 -0
  13. package/dist/dialect/databricks/databricks.d.ts +11 -12
  14. package/dist/dialect/databricks/databricks.js +24 -36
  15. package/dist/dialect/dialect.d.ts +56 -170
  16. package/dist/dialect/dialect.js +89 -90
  17. package/dist/dialect/duckdb/duckdb.d.ts +2 -2
  18. package/dist/dialect/duckdb/duckdb.js +1 -1
  19. package/dist/dialect/index.d.ts +1 -1
  20. package/dist/dialect/index.js +2 -2
  21. package/dist/dialect/mysql/mysql.d.ts +11 -12
  22. package/dist/dialect/mysql/mysql.js +20 -32
  23. package/dist/dialect/pg_impl.d.ts +9 -10
  24. package/dist/dialect/pg_impl.js +27 -73
  25. package/dist/dialect/postgres/postgres.d.ts +4 -4
  26. package/dist/dialect/postgres/postgres.js +4 -12
  27. package/dist/dialect/snowflake/snowflake.d.ts +11 -13
  28. package/dist/dialect/snowflake/snowflake.js +30 -82
  29. package/dist/dialect/sqlserver/sqlserver.d.ts +12 -13
  30. package/dist/dialect/sqlserver/sqlserver.js +46 -47
  31. package/dist/dialect/standardsql/standardsql.d.ts +11 -16
  32. package/dist/dialect/standardsql/standardsql.js +22 -73
  33. package/dist/dialect/trino/trino.d.ts +16 -18
  34. package/dist/dialect/trino/trino.js +127 -181
  35. package/dist/index.d.ts +2 -2
  36. package/dist/index.js +2 -2
  37. package/dist/lang/ast/expressions/boolean-value.d.ts +24 -0
  38. package/dist/lang/ast/expressions/boolean-value.js +41 -0
  39. package/dist/lang/ast/expressions/case.js +7 -0
  40. package/dist/lang/ast/expressions/expr-alternation-tree.js +11 -0
  41. package/dist/lang/ast/expressions/expr-cast.js +5 -0
  42. package/dist/lang/ast/expressions/expr-coalesce.js +4 -0
  43. package/dist/lang/ast/expressions/expr-func.js +13 -2
  44. package/dist/lang/ast/expressions/expr-minus.js +5 -2
  45. package/dist/lang/ast/expressions/expr-null.js +4 -0
  46. package/dist/lang/ast/expressions/pick-when.js +7 -0
  47. package/dist/lang/ast/field-space/index-field-space.js +13 -1
  48. package/dist/lang/ast/field-space/query-spaces.js +11 -0
  49. package/dist/lang/ast/query-builders/reduce-builder.js +1 -1
  50. package/dist/lang/ast/query-items/field-declaration.d.ts +5 -0
  51. package/dist/lang/ast/query-items/field-declaration.js +22 -16
  52. package/dist/lang/ast/query-items/field-references.d.ts +6 -0
  53. package/dist/lang/ast/query-items/field-references.js +23 -0
  54. package/dist/lang/ast/query-properties/filters.js +3 -1
  55. package/dist/lang/ast/statements/import-statement.js +13 -0
  56. package/dist/lang/ast/types/expression-def.js +17 -2
  57. package/dist/lang/ast/types/malloy-element.d.ts +24 -1
  58. package/dist/lang/ast/types/malloy-element.js +63 -26
  59. package/dist/lang/ast/view-elements/reference-view.js +4 -0
  60. package/dist/lang/ast/view-elements/refine-utils.js +1 -0
  61. package/dist/lang/composite-source-utils.js +10 -17
  62. package/dist/lang/parse-log.d.ts +12 -0
  63. package/dist/lang/parse-log.js +2 -0
  64. package/dist/lang/test/test-translator.d.ts +2 -1
  65. package/dist/lang/test/test-translator.js +37 -3
  66. package/dist/model/expression_compiler.js +8 -7
  67. package/dist/model/filter_compilers.js +13 -12
  68. package/dist/model/given_binding.d.ts +8 -0
  69. package/dist/model/given_binding.js +13 -0
  70. package/dist/model/index.d.ts +1 -1
  71. package/dist/model/index.js +2 -1
  72. package/dist/model/sql_compiled.d.ts +19 -20
  73. package/dist/model/sql_compiled.js +29 -17
  74. package/dist/version.d.ts +1 -1
  75. package/dist/version.js +1 -1
  76. package/package.json +4 -4
@@ -54,6 +54,7 @@ const sqlServerToMalloyTypes = {
54
54
  'datetime': { type: 'timestamp' },
55
55
  'datetime2': { type: 'timestamp' },
56
56
  'smalldatetime': { type: 'timestamp' },
57
+ 'datetimeoffset': { type: 'timestamptz' },
57
58
  };
58
59
  function parseSQLServerType(sqlType) {
59
60
  var _a, _b;
@@ -160,7 +161,9 @@ class SQLServerDialect extends dialect_1.Dialect {
160
161
  // condition is expected, `true` and `false` are (1=1) and (1=0), a `bit`
161
162
  // column is an integer, and a cast to boolean is refused.
162
163
  this.booleanType = 'none';
163
- this.hasTimestamptz = false;
164
+ // A datetimeoffset is an instant. Its clock is read at UTC, or in the
165
+ // query's time zone, never at the offset it was written in.
166
+ this.hasTimestamptz = true;
164
167
  // A bigint arrives from the driver as text and is read as a JavaScript number
165
168
  this.supportsBigIntPrecision = false;
166
169
  this.maxIdentifierLength = 128;
@@ -202,6 +205,8 @@ class SQLServerDialect extends dialect_1.Dialect {
202
205
  return 'DATE';
203
206
  case 'timestamp':
204
207
  return 'DATETIME2';
208
+ case 'timestamptz':
209
+ return 'DATETIMEOFFSET';
205
210
  case 'record':
206
211
  case 'array':
207
212
  return 'NVARCHAR(MAX)';
@@ -374,42 +379,31 @@ class SQLServerDialect extends dialect_1.Dialect {
374
379
  sqlNowExpr() {
375
380
  return 'SYSUTCDATETIME()';
376
381
  }
377
- sqlTimeExtractExpr(qi, from) {
378
- let extractFrom = from.e.sql;
379
- if (malloy_types_1.TD.isAnyTimestamp(from.e.typeDef)) {
380
- const tz = (0, dialect_1.qtz)(qi);
381
- if (tz) {
382
- extractFrom = this.sqlConvertToCivilTime(extractFrom !== null && extractFrom !== void 0 ? extractFrom : '', tz, from.e.typeDef).sql;
383
- }
384
- }
385
- if (from.units === 'day_of_week') {
382
+ sqlCivilExtract(expr, units, _civilType) {
383
+ if (units === 'day_of_week') {
386
384
  // Days since a Sunday, so the answer does not follow DATEFIRST
387
- return `((DATEDIFF(day, '19000107', ${extractFrom}) % 7 + 7) % 7 + 1)`;
385
+ return `((DATEDIFF(day, '19000107', ${expr}) % 7 + 7) % 7 + 1)`;
388
386
  }
389
387
  // Malloy's week of the year is the ISO week; DATEPART(week) counts from
390
388
  // January 1st and follows DATEFIRST
391
- const part = from.units === 'week' ? 'iso_week' : datePartMap[from.units];
389
+ const part = units === 'week' ? 'iso_week' : datePartMap[units];
392
390
  if (part === undefined) {
393
- throw new Error(`Unknown SQL Server date part '${from.units}'`);
391
+ throw new Error(`Unknown SQL Server date part '${units}'`);
394
392
  }
395
- return `DATEPART(${part}, ${extractFrom})`;
393
+ return `DATEPART(${part}, ${expr})`;
394
+ }
395
+ sqlCivilToDate(expr) {
396
+ return `CAST(${expr} AS DATE)`;
396
397
  }
397
- sqlCast(qi, cast) {
398
+ sqlDateToCivil(expr) {
399
+ return `CAST(${expr} AS DATETIME2)`;
400
+ }
401
+ sqlCast(_qi, cast) {
398
402
  const expr = cast.e.sql || '';
399
403
  const { srcTypeDef, dstTypeDef, dstSQLType } = this.sqlCastPrep(cast);
400
404
  if ((dstTypeDef === null || dstTypeDef === void 0 ? void 0 : dstTypeDef.type) === 'boolean') {
401
405
  return this.unsupported('a cast to boolean: there are no boolean values');
402
406
  }
403
- const tz = (0, dialect_1.qtz)(qi);
404
- if (tz && srcTypeDef && dstTypeDef) {
405
- if (malloy_types_1.TD.isTimestamp(srcTypeDef) && malloy_types_1.TD.isDate(dstTypeDef)) {
406
- const civil = this.sqlConvertToCivilTime(expr, tz, srcTypeDef).sql;
407
- return `CAST(${civil} AS DATE)`;
408
- }
409
- if (malloy_types_1.TD.isDate(srcTypeDef) && malloy_types_1.TD.isTimestamp(dstTypeDef)) {
410
- return this.sqlConvertFromCivilTime(`CAST(${expr} AS DATETIME2)`, tz, dstTypeDef);
411
- }
412
- }
413
407
  if (!malloy_types_1.TD.eq(srcTypeDef, dstTypeDef)) {
414
408
  const castFunc = cast.safe ? 'TRY_CAST' : 'CAST';
415
409
  return `${castFunc}(${expr} AS ${dstSQLType})`;
@@ -422,16 +416,11 @@ class SQLServerDialect extends dialect_1.Dialect {
422
416
  sqlDateLiteral(_qi, literal) {
423
417
  return `CAST('${literal}' AS DATE)`;
424
418
  }
425
- sqlTimestampLiteral(qi, literal, timezone) {
426
- const tz = timezone || (0, dialect_1.qtz)(qi);
427
- const ts = `CAST('${literal}' AS DATETIME2)`;
428
- if (tz) {
429
- return this.sqlConvertFromCivilTime(ts, tz, { type: 'timestamp' });
430
- }
431
- return ts;
419
+ sqlCivilLiteral(literal) {
420
+ return `CAST('${literal}' AS DATETIME2)`;
432
421
  }
433
- sqlTimestamptzLiteral(_qi, _literal, _timezone) {
434
- throw new Error('SQL Server dialect does not support timestamptz');
422
+ sqlTimestamptzLiteral(_qi, literal, timezone) {
423
+ return this.sqlConvertFromCivilTime(this.sqlCivilLiteral(literal), timezone, { type: 'timestamptz' });
435
424
  }
436
425
  // AT TIME ZONE takes a Windows time zone name
437
426
  sqlTimezoneLiteral(timezone) {
@@ -441,24 +430,34 @@ class SQLServerDialect extends dialect_1.Dialect {
441
430
  }
442
431
  return this.sqlLiteralString(windowsName);
443
432
  }
444
- sqlConvertToCivilTime(expr, timezone, _typeDef) {
433
+ // Civil time is a datetime2, which has no zone. AT TIME ZONE 'UTC' labels
434
+ // a datetime2 as UTC and moves a datetimeoffset to UTC, so one expression
435
+ // reads the clock of either; a CAST alone would read a datetimeoffset's
436
+ // clock at the offset it was written in.
437
+ sqlConvertToCivilTime(expr, timezone, typeDef) {
445
438
  if (timezone === 'UTC') {
446
- return { sql: expr, typeDef: { type: 'timestamp' } };
439
+ return malloy_types_1.TD.isTimestamptz(typeDef)
440
+ ? `CAST((${expr} AT TIME ZONE 'UTC') AS DATETIME2)`
441
+ : expr;
447
442
  }
448
443
  const tz = this.sqlTimezoneLiteral(timezone);
449
- return {
450
- sql: `CAST((${expr} AT TIME ZONE 'UTC') AT TIME ZONE ${tz} AS DATETIME2)`,
451
- typeDef: { type: 'timestamp' },
452
- };
453
- }
454
- sqlConvertFromCivilTime(expr, timezone, _destTypeDef) {
444
+ return `CAST((${expr} AT TIME ZONE 'UTC') AT TIME ZONE ${tz} AS DATETIME2)`;
445
+ }
446
+ sqlConvertFromCivilTime(expr, timezone, destTypeDef) {
447
+ if (malloy_types_1.TD.isTimestamptz(destTypeDef)) {
448
+ // A datetime2 cast to datetimeoffset is at +00:00
449
+ return timezone === 'UTC'
450
+ ? `CAST(${expr} AS DATETIMEOFFSET)`
451
+ : `(${expr} AT TIME ZONE ${this.sqlTimezoneLiteral(timezone)})`;
452
+ }
455
453
  if (timezone === 'UTC') {
456
454
  return expr;
457
455
  }
458
456
  const tz = this.sqlTimezoneLiteral(timezone);
459
457
  return `CAST((${expr} AT TIME ZONE ${tz}) AT TIME ZONE 'UTC' AS DATETIME2)`;
460
458
  }
461
- sqlTruncate(expr, unit, typeDef, _inCivilTime, _timezone) {
459
+ sqlTruncate(expr, unit, civilType) {
460
+ const isDate = civilType === dialect_1.CivilTime.Date;
462
461
  // Truncation is DATEADD of the whole units since an anchor: 1900-01-01
463
462
  // for a calendar unit, the value's own midnight for a clock unit, so the
464
463
  // count fits an int. SQL Server 2017 has no DATETRUNC.
@@ -466,25 +465,25 @@ class SQLServerDialect extends dialect_1.Dialect {
466
465
  if (unit === 'week') {
467
466
  // Malloy weeks start on Sunday whatever DATEFIRST says, so count days
468
467
  // from a known Sunday.
469
- const day = malloy_types_1.TD.isDate(typeDef) ? expr : midnight;
468
+ const day = isDate ? expr : midnight;
470
469
  return `DATEADD(day, -((DATEDIFF(day, '19000107', ${expr}) % 7 + 7) % 7), ${day})`;
471
470
  }
472
471
  const part = datePartMap[unit];
473
472
  if (part === undefined) {
474
473
  throw new Error(`Unknown SQL Server date part '${unit}'`);
475
474
  }
476
- if (unit === 'day' && !malloy_types_1.TD.isDate(typeDef)) {
475
+ if (unit === 'day' && !isDate) {
477
476
  return midnight;
478
477
  }
479
478
  if (unit === 'hour' || unit === 'minute' || unit === 'second') {
480
479
  return `DATEADD(${part}, DATEDIFF(${part}, ${midnight}, ${expr}), ${midnight})`;
481
480
  }
482
481
  const truncated = `DATEADD(${part}, DATEDIFF(${part}, '19000101', ${expr}), '19000101')`;
483
- return malloy_types_1.TD.isDate(typeDef)
482
+ return isDate
484
483
  ? `CAST(${truncated} AS DATE)`
485
484
  : `CAST(${truncated} AS DATETIME2)`;
486
485
  }
487
- sqlOffsetTime(expr, op, magnitude, unit, _typeDef, _inCivilTime, _timezone) {
486
+ sqlOffsetTime(expr, op, magnitude, unit, _civilType) {
488
487
  const part = datePartMap[unit];
489
488
  if (part === undefined) {
490
489
  throw new Error(`Unknown SQL Server date part '${unit}'`);
@@ -1,7 +1,7 @@
1
- import type { Sampling, AtomicTypeDef, TimeExtractExpr, TypecastExpr, RegexMatchExpr, MeasureTimeExpr, BasicAtomicTypeDef, RecordLiteralNode, ArrayLiteralNode, TimestampUnit, TimestampTypeDef } from '../../model/malloy_types';
1
+ import type { Sampling, AtomicTypeDef, TypecastExpr, RegexMatchExpr, MeasureTimeExpr, BasicAtomicTypeDef, RecordLiteralNode, ArrayLiteralNode, TimestampUnit, ATimestampTypeDef, ExtractUnit } from '../../model/malloy_types';
2
2
  import type { DialectFunctionOverloadDef } from '../functions';
3
3
  import type { CompiledOrderBy, DialectFieldList, IntegerTypeMapping, OrderByRequest, QueryInfo } from '../dialect';
4
- import { Dialect, type LateralJoinExpression } from '../dialect';
4
+ import { CivilTime, Dialect, type LateralJoinExpression } from '../dialect';
5
5
  export declare class StandardSQLDialect extends Dialect {
6
6
  name: string;
7
7
  stringLiteralStyle: "backslash";
@@ -36,10 +36,6 @@ export declare class StandardSQLDialect extends Dialect {
36
36
  private bqRejectBacktick;
37
37
  sqlQuoteIdentifier(identifier: string): string;
38
38
  tablePathBareIdentRegex: RegExp;
39
- needsCivilTimeComputation(typeDef: AtomicTypeDef, truncateTo: TimestampUnit | undefined, offsetUnit: TimestampUnit | undefined, qi: QueryInfo): {
40
- needed: boolean;
41
- tz: string | undefined;
42
- };
43
39
  sqlGroupSetTable(groupSetCount: number): string;
44
40
  sqlAnyValue(groupSet: number, fieldName: string): string;
45
41
  sqlOrderBy(orderTerms: string[], obr?: OrderByRequest): string;
@@ -57,19 +53,18 @@ export declare class StandardSQLDialect extends Dialect {
57
53
  sqlCreateFunctionCombineLastStage(lastStageName: string): string;
58
54
  sqlSelectAliasAsStruct(alias: string, dialectFieldList: DialectFieldList): string;
59
55
  sqlNowExpr(): string;
60
- sqlTimeExtractExpr(qi: QueryInfo, te: TimeExtractExpr): string;
61
- sqlConvertToCivilTime(expr: string, timezone: string, _typeDef: AtomicTypeDef): {
62
- sql: string;
63
- typeDef: AtomicTypeDef;
64
- };
65
- sqlConvertFromCivilTime(expr: string, timezone: string, _destTypeDef: TimestampTypeDef): string;
66
- sqlTruncate(expr: string, unit: TimestampUnit, typeDef: AtomicTypeDef, inCivilTime: boolean, timezone?: string): string;
67
- sqlOffsetTime(expr: string, op: '+' | '-', magnitude: string, unit: TimestampUnit, typeDef: AtomicTypeDef, inCivilTime: boolean, _timezone?: string): string;
56
+ sqlCivilExtract(expr: string, units: ExtractUnit, _civilType: CivilTime): string;
57
+ sqlConvertToCivilTime(expr: string, timezone: string, _typeDef: ATimestampTypeDef): string;
58
+ sqlConvertFromCivilTime(expr: string, timezone: string, _destTypeDef: ATimestampTypeDef): string;
59
+ sqlTruncate(expr: string, unit: TimestampUnit, civilType: CivilTime): string;
60
+ sqlOffsetTime(expr: string, op: '+' | '-', magnitude: string, unit: TimestampUnit, civilType: CivilTime): string;
61
+ sqlCivilToDate(expr: string): string;
62
+ sqlDateToCivil(expr: string): string;
68
63
  ignoreInProject(fieldName: string): boolean;
69
- sqlCast(qi: QueryInfo, cast: TypecastExpr): string;
64
+ sqlCast(_qi: QueryInfo, cast: TypecastExpr): string;
70
65
  sqlRegexpMatch(match: RegexMatchExpr): string;
71
66
  sqlDateLiteral(_qi: QueryInfo, literal: string): string;
72
- sqlTimestampLiteral(qi: QueryInfo, literal: string, timezone: string | undefined): string;
67
+ sqlCivilLiteral(literal: string): string;
73
68
  sqlTimestamptzLiteral(_qi: QueryInfo, _literal: string, _timezone: string): string;
74
69
  sqlMeasureTimeExpr(measure: MeasureTimeExpr): string;
75
70
  sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
@@ -26,15 +26,6 @@ const extractMap = {
26
26
  'day_of_week': 'dayofweek',
27
27
  'day_of_year': 'dayofyear',
28
28
  };
29
- /**
30
- * Return a non UTC timezone, if one was specificed.
31
- */
32
- function qtz(qi) {
33
- const tz = qi.queryTimezone;
34
- if (tz && tz !== 'UTC') {
35
- return tz;
36
- }
37
- }
38
29
  const bqToMalloyTypes = {
39
30
  'DATE': { type: 'date' },
40
31
  'STRING': { type: 'string' },
@@ -124,17 +115,6 @@ class StandardSQLDialect extends dialect_1.Dialect {
124
115
  this.bqRejectBacktick(identifier, 'identifier');
125
116
  return super.sqlQuoteIdentifier(identifier);
126
117
  }
127
- needsCivilTimeComputation(typeDef, truncateTo, offsetUnit, qi) {
128
- // In addition to using "civil" space for units where a query time zone is
129
- // set, BigQuery also uses civil space for unit operations not supported
130
- // by the TIMESTAMP functions.
131
- const calendarUnits = ['day', 'week', 'month', 'quarter', 'year'];
132
- const isCalendarTruncate = truncateTo !== undefined && calendarUnits.includes(truncateTo);
133
- const isCalendarOffset = offsetUnit !== undefined && calendarUnits.includes(offsetUnit);
134
- const needed = malloy_types_1.TD.isAnyTimestamp(typeDef) && (isCalendarTruncate || isCalendarOffset);
135
- const tz = needed ? qtz(qi) || 'UTC' : undefined;
136
- return { needed, tz };
137
- }
138
118
  sqlGroupSetTable(groupSetCount) {
139
119
  return `CROSS JOIN (SELECT row_number() OVER() -1 group_set FROM UNNEST(GENERATE_ARRAY(0,${groupSetCount},1)))`;
140
120
  }
@@ -249,64 +229,38 @@ ${(0, utils_1.indent)(sql)}
249
229
  sqlNowExpr() {
250
230
  return 'CURRENT_TIMESTAMP()';
251
231
  }
252
- sqlTimeExtractExpr(qi, te) {
253
- const extractTo = extractMap[te.units] || te.units;
254
- const tz = malloy_types_1.TD.isAnyTimestamp(te.e.typeDef) && qtz(qi);
255
- const tzAdd = tz ? ` AT TIME ZONE ${this.sqlTimezoneLiteral(tz)}` : '';
256
- return `EXTRACT(${extractTo} FROM ${te.e.sql}${tzAdd})`;
232
+ sqlCivilExtract(expr, units, _civilType) {
233
+ return `EXTRACT(${extractMap[units] || units} FROM ${expr})`;
257
234
  }
235
+ // Civil time is a DATETIME, which has no zone
258
236
  sqlConvertToCivilTime(expr, timezone, _typeDef) {
259
- // BigQuery has no timestamptz type, so typeDef.timestamptz will never be true
260
- return {
261
- sql: `DATETIME(${expr}, ${this.sqlTimezoneLiteral(timezone)})`,
262
- typeDef: { type: 'timestamp' },
263
- };
237
+ return `DATETIME(${expr}, ${this.sqlTimezoneLiteral(timezone)})`;
264
238
  }
265
239
  sqlConvertFromCivilTime(expr, timezone, _destTypeDef) {
266
240
  return `TIMESTAMP(${expr}, ${this.sqlTimezoneLiteral(timezone)})`;
267
241
  }
268
- sqlTruncate(expr, unit, typeDef, inCivilTime, timezone) {
269
- if (inCivilTime) {
270
- // Operating on DATETIME (civil time)
271
- return `DATETIME_TRUNC(${expr}, ${unit})`;
272
- }
273
- // Operating on DATE or TIMESTAMP
274
- if (malloy_types_1.TD.isDate(typeDef)) {
275
- return `DATE_TRUNC(${expr}, ${unit})`;
276
- }
277
- // TIMESTAMP truncation with optional timezone
278
- const tzParam = timezone ? `, ${this.sqlTimezoneLiteral(timezone)}` : '';
279
- return `TIMESTAMP_TRUNC(${expr}, ${unit}${tzParam})`;
280
- }
281
- sqlOffsetTime(expr, op, magnitude, unit, typeDef, inCivilTime, _timezone) {
282
- if (inCivilTime) {
283
- // Operating on DATETIME (civil time)
284
- const funcName = op === '+' ? 'DATETIME_ADD' : 'DATETIME_SUB';
285
- return `${funcName}(${expr}, INTERVAL ${magnitude} ${unit})`;
286
- }
287
- // Operating on DATE or TIMESTAMP
288
- const baseType = typeDef.type;
289
- if (baseType === 'date') {
290
- const funcName = op === '+' ? 'DATE_ADD' : 'DATE_SUB';
291
- return `${funcName}(${expr}, INTERVAL ${magnitude} ${unit})`;
292
- }
293
- // TIMESTAMP with sub-day units only (calendar units go through civil time)
294
- const funcName = op === '+' ? 'TIMESTAMP_ADD' : 'TIMESTAMP_SUB';
242
+ sqlTruncate(expr, unit, civilType) {
243
+ return civilType === dialect_1.CivilTime.Date
244
+ ? `DATE_TRUNC(${expr}, ${unit})`
245
+ : `DATETIME_TRUNC(${expr}, ${unit})`;
246
+ }
247
+ sqlOffsetTime(expr, op, magnitude, unit, civilType) {
248
+ const funcType = civilType === dialect_1.CivilTime.Date ? 'DATE' : 'DATETIME';
249
+ const funcName = `${funcType}_${op === '+' ? 'ADD' : 'SUB'}`;
295
250
  return `${funcName}(${expr}, INTERVAL ${magnitude} ${unit})`;
296
251
  }
252
+ sqlCivilToDate(expr) {
253
+ return `DATE(${expr})`;
254
+ }
255
+ sqlDateToCivil(expr) {
256
+ return `DATETIME(${expr})`;
257
+ }
297
258
  ignoreInProject(fieldName) {
298
259
  return fieldName === '_PARTITIONTIME';
299
260
  }
300
- sqlCast(qi, cast) {
301
- const { op, srcTypeDef, dstTypeDef, dstSQLType } = this.sqlCastPrep(cast);
302
- const tz = qtz(qi);
261
+ sqlCast(_qi, cast) {
262
+ const { srcTypeDef, dstTypeDef, dstSQLType } = this.sqlCastPrep(cast);
303
263
  const src = cast.e.sql || '';
304
- if (op === 'timestamp::date' && tz) {
305
- return `DATE(${src},${this.sqlTimezoneLiteral(tz)})`;
306
- }
307
- if (op === 'date::timestamp' && tz) {
308
- return `TIMESTAMP(${src}, ${this.sqlTimezoneLiteral(tz)})`;
309
- }
310
264
  if (!malloy_types_1.TD.eq(srcTypeDef, dstTypeDef)) {
311
265
  const castFunc = cast.safe ? 'SAFE_CAST' : 'CAST';
312
266
  return `${castFunc}(${src} AS ${dstSQLType})`;
@@ -319,13 +273,8 @@ ${(0, utils_1.indent)(sql)}
319
273
  sqlDateLiteral(_qi, literal) {
320
274
  return `DATE('${literal}')`;
321
275
  }
322
- sqlTimestampLiteral(qi, literal, timezone) {
323
- let timestampArgs = `'${literal}'`;
324
- const tz = timezone || qtz(qi);
325
- if (tz && tz !== 'UTC') {
326
- timestampArgs += `,${this.sqlTimezoneLiteral(tz)}`;
327
- }
328
- return `TIMESTAMP(${timestampArgs})`;
276
+ sqlCivilLiteral(literal) {
277
+ return `DATETIME '${literal}'`;
329
278
  }
330
279
  sqlTimestamptzLiteral(_qi, _literal, _timezone) {
331
280
  throw new Error('BigQuery does not support timestamptz');
@@ -1,6 +1,6 @@
1
- import type { Expr, Sampling, AtomicTypeDef, ATimestampTypeDef, TypecastExpr, RegexMatchExpr, MeasureTimeExpr, TimeExtractExpr, BasicAtomicTypeDef, RecordLiteralNode, OrderBy } from '../../model/malloy_types';
1
+ import type { Expr, Sampling, AtomicTypeDef, ATimestampTypeDef, TypecastExpr, RegexMatchExpr, MeasureTimeExpr, TimeExtractExpr, BasicAtomicTypeDef, RecordLiteralNode, OrderBy, TimestampUnit, ExtractUnit, TimeExpr } from '../../model/malloy_types';
2
2
  import type { DialectFunctionOverloadDef } from '../functions';
3
- import type { CompiledOrderBy, DialectFieldList, OrderByClauseType, QueryInfo } from '../dialect';
3
+ import type { CivilTime, CompiledOrderBy, DialectFieldList, OrderByClauseType, QueryInfo, TimeOffset } from '../dialect';
4
4
  import { PostgresBase } from '../pg_impl';
5
5
  export declare class TrinoDialect extends PostgresBase {
6
6
  name: string;
@@ -52,14 +52,11 @@ export declare class TrinoDialect extends PostgresBase {
52
52
  sqlCreateFunctionCombineLastStage(lastStageName: string, fieldList: DialectFieldList, orderBy: OrderBy[] | undefined): string;
53
53
  sqlSelectAliasAsStruct(alias: string, fieldList: DialectFieldList): string;
54
54
  keywords: string[];
55
- sqlConvertToCivilTime(expr: string, timezone: string, typeDef: AtomicTypeDef): {
56
- sql: string;
57
- typeDef: AtomicTypeDef;
58
- };
59
- sqlConvertFromCivilTime(expr: string, _timezone: string, destTypeDef: ATimestampTypeDef): string;
60
- sqlTruncate(expr: string, unit: string, _typeDef: AtomicTypeDef, _inCivilTime: boolean, _timezone?: string): string;
61
- sqlOffsetTime(expr: string, op: '+' | '-', magnitude: string, unit: string, _typeDef: AtomicTypeDef, _inCivilTime: boolean, _timezone?: string): string;
62
- sqlCast(qi: QueryInfo, cast: TypecastExpr): string;
55
+ sqlConvertToCivilTime(expr: string, timezone: string, typeDef: ATimestampTypeDef): string;
56
+ sqlConvertFromCivilTime(expr: string, timezone: string, destTypeDef: ATimestampTypeDef): string;
57
+ sqlTruncate(expr: string, unit: TimestampUnit, _civilType: CivilTime): string;
58
+ sqlOffsetTime(expr: string, op: '+' | '-', magnitude: string, unit: TimestampUnit, _civilType: CivilTime): string;
59
+ sqlCast(_qi: QueryInfo, cast: TypecastExpr): string;
63
60
  sqlRegexpMatch(reCmp: RegexMatchExpr): string;
64
61
  sqlMeasureTimeExpr(mf: MeasureTimeExpr): string;
65
62
  sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
@@ -77,9 +74,8 @@ export declare class TrinoDialect extends PostgresBase {
77
74
  sqlStringAggDistinct(distinctKey: string, valueSQL: string, separatorSQL: string): string;
78
75
  validateTypeName(sqlType: string): boolean;
79
76
  sqlDateLiteral(_qi: QueryInfo, literal: string): string;
80
- sqlTimestampLiteral(qi: QueryInfo, literal: string, timezone: string | undefined): string;
81
77
  sqlTimestamptzLiteral(_qi: QueryInfo, literal: string, timezone: string): string;
82
- sqlTimeExtractExpr(qi: QueryInfo, from: TimeExtractExpr): string;
78
+ sqlCivilExtract(expr: string, units: ExtractUnit, _civilType: CivilTime): string;
83
79
  sqlLiteralRecord(lit: RecordLiteralNode): string;
84
80
  }
85
81
  export declare class PrestoDialect extends TrinoDialect {
@@ -90,13 +86,15 @@ export declare class PrestoDialect extends TrinoDialect {
90
86
  sqlDateLiteral(_qi: QueryInfo, literal: string): string;
91
87
  sqlTimestampLiteral(qi: QueryInfo, literal: string, timezone: string | undefined): string;
92
88
  sqlTimestamptzLiteral(_qi: QueryInfo, literal: string, timezone: string): string;
93
- sqlConvertToCivilTime(expr: string, timezone: string, _typeDef: AtomicTypeDef): {
94
- sql: string;
95
- typeDef: AtomicTypeDef;
96
- };
97
- sqlConvertFromCivilTime(expr: string, _timezone: string, destTypeDef: ATimestampTypeDef): string;
98
- sqlCast(qi: QueryInfo, cast: TypecastExpr): string;
89
+ sqlConvertToCivilTime(): string;
90
+ sqlConvertFromCivilTime(): string;
91
+ /** The instant `expr`, showing the clock of `timezone` */
92
+ private inZone;
93
+ /** An instant from inZone, as a value of `typeDef` */
94
+ private fromZone;
99
95
  sqlTimeExtractExpr(qi: QueryInfo, from: TimeExtractExpr): string;
96
+ sqlTruncAndOffset(baseExpr: TimeExpr, qi: QueryInfo, truncateTo?: TimestampUnit, offset?: TimeOffset): string;
97
+ sqlTimeCast(qi: QueryInfo, cast: TypecastExpr): string | undefined;
100
98
  sqlUnnestAlias(source: string, alias: string, _fieldList: DialectFieldList, needDistinctKey: boolean, isArray: boolean, _isInNestedPipeline: boolean): string;
101
99
  getDialectFunctions(): {
102
100
  [name: string]: DialectFunctionOverloadDef[];