@malloydata/malloy 0.0.203-dev241021171612 → 0.0.203-dev241022210817

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 (30) hide show
  1. package/dist/dialect/dialect.d.ts +11 -0
  2. package/dist/dialect/dialect.js +27 -0
  3. package/dist/dialect/duckdb/duckdb.js +2 -2
  4. package/dist/dialect/mysql/mysql.js +12 -15
  5. package/dist/dialect/pg_impl.js +7 -9
  6. package/dist/dialect/snowflake/snowflake.js +12 -17
  7. package/dist/dialect/standardsql/standardsql.js +13 -16
  8. package/dist/dialect/trino/trino.js +9 -12
  9. package/dist/lang/ast/expressions/expr-granular-time.js +1 -1
  10. package/dist/lang/ast/expressions/expr-record-literal.d.ts +1 -1
  11. package/dist/lang/ast/expressions/expr-record-literal.js +28 -25
  12. package/dist/lang/ast/expressions/expr-time-extract.js +3 -3
  13. package/dist/lang/ast/expressions/expr-time.js +2 -2
  14. package/dist/lang/ast/expressions/for-range.js +1 -1
  15. package/dist/lang/ast/expressions/time-literal.js +1 -1
  16. package/dist/lang/ast/time-utils.d.ts +1 -3
  17. package/dist/lang/ast/time-utils.js +24 -34
  18. package/dist/lang/ast/types/expression-def.js +2 -2
  19. package/dist/lang/lib/Malloy/MalloyParser.d.ts +49 -14
  20. package/dist/lang/lib/Malloy/MalloyParser.js +1784 -1538
  21. package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +48 -11
  22. package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +30 -7
  23. package/dist/lang/malloy-to-ast.d.ts +5 -1
  24. package/dist/lang/malloy-to-ast.js +25 -29
  25. package/dist/lang/parse-log.d.ts +1 -0
  26. package/dist/lang/test/test-translator.js +1 -1
  27. package/dist/model/malloy_query.js +1 -1
  28. package/dist/model/malloy_types.d.ts +41 -14
  29. package/dist/model/malloy_types.js +83 -2
  30. package/package.json +1 -1
@@ -123,5 +123,16 @@ export declare abstract class Dialect {
123
123
  abstract sqlTypeToMalloyType(sqlType: string): LeafAtomicTypeDef;
124
124
  abstract malloyTypeToSQLType(malloyType: AtomicTypeDef): string;
125
125
  abstract validateTypeName(sqlType: string): boolean;
126
+ /**
127
+ * Helper function for sql cast implementations. Handles the
128
+ * wrangling of the raw type and also inferring the source
129
+ * type if it was not provided.
130
+ */
131
+ sqlCastPrep(cast: TypecastExpr): {
132
+ op: string;
133
+ srcTypeDef: LeafAtomicTypeDef | undefined;
134
+ dstTypeDef: LeafAtomicTypeDef | undefined;
135
+ dstSQLType: string;
136
+ };
126
137
  }
127
138
  export {};
@@ -23,6 +23,7 @@
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");
26
27
  function isDialectFieldStruct(d) {
27
28
  return d.type === 'struct';
28
29
  }
