@malloydata/malloy 0.0.434 → 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 (103) 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/compile.d.ts +0 -1
  4. package/dist/api/foundation/compile.js +0 -3
  5. package/dist/api/foundation/core.d.ts +16 -4
  6. package/dist/api/foundation/core.js +23 -23
  7. package/dist/api/foundation/index.d.ts +1 -1
  8. package/dist/api/foundation/runtime.d.ts +21 -3
  9. package/dist/api/foundation/runtime.js +45 -54
  10. package/dist/api/foundation/types.d.ts +43 -4
  11. package/dist/connection/dbmeta.d.ts +29 -0
  12. package/dist/connection/dbmeta.js +46 -0
  13. package/dist/connection/index.d.ts +1 -0
  14. package/dist/connection/index.js +1 -0
  15. package/dist/dialect/databricks/databricks.d.ts +11 -12
  16. package/dist/dialect/databricks/databricks.js +24 -36
  17. package/dist/dialect/dialect.d.ts +70 -171
  18. package/dist/dialect/dialect.js +123 -92
  19. package/dist/dialect/dialect_map.js +2 -0
  20. package/dist/dialect/duckdb/duckdb.d.ts +2 -2
  21. package/dist/dialect/duckdb/duckdb.js +1 -1
  22. package/dist/dialect/index.d.ts +3 -2
  23. package/dist/dialect/index.js +4 -2
  24. package/dist/dialect/mysql/mysql.d.ts +11 -12
  25. package/dist/dialect/mysql/mysql.js +20 -32
  26. package/dist/dialect/pg_impl.d.ts +9 -10
  27. package/dist/dialect/pg_impl.js +27 -73
  28. package/dist/dialect/postgres/postgres.d.ts +4 -4
  29. package/dist/dialect/postgres/postgres.js +4 -12
  30. package/dist/dialect/snowflake/snowflake.d.ts +11 -13
  31. package/dist/dialect/snowflake/snowflake.js +30 -82
  32. package/dist/dialect/sqlserver/dialect_functions.d.ts +2 -0
  33. package/dist/dialect/sqlserver/dialect_functions.js +42 -0
  34. package/dist/dialect/sqlserver/function_overrides.d.ts +2 -0
  35. package/dist/dialect/sqlserver/function_overrides.js +55 -0
  36. package/dist/dialect/sqlserver/index.d.ts +1 -0
  37. package/dist/dialect/sqlserver/index.js +22 -0
  38. package/dist/dialect/sqlserver/sqlserver.d.ts +101 -0
  39. package/dist/dialect/sqlserver/sqlserver.js +537 -0
  40. package/dist/dialect/sqlserver/windows_zones.d.ts +1 -0
  41. package/dist/dialect/sqlserver/windows_zones.js +613 -0
  42. package/dist/dialect/standardsql/standardsql.d.ts +11 -16
  43. package/dist/dialect/standardsql/standardsql.js +22 -73
  44. package/dist/dialect/trino/trino.d.ts +16 -18
  45. package/dist/dialect/trino/trino.js +127 -181
  46. package/dist/index.d.ts +2 -2
  47. package/dist/index.js +6 -4
  48. package/dist/lang/ast/expressions/boolean-value.d.ts +24 -0
  49. package/dist/lang/ast/expressions/boolean-value.js +41 -0
  50. package/dist/lang/ast/expressions/case.js +7 -0
  51. package/dist/lang/ast/expressions/expr-alternation-tree.js +11 -0
  52. package/dist/lang/ast/expressions/expr-cast.js +5 -0
  53. package/dist/lang/ast/expressions/expr-coalesce.js +4 -0
  54. package/dist/lang/ast/expressions/expr-func.js +13 -2
  55. package/dist/lang/ast/expressions/expr-minus.js +5 -2
  56. package/dist/lang/ast/expressions/expr-null.js +4 -0
  57. package/dist/lang/ast/expressions/pick-when.js +7 -0
  58. package/dist/lang/ast/field-space/index-field-space.js +13 -1
  59. package/dist/lang/ast/field-space/query-spaces.js +11 -0
  60. package/dist/lang/ast/query-builders/reduce-builder.js +1 -1
  61. package/dist/lang/ast/query-items/field-declaration.d.ts +5 -0
  62. package/dist/lang/ast/query-items/field-declaration.js +22 -16
  63. package/dist/lang/ast/query-items/field-references.d.ts +6 -0
  64. package/dist/lang/ast/query-items/field-references.js +23 -0
  65. package/dist/lang/ast/query-properties/filters.js +3 -1
  66. package/dist/lang/ast/source-elements/named-source.js +0 -2
  67. package/dist/lang/ast/source-elements/sql-source.js +0 -3
  68. package/dist/lang/ast/source-elements/table-source.js +1 -2
  69. package/dist/lang/ast/statements/import-statement.js +17 -0
  70. package/dist/lang/ast/types/expression-def.js +17 -2
  71. package/dist/lang/ast/types/malloy-element.d.ts +24 -8
  72. package/dist/lang/ast/types/malloy-element.js +63 -44
  73. package/dist/lang/ast/view-elements/reference-view.js +4 -0
  74. package/dist/lang/ast/view-elements/refine-utils.js +1 -0
  75. package/dist/lang/composite-source-utils.js +10 -17
  76. package/dist/lang/parse-log.d.ts +12 -0
  77. package/dist/lang/parse-log.js +2 -0
  78. package/dist/lang/parse-malloy.d.ts +17 -2
  79. package/dist/lang/parse-malloy.js +48 -14
  80. package/dist/lang/parse-tree-walkers/find-external-references.d.ts +3 -3
  81. package/dist/lang/parse-tree-walkers/find-external-references.js +17 -16
  82. package/dist/lang/test/test-translator.d.ts +11 -1
  83. package/dist/lang/test/test-translator.js +51 -3
  84. package/dist/model/expression_compiler.js +9 -8
  85. package/dist/model/filter_compilers.js +13 -12
  86. package/dist/model/given_binding.d.ts +8 -0
  87. package/dist/model/given_binding.js +13 -0
  88. package/dist/model/index.d.ts +1 -1
  89. package/dist/model/index.js +2 -1
  90. package/dist/model/query_query.d.ts +3 -1
  91. package/dist/model/query_query.js +157 -139
  92. package/dist/model/source_def_utils.d.ts +7 -1
  93. package/dist/model/source_def_utils.js +20 -0
  94. package/dist/model/sql_compiled.d.ts +19 -20
  95. package/dist/model/sql_compiled.js +29 -17
  96. package/dist/test/index.js +16 -8
  97. package/dist/test/matchers.d.ts +1 -1
  98. package/dist/test/matchers.js +1 -1
  99. package/dist/test/test-models.js +6 -13
  100. package/dist/version.d.ts +1 -1
  101. package/dist/version.js +1 -1
  102. package/femto-config.motly +13 -1
  103. package/package.json +7 -5
