@malloydata/malloy 0.0.435 → 0.0.437
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.
- package/dist/api/foundation/build_targets.d.ts +5 -6
- package/dist/api/foundation/build_targets.js +74 -6
- package/dist/api/foundation/core.d.ts +16 -4
- package/dist/api/foundation/core.js +23 -23
- package/dist/api/foundation/index.d.ts +1 -1
- package/dist/api/foundation/runtime.d.ts +21 -2
- package/dist/api/foundation/runtime.js +44 -31
- package/dist/api/foundation/types.d.ts +43 -3
- package/dist/connection/dbmeta.d.ts +29 -0
- package/dist/connection/dbmeta.js +46 -0
- package/dist/connection/index.d.ts +1 -0
- package/dist/connection/index.js +1 -0
- package/dist/dialect/databricks/databricks.d.ts +11 -12
- package/dist/dialect/databricks/databricks.js +24 -36
- package/dist/dialect/dialect.d.ts +56 -170
- package/dist/dialect/dialect.js +89 -90
- package/dist/dialect/duckdb/duckdb.d.ts +2 -2
- package/dist/dialect/duckdb/duckdb.js +1 -1
- package/dist/dialect/index.d.ts +1 -1
- package/dist/dialect/index.js +2 -2
- package/dist/dialect/mysql/mysql.d.ts +11 -12
- package/dist/dialect/mysql/mysql.js +20 -32
- package/dist/dialect/pg_impl.d.ts +9 -10
- package/dist/dialect/pg_impl.js +27 -73
- package/dist/dialect/postgres/postgres.d.ts +4 -4
- package/dist/dialect/postgres/postgres.js +10 -14
- package/dist/dialect/snowflake/snowflake.d.ts +11 -13
- package/dist/dialect/snowflake/snowflake.js +30 -82
- package/dist/dialect/sqlserver/sqlserver.d.ts +12 -13
- package/dist/dialect/sqlserver/sqlserver.js +46 -47
- package/dist/dialect/standardsql/standardsql.d.ts +11 -16
- package/dist/dialect/standardsql/standardsql.js +22 -73
- package/dist/dialect/trino/trino.d.ts +16 -18
- package/dist/dialect/trino/trino.js +127 -181
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/lang/ast/expressions/boolean-value.d.ts +24 -0
- package/dist/lang/ast/expressions/boolean-value.js +41 -0
- package/dist/lang/ast/expressions/case.js +7 -0
- package/dist/lang/ast/expressions/expr-alternation-tree.js +11 -0
- package/dist/lang/ast/expressions/expr-cast.js +5 -0
- package/dist/lang/ast/expressions/expr-coalesce.js +4 -0
- package/dist/lang/ast/expressions/expr-func.js +13 -2
- package/dist/lang/ast/expressions/expr-minus.js +5 -2
- package/dist/lang/ast/expressions/expr-null.js +4 -0
- package/dist/lang/ast/expressions/expr-props.js +1 -1
- package/dist/lang/ast/expressions/pick-when.js +7 -0
- package/dist/lang/ast/expressions/time-literal.js +6 -1
- package/dist/lang/ast/field-space/index-field-space.js +13 -1
- package/dist/lang/ast/field-space/query-spaces.js +11 -0
- package/dist/lang/ast/query-builders/reduce-builder.js +1 -1
- package/dist/lang/ast/query-items/field-declaration.d.ts +5 -0
- package/dist/lang/ast/query-items/field-declaration.js +22 -16
- package/dist/lang/ast/query-items/field-references.d.ts +6 -0
- package/dist/lang/ast/query-items/field-references.js +23 -0
- package/dist/lang/ast/query-properties/drill.js +7 -1
- package/dist/lang/ast/query-properties/filters.js +3 -1
- package/dist/lang/ast/statements/import-statement.js +13 -0
- package/dist/lang/ast/types/expression-def.js +17 -2
- package/dist/lang/ast/types/malloy-element.d.ts +24 -1
- package/dist/lang/ast/types/malloy-element.js +63 -26
- package/dist/lang/ast/view-elements/reference-view.js +4 -0
- package/dist/lang/ast/view-elements/refine-utils.js +1 -0
- package/dist/lang/composite-source-utils.js +10 -17
- package/dist/lang/lib/Malloy/MalloyLexer.js +976 -978
- package/dist/lang/parse-log.d.ts +12 -0
- package/dist/lang/parse-log.js +2 -0
- package/dist/lang/test/test-translator.d.ts +2 -1
- package/dist/lang/test/test-translator.js +37 -3
- package/dist/model/expression_compiler.js +8 -7
- package/dist/model/filter_compilers.js +13 -12
- package/dist/model/given_binding.d.ts +8 -0
- package/dist/model/given_binding.js +13 -0
- package/dist/model/index.d.ts +1 -1
- package/dist/model/index.js +2 -1
- package/dist/model/query_query.js +11 -2
- package/dist/model/sql_compiled.d.ts +19 -20
- package/dist/model/sql_compiled.js +29 -17
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -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
|
-
|
|
344
|
-
|
|
345
|
-
|
|
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
|
-
|
|
353
|
-
|
|
354
|
-
|
|
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,
|
|
359
|
-
|
|
360
|
-
if (destTypeDef
|
|
361
|
-
|
|
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
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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
|
-
|
|
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
|
-
|
|
583
|
-
|
|
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
|
|
634
|
-
if (tz) {
|
|
635
|
-
return `
|
|
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
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
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 `
|
|
602
|
+
return `(${expr}) AT TIME ZONE ${this.sqlTimezoneLiteral(timezone)}`;
|
|
655
603
|
}
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
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
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
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
|
-
|
|
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, SQLServerDialect, registerDialect, getDialect, arg,
|
|
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';
|
package/dist/index.js
CHANGED
|
@@ -37,7 +37,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
37
37
|
};
|
|
38
38
|
})();
|
|
39
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
-
exports.malloyToQuery = exports.constantExprToSQL = exports.isDateUnit = exports.isTimestampUnit = exports.composeSQLExpr = exports.indent = exports.expressionIsUngroupedAggregate = exports.expressionIsScalar = exports.expressionIsCalculation = exports.expressionIsAnalytic = exports.expressionIsAggregate = exports.mkFieldDef = exports.mkArrayDef = exports.isBasicArray = exports.isRepeatedRecord = exports.isSamplingRows = exports.isSamplingPercent = exports.isSamplingEnable = exports.isJoinedSource = exports.isJoined = exports.isCompoundArrayData = exports.isBasicAtomic = exports.isAtomic = exports.isSourceDef = exports.validateDottedTablePath = exports.decodeDottedTablePath = exports.Dialect = exports.spread = exports.literal = exports.variadicParam = exports.param = exports.makeParam = exports.sql = exports.maxScalar = exports.minAggregate = exports.anyExprType = exports.minScalar = exports.overload = exports.
|
|
40
|
+
exports.malloyToQuery = exports.constantExprToSQL = exports.isDateUnit = exports.isTimestampUnit = exports.composeSQLExpr = exports.indent = exports.expressionIsUngroupedAggregate = exports.expressionIsScalar = exports.expressionIsCalculation = exports.expressionIsAnalytic = exports.expressionIsAggregate = exports.mkFieldDef = exports.mkArrayDef = exports.isBasicArray = exports.isRepeatedRecord = exports.isSamplingRows = exports.isSamplingPercent = exports.isSamplingEnable = exports.isJoinedSource = exports.isJoined = exports.isCompoundArrayData = exports.isBasicAtomic = exports.isAtomic = exports.isSourceDef = exports.validateDottedTablePath = exports.decodeDottedTablePath = exports.Dialect = exports.spread = exports.literal = exports.variadicParam = exports.param = exports.makeParam = exports.sql = exports.maxScalar = exports.minAggregate = exports.anyExprType = exports.minScalar = exports.overload = exports.queryZone = exports.arg = exports.getDialect = exports.registerDialect = exports.SQLServerDialect = exports.DatabricksDialect = exports.MySQLDialect = exports.SnowflakeDialect = exports.PostgresDialect = exports.TrinoDialect = exports.StandardSQLDialect = exports.DuckDBDialect = void 0;
|
|
41
41
|
exports.PersistSource = exports.annotationToTaglines = exports.annotationToTag = exports.tagFromAnnotations = exports.annotationsForRoute = exports.payloadOf = exports.routeOf = exports.RoutedNote = exports.Annotations = exports.sqlKey = exports.API = exports.sourceDefToSourceInfo = exports.modelDefToModelInfo = exports.toAsyncGenerator = exports.createConnectionsFromConfig = exports.getRegisteredConnectionTypes = exports.getConnectionTypeDisplayName = exports.getConnectionProperties = exports.registerConnectionType = exports.discoverConfig = exports.defaultConfigOverlays = exports.contextOverlay = exports.envOverlay = exports.MalloyConfig = exports.Manifest = exports.CacheManager = exports.InMemoryModelCache = exports.Explore = exports.DataWriter = exports.Parse = exports.JSONWriter = exports.CSVWriter = exports.QueryMaterializer = exports.Result = exports.PreparedResult = exports.TimestampTimeframe = exports.DateTimeframe = exports.SourceRelationship = exports.JoinRelationship = exports.MalloyError = exports.FixedConnectionMap = exports.InMemoryURLReader = exports.EmptyURLReader = exports.SingleConnectionRuntime = exports.ConnectionRuntime = exports.AtomicFieldType = exports.Runtime = exports.Malloy = exports.Model = exports.MalloyTranslator = void 0;
|
|
42
42
|
exports.makeDigest = exports.Reference = exports.EMPTY_BUILD_MANIFEST = void 0;
|
|
43
43
|
var dialect_1 = require("./dialect");
|
|
@@ -52,7 +52,7 @@ Object.defineProperty(exports, "SQLServerDialect", { enumerable: true, get: func
|
|
|
52
52
|
Object.defineProperty(exports, "registerDialect", { enumerable: true, get: function () { return dialect_1.registerDialect; } });
|
|
53
53
|
Object.defineProperty(exports, "getDialect", { enumerable: true, get: function () { return dialect_1.getDialect; } });
|
|
54
54
|
Object.defineProperty(exports, "arg", { enumerable: true, get: function () { return dialect_1.arg; } });
|
|
55
|
-
Object.defineProperty(exports, "
|
|
55
|
+
Object.defineProperty(exports, "queryZone", { enumerable: true, get: function () { return dialect_1.queryZone; } });
|
|
56
56
|
Object.defineProperty(exports, "overload", { enumerable: true, get: function () { return dialect_1.overload; } });
|
|
57
57
|
Object.defineProperty(exports, "minScalar", { enumerable: true, get: function () { return dialect_1.minScalar; } });
|
|
58
58
|
Object.defineProperty(exports, "anyExprType", { enumerable: true, get: function () { return dialect_1.anyExprType; } });
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ExprValue } from '../types/expr-value';
|
|
2
|
+
import type { FieldSpace } from '../types/field-space';
|
|
3
|
+
import type { MalloyElement } from '../types/malloy-element';
|
|
4
|
+
/**
|
|
5
|
+
* On a dialect with booleanType 'none' a boolean is a condition and never a
|
|
6
|
+
* value. When `type` is a boolean about to be used as a value, logs an error
|
|
7
|
+
* at `logTo` and returns an error-typed value for the caller to return in
|
|
8
|
+
* place of what it was building, so the enclosing expressions see an error
|
|
9
|
+
* and stay quiet. Otherwise returns undefined. `where` says how the boolean
|
|
10
|
+
* was used, `hint` what to write instead.
|
|
11
|
+
*/
|
|
12
|
+
export declare function booleanValueError(fs: FieldSpace, type: {
|
|
13
|
+
type: string;
|
|
14
|
+
} | undefined, where: string, logTo: MalloyElement, hint: string): ExprValue | undefined;
|
|
15
|
+
/** The hint where a boolean's unknown state is examined: `is null`, `??` */
|
|
16
|
+
export declare const CONDITION_HINT = "test the condition itself; unknown already tests as false";
|
|
17
|
+
/** The hint for a boolean compared with anything */
|
|
18
|
+
export declare const COMPARE_HINT = "test the condition itself, or its not";
|
|
19
|
+
/** The hint where a number would do: a function argument, a cast */
|
|
20
|
+
export declare const NUMBER_HINT = "write the value, pick 1 when \u2026 else 0";
|
|
21
|
+
/** The hint for a boolean as a result column, from the source text it came from */
|
|
22
|
+
export declare function resultColumnHint(src: string): string;
|
|
23
|
+
/** The hint for a `pick` or `case` whose result is a boolean */
|
|
24
|
+
export declare const CHOICE_HINT = "write values, pick 'yes' when \u2026 else 'no', or the condition itself with and, or and not";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright Contributors to the Malloy project
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.CHOICE_HINT = exports.NUMBER_HINT = exports.COMPARE_HINT = exports.CONDITION_HINT = void 0;
|
|
8
|
+
exports.booleanValueError = booleanValueError;
|
|
9
|
+
exports.resultColumnHint = resultColumnHint;
|
|
10
|
+
/**
|
|
11
|
+
* On a dialect with booleanType 'none' a boolean is a condition and never a
|
|
12
|
+
* value. When `type` is a boolean about to be used as a value, logs an error
|
|
13
|
+
* at `logTo` and returns an error-typed value for the caller to return in
|
|
14
|
+
* place of what it was building, so the enclosing expressions see an error
|
|
15
|
+
* and stay quiet. Otherwise returns undefined. `where` says how the boolean
|
|
16
|
+
* was used, `hint` what to write instead.
|
|
17
|
+
*/
|
|
18
|
+
function booleanValueError(fs, type, where, logTo, hint) {
|
|
19
|
+
const dialect = fs.dialectObj();
|
|
20
|
+
if ((type === null || type === void 0 ? void 0 : type.type) !== 'boolean' || (dialect === null || dialect === void 0 ? void 0 : dialect.booleanType) !== 'none') {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
return logTo.loggedErrorExpr('boolean-value-unsupported', {
|
|
24
|
+
dialect: dialect.name,
|
|
25
|
+
where,
|
|
26
|
+
hint,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/** The hint where a boolean's unknown state is examined: `is null`, `??` */
|
|
30
|
+
exports.CONDITION_HINT = 'test the condition itself; unknown already tests as false';
|
|
31
|
+
/** The hint for a boolean compared with anything */
|
|
32
|
+
exports.COMPARE_HINT = 'test the condition itself, or its not';
|
|
33
|
+
/** The hint where a number would do: a function argument, a cast */
|
|
34
|
+
exports.NUMBER_HINT = 'write the value, pick 1 when … else 0';
|
|
35
|
+
/** The hint for a boolean as a result column, from the source text it came from */
|
|
36
|
+
function resultColumnHint(src) {
|
|
37
|
+
return `write the value, pick 'yes' when ${src} else 'no'`;
|
|
38
|
+
}
|
|
39
|
+
/** The hint for a `pick` or `case` whose result is a boolean */
|
|
40
|
+
exports.CHOICE_HINT = "write values, pick 'yes' when … else 'no', or the condition itself with and, or and not";
|
|
41
|
+
//# sourceMappingURL=boolean-value.js.map
|
|
@@ -42,6 +42,7 @@ const expr_value_1 = require("../types/expr-value");
|
|
|
42
42
|
const expression_def_1 = require("../types/expression-def");
|
|
43
43
|
const malloy_element_1 = require("../types/malloy-element");
|
|
44
44
|
const TDU = __importStar(require("../typedesc-utils"));
|
|
45
|
+
const boolean_value_1 = require("./boolean-value");
|
|
45
46
|
function typeCoalesce(ev1, ev2) {
|
|
46
47
|
return ev1 === undefined || ev1.type === 'null' || ev1.type === 'error'
|
|
47
48
|
? ev2
|
|
@@ -68,6 +69,9 @@ class Case extends expression_def_1.ExpressionDef {
|
|
|
68
69
|
let value = undefined;
|
|
69
70
|
if (this.value) {
|
|
70
71
|
const v = this.value.getExpression(fs);
|
|
72
|
+
const noSubject = (0, boolean_value_1.booleanValueError)(fs, v, 'as the subject of a case', this.value, 'write the conditions, case when … then …');
|
|
73
|
+
if (noSubject)
|
|
74
|
+
return noSubject;
|
|
71
75
|
dependents.push(v);
|
|
72
76
|
resultExpr.kids.caseValue = v.value;
|
|
73
77
|
value = v;
|
|
@@ -118,6 +122,9 @@ class Case extends expression_def_1.ExpressionDef {
|
|
|
118
122
|
dependents.push(elseValue);
|
|
119
123
|
resultExpr.kids.caseElse = elseValue.value;
|
|
120
124
|
}
|
|
125
|
+
const noCase = (0, boolean_value_1.booleanValueError)(fs, returnType, 'as the result of a case', this, boolean_value_1.CHOICE_HINT);
|
|
126
|
+
if (noCase)
|
|
127
|
+
return noCase;
|
|
121
128
|
return (0, expr_value_1.computedExprValue)({
|
|
122
129
|
value: resultExpr,
|
|
123
130
|
dataType: returnType ? TDU.atomicDef(returnType) : { type: 'null' },
|
|
@@ -8,6 +8,7 @@ exports.ExprAlternationTree = void 0;
|
|
|
8
8
|
const expr_value_1 = require("../types/expr-value");
|
|
9
9
|
const expression_def_1 = require("../types/expression-def");
|
|
10
10
|
const binary_operators_1 = require("../types/binary_operators");
|
|
11
|
+
const boolean_value_1 = require("./boolean-value");
|
|
11
12
|
/**
|
|
12
13
|
* Return a flattened version of an alternation tree, if the tree is
|
|
13
14
|
* composed entirely values and "or"s.
|
|
@@ -58,6 +59,16 @@ class ExprAlternationTree extends expression_def_1.ExpressionDef {
|
|
|
58
59
|
if (inList.length > 0 && (applyOp === '=' || applyOp === '!=')) {
|
|
59
60
|
const isIn = expr.getExpression(fs);
|
|
60
61
|
const values = inList.map(v => v.getExpression(fs));
|
|
62
|
+
// A boolean on either side of the comparison, the tested value or
|
|
63
|
+
// any of the choices, is a boolean compared with something.
|
|
64
|
+
for (const [el, val] of [
|
|
65
|
+
[expr, isIn],
|
|
66
|
+
...inList.map((el, i) => [el, values[i]]),
|
|
67
|
+
]) {
|
|
68
|
+
const noIn = (0, boolean_value_1.booleanValueError)(fs, val, `compared with ${applyOp}`, el, boolean_value_1.COMPARE_HINT);
|
|
69
|
+
if (noIn)
|
|
70
|
+
return noIn;
|
|
71
|
+
}
|
|
61
72
|
return (0, expr_value_1.computedExprValue)({
|
|
62
73
|
dataType: { type: 'boolean' },
|
|
63
74
|
value: {
|
|
@@ -8,6 +8,7 @@ exports.ExprCast = void 0;
|
|
|
8
8
|
const time_utils_1 = require("../time-utils");
|
|
9
9
|
const expr_value_1 = require("../types/expr-value");
|
|
10
10
|
const expression_def_1 = require("../types/expression-def");
|
|
11
|
+
const boolean_value_1 = require("./boolean-value");
|
|
11
12
|
class ExprCast extends expression_def_1.ExpressionDef {
|
|
12
13
|
constructor(expr, castType, safe = false) {
|
|
13
14
|
super({ expr: expr });
|
|
@@ -38,6 +39,10 @@ class ExprCast extends expression_def_1.ExpressionDef {
|
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
41
|
}
|
|
42
|
+
const noCast = (0, boolean_value_1.booleanValueError)(fs, expr, 'in a cast', this, boolean_value_1.NUMBER_HINT) ||
|
|
43
|
+
(0, boolean_value_1.booleanValueError)(fs, dataType, 'as the type of a cast', this, 'write a comparison');
|
|
44
|
+
if (noCast)
|
|
45
|
+
return noCast;
|
|
41
46
|
return (0, expr_value_1.computedExprValue)({
|
|
42
47
|
dataType,
|
|
43
48
|
value: (0, time_utils_1.castTo)(this.castType, expr.value, expr.type, this.safe),
|
|
@@ -42,6 +42,7 @@ const model_1 = require("../../../model");
|
|
|
42
42
|
const composite_source_utils_1 = require("../../composite-source-utils");
|
|
43
43
|
const TDU = __importStar(require("../typedesc-utils"));
|
|
44
44
|
const expression_def_1 = require("../types/expression-def");
|
|
45
|
+
const boolean_value_1 = require("./boolean-value");
|
|
45
46
|
class ExprCoalesce extends expression_def_1.ExpressionDef {
|
|
46
47
|
constructor(expr, altExpr) {
|
|
47
48
|
super({ expr, altExpr });
|
|
@@ -53,6 +54,9 @@ class ExprCoalesce extends expression_def_1.ExpressionDef {
|
|
|
53
54
|
computeExpression(fs) {
|
|
54
55
|
const maybeNull = this.expr.getExpression(fs);
|
|
55
56
|
const whenNull = this.altExpr.getExpression(fs);
|
|
57
|
+
const noCoalesce = (0, boolean_value_1.booleanValueError)(fs, maybeNull, 'in ??', this, boolean_value_1.CONDITION_HINT);
|
|
58
|
+
if (noCoalesce)
|
|
59
|
+
return noCoalesce;
|
|
56
60
|
if (maybeNull.type === 'null') {
|
|
57
61
|
return whenNull;
|
|
58
62
|
}
|
|
@@ -48,6 +48,7 @@ const field_space_1 = require("../types/field-space");
|
|
|
48
48
|
const utils_2 = require("../../../model/utils");
|
|
49
49
|
const TDU = __importStar(require("../typedesc-utils"));
|
|
50
50
|
const composite_source_utils_1 = require("../../composite-source-utils");
|
|
51
|
+
const boolean_value_1 = require("./boolean-value");
|
|
51
52
|
// Built-in functions that take a string literal of user-supplied SQL
|
|
52
53
|
// and emit it directly. Gated by experimental.sql_functions in plain
|
|
53
54
|
// Malloy; rejected unconditionally in restricted queries because they
|
|
@@ -111,9 +112,14 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
111
112
|
return { found: func, error: undefined };
|
|
112
113
|
}
|
|
113
114
|
getPropsExpression(fs, props) {
|
|
114
|
-
var _a, _b, _c, _d, _e;
|
|
115
|
+
var _a, _b, _c, _d, _e, _f;
|
|
115
116
|
const argExprsWithoutImplicit = this.args.map(arg => arg.getExpression(fs));
|
|
116
117
|
if (this.isRaw) {
|
|
118
|
+
for (const [i, argExpr] of argExprsWithoutImplicit.entries()) {
|
|
119
|
+
const noArg = (0, boolean_value_1.booleanValueError)(fs, argExpr, `as an argument of ${this.name}`, this.args[i], boolean_value_1.NUMBER_HINT);
|
|
120
|
+
if (noArg)
|
|
121
|
+
return noArg;
|
|
122
|
+
}
|
|
117
123
|
const funcCall = [`${this.name}(`];
|
|
118
124
|
argExprsWithoutImplicit.forEach((expr, i) => {
|
|
119
125
|
if (i !== 0) {
|
|
@@ -182,6 +188,11 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
182
188
|
.join(', ')})`);
|
|
183
189
|
}
|
|
184
190
|
const { overload, expressionTypeErrors, evalSpaceErrors, nullabilityErrors, returnType, } = result;
|
|
191
|
+
for (const [i, argExpr] of argExprs.entries()) {
|
|
192
|
+
const noArg = (0, boolean_value_1.booleanValueError)(fs, argExpr, `as an argument of ${this.name}`, (_e = this.args[i - (implicitExpr ? 1 : 0)]) !== null && _e !== void 0 ? _e : this, boolean_value_1.NUMBER_HINT);
|
|
193
|
+
if (noArg)
|
|
194
|
+
return noArg;
|
|
195
|
+
}
|
|
185
196
|
// Report errors for expression type mismatch
|
|
186
197
|
for (const error of expressionTypeErrors) {
|
|
187
198
|
const adjustedIndex = error.argIndex - (implicitExpr ? 1 : 0);
|
|
@@ -214,7 +225,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
214
225
|
}
|
|
215
226
|
const type = overload.returnType;
|
|
216
227
|
const expressionType = (0, malloy_types_1.maxOfExpressionTypes)([
|
|
217
|
-
(
|
|
228
|
+
(_f = type.expressionType) !== null && _f !== void 0 ? _f : 'scalar',
|
|
218
229
|
...argExprs.map(e => e.expressionType),
|
|
219
230
|
]);
|
|
220
231
|
if (!(0, malloy_types_1.expressionIsAggregate)(overload.returnType.expressionType) &&
|