@@ -201,6 +202,32 @@ class Dialect {
201
202
  ''
202
203
  )`;
203
204
  }
205
+ /**
206
+ * Helper function for sql cast implementations. Handles the
207
+ * wrangling of the raw type and also inferring the source
208
+ * type if it was not provided.
209
+ */
210
+ sqlCastPrep(cast) {
211
+ let srcTypeDef = cast.srcType || cast.e.typeDef;
212
+ const src = (srcTypeDef === null || srcTypeDef === void 0 ? void 0 : srcTypeDef.type) || 'unknown';
213
+ if (srcTypeDef && !(0, malloy_types_1.isLeafAtomic)(srcTypeDef)) {
214
+ srcTypeDef = undefined;
215
+ }
216
+ if ((0, malloy_types_1.isRawCast)(cast)) {
217
+ return {
218
+ op: `${src}::'${cast.dstSQLType}'`,
219
+ srcTypeDef,
220
+ dstTypeDef: undefined,
221
+ dstSQLType: cast.dstSQLType,
222
+ };
223
+ }
224
+ return {
225
+ op: `${src}::${cast.dstType.type}`,
226
+ srcTypeDef,
227
+ dstTypeDef: cast.dstType,
228
+ dstSQLType: this.malloyTypeToSQLType(cast.dstType),
229
+ };
230
+ }
204
231
  }
205
232
  exports.Dialect = Dialect;
206
233
  //# sourceMappingURL=dialect.js.map
@@ -330,10 +330,10 @@ class DuckDBDialect extends pg_impl_1.PostgresBase {
330
330
  let lVal = from.sql || '';
331
331
  let rVal = to.sql || '';
332
332
  if (!(0, dialect_1.inDays)(df.units)) {
333
- if (from.dataType === 'date') {
333
+ if (malloy_types_1.TD.isDate(from.typeDef)) {
334
334
  lVal = `${lVal}::TIMESTAMP`;
335
335
  }
336
- if (to.dataType === 'date') {
336
+ if (malloy_types_1.TD.isDate(to.typeDef)) {
337
337
  rVal = `${rVal}::TIMESTAMP`;
338
338
  }
339
339
  }
@@ -278,7 +278,7 @@ class MySQLDialect extends dialect_1.Dialect {
278
278
  if (trunc.units === 'week') {
279
279
  truncThis = `DATE_SUB(${truncThis}, INTERVAL DAYOFWEEK(${truncThis}) - 1 DAY)`;
280
280
  }
281
- if (trunc.e.dataType === 'timestamp') {
281
+ if (malloy_types_1.TD.isTimestamp(trunc.e.typeDef)) {
282
282
  const tz = (0, dialect_1.qtz)(qi);
283
283
  if (tz) {
284
284
  const civilSource = `(CONVERT_TZ(${truncThis}, 'UTC','${tz}'))`;
@@ -318,7 +318,7 @@ class MySQLDialect extends dialect_1.Dialect {
318
318
  sqlTimeExtractExpr(qi, te) {
319
319
  const msUnits = msExtractionMap[te.units] || te.units;
320
320
  let extractFrom = te.e.sql;
321
- if (te.e.dataType === 'timestamp') {
321
+ if (malloy_types_1.TD.isTimestamp(te.e.typeDef)) {
322
322
  const tz = (0, dialect_1.qtz)(qi);
323
323
  if (tz) {
324
324
  extractFrom = `CONVERT_TZ(${extractFrom}, 'UTC', '${tz}')`;
@@ -341,34 +341,31 @@ class MySQLDialect extends dialect_1.Dialect {
341
341
  return `(${df.kids.base.sql})${df.op}${interval}`;
342
342
  }
343
343
  sqlCast(qi, cast) {
344
- const op = `${cast.srcType}::${cast.dstType}`;
344
+ const srcSQL = cast.e.sql || 'internal-error-in-sql-generation';
345
+ const { op, srcTypeDef, dstTypeDef, dstSQLType } = this.sqlCastPrep(cast);
345
346
  const tz = (0, dialect_1.qtz)(qi);
346
347
  if (op === 'timestamp::date' && tz) {
347
- return `CAST(CONVERT_TZ(${cast.e.sql}, 'UTC', '${tz}') AS DATE) `;
348
+ return `CAST(CONVERT_TZ(${srcSQL}, 'UTC', '${tz}') AS DATE) `;
348
349
  }
349
350
  else if (op === 'date::timestamp' && tz) {
350
- return ` CONVERT_TZ(${cast.e.sql}, '${tz}', 'UTC')`;
351
+ return ` CONVERT_TZ(${srcSQL}, '${tz}', 'UTC')`;
351
352
  }
352
- if (cast.srcType !== cast.dstType) {
353
- const dstType = typeof cast.dstType === 'string'
354
- ? this.malloyTypeToSQLType({ type: cast.dstType })
355
- : cast.dstType.raw;
353
+ if (!malloy_types_1.TD.eq(srcTypeDef, dstTypeDef)) {
356
354
  if (cast.safe) {
357
355
  throw new Error("Mysql dialect doesn't support Safe Cast");
358
356
  }
359
- if (cast.dstType === 'string') {
360
- return `CONCAT(${cast.e.sql}, '')`;
357
+ if (malloy_types_1.TD.isString(dstTypeDef)) {
358
+ return `CONCAT(${srcSQL}, '')`;
361
359
  }
362
- return `CAST(${cast.e.sql} AS ${dstType})`;
360
+ return `CAST(${srcSQL} AS ${dstSQLType})`;
363
361
  }
364
- // LTNOTE: I don't understand how this could be undefined.
365
- return cast.e.sql || 'weirdly undefined';
362
+ return srcSQL;
366
363
  }
367
364
  sqlRegexpMatch(df) {
368
365
  return `REGEXP_LIKE(${df.kids.expr.sql}, ${df.kids.regex.sql})`;
369
366
  }
370
367
  sqlLiteralTime(qi, lt) {
371
- if (lt.dataType === 'date') {
368
+ if (malloy_types_1.TD.isDate(lt.typeDef)) {
372
369
  return `DATE '${lt.literal}'`;
373
370
  }
374
371
  const tz = lt.timezone || (0, dialect_1.qtz)(qi);
@@ -7,6 +7,7 @@
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.PostgresBase = exports.timeExtractMap = void 0;
10
+ const malloy_types_1 = require("../model/malloy_types");
10
11
  const dialect_1 = require("./dialect");
11
12
  exports.timeExtractMap = {
12
13
  'day_of_week': 'dow',
@@ -21,7 +22,7 @@ class PostgresBase extends dialect_1.Dialect {
21
22
  // adjusting for monday/sunday weeks
22
23
  const week = df.units === 'week';
23
24
  const truncThis = week ? `${df.e.sql} + INTERVAL '1' DAY` : df.e.sql;
24
- if (df.e.dataType === 'timestamp') {
25
+ if (malloy_types_1.TD.isTimestamp(df.e.typeDef)) {
25
26
  const tz = (0, dialect_1.qtz)(qi);
26
27
  if (tz) {
27
28
  const civilSource = `(${truncThis}::TIMESTAMPTZ AT TIME ZONE '${tz}')`;
@@ -44,7 +45,7 @@ class PostgresBase extends dialect_1.Dialect {
44
45
  sqlTimeExtractExpr(qi, from) {
45
46
  const units = exports.timeExtractMap[from.units] || from.units;
46
47
  let extractFrom = from.e.sql;
47
- if (from.e.dataType === 'timestamp') {
48
+ if (malloy_types_1.TD.isTimestamp(from.e.typeDef)) {
48
49
  const tz = (0, dialect_1.qtz)(qi);
49
50
  if (tz) {
50
51
  extractFrom = `(${extractFrom}::TIMESTAMPTZ AT TIME ZONE '${tz}')`;
@@ -55,7 +56,7 @@ class PostgresBase extends dialect_1.Dialect {
55
56
  }
56
57
  sqlCast(qi, cast) {
57
58
  const expr = cast.e.sql || '';
58
- const op = `${cast.srcType}::${cast.dstType}`;
59
+ const { op, srcTypeDef, dstTypeDef, dstSQLType } = this.sqlCastPrep(cast);
59
60
  const tz = (0, dialect_1.qtz)(qi);
60
61
  if (op === 'timestamp::date' && tz) {
61
62
  const tstz = `${expr}::TIMESTAMPTZ`;
@@ -64,12 +65,9 @@ class PostgresBase extends dialect_1.Dialect {
64
65
  else if (op === 'date::timestamp' && tz) {
65
66
  return `CAST((${expr})::TIMESTAMP AT TIME ZONE '${tz}' AS TIMESTAMP)`;
66
67
  }
67
- if (cast.srcType !== cast.dstType) {
68
- const dstType = typeof cast.dstType === 'string'
69
- ? this.malloyTypeToSQLType({ type: cast.dstType })
70
- : cast.dstType.raw;
68
+ if (!malloy_types_1.TD.eq(srcTypeDef, dstTypeDef)) {
71
69
  const castFunc = cast.safe ? 'TRY_CAST' : 'CAST';
72
- return `${castFunc}(${expr} AS ${dstType})`;
70
+ return `${castFunc}(${expr} AS ${dstSQLType})`;
73
71
  }
74
72
  return expr;
75
73
  }
@@ -77,7 +75,7 @@ class PostgresBase extends dialect_1.Dialect {
77
75
  return `${df.kids.expr.sql} ~ ${df.kids.regex.sql}`;
78
76
  }
79
77
  sqlLiteralTime(qi, lt) {
80
- if (lt.dataType === 'date') {
78
+ if (malloy_types_1.TD.isDate(lt.typeDef)) {
81
79
  return `DATE '${lt.literal}'`;
82
80
  }
83
81
  const tz = lt.timezone || (0, dialect_1.qtz)(qi);
@@ -239,7 +239,7 @@ ${(0, utils_1.indent)(sql)}
239
239
  sqlTruncExpr(qi, te) {
240
240
  const tz = (0, dialect_1.qtz)(qi);
241
241
  let truncThis = te.e.sql;
242
- if (tz && te.e.dataType === 'timestamp') {
242
+ if (tz && malloy_types_1.TD.isTimestamp(te.e.typeDef)) {
243
243
  truncThis = `CONVERT_TIMEZONE('${tz}',${truncThis})`;
244
244
  }
245
245
  return `DATE_TRUNC('${te.units}',${truncThis})`;
@@ -248,7 +248,7 @@ ${(0, utils_1.indent)(sql)}
248
248
  const extractUnits = extractionMap[from.units] || from.units;
249
249
  let extractFrom = from.e.sql;
250
250
  const tz = (0, dialect_1.qtz)(qi);
251
- if (tz && from.e.dataType === 'timestamp') {
251
+ if (tz && malloy_types_1.TD.isTimestamp(from.e.typeDef)) {
252
252
  extractFrom = `CONVERT_TIMEZONE('${tz}', ${extractFrom})`;
253
253
  }
254
254
  return `EXTRACT(${extractUnits} FROM ${extractFrom})`;
@@ -271,10 +271,11 @@ ${(0, utils_1.indent)(sql)}
271
271
  }
272
272
  sqlCast(qi, cast) {
273
273
  const src = cast.e.sql || '';
274
- if (cast.srcType === cast.dstType) {
274
+ const { op, srcTypeDef, dstTypeDef, dstSQLType } = this.sqlCastPrep(cast);
275
+ if (malloy_types_1.TD.eq(srcTypeDef, dstTypeDef)) {
275
276
  return src;
276
277
  }
277
- if (cast.safe && typeof cast.srcType !== 'string') {
278
+ if (cast.safe && !malloy_types_1.TD.isString(srcTypeDef)) {
278
279
  // safe cast is only supported for a few combinations of src -> dst types
279
280
  // so we will not support it in the general case
280
281
  // see: https://docs.snowflake.com/en/sql-reference/functions/try_cast
@@ -283,22 +284,19 @@ ${(0, utils_1.indent)(sql)}
283
284
  }
284
285
  const tz = (0, dialect_1.qtz)(qi);
285
286
  // casting timestamps and dates
286
- if (cast.dstType === 'date' && cast.srcType === 'timestamp') {
287
+ if (op === 'timestamp::date') {
287
288
  let castExpr = src;
288
289
  if (tz) {
289
290
  castExpr = `CONVERT_TIMEZONE('${tz}', ${castExpr})`;
290
291
  }
291
292
  return `TO_DATE(${castExpr})`;
292
293
  }
293
- else if (cast.dstType === 'timestamp' && cast.srcType === 'date') {
294
+ else if (op === 'date::timestamp') {
294
295
  const retExpr = `TO_TIMESTAMP(${src})`;
295
296
  return this.atTz(retExpr, tz);
296
297
  }
297
- const dstType = typeof cast.dstType === 'string'
298
- ? this.malloyTypeToSQLType({ type: cast.dstType })
299
- : cast.dstType.raw;
300
298
  const castFunc = cast.safe ? 'TRY_CAST' : 'CAST';
301
- return `${castFunc}(${src} AS ${dstType})`;
299
+ return `${castFunc}(${src} AS ${dstSQLType})`;
302
300
  }
303
301
  sqlLiteralTime(qi, lf) {
304
302
  var _a;
@@ -313,19 +311,16 @@ ${(0, utils_1.indent)(sql)}
313
311
  ret = `${retTimeString} || ${targetTimeZoneSuffix}`;
314
312
  ret = `(${ret})::TIMESTAMP_TZ`;
315
313
  }
316
- switch (lf.dataType) {
317
- case 'date':
318
- return `TO_DATE(${ret})`;
319
- case 'timestamp': {
320
- return ret;
321
- }
314
+ if (malloy_types_1.TD.isDate(lf.typeDef)) {
315
+ return `TO_DATE(${ret})`;
322
316
  }
317
+ return ret;
323
318
  }
324
319
  sqlMeasureTimeExpr(df) {
325
320
  const from = df.kids.left;
326
321
  const to = df.kids.right;
327
322
  let extractUnits = 'nanoseconds';
328
- if (from.dataType === 'date' || to.dataType === 'date') {
323
+ if (malloy_types_1.TD.isDate(from.typeDef) || malloy_types_1.TD.isDate(to.typeDef)) {
329
324
  extractUnits = 'seconds';
330
325
  }
331
326
  return `TIMESTAMPDIFF(
@@ -308,7 +308,7 @@ ${(0, utils_1.indent)(sql)}
308
308
  sqlTruncExpr(qi, trunc) {
309
309
  const tz = qtz(qi);
310
310
  const tzAdd = tz ? `, "${tz}"` : '';
311
- if (trunc.e.dataType === 'date') {
311
+ if (malloy_types_1.TD.isDate(trunc.e.typeDef)) {
312
312
  if (dateMeasureable(trunc.units)) {
313
313
  return `DATE_TRUNC(${trunc.e.sql},${trunc.units})`;
314
314
  }
@@ -318,13 +318,13 @@ ${(0, utils_1.indent)(sql)}
318
318
  }
319
319
  sqlTimeExtractExpr(qi, te) {
320
320
  const extractTo = extractMap[te.units] || te.units;
321
- const tz = te.e.dataType === 'timestamp' && qtz(qi);
321
+ const tz = malloy_types_1.TD.isTimestamp(te.e.typeDef) && qtz(qi);
322
322
  const tzAdd = tz ? ` AT TIME ZONE '${tz}'` : '';
323
323
  return `EXTRACT(${extractTo} FROM ${te.e.sql}${tzAdd})`;
324
324
  }
325
325
  sqlAlterTimeExpr(df) {
326
326
  const from = df.kids.base;
327
- let dataType = from.dataType;
327
+ let dataType = from === null || from === void 0 ? void 0 : from.typeDef.type;
328
328
  let sql = from.sql;
329
329
  if (df.units !== 'day' && timestampMeasureable(df.units)) {
330
330
  // The units must be done in timestamp, no matter the input type
@@ -340,16 +340,16 @@ ${(0, utils_1.indent)(sql)}
340
340
  const funcTail = df.op === '+' ? '_ADD' : '_SUB';
341
341
  const funcName = `${dataType.toUpperCase()}${funcTail}`;
342
342
  const newTime = `${funcName}(${sql}, INTERVAL ${df.kids.delta.sql} ${df.units})`;
343
- if (dataType === from.dataType) {
343
+ if (dataType === from.typeDef.type) {
344
344
  return newTime;
345
345
  }
346
- return `${from.dataType.toUpperCase()}(${newTime})`;
346
+ return `${from.typeDef.type.toUpperCase()}(${newTime})`;
347
347
  }
348
348
  ignoreInProject(fieldName) {
349
349
  return fieldName === '_PARTITIONTIME';
350
350
  }
351
351
  sqlCast(qi, cast) {
352
- const op = `${cast.srcType}::${cast.dstType}`;
352
+ const { op, srcTypeDef, dstTypeDef, dstSQLType } = this.sqlCastPrep(cast);
353
353
  const tz = qtz(qi);
354
354
  const src = cast.e.sql || '';
355
355
  if (op === 'timestamp::date' && tz) {
@@ -358,12 +358,9 @@ ${(0, utils_1.indent)(sql)}
358
358
  if (op === 'date::timestamp' && tz) {
359
359
  return `TIMESTAMP(${src}, '${tz}')`;
360
360
  }
361
- if (cast.srcType !== cast.dstType) {
362
- const dstType = typeof cast.dstType === 'string'
363
- ? this.malloyTypeToSQLType({ type: cast.dstType })
364
- : cast.dstType.raw;
361
+ if (!malloy_types_1.TD.eq(srcTypeDef, dstTypeDef)) {
365
362
  const castFunc = cast.safe ? 'SAFE_CAST' : 'CAST';
366
- return `${castFunc}(${src} AS ${dstType})`;
363
+ return `${castFunc}(${src} AS ${dstSQLType})`;
367
364
  }
368
365
  return src;
369
366
  }
@@ -371,10 +368,10 @@ ${(0, utils_1.indent)(sql)}
371
368
  return `REGEXP_CONTAINS(${match.kids.expr.sql},${match.kids.regex.sql})`;
372
369
  }
373
370
  sqlLiteralTime(qi, lit) {
374
- if (lit.dataType === 'date') {
371
+ if (malloy_types_1.TD.isDate(lit.typeDef)) {
375
372
  return `DATE('${lit.literal}')`;
376
373
  }
377
- else if (lit.dataType === 'timestamp') {
374
+ else if (malloy_types_1.TD.isTimestamp(lit.typeDef)) {
378
375
  let timestampArgs = `'${lit.literal}'`;
379
376
  const tz = lit.timezone || qtz(qi);
380
377
  if (tz && tz !== 'UTC') {
@@ -383,7 +380,7 @@ ${(0, utils_1.indent)(sql)}
383
380
  return `TIMESTAMP(${timestampArgs})`;
384
381
  }
385
382
  else {
386
- throw new Error(`Unsupported Literal time format ${lit.dataType}`);
383
+ throw new Error(`Unsupported Literal time format ${lit.typeDef}`);
387
384
  }
388
385
  }
389
386
  sqlMeasureTimeExpr(measure) {
@@ -405,10 +402,10 @@ ${(0, utils_1.indent)(sql)}
405
402
  if (!timestampMeasureable(measureIn)) {
406
403
  throw new Error(`Measure in '${measureIn} not implemented`);
407
404
  }
408
- if (from.dataType !== to.dataType) {
405
+ if (!malloy_types_1.TD.eq(from.typeDef, to.typeDef)) {
409
406
  throw new Error("Can't measure difference between different types");
410
407
  }
411
- if (from.dataType === 'date') {
408
+ if (malloy_types_1.TD.isDate(from.typeDef)) {
412
409
  lVal = `TIMESTAMP(${lVal})`;
413
410
  rVal = `TIMESTAMP(${rVal})`;
414
411
  }
@@ -370,22 +370,19 @@ ${(0, utils_1.indent)(sql)}
370
370
  return `DATE_ADD('${timeframe}', ${n}, ${df.kids.base.sql})`;
371
371
  }
372
372
  sqlCast(qi, cast) {
373
- const op = `${cast.srcType}=>${cast.dstType}`;
373
+ const { op, srcTypeDef, dstTypeDef, dstSQLType } = this.sqlCastPrep(cast);
374
374
  const tz = qtz(qi);
375
375
  const expr = cast.e.sql || '';
376
- if (op === 'timestamp=>date' && tz) {
376
+ if (op === 'timestamp::date' && tz) {
377
377
  const tstz = `CAST(${expr} as TIMESTAMP)`;
378
378
  return `CAST((${tstz}) AT TIME ZONE '${tz}' AS DATE)`;
379
379
  }
380
- else if (op === 'date=>timestamp' && tz) {
380
+ else if (op === 'date::timestamp' && tz) {
381
381
  return `CAST(CONCAT(CAST(CAST(${expr} AS TIMESTAMP) AS VARCHAR), ' ${tz}') AS TIMESTAMP WITH TIME ZONE)`;
382
382
  }
383
- if (cast.srcType !== cast.dstType) {
384
- const dstType = typeof cast.dstType === 'string'
385
- ? this.malloyTypeToSQLType({ type: cast.dstType })
386
- : cast.dstType.raw;
383
+ if (!malloy_types_1.TD.eq(srcTypeDef, dstTypeDef)) {
387
384
  const castFunc = cast.safe ? 'TRY_CAST' : 'CAST';
388
- return `${castFunc}(${expr} AS ${dstType})`;
385
+ return `${castFunc}(${expr} AS ${dstSQLType})`;
389
386
  }
390
387
  return expr;
391
388
  }
@@ -411,10 +408,10 @@ ${(0, utils_1.indent)(sql)}
411
408
  if (!timestampMeasureable(measureIn)) {
412
409
  throw new Error(`Measure in '${measureIn} not implemented`);
413
410
  }
414
- if (from.dataType !== to.dataType) {
411
+ if (!malloy_types_1.TD.eq(from.typeDef, to.typeDef)) {
415
412
  throw new Error("Can't measure difference between different types");
416
413
  }
417
- if (from.dataType === 'date') {
414
+ if (malloy_types_1.TD.isDate(from.typeDef)) {
418
415
  lVal = `CAST(${lVal} AS TIMESTAMP)`;
419
416
  rVal = `CAST(${rVal} AS TIMESTAMP)`;
420
417
  }
@@ -496,7 +493,7 @@ ${(0, utils_1.indent)(sql)}
496
493
  return sqlType.match(/^[A-Za-z\s(),<>0-9]*$/) !== null;
497
494
  }
498
495
  sqlLiteralTime(qi, lit) {
499
- if (lit.dataType === 'date') {
496
+ if (malloy_types_1.TD.isDate(lit.typeDef)) {
500
497
  return `DATE '${lit.literal}'`;
501
498
  }
502
499
  const tz = lit.timezone || qtz(qi);
@@ -508,7 +505,7 @@ ${(0, utils_1.indent)(sql)}
508
505
  sqlTimeExtractExpr(qi, from) {
509
506
  const pgUnits = pg_impl_1.timeExtractMap[from.units] || from.units;
510
507
  let extractFrom = from.e.sql || '';
511
- if (from.e.dataType === 'timestamp') {
508
+ if (malloy_types_1.TD.isTimestamp(from.e.typeDef)) {
512
509
  const tz = qtz(qi);
513
510
  if (tz) {
514
511
  extractFrom = `at_timezone(${extractFrom},'${tz}')`;
@@ -61,7 +61,7 @@ class ExprGranularTime extends expression_def_1.ExpressionDef {
61
61
  if (this.truncate) {
62
62
  tsVal.value = {
63
63
  node: 'trunc',
64
- e: { ...exprVal.value, dataType: exprVal.dataType },
64
+ e: (0, malloy_types_1.mkTemporal)(exprVal.value, exprVal.dataType),
65
65
  units: timeframe,
66
66
  };
67
67
  }
@@ -12,5 +12,5 @@ export declare class RecordLiteral extends ExpressionDef {
12
12
  readonly pairs: RecordElement[];
13
13
  elementType: string;
14
14
  constructor(pairs: RecordElement[]);
15
- getExpression(fs: FieldSpace): ExprValue;
15
+ getExpression(_fs: FieldSpace): ExprValue;
16
16
  }
@@ -7,7 +7,6 @@
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.RecordLiteral = exports.RecordElement = void 0;
10
- const model_1 = require("../../../model");
11
10
  const expression_def_1 = require("../types/expression-def");
12
11
  const malloy_element_1 = require("../types/malloy-element");
13
12
  class RecordElement extends malloy_element_1.MalloyElement {
@@ -27,30 +26,34 @@ class RecordLiteral extends expression_def_1.ExpressionDef {
27
26
  this.elementType = 'record literal';
28
27
  this.has({ pairs });
29
28
  }
30
- getExpression(fs) {
31
- const recLit = {
32
- node: 'recordLiteral',
33
- kids: {},
34
- };
35
- let resultExprType = 'scalar';
36
- for (const el of this.pairs) {
37
- const xVal = el.value.getExpression(fs);
38
- const expr = { dataType: 'error', ...xVal.value };
39
- if (expr.dataType === 'error' && (0, model_1.isAtomicFieldType)(xVal.dataType)) {
40
- expr.dataType = xVal.dataType;
41
- }
42
- if (expr.dataType === 'error' && xVal.dataType !== 'error') {
43
- this.logError('illegal-record-property-type', `Type '${xVal.dataType}' not a legal record value`);
44
- }
45
- recLit.kids[el.key] = expr;
46
- resultExprType = (0, model_1.maxExpressionType)(xVal.expressionType, resultExprType);
47
- }
48
- return {
49
- dataType: 'record',
50
- value: recLit,
51
- expressionType: resultExprType,
52
- evalSpace: 'literal',
53
- };
29
+ getExpression(_fs) {
30
+ throw new Error('get expression on record todo');
31
+ // const recLit: RecordLiteralNode = {
32
+ // node: 'recordLiteral',
33
+ // kids: {},
34
+ // };
35
+ // let resultExprType: ExpressionType = 'scalar';
36
+ // for (const el of this.pairs) {
37
+ // const xVal = el.value.getExpression(fs);
38
+ // const expr: TypedExpr = {typeDef: 'error', ...xVal.value};
39
+ // if (TD.isError(expr.typeDef) && isAtomicFieldType(xVal.dataType)) {
40
+ // expr.typeDef = xVal.dataType;
41
+ // }
42
+ // if (TD.isError(expr.typeDef) && xVal.dataType !== 'error') {
43
+ // this.logError(
44
+ // 'illegal-record-property-type',
45
+ // `Type '${xVal.dataType}' not a legal record value`
46
+ // );
47
+ // }
48
+ // recLit.kids[el.key] = expr;
49
+ // resultExprType = maxExpressionType(xVal.expressionType, resultExprType);
50
+ // }
51
+ // return {
52
+ // dataType: 'record',
53
+ // value: recLit,
54
+ // expressionType: resultExprType,
55
+ // evalSpace: 'literal',
56
+ // };
54
57
  }
55
58
  }
56
59
  exports.RecordLiteral = RecordLiteral;
@@ -105,8 +105,8 @@ class ExprTimeExtract extends expression_def_1.ExpressionDef {
105
105
  node: 'timeDiff',
106
106
  units: extractTo,
107
107
  kids: {
108
- left: { ...first.value, dataType: valueType },
109
- right: { ...last.value, dataType: valueType },
108
+ left: (0, malloy_types_1.mkTemporal)(first.value, valueType),
109
+ right: (0, malloy_types_1.mkTemporal)(last.value, valueType),
110
110
  },
111
111
  },
112
112
  };
@@ -120,7 +120,7 @@ class ExprTimeExtract extends expression_def_1.ExpressionDef {
120
120
  evalSpace: argV.evalSpace,
121
121
  value: {
122
122
  node: 'extract',
123
- e: { ...argV.value, dataType: argV.dataType },
123
+ e: (0, malloy_types_1.mkTemporal)(argV.value, argV.dataType),
124
124
  units: extractTo,
125
125
  },
126
126
  };
@@ -46,11 +46,11 @@ class ExprTime extends expression_def_1.ExpressionDef {
46
46
  const toTs = {
47
47
  node: 'cast',
48
48
  safe: false,
49
- dstType: timeType,
49
+ dstType: { type: timeType },
50
50
  e: expr.value,
51
51
  };
52
52
  if ((0, malloy_types_1.isTemporalField)(expr.dataType)) {
53
- toTs.srcType = expr.dataType;
53
+ toTs.srcType = { type: expr.dataType };
54
54
  }
55
55
  value = toTs;
56
56
  }
@@ -84,7 +84,7 @@ class ForRange extends expression_def_1.ExpressionDef {
84
84
  from = tsVersion;
85
85
  }
86
86
  else {
87
- from = (0, time_utils_1.castDateToTimestamp)(from);
87
+ from = (0, time_utils_1.castTo)('timestamp', from, 'date');
88
88
  }
89
89
  rangeStart = new expr_time_1.ExprTime('timestamp', from, startV.expressionType);
90
90
  }
@@ -72,7 +72,7 @@ class TimeLiteral extends expression_def_1.ExpressionDef {
72
72
  const timeFrag = {
73
73
  node: 'timeLiteral',
74
74
  literal: val,
75
- dataType: typ,
75
+ typeDef: { type: typ },
76
76
  };
77
77
  if (this.timeZone) {
78
78
  timeFrag.timezone = this.timeZone;
@@ -4,7 +4,5 @@ export declare function timeOffset(timeType: TemporalFieldType, from: Expr, op:
4
4
  export declare function castTo(castType: CastType | {
5
5
  raw: string;
6
6
  }, from: Expr, fromType: FieldValueType, safe?: boolean): TypecastExpr;
7
- export declare function castTimestampToDate(from: Expr, safe?: boolean): TypecastExpr;
8
- export declare function castDateToTimestamp(from: Expr, safe?: boolean): TypecastExpr;
9
7
  export declare function resolution(timeframe: string): TemporalFieldType;
10
- export declare function timeResult(t: TimeResult, tt: TimestampUnit | undefined): TimeResult;
8
+ export declare function mkTimeResult(t: TimeResult, tt: TimestampUnit | undefined): TimeResult;