@@ -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[];
@@ -23,15 +23,6 @@ function timestampMeasureable(units) {
23
23
  'day',
24
24
  ].includes(units);
25
25
  }
26
- /**
27
- * Return a non UTC timezone, if one was specificed.
28
- */
29
- function qtz(qi) {
30
- const tz = qi.queryTimezone;
31
- if (tz && tz !== 'UTC') {
32
- return tz;
33
- }
34
- }
35
26
  const trinoToMalloyTypes = {
36
27
  'varchar': { type: 'string' },
37
28
  'integer': { type: 'number', numberType: 'integer' },
@@ -57,6 +48,33 @@ const trinoToMalloyTypes = {
57
48
  // TIME
58
49
  // GEOGRAPHY
59
50
  };
51
+ function trinoTrunc(expr, unit) {
52
+ // Weeks start on Monday here, so truncate the following day
53
+ if (unit === 'week') {
54
+ return `(DATE_TRUNC('${unit}', (${expr} + INTERVAL '1' DAY)) - INTERVAL '1' DAY)`;
55
+ }
56
+ return `DATE_TRUNC('${unit}', ${expr})`;
57
+ }
58
+ function trinoDateAdd(expr, op, magnitude, unit) {
59
+ // DATE_ADD has no quarter or week
60
+ let offsetUnit = unit;
61
+ let offsetMag = magnitude;
62
+ if (unit === 'quarter') {
63
+ offsetUnit = 'month';
64
+ offsetMag = `${magnitude}*3`;
65
+ }
66
+ else if (unit === 'week') {
67
+ offsetUnit = 'day';
68
+ offsetMag = `${magnitude}*7`;
69
+ }
70
+ const n = op === '-' ? `(${offsetMag})*-1` : offsetMag;
71
+ return `DATE_ADD('${offsetUnit}', ${n}, ${expr})`;
72
+ }
73
+ function trinoExtract(expr, units) {
74
+ const extracted = `EXTRACT(${pg_impl_1.timeExtractMap[units] || units} FROM ${expr})`;
75
+ // Trino counts the days of a week from 1 on Monday
76
+ return units === 'day_of_week' ? `mod(${extracted}+1,7)` : extracted;
77
+ }
60
78
  class TrinoDialect extends pg_impl_1.PostgresBase {
61
79
  constructor() {
62
80
  super(...arguments);
@@ -339,87 +357,34 @@ ${(0, utils_1.indent)(sql)}
339
357
  const definitions = this.buildTypeExpression(fieldList);
340
358
  return `CAST(ROW(${fields}) as ROW(${definitions}))`;
341
359
  }
360
+ // Civil time is a TIMESTAMP, which Trino keeps without a zone
342
361
  sqlConvertToCivilTime(expr, timezone, typeDef) {
343
- // Trino civil time = TIMESTAMPTZ with query timezone as stored timezone
344
- // Operations (extract, truncate, etc.) happen in the stored timezone
345
- if (typeDef.type === 'timestamp') {
346
- // TIMESTAMP (UTC wall clock) → TIMESTAMPTZ in query timezone
347
- return {
348
- sql: `at_timezone(with_timezone(${expr}, 'UTC'), ${this.sqlTimezoneLiteral(timezone)})`,
349
- typeDef: { type: 'timestamptz' },
350
- };
362
+ const tz = this.sqlTimezoneLiteral(timezone);
363
+ if (malloy_types_1.TD.isTimestamptz(typeDef)) {
364
+ return `CAST(at_timezone(${expr}, ${tz}) AS TIMESTAMP)`;
351
365
  }
352
- // TIMESTAMPTZ → TIMESTAMPTZ in query timezone (same instant, different stored tz)
353
- return {
354
- sql: `at_timezone(${expr}, ${this.sqlTimezoneLiteral(timezone)})`,
355
- typeDef: { type: 'timestamptz' },
356
- };
366
+ return timezone === 'UTC'
367
+ ? expr
368
+ : `CAST(at_timezone(with_timezone(${expr}, 'UTC'), ${tz}) AS TIMESTAMP)`;
357
369
  }
358
- sqlConvertFromCivilTime(expr, _timezone, destTypeDef) {
359
- // From civil TIMESTAMPTZ (in query timezone) to destination type
360
- if (destTypeDef.type === 'timestamptz') {
361
- // Already TIMESTAMPTZ, keep as-is
362
- return expr;
363
- }
364
- // To TIMESTAMP: convert to UTC and cast to plain TIMESTAMP
365
- return `CAST(at_timezone(${expr}, 'UTC') AS TIMESTAMP)`;
366
- }
367
- sqlTruncate(expr, unit, _typeDef, _inCivilTime, _timezone) {
368
- // Trino starts weeks on Monday, Malloy wants Sunday
369
- // Add 1 day before truncating, subtract 1 day after
370
- if (unit === 'week') {
371
- return `(DATE_TRUNC('${unit}', (${expr} + INTERVAL '1' DAY)) - INTERVAL '1' DAY)`;
370
+ sqlConvertFromCivilTime(expr, timezone, destTypeDef) {
371
+ const tz = this.sqlTimezoneLiteral(timezone);
372
+ if (malloy_types_1.TD.isTimestamptz(destTypeDef)) {
373
+ return `with_timezone(${expr}, ${tz})`;
372
374
  }
373
- return `DATE_TRUNC('${unit}', ${expr})`;
374
- }
375
- sqlOffsetTime(expr, op, magnitude, unit, _typeDef, _inCivilTime, _timezone) {
376
- // Convert quarter/week to supported units
377
- let offsetUnit = unit;
378
- let offsetMag = magnitude;
379
- if (unit === 'quarter') {
380
- offsetUnit = 'month';
381
- offsetMag = `${magnitude}*3`;
382
- }
383
- else if (unit === 'week') {
384
- offsetUnit = 'day';
385
- offsetMag = `${magnitude}*7`;
386
- }
387
- // Handle subtraction by negating
388
- const n = op === '-' ? `(${offsetMag})*-1` : offsetMag;
389
- return `DATE_ADD('${offsetUnit}', ${n}, ${expr})`;
375
+ return timezone === 'UTC'
376
+ ? expr
377
+ : `CAST(at_timezone(with_timezone(${expr}, ${tz}), 'UTC') AS TIMESTAMP)`;
378
+ }
379
+ sqlTruncate(expr, unit, _civilType) {
380
+ return trinoTrunc(expr, unit);
390
381
  }
391
- sqlCast(qi, cast) {
382
+ sqlOffsetTime(expr, op, magnitude, unit, _civilType) {
383
+ return trinoDateAdd(expr, op, magnitude, unit);
384
+ }
385
+ sqlCast(_qi, cast) {
392
386
  const { srcTypeDef, dstTypeDef, dstSQLType } = this.sqlCastPrep(cast);
393
- const tz = qtz(qi);
394
387
  const expr = cast.e.sql || '';
395
- // Timezone-aware casts when query timezone is set
396
- if (tz && srcTypeDef && dstTypeDef) {
397
- // TIMESTAMP → DATE: interpret as UTC, convert to query timezone
398
- if (malloy_types_1.TD.isTimestamp(srcTypeDef) && malloy_types_1.TD.isDate(dstTypeDef)) {
399
- return `CAST(at_timezone(with_timezone(${expr}, 'UTC'), ${this.sqlTimezoneLiteral(tz)}) AS DATE)`;
400
- }
401
- // TIMESTAMPTZ → DATE: convert to query timezone
402
- if (malloy_types_1.TD.isTimestamptz(srcTypeDef) && malloy_types_1.TD.isDate(dstTypeDef)) {
403
- return `CAST(at_timezone(${expr}, ${this.sqlTimezoneLiteral(tz)}) AS DATE)`;
404
- }
405
- // DATE → TIMESTAMP: interpret date in query timezone, return UTC wall clock
406
- if (malloy_types_1.TD.isDate(srcTypeDef) && malloy_types_1.TD.isTimestamp(dstTypeDef)) {
407
- return `CAST(at_timezone(with_timezone(CAST(${expr} AS TIMESTAMP), ${this.sqlTimezoneLiteral(tz)}), 'UTC') AS TIMESTAMP)`;
408
- }
409
- // DATE → TIMESTAMPTZ: interpret date in query timezone
410
- if (malloy_types_1.TD.isDate(srcTypeDef) && malloy_types_1.TD.isTimestamptz(dstTypeDef)) {
411
- return `with_timezone(CAST(${expr} AS TIMESTAMP), ${this.sqlTimezoneLiteral(tz)})`;
412
- }
413
- // TIMESTAMPTZ → TIMESTAMP: convert to query timezone wall clock
414
- if (malloy_types_1.TD.isTimestamptz(srcTypeDef) && malloy_types_1.TD.isTimestamp(dstTypeDef)) {
415
- return `CAST(at_timezone(${expr}, ${this.sqlTimezoneLiteral(tz)}) AS TIMESTAMP)`;
416
- }
417
- // TIMESTAMP → TIMESTAMPTZ: interpret TIMESTAMP as being in query timezone
418
- if (malloy_types_1.TD.isTimestamp(srcTypeDef) && malloy_types_1.TD.isTimestamptz(dstTypeDef)) {
419
- return `with_timezone(${expr}, ${this.sqlTimezoneLiteral(tz)})`;
420
- }
421
- }
422
- // No special handling needed, or no query timezone
423
388
  if (!malloy_types_1.TD.eq(srcTypeDef, dstTypeDef)) {
424
389
  const castFunc = cast.safe ? 'TRY_CAST' : 'CAST';
425
390
  return `${castFunc}(${expr} AS ${dstSQLType})`;
@@ -567,37 +532,12 @@ ${(0, utils_1.indent)(sql)}
567
532
  sqlDateLiteral(_qi, literal) {
568
533
  return `DATE '${literal}'`;
569
534
  }
570
- sqlTimestampLiteral(qi, literal, timezone) {
571
- const tz = timezone || qtz(qi);
572
- if (tz) {
573
- // Interpret wall clock time in timezone, convert to UTC wall clock, cast to TIMESTAMP
574
- return `CAST(at_timezone(with_timezone(TIMESTAMP '${literal}', ${this.sqlTimezoneLiteral(tz)}), 'UTC') AS TIMESTAMP)`;
575
- }
576
- return `TIMESTAMP '${literal}'`;
577
- }
578
535
  sqlTimestamptzLiteral(_qi, literal, timezone) {
579
536
  // Use with_timezone to create a TIMESTAMP WITH TIME ZONE
580
537
  return `with_timezone(TIMESTAMP '${literal}', ${this.sqlTimezoneLiteral(timezone)})`;
581
538
  }
582
- sqlTimeExtractExpr(qi, from) {
583
- const pgUnits = pg_impl_1.timeExtractMap[from.units] || from.units;
584
- let extractFrom = from.e.sql || '';
585
- if (malloy_types_1.TD.isAnyTimestamp(from.e.typeDef)) {
586
- const tz = qtz(qi);
587
- if (tz) {
588
- // Convert both TIMESTAMP and TIMESTAMPTZ to query timezone for extraction
589
- if (from.e.typeDef.type === 'timestamp') {
590
- // TIMESTAMP: interpret as UTC, convert to query timezone
591
- extractFrom = `at_timezone(with_timezone(${extractFrom}, 'UTC'), ${this.sqlTimezoneLiteral(tz)})`;
592
- }
593
- else {
594
- // TIMESTAMPTZ: convert to query timezone
595
- extractFrom = `at_timezone(${extractFrom}, ${this.sqlTimezoneLiteral(tz)})`;
596
- }
597
- }
598
- }
599
- const extracted = `EXTRACT(${pgUnits} FROM ${extractFrom})`;
600
- return from.units === 'day_of_week' ? `mod(${extracted}+1,7)` : extracted;
539
+ sqlCivilExtract(expr, units, _civilType) {
540
+ return trinoExtract(expr, units);
601
541
  }
602
542
  sqlLiteralRecord(lit) {
603
543
  var _a, _b;
@@ -630,91 +570,97 @@ class PrestoDialect extends TrinoDialect {
630
570
  return `DATE '${literal}'`;
631
571
  }
632
572
  sqlTimestampLiteral(qi, literal, timezone) {
633
- const tz = timezone || qtz(qi);
634
- if (tz) {
635
- return `CAST(TIMESTAMP '${literal} ${this.checkedTimezoneName(tz)}' AT TIME ZONE 'UTC' AS TIMESTAMP)`;
573
+ const tz = timezone !== null && timezone !== void 0 ? timezone : (0, dialect_1.queryZone)(qi);
574
+ if (tz === 'UTC') {
575
+ return `TIMESTAMP '${literal}'`;
636
576
  }
637
- return `TIMESTAMP '${literal}'`;
577
+ return `CAST(TIMESTAMP '${literal} ${this.checkedTimezoneName(tz)}' AS TIMESTAMP)`;
638
578
  }
639
579
  sqlTimestamptzLiteral(_qi, literal, timezone) {
640
580
  return `TIMESTAMP '${literal} ${this.checkedTimezoneName(timezone)}'`;
641
581
  }
642
- sqlConvertToCivilTime(expr, timezone, _typeDef) {
643
- // Presto's AT TIME ZONE operator (not function) produces TIMESTAMPTZ
644
- // Reinterprets the instant in the target timezone
645
- return {
646
- sql: `${expr} AT TIME ZONE ${this.sqlTimezoneLiteral(timezone)}`,
647
- typeDef: { type: 'timestamptz' },
648
- };
649
- }
650
- sqlConvertFromCivilTime(expr, _timezone, destTypeDef) {
651
- if (destTypeDef.type === 'timestamptz') {
582
+ /*
583
+ * Presto cannot meet the civil contract: its only way to read a date and
584
+ * time of day as an instant in a zone is to parse a string, which fails
585
+ * on a time the zone skips. So Presto never converts to civil time. It
586
+ * places an instant in the zone as a TIMESTAMP WITH TIME ZONE, whose
587
+ * functions read the clock in that zone and resolve any skipped or
588
+ * repeated time themselves. A Presto TIMESTAMP is an instant shown in the
589
+ * session zone, which is UTC.
590
+ */
591
+ sqlConvertToCivilTime() {
592
+ throw new Error('Presto has no civil time');
593
+ }
594
+ sqlConvertFromCivilTime() {
595
+ throw new Error('Presto has no civil time');
596
+ }
597
+ /** The instant `expr`, showing the clock of `timezone` */
598
+ inZone(expr, typeDef, timezone) {
599
+ if (malloy_types_1.TD.isTimestamp(typeDef) && timezone === 'UTC') {
652
600
  return expr;
653
601
  }
654
- return `CAST(${expr} AT TIME ZONE 'UTC' AS TIMESTAMP)`;
602
+ return `(${expr}) AT TIME ZONE ${this.sqlTimezoneLiteral(timezone)}`;
655
603
  }
656
- sqlCast(qi, cast) {
657
- const { srcTypeDef, dstTypeDef, dstSQLType } = this.sqlCastPrep(cast);
658
- const tz = qtz(qi);
659
- const expr = cast.e.sql || '';
660
- // Timezone-aware casts when query timezone is set
661
- // Presto uses AT TIME ZONE operator instead of Trino's with_timezone/at_timezone functions
662
- if (tz && srcTypeDef && dstTypeDef) {
663
- // TIMESTAMP → DATE: interpret as UTC, convert to query timezone
664
- if (malloy_types_1.TD.isTimestamp(srcTypeDef) && malloy_types_1.TD.isDate(dstTypeDef)) {
665
- return `CAST((${expr} AT TIME ZONE 'UTC') AT TIME ZONE ${this.sqlTimezoneLiteral(tz)} AS DATE)`;
666
- }
667
- // TIMESTAMPTZ → DATE: convert to query timezone
668
- if (malloy_types_1.TD.isTimestamptz(srcTypeDef) && malloy_types_1.TD.isDate(dstTypeDef)) {
669
- return `CAST(${expr} AT TIME ZONE ${this.sqlTimezoneLiteral(tz)} AS DATE)`;
670
- }
671
- // DATE → TIMESTAMP: interpret date in query timezone, return UTC wall clock
672
- // Presto doesn't have a way to interpret TIMESTAMP in a non-UTC timezone,
673
- // so we build a TIMESTAMPTZ literal string and cast it
674
- if (malloy_types_1.TD.isDate(srcTypeDef) && malloy_types_1.TD.isTimestamp(dstTypeDef)) {
675
- const tstzLiteral = `CAST(CAST(${expr} AS VARCHAR) || ' 00:00:00 ${this.checkedTimezoneName(tz)}' AS TIMESTAMP WITH TIME ZONE)`;
676
- return `CAST(${tstzLiteral} AS TIMESTAMP)`;
677
- }
678
- // DATE → TIMESTAMPTZ: interpret date in query timezone
679
- if (malloy_types_1.TD.isDate(srcTypeDef) && malloy_types_1.TD.isTimestamptz(dstTypeDef)) {
680
- return `CAST(CAST(${expr} AS VARCHAR) || ' 00:00:00 ${this.checkedTimezoneName(tz)}' AS TIMESTAMP WITH TIME ZONE)`;
681
- }
682
- // TIMESTAMPTZ → TIMESTAMP: convert to query timezone wall clock
683
- if (malloy_types_1.TD.isTimestamptz(srcTypeDef) && malloy_types_1.TD.isTimestamp(dstTypeDef)) {
684
- return `CAST(${expr} AT TIME ZONE ${this.sqlTimezoneLiteral(tz)} AS TIMESTAMP)`;
685
- }
686
- // TIMESTAMP → TIMESTAMPTZ: interpret TIMESTAMP as UTC
687
- if (malloy_types_1.TD.isTimestamp(srcTypeDef) && malloy_types_1.TD.isTimestamptz(dstTypeDef)) {
688
- return `${expr} AT TIME ZONE 'UTC'`;
689
- }
690
- }
691
- // No special handling needed, or no query timezone
692
- if (!malloy_types_1.TD.eq(srcTypeDef, dstTypeDef)) {
693
- const castFunc = cast.safe ? 'TRY_CAST' : 'CAST';
694
- return `${castFunc}(${expr} AS ${dstSQLType})`;
604
+ /** An instant from inZone, as a value of `typeDef` */
605
+ fromZone(expr, typeDef, timezone) {
606
+ if (malloy_types_1.TD.isTimestamp(typeDef) && timezone !== 'UTC') {
607
+ return `CAST(${expr} AS TIMESTAMP)`;
695
608
  }
696
609
  return expr;
697
610
  }
698
611
  sqlTimeExtractExpr(qi, from) {
699
- const pgUnits = pg_impl_1.timeExtractMap[from.units] || from.units;
700
- let extractFrom = from.e.sql || '';
701
- if (malloy_types_1.TD.isAnyTimestamp(from.e.typeDef)) {
702
- const tz = qtz(qi);
703
- if (tz) {
704
- // Convert both TIMESTAMP and TIMESTAMPTZ to query timezone for extraction
705
- if (from.e.typeDef.type === 'timestamp') {
706
- // TIMESTAMP: interpret as UTC, convert to query timezone
707
- // Presto uses AT TIME ZONE operator
708
- extractFrom = `(${extractFrom} AT TIME ZONE 'UTC') AT TIME ZONE ${this.sqlTimezoneLiteral(tz)}`;
709
- }
710
- else {
711
- // TIMESTAMPTZ: convert to query timezone
712
- extractFrom = `${extractFrom} AT TIME ZONE ${this.sqlTimezoneLiteral(tz)}`;
713
- }
612
+ const time = from.e;
613
+ const expr = malloy_types_1.TD.isAnyTimestamp(time.typeDef)
614
+ ? this.inZone(time.sql, time.typeDef, (0, dialect_1.queryZone)(qi))
615
+ : time.sql;
616
+ return trinoExtract(expr, from.units);
617
+ }
618
+ sqlTruncAndOffset(baseExpr, qi, truncateTo, offset) {
619
+ const timeType = baseExpr.typeDef;
620
+ // Adding hours, minutes or seconds to an instant needs no zone
621
+ const usesQueryZone = malloy_types_1.TD.isAnyTimestamp(timeType) &&
622
+ (truncateTo !== undefined ||
623
+ (offset !== undefined && (0, malloy_types_1.isDateUnit)(offset.unit)));
624
+ const zone = (0, dialect_1.queryZone)(qi);
625
+ let sql = usesQueryZone
626
+ ? this.inZone(baseExpr.sql, timeType, zone)
627
+ : baseExpr.sql;
628
+ if (truncateTo) {
629
+ sql = trinoTrunc(sql, truncateTo);
630
+ }
631
+ if (offset) {
632
+ sql = trinoDateAdd(sql, offset.op, offset.magnitude, offset.unit);
633
+ }
634
+ return usesQueryZone ? this.fromZone(sql, timeType, zone) : sql;
635
+ }
636
+ sqlTimeCast(qi, cast) {
637
+ var _a;
638
+ const { srcTypeDef, dstTypeDef } = this.sqlCastPrep(cast);
639
+ const expr = (_a = cast.e.sql) !== null && _a !== void 0 ? _a : '';
640
+ const zone = (0, dialect_1.queryZone)(qi);
641
+ if (malloy_types_1.TD.isAnyTimestamp(srcTypeDef)) {
642
+ if (malloy_types_1.TD.isDate(dstTypeDef)) {
643
+ return `CAST(${this.inZone(expr, srcTypeDef, zone)} AS DATE)`;
644
+ }
645
+ if (malloy_types_1.TD.isTimestamp(dstTypeDef) && malloy_types_1.TD.isTimestamptz(srcTypeDef)) {
646
+ return `CAST(${expr} AS TIMESTAMP)`;
647
+ }
648
+ if (malloy_types_1.TD.isTimestamptz(dstTypeDef) && malloy_types_1.TD.isTimestamp(srcTypeDef)) {
649
+ return `(${expr}) AT TIME ZONE 'UTC'`;
650
+ }
651
+ }
652
+ if (malloy_types_1.TD.isDate(srcTypeDef) && malloy_types_1.TD.isAnyTimestamp(dstTypeDef)) {
653
+ if (zone === 'UTC') {
654
+ const midnight = `CAST(${expr} AS TIMESTAMP)`;
655
+ return malloy_types_1.TD.isTimestamp(dstTypeDef)
656
+ ? midnight
657
+ : `(${midnight}) AT TIME ZONE 'UTC'`;
714
658
  }
659
+ // Fails in a zone which skips the midnight starting the date
660
+ const midnight = `CAST(CAST(${expr} AS VARCHAR) || ' 00:00:00 ${this.checkedTimezoneName(zone)}' AS TIMESTAMP WITH TIME ZONE)`;
661
+ return this.fromZone(midnight, dstTypeDef, zone);
715
662
  }
716
- const extracted = `EXTRACT(${pgUnits} FROM ${extractFrom})`;
717
- return from.units === 'day_of_week' ? `mod(${extracted}+1,7)` : extracted;
663
+ return undefined;
718
664
  }
719
665
  sqlUnnestAlias(source, alias, _fieldList, needDistinctKey, isArray, _isInNestedPipeline) {
720
666
  if (isArray) {
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { DuckDBDialect, StandardSQLDialect, TrinoDialect, PostgresDialect, SnowflakeDialect, MySQLDialect, DatabricksDialect, registerDialect, arg, qtz, overload, minScalar, anyExprType, minAggregate, maxScalar, sql, makeParam, param, variadicParam, literal, spread, Dialect, decodeDottedTablePath, validateDottedTablePath, } from './dialect';
1
+ export { DuckDBDialect, StandardSQLDialect, TrinoDialect, PostgresDialect, SnowflakeDialect, MySQLDialect, DatabricksDialect, SQLServerDialect, registerDialect, getDialect, arg, queryZone, overload, minScalar, anyExprType, minAggregate, maxScalar, sql, makeParam, param, variadicParam, literal, spread, Dialect, decodeDottedTablePath, validateDottedTablePath, } from './dialect';
2
2
  export type { DialectFieldList, DialectFunctionOverloadDef, QueryInfo, MalloyStandardFunctionImplementations, DefinitionBlueprint, DefinitionBlueprintMap, OverloadedDefinitionBlueprint, DecodeDottedTablePathResult, DottedTablePathOptions, TablePathEscapeStyle, TablePathSegment, ValidateTablePathResult, } from './dialect';
3
3
  export type { QueryRecord, StructDef, TableSourceDef, SQLSourceDef, SourceDef, JoinFieldDef, NamedSourceDefs, MalloyQueryData, DateUnit, ExtractUnit, TimestampUnit, TemporalFieldType, QueryData, QueryValue, Expr, FilterCondition, Argument, Parameter, FieldDef, PipeSegment, QueryFieldDef, IndexFieldDef, TurtleDef, SearchValueMapResult, SearchIndexResult, ModelDef, Query, QueryResult, QueryResultDef, QueryRunStats, QueryScalar, NamedQueryDef, NamedModelObject, ExpressionType, FunctionDef, FunctionOverloadDef, FunctionParameterDef, ExpressionValueType, TypeDesc, FunctionParamTypeDesc, DocumentLocation, DocumentRange, DocumentPosition, Sampling, BasicAtomicTypeDef, BasicAtomicDef, AtomicTypeDef, AtomicFieldDef, ArrayDef, ArrayTypeDef, RecordTypeDef, RepeatedRecordTypeDef, RecordDef, RepeatedRecordDef, RecordLiteralNode, StringLiteralNode, ArrayLiteralNode, SourceComponentInfo, DateLiteralNode, TimestampLiteralNode, TimestamptzLiteralNode, TimeLiteralExpr, TypecastExpr, BuildID, BuildManifest, BuildManifestEntry, GivenValue, VirtualMap, } from './model';
4
4
  export { isSourceDef, isAtomic, isBasicAtomic, isCompoundArrayData, isJoined, isJoinedSource, isSamplingEnable, isSamplingPercent, isSamplingRows, isRepeatedRecord, isBasicArray, mkArrayDef, mkFieldDef, expressionIsAggregate, expressionIsAnalytic, expressionIsCalculation, expressionIsScalar, expressionIsUngroupedAggregate, indent, composeSQLExpr, isTimestampUnit, isDateUnit, constantExprToSQL, } from './model';
@@ -25,7 +25,7 @@ export { routeOf, payloadOf, annotationsForRoute, tagFromAnnotations, } from './
25
25
  /** @deprecated — use the `.annotations` view on a Foundation entity
26
26
  * (`entity.annotations.parseAsTag(route)` / `.texts(route)`). */
27
27
  export { annotationToTag, annotationToTaglines, } from './api/foundation/annotation';
28
- export type { BuildGraph, BuildNode, BuildPlan, BuildTarget, BuildTargets, ConnectionBuild, } from './api/foundation';
28
+ export type { BuildGraph, BuildNode, BuildPlan, BuildTarget, BuildTargetOptions, BuildTargets, ConnectionBuild, UnbuildableSource, } from './api/foundation';
29
29
  export { PersistSource, EMPTY_BUILD_MANIFEST } from './api/foundation';
30
30
  export { Reference } from './api/foundation';
31
31
  export type { ReferenceKind } from './api/foundation';