@malloydata/malloy 0.0.177-dev240828173040 → 0.0.177-dev240829030921
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dialect/dialect.d.ts +23 -13
- package/dist/dialect/dialect.js +33 -27
- package/dist/dialect/duckdb/duckdb.d.ts +7 -11
- package/dist/dialect/duckdb/duckdb.js +34 -100
- package/dist/dialect/duckdb/functions/greatest_and_least.js +5 -12
- package/dist/dialect/functions/concat.js +1 -1
- package/dist/dialect/functions/greatest_and_least.js +1 -1
- package/dist/dialect/functions/simple_numeric_functions.js +1 -1
- package/dist/dialect/functions/sql.js +5 -15
- package/dist/dialect/functions/string_agg.js +2 -2
- package/dist/dialect/functions/trim_functions.js +2 -2
- package/dist/dialect/functions/util.d.ts +6 -9
- package/dist/dialect/functions/util.js +29 -38
- package/dist/dialect/index.d.ts +1 -1
- package/dist/dialect/index.js +1 -2
- package/dist/dialect/pg_impl.d.ts +15 -0
- package/dist/dialect/pg_impl.js +91 -0
- package/dist/dialect/postgres/functions/greatest_and_least.js +1 -3
- package/dist/dialect/postgres/functions/string_agg.js +2 -2
- package/dist/dialect/postgres/postgres.d.ts +7 -11
- package/dist/dialect/postgres/postgres.js +29 -92
- package/dist/dialect/snowflake/functions/string_agg.js +2 -2
- package/dist/dialect/snowflake/snowflake.d.ts +9 -9
- package/dist/dialect/snowflake/snowflake.js +41 -48
- package/dist/dialect/standardsql/functions/string_agg.js +4 -4
- package/dist/dialect/standardsql/standardsql.d.ts +9 -9
- package/dist/dialect/standardsql/standardsql.js +56 -51
- package/dist/dialect/trino/functions/concat.js +1 -1
- package/dist/dialect/trino/functions/string_agg.js +2 -2
- package/dist/dialect/trino/trino.d.ts +11 -12
- package/dist/dialect/trino/trino.js +59 -83
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -4
- package/dist/lang/ast/ast-utils.d.ts +1 -1
- package/dist/lang/ast/ast-utils.js +2 -2
- package/dist/lang/ast/expressions/apply.js +1 -2
- package/dist/lang/ast/expressions/binary-boolean.d.ts +2 -1
- package/dist/lang/ast/expressions/binary-boolean.js +6 -3
- package/dist/lang/ast/expressions/binary-numeric.d.ts +2 -1
- package/dist/lang/ast/expressions/boolean.js +1 -1
- package/dist/lang/ast/expressions/constant-expression.d.ts +3 -3
- package/dist/lang/ast/expressions/constant-expression.js +0 -23
- package/dist/lang/ast/expressions/expr-aggregate-function.js +24 -34
- package/dist/lang/ast/expressions/expr-alternation-tree.d.ts +6 -3
- package/dist/lang/ast/expressions/expr-alternation-tree.js +10 -5
- package/dist/lang/ast/expressions/expr-cast.js +1 -2
- package/dist/lang/ast/expressions/expr-coalesce.js +4 -1
- package/dist/lang/ast/expressions/expr-compare.d.ts +3 -3
- package/dist/lang/ast/expressions/expr-count-distinct.js +1 -1
- package/dist/lang/ast/expressions/expr-count.js +3 -3
- package/dist/lang/ast/expressions/expr-func.js +15 -18
- package/dist/lang/ast/expressions/expr-granular-time.js +8 -10
- package/dist/lang/ast/expressions/expr-id-reference.js +2 -2
- package/dist/lang/ast/expressions/expr-minus.js +5 -4
- package/dist/lang/ast/expressions/expr-not.js +1 -1
- package/dist/lang/ast/expressions/expr-now.js +1 -6
- package/dist/lang/ast/expressions/expr-null.js +1 -1
- package/dist/lang/ast/expressions/expr-number.js +1 -1
- package/dist/lang/ast/expressions/expr-parens.js +1 -1
- package/dist/lang/ast/expressions/expr-props.js +4 -7
- package/dist/lang/ast/expressions/expr-regex.js +1 -3
- package/dist/lang/ast/expressions/expr-string.js +1 -7
- package/dist/lang/ast/expressions/expr-time-extract.js +12 -16
- package/dist/lang/ast/expressions/expr-time.d.ts +2 -2
- package/dist/lang/ast/expressions/expr-time.js +4 -6
- package/dist/lang/ast/expressions/expr-ungroup.js +2 -2
- package/dist/lang/ast/expressions/for-range.d.ts +2 -1
- package/dist/lang/ast/expressions/function-ordering.js +5 -5
- package/dist/lang/ast/expressions/partial-compare.d.ts +3 -3
- package/dist/lang/ast/expressions/pick-when.js +24 -8
- package/dist/lang/ast/expressions/range.d.ts +2 -1
- package/dist/lang/ast/expressions/range.js +4 -2
- package/dist/lang/ast/expressions/time-literal.d.ts +4 -3
- package/dist/lang/ast/expressions/time-literal.js +5 -10
- package/dist/lang/ast/expressions/top-by.js +1 -2
- package/dist/lang/ast/expressions/utils.d.ts +3 -12
- package/dist/lang/ast/expressions/utils.js +8 -56
- package/dist/lang/ast/field-space/reference-field.js +1 -1
- package/dist/lang/ast/index.d.ts +1 -1
- package/dist/lang/ast/index.js +1 -1
- package/dist/lang/ast/query-builders/index-builder.d.ts +2 -2
- package/dist/lang/ast/query-builders/reduce-builder.d.ts +2 -2
- package/dist/lang/ast/query-items/field-declaration.js +1 -5
- package/dist/lang/ast/query-properties/filters.d.ts +3 -3
- package/dist/lang/ast/query-properties/filters.js +6 -5
- package/dist/lang/ast/query-properties/top.js +1 -2
- package/dist/lang/ast/source-elements/refined-source.js +1 -1
- package/dist/lang/ast/source-properties/joins.js +11 -10
- package/dist/lang/ast/time-utils.d.ts +5 -7
- package/dist/lang/ast/time-utils.js +17 -57
- package/dist/lang/ast/types/binary_operators.d.ts +9 -0
- package/dist/lang/ast/types/binary_operators.js +28 -0
- package/dist/lang/ast/types/expr-result.d.ts +3 -3
- package/dist/lang/ast/types/expression-def.d.ts +4 -3
- package/dist/lang/ast/types/expression-def.js +43 -50
- package/dist/lang/lib/Malloy/MalloyParser.d.ts +0 -11
- package/dist/lang/lib/Malloy/MalloyParser.js +803 -858
- package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +0 -13
- package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +0 -8
- package/dist/lang/malloy-to-ast.d.ts +0 -1
- package/dist/lang/malloy-to-ast.js +0 -4
- package/dist/lang/test/expressions.spec.js +42 -86
- package/dist/lang/test/field-symbols.spec.js +8 -6
- package/dist/lang/test/literals.spec.js +6 -6
- package/dist/lang/test/model_serialization.spec.js +5 -5
- package/dist/lang/test/test-translator.js +9 -7
- package/dist/malloy.d.ts +3 -3
- package/dist/malloy.js +1 -1
- package/dist/model/index.d.ts +1 -1
- package/dist/model/index.js +2 -1
- package/dist/model/malloy_query.d.ts +24 -19
- package/dist/model/malloy_query.js +272 -244
- package/dist/model/malloy_types.d.ts +224 -205
- package/dist/model/malloy_types.js +19 -98
- package/dist/model/utils.d.ts +10 -3
- package/dist/model/utils.js +84 -219
- package/package.json +1 -1
- package/dist/lang/ast/types/comparison.d.ts +0 -11
- package/dist/lang/ast/types/comparison.js +0 -41
- package/dist/lang/ast/types/equality.d.ts +0 -7
- package/dist/lang/ast/types/equality.js +0 -37
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.PostgresBase = exports.timeExtractMap = void 0;
|
|
10
|
+
const dialect_1 = require("./dialect");
|
|
11
|
+
exports.timeExtractMap = {
|
|
12
|
+
'day_of_week': 'dow',
|
|
13
|
+
'day_of_year': 'doy',
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Many SQL implementations started with the PostGres source, and therefore can use the
|
|
17
|
+
* same implementations for the much of the SQL code generation
|
|
18
|
+
*/
|
|
19
|
+
class PostgresBase extends dialect_1.Dialect {
|
|
20
|
+
sqlTruncExpr(qi, df) {
|
|
21
|
+
// adjusting for monday/sunday weeks
|
|
22
|
+
const week = df.units === 'week';
|
|
23
|
+
const truncThis = week ? `${df.e.sql} + INTERVAL '1' DAY` : df.e.sql;
|
|
24
|
+
if (df.e.dataType === 'timestamp') {
|
|
25
|
+
const tz = (0, dialect_1.qtz)(qi);
|
|
26
|
+
if (tz) {
|
|
27
|
+
const civilSource = `(${truncThis}::TIMESTAMPTZ AT TIME ZONE '${tz}')`;
|
|
28
|
+
let civilTrunc = `DATE_TRUNC('${df.units}', ${civilSource})`;
|
|
29
|
+
// MTOY todo ... only need to do this if this is a date ...
|
|
30
|
+
civilTrunc = `${civilTrunc}::TIMESTAMP`;
|
|
31
|
+
const truncTsTz = `${civilTrunc} AT TIME ZONE '${tz}'`;
|
|
32
|
+
return `(${truncTsTz})::TIMESTAMP`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
let result = `DATE_TRUNC('${df.units}', ${truncThis})`;
|
|
36
|
+
if (week) {
|
|
37
|
+
result = `(${result} - INTERVAL '1' DAY)`;
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
sqlNowExpr() {
|
|
42
|
+
return 'LOCALTIMESTAMP';
|
|
43
|
+
}
|
|
44
|
+
sqlTimeExtractExpr(qi, from) {
|
|
45
|
+
const units = exports.timeExtractMap[from.units] || from.units;
|
|
46
|
+
let extractFrom = from.e.sql;
|
|
47
|
+
if (from.e.dataType === 'timestamp') {
|
|
48
|
+
const tz = (0, dialect_1.qtz)(qi);
|
|
49
|
+
if (tz) {
|
|
50
|
+
extractFrom = `(${extractFrom}::TIMESTAMPTZ AT TIME ZONE '${tz}')`;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const extracted = `EXTRACT(${units} FROM ${extractFrom})`;
|
|
54
|
+
return from.units === 'day_of_week' ? `mod(${extracted}+1,7)` : extracted;
|
|
55
|
+
}
|
|
56
|
+
sqlCast(qi, cast) {
|
|
57
|
+
const expr = cast.e.sql || '';
|
|
58
|
+
const op = `${cast.srcType}::${cast.dstType}`;
|
|
59
|
+
const tz = (0, dialect_1.qtz)(qi);
|
|
60
|
+
if (op === 'timestamp::date' && tz) {
|
|
61
|
+
const tstz = `${expr}::TIMESTAMPTZ`;
|
|
62
|
+
return `CAST((${tstz}) AT TIME ZONE '${tz}' AS DATE)`;
|
|
63
|
+
}
|
|
64
|
+
else if (op === 'date::timestamp' && tz) {
|
|
65
|
+
return `CAST((${expr})::TIMESTAMP AT TIME ZONE '${tz}' AS TIMESTAMP)`;
|
|
66
|
+
}
|
|
67
|
+
if (cast.srcType !== cast.dstType) {
|
|
68
|
+
const dstType = typeof cast.dstType === 'string'
|
|
69
|
+
? this.malloyTypeToSQLType({ type: cast.dstType })
|
|
70
|
+
: cast.dstType.raw;
|
|
71
|
+
const castFunc = cast.safe ? 'TRY_CAST' : 'CAST';
|
|
72
|
+
return `${castFunc}(${expr} AS ${dstType})`;
|
|
73
|
+
}
|
|
74
|
+
return expr;
|
|
75
|
+
}
|
|
76
|
+
sqlRegexpMatch(df) {
|
|
77
|
+
return `${df.kids.expr.sql} ~ ${df.kids.regex.sql}`;
|
|
78
|
+
}
|
|
79
|
+
sqlLiteralTime(qi, lt) {
|
|
80
|
+
if (lt.dataType === 'date') {
|
|
81
|
+
return `DATE '${lt.literal}'`;
|
|
82
|
+
}
|
|
83
|
+
const tz = lt.timezone || (0, dialect_1.qtz)(qi);
|
|
84
|
+
if (tz) {
|
|
85
|
+
return `TIMESTAMPTZ '${lt.literal} ${tz}'::TIMESTAMP`;
|
|
86
|
+
}
|
|
87
|
+
return `TIMESTAMP '${lt.literal}'`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.PostgresBase = PostgresBase;
|
|
91
|
+
//# sourceMappingURL=pg_impl.js.map
|
|
@@ -34,9 +34,7 @@ const types = [
|
|
|
34
34
|
function greatestOrLeast(fn) {
|
|
35
35
|
return types.map(type => (0, util_1.overload)((0, util_1.minScalar)(type), [(0, util_1.params)('values', (0, util_1.anyExprType)(type))],
|
|
36
36
|
// We match BigQuery null behavior here -- if any argument is null, return null
|
|
37
|
-
|
|
38
|
-
(0, util_1.sqlFragment)('CASE WHEN NUM_NULLS(', (0, util_1.spread)((0, util_1.arg)('values')), `) > 0 THEN NULL ELSE ${fn}(`, (0, util_1.spread)((0, util_1.arg)('values')), ') END'),
|
|
39
|
-
]));
|
|
37
|
+
(0, util_1.sql) `CASE WHEN NUM_NULLS(${(0, util_1.spread)((0, util_1.arg)('values'))}) > 0 THEN NULL ELSE ${fn}(${(0, util_1.spread)((0, util_1.arg)('values'))}) END`));
|
|
40
38
|
}
|
|
41
39
|
const fnGreatest = () => greatestOrLeast('GREATEST');
|
|
42
40
|
exports.fnGreatest = fnGreatest;
|
|
@@ -27,7 +27,7 @@ const util_1 = require("../../functions/util");
|
|
|
27
27
|
function fnStringAgg() {
|
|
28
28
|
const value = (0, util_1.makeParam)('value', (0, util_1.maxScalar)('string'));
|
|
29
29
|
const separator = (0, util_1.makeParam)('separator', (0, util_1.literal)((0, util_1.maxScalar)('string')));
|
|
30
|
-
const orderBy = {
|
|
30
|
+
const orderBy = { node: 'aggregate_order_by' };
|
|
31
31
|
return [
|
|
32
32
|
(0, util_1.overload)((0, util_1.minAggregate)('string'), [value.param], (0, util_1.sql) `STRING_AGG(${value.arg}, ','${orderBy})`, { supportsOrderBy: true }),
|
|
33
33
|
(0, util_1.overload)((0, util_1.minAggregate)('string'), [value.param, separator.param], (0, util_1.sql) `STRING_AGG(${value.arg}, ${separator.arg}${orderBy})`, { supportsOrderBy: true }),
|
|
@@ -37,7 +37,7 @@ exports.fnStringAgg = fnStringAgg;
|
|
|
37
37
|
function fnStringAggDistinct() {
|
|
38
38
|
const value = (0, util_1.makeParam)('value', (0, util_1.maxScalar)('string'));
|
|
39
39
|
const separator = (0, util_1.makeParam)('separator', (0, util_1.literal)((0, util_1.maxScalar)('string')));
|
|
40
|
-
const orderBy = {
|
|
40
|
+
const orderBy = { node: 'aggregate_order_by' };
|
|
41
41
|
return [
|
|
42
42
|
(0, util_1.overload)((0, util_1.minAggregate)('string'), [value.param], (0, util_1.sql) `STRING_AGG(DISTINCT ${value.arg}, ','${orderBy})`, {
|
|
43
43
|
isSymmetric: true,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Sampling, FieldAtomicTypeDef, TimeDeltaExpr, TypecastExpr, MeasureTimeExpr } from '../../model/malloy_types';
|
|
2
2
|
import { DialectFunctionOverloadDef } from '../functions';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { DialectFieldList, QueryInfo } from '../dialect';
|
|
4
|
+
import { PostgresBase } from '../pg_impl';
|
|
5
|
+
export declare class PostgresDialect extends PostgresBase {
|
|
5
6
|
name: string;
|
|
6
7
|
defaultNumberType: string;
|
|
7
8
|
defaultDecimalType: string;
|
|
@@ -42,14 +43,9 @@ export declare class PostgresDialect extends Dialect {
|
|
|
42
43
|
sqlSelectAliasAsStruct(alias: string): string;
|
|
43
44
|
sqlMaybeQuoteIdentifier(identifier: string): string;
|
|
44
45
|
sqlCreateTableAsSelect(_tableName: string, _sql: string): string;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
sqlAlterTime(op: '+' | '-', expr: TimeValue, n: Expr, timeframe: DateUnit): Expr;
|
|
49
|
-
sqlCast(qi: QueryInfo, cast: TypecastFragment): Expr;
|
|
50
|
-
sqlRegexpMatch(expr: Expr, regexp: Expr): Expr;
|
|
51
|
-
sqlLiteralTime(qi: QueryInfo, timeString: string, type: TimeFieldType, timezone: string | undefined): string;
|
|
52
|
-
sqlMeasureTime(from: TimeValue, to: TimeValue, units: string): Expr;
|
|
46
|
+
sqlAlterTimeExpr(df: TimeDeltaExpr): string;
|
|
47
|
+
sqlCast(qi: QueryInfo, cast: TypecastExpr): string;
|
|
48
|
+
sqlMeasureTimeExpr(df: MeasureTimeExpr): string;
|
|
53
49
|
sqlSumDistinct(key: string, value: string, funcName: string): string;
|
|
54
50
|
sqlAggDistinct(key: string, values: string[], func: (valNames: string[]) => string): string;
|
|
55
51
|
sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
|
|
@@ -26,11 +26,7 @@ exports.PostgresDialect = void 0;
|
|
|
26
26
|
const utils_1 = require("../../model/utils");
|
|
27
27
|
const malloy_types_1 = require("../../model/malloy_types");
|
|
28
28
|
const functions_1 = require("./functions");
|
|
29
|
-
const
|
|
30
|
-
const pgExtractionMap = {
|
|
31
|
-
'day_of_week': 'dow',
|
|
32
|
-
'day_of_year': 'doy',
|
|
33
|
-
};
|
|
29
|
+
const pg_impl_1 = require("../pg_impl");
|
|
34
30
|
const pgMakeIntervalMap = {
|
|
35
31
|
'year': 'years',
|
|
36
32
|
'month': 'months',
|
|
@@ -73,7 +69,7 @@ const postgresToMalloyTypes = {
|
|
|
73
69
|
'pg_ndistinct': { type: 'number', numberType: 'integer' },
|
|
74
70
|
'varchar': { type: 'string' },
|
|
75
71
|
};
|
|
76
|
-
class PostgresDialect extends
|
|
72
|
+
class PostgresDialect extends pg_impl_1.PostgresBase {
|
|
77
73
|
constructor() {
|
|
78
74
|
super(...arguments);
|
|
79
75
|
this.name = 'postgres';
|
|
@@ -243,99 +239,40 @@ class PostgresDialect extends dialect_1.Dialect {
|
|
|
243
239
|
sqlCreateTableAsSelect(_tableName, _sql) {
|
|
244
240
|
throw new Error('Not implemented Yet');
|
|
245
241
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
sqlTrunc(qi, sqlTime, units) {
|
|
250
|
-
// adjusting for monday/sunday weeks
|
|
251
|
-
const week = units === 'week';
|
|
252
|
-
const truncThis = week
|
|
253
|
-
? (0, malloy_types_1.mkExpr) `${sqlTime.value} + INTERVAL '1' DAY`
|
|
254
|
-
: sqlTime.value;
|
|
255
|
-
if (sqlTime.valueType === 'timestamp') {
|
|
256
|
-
const tz = (0, dialect_1.qtz)(qi);
|
|
257
|
-
if (tz) {
|
|
258
|
-
const civilSource = (0, malloy_types_1.mkExpr) `(${truncThis}::TIMESTAMPTZ AT TIME ZONE '${tz}')`;
|
|
259
|
-
let civilTrunc = (0, malloy_types_1.mkExpr) `DATE_TRUNC('${units}', ${civilSource})`;
|
|
260
|
-
// MTOY todo ... only need to do this if this is a date ...
|
|
261
|
-
civilTrunc = (0, malloy_types_1.mkExpr) `${civilTrunc}::TIMESTAMP`;
|
|
262
|
-
const truncTsTz = (0, malloy_types_1.mkExpr) `${civilTrunc} AT TIME ZONE '${tz}'`;
|
|
263
|
-
return (0, malloy_types_1.mkExpr) `(${truncTsTz})::TIMESTAMP`;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
let result = (0, malloy_types_1.mkExpr) `DATE_TRUNC('${units}', ${truncThis})`;
|
|
267
|
-
if (week) {
|
|
268
|
-
result = (0, malloy_types_1.mkExpr) `(${result} - INTERVAL '1' DAY)`;
|
|
269
|
-
}
|
|
270
|
-
return result;
|
|
271
|
-
}
|
|
272
|
-
sqlExtract(qi, from, units) {
|
|
273
|
-
const pgUnits = pgExtractionMap[units] || units;
|
|
274
|
-
let extractFrom = from.value;
|
|
275
|
-
if (from.valueType === 'timestamp') {
|
|
276
|
-
const tz = (0, dialect_1.qtz)(qi);
|
|
277
|
-
if (tz) {
|
|
278
|
-
extractFrom = (0, malloy_types_1.mkExpr) `(${extractFrom}::TIMESTAMPTZ AT TIME ZONE '${tz}')`;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
const extracted = (0, malloy_types_1.mkExpr) `EXTRACT(${pgUnits} FROM ${extractFrom})`;
|
|
282
|
-
return units === 'day_of_week' ? (0, malloy_types_1.mkExpr) `(${extracted}+1)` : extracted;
|
|
283
|
-
}
|
|
284
|
-
sqlAlterTime(op, expr, n, timeframe) {
|
|
242
|
+
sqlAlterTimeExpr(df) {
|
|
243
|
+
let timeframe = df.units;
|
|
244
|
+
let n = df.kids.delta.sql;
|
|
285
245
|
if (timeframe === 'quarter') {
|
|
286
246
|
timeframe = 'month';
|
|
287
|
-
n =
|
|
247
|
+
n = `${n}*3`;
|
|
288
248
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
sqlCast(qi, cast) {
|
|
293
|
-
const op = `${cast.srcType}::${cast.dstType}`;
|
|
294
|
-
const tz = (0, dialect_1.qtz)(qi);
|
|
295
|
-
if (op === 'timestamp::date' && tz) {
|
|
296
|
-
const tstz = (0, malloy_types_1.mkExpr) `${cast.expr}::TIMESTAMPTZ`;
|
|
297
|
-
return (0, malloy_types_1.mkExpr) `CAST((${tstz}) AT TIME ZONE '${tz}' AS DATE)`;
|
|
298
|
-
}
|
|
299
|
-
else if (op === 'date::timestamp' && tz) {
|
|
300
|
-
return (0, malloy_types_1.mkExpr) `CAST((${cast.expr})::TIMESTAMP AT TIME ZONE '${tz}' AS TIMESTAMP)`;
|
|
301
|
-
}
|
|
302
|
-
if (cast.srcType !== cast.dstType) {
|
|
303
|
-
const dstType = typeof cast.dstType === 'string'
|
|
304
|
-
? this.malloyTypeToSQLType({ type: cast.dstType })
|
|
305
|
-
: cast.dstType.raw;
|
|
306
|
-
if (cast.safe) {
|
|
307
|
-
throw new Error("Postgres dialect doesn't support Safe Cast");
|
|
308
|
-
}
|
|
309
|
-
const castFunc = 'CAST';
|
|
310
|
-
return (0, malloy_types_1.mkExpr) `${castFunc}(${cast.expr} AS ${dstType})`;
|
|
249
|
+
else if (timeframe === 'week') {
|
|
250
|
+
timeframe = 'day';
|
|
251
|
+
n = `${n}*7`;
|
|
311
252
|
}
|
|
312
|
-
|
|
253
|
+
const interval = `make_interval(${pgMakeIntervalMap[timeframe]}=>${n})`;
|
|
254
|
+
return `(${df.kids.base.sql})${df.op}${interval}`;
|
|
313
255
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
sqlLiteralTime(qi, timeString, type, timezone) {
|
|
318
|
-
if (type === 'date') {
|
|
319
|
-
return `DATE '${timeString}'`;
|
|
320
|
-
}
|
|
321
|
-
const tz = timezone || (0, dialect_1.qtz)(qi);
|
|
322
|
-
if (tz) {
|
|
323
|
-
return `TIMESTAMPTZ '${timeString} ${tz}'::TIMESTAMP`;
|
|
256
|
+
sqlCast(qi, cast) {
|
|
257
|
+
if (cast.safe) {
|
|
258
|
+
throw new Error("Postgres dialect doesn't support Safe Cast");
|
|
324
259
|
}
|
|
325
|
-
return
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
260
|
+
return super.sqlCast(qi, cast);
|
|
261
|
+
}
|
|
262
|
+
sqlMeasureTimeExpr(df) {
|
|
263
|
+
const from = df.kids.left;
|
|
264
|
+
const to = df.kids.right;
|
|
265
|
+
let lVal = from.sql;
|
|
266
|
+
let rVal = to.sql;
|
|
267
|
+
if (inSeconds[df.units]) {
|
|
268
|
+
lVal = `EXTRACT(EPOCH FROM ${lVal})`;
|
|
269
|
+
rVal = `EXTRACT(EPOCH FROM ${rVal})`;
|
|
270
|
+
const duration = `${rVal}-${lVal}`;
|
|
271
|
+
return df.units === 'second'
|
|
272
|
+
? `FLOOR(${duration})`
|
|
273
|
+
: `FLOOR((${duration})/${inSeconds[df.units].toString()}.0)`;
|
|
337
274
|
}
|
|
338
|
-
throw new Error(`Unknown or unhandled postgres time unit: ${units}`);
|
|
275
|
+
throw new Error(`Unknown or unhandled postgres time unit: ${df.units}`);
|
|
339
276
|
}
|
|
340
277
|
sqlSumDistinct(key, value, funcName) {
|
|
341
278
|
// return `sum_distinct(list({key:${key}, val: ${value}}))`;
|
|
@@ -28,7 +28,7 @@ function fnStringAgg() {
|
|
|
28
28
|
const value = (0, util_1.makeParam)('value', (0, util_1.maxScalar)('string'));
|
|
29
29
|
const separator = (0, util_1.makeParam)('separator', (0, util_1.literal)((0, util_1.maxScalar)('string')));
|
|
30
30
|
const orderBy = {
|
|
31
|
-
|
|
31
|
+
node: 'aggregate_order_by',
|
|
32
32
|
prefix: ' WITHIN GROUP(',
|
|
33
33
|
suffix: ')',
|
|
34
34
|
};
|
|
@@ -42,7 +42,7 @@ function fnStringAggDistinct() {
|
|
|
42
42
|
const value = (0, util_1.makeParam)('value', (0, util_1.maxScalar)('string'));
|
|
43
43
|
const separator = (0, util_1.makeParam)('separator', (0, util_1.literal)((0, util_1.maxScalar)('string')));
|
|
44
44
|
const orderBy = {
|
|
45
|
-
|
|
45
|
+
node: 'aggregate_order_by',
|
|
46
46
|
prefix: ' WITHIN GROUP(',
|
|
47
47
|
suffix: ')',
|
|
48
48
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Sampling, FieldAtomicTypeDef, TimeTruncExpr, TimeExtractExpr, TimeDeltaExpr, TypecastExpr, TimeLiteralNode, MeasureTimeExpr, RegexMatchExpr } from '../../model/malloy_types';
|
|
2
2
|
import { DialectFunctionOverloadDef } from '../functions';
|
|
3
3
|
import { Dialect, DialectFieldList, QueryInfo } from '../dialect';
|
|
4
4
|
export declare class SnowflakeDialect extends Dialect {
|
|
@@ -43,15 +43,15 @@ export declare class SnowflakeDialect extends Dialect {
|
|
|
43
43
|
sqlSelectAliasAsStruct(alias: string): string;
|
|
44
44
|
sqlMaybeQuoteIdentifier(identifier: string): string;
|
|
45
45
|
sqlCreateTableAsSelect(tableName: string, sql: string): string;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
sqlTruncExpr(qi: QueryInfo, te: TimeTruncExpr): string;
|
|
47
|
+
sqlTimeExtractExpr(qi: QueryInfo, from: TimeExtractExpr): string;
|
|
48
|
+
sqlAlterTimeExpr(df: TimeDeltaExpr): string;
|
|
49
49
|
private atTz;
|
|
50
|
-
|
|
51
|
-
sqlCast(qi: QueryInfo, cast:
|
|
52
|
-
sqlLiteralTime(qi: QueryInfo,
|
|
53
|
-
|
|
54
|
-
sqlRegexpMatch(
|
|
50
|
+
sqlNowExpr(): string;
|
|
51
|
+
sqlCast(qi: QueryInfo, cast: TypecastExpr): string;
|
|
52
|
+
sqlLiteralTime(qi: QueryInfo, lf: TimeLiteralNode): string;
|
|
53
|
+
sqlMeasureTimeExpr(df: MeasureTimeExpr): string;
|
|
54
|
+
sqlRegexpMatch(compare: RegexMatchExpr): string;
|
|
55
55
|
sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
|
|
56
56
|
sqlOrderBy(orderTerms: string[]): string;
|
|
57
57
|
sqlLiteralString(literal: string): string;
|
|
@@ -141,20 +141,11 @@ class SnowflakeDialect extends dialect_1.Dialect {
|
|
|
141
141
|
}
|
|
142
142
|
sqlUnnestAlias(source, alias, _fieldList, _needDistinctKey, isArray, _isInNestedPipeline) {
|
|
143
143
|
if (isArray) {
|
|
144
|
-
// if (needDistinctKey) {
|
|
145
|
-
// // return `LEFT JOIN UNNEST(ARRAY(( SELECT AS STRUCT row_number() over() as __row_id, value FROM UNNEST(${source}) value))) as ${alias}`;
|
|
146
|
-
// } else {
|
|
147
|
-
// return `LEFT JOIN UNNEST(ARRAY((SELECT AS STRUCT value FROM unnest(${source}) value))) as ${alias}`;
|
|
148
|
-
// }
|
|
149
144
|
return `,LATERAL FLATTEN(INPUT => ${source}) AS ${alias}_1, LATERAL (SELECT ${alias}_1.INDEX, object_construct('value', ${alias}_1.value) as value ) as ${alias}`;
|
|
150
145
|
}
|
|
151
146
|
else {
|
|
152
147
|
// have to have a non empty row or it treats it like an inner join :barf-emoji:
|
|
153
148
|
return `LEFT JOIN LATERAL FLATTEN(INPUT => ifnull(${source},[1])) AS ${alias}`;
|
|
154
|
-
// return `LEFT JOIN UNNEST(ARRAY(( SELECT AS STRUCT row_number() over() as __row_id, * FROM UNNEST(${source})))) as ${alias}`;
|
|
155
|
-
// } else {
|
|
156
|
-
// return `LEFT JOIN UNNEST(${source}) as ${alias}`;
|
|
157
|
-
// }
|
|
158
149
|
}
|
|
159
150
|
}
|
|
160
151
|
/*
|
|
@@ -243,43 +234,43 @@ ${(0, utils_1.indent)(sql)}
|
|
|
243
234
|
);
|
|
244
235
|
`;
|
|
245
236
|
}
|
|
246
|
-
|
|
237
|
+
sqlTruncExpr(qi, te) {
|
|
247
238
|
const tz = (0, dialect_1.qtz)(qi);
|
|
248
|
-
let truncThis =
|
|
249
|
-
if (tz &&
|
|
250
|
-
truncThis =
|
|
239
|
+
let truncThis = te.e.sql;
|
|
240
|
+
if (tz && te.e.dataType === 'timestamp') {
|
|
241
|
+
truncThis = `CONVERT_TIMEZONE('${tz}',${truncThis})`;
|
|
251
242
|
}
|
|
252
|
-
return
|
|
243
|
+
return `DATE_TRUNC('${te.units}',${truncThis})`;
|
|
253
244
|
}
|
|
254
|
-
|
|
255
|
-
const extractUnits = extractionMap[units] || units;
|
|
256
|
-
let extractFrom = from.
|
|
245
|
+
sqlTimeExtractExpr(qi, from) {
|
|
246
|
+
const extractUnits = extractionMap[from.units] || from.units;
|
|
247
|
+
let extractFrom = from.e.sql;
|
|
257
248
|
const tz = (0, dialect_1.qtz)(qi);
|
|
258
|
-
if (tz && from.
|
|
259
|
-
extractFrom =
|
|
249
|
+
if (tz && from.e.dataType === 'timestamp') {
|
|
250
|
+
extractFrom = `CONVERT_TIMEZONE('${tz}', ${extractFrom})`;
|
|
260
251
|
}
|
|
261
|
-
|
|
262
|
-
return extracted;
|
|
252
|
+
return `EXTRACT(${extractUnits} FROM ${extractFrom})`;
|
|
263
253
|
}
|
|
264
|
-
|
|
265
|
-
const interval =
|
|
266
|
-
return
|
|
254
|
+
sqlAlterTimeExpr(df) {
|
|
255
|
+
const interval = `INTERVAL '${df.kids.delta.sql} ${df.units}'`;
|
|
256
|
+
return `(${df.kids.base.sql})${df.op}${interval}`;
|
|
267
257
|
}
|
|
268
|
-
atTz(
|
|
258
|
+
atTz(sqlExpr, tz) {
|
|
269
259
|
if (tz !== undefined) {
|
|
270
|
-
return
|
|
271
|
-
TO_CHAR(${
|
|
260
|
+
return `(
|
|
261
|
+
TO_CHAR(${sqlExpr}::TIMESTAMP_NTZ, 'YYYY-MM-DD HH24:MI:SS.FF9') ||
|
|
272
262
|
TO_CHAR(CONVERT_TIMEZONE('${tz}', '1970-01-01 00:00:00'), 'TZHTZM')
|
|
273
263
|
)::TIMESTAMP_TZ`;
|
|
274
264
|
}
|
|
275
|
-
return
|
|
265
|
+
return `${sqlExpr}::TIMESTAMP_NTZ`;
|
|
276
266
|
}
|
|
277
|
-
|
|
278
|
-
return
|
|
267
|
+
sqlNowExpr() {
|
|
268
|
+
return 'CURRENT_TIMESTAMP()';
|
|
279
269
|
}
|
|
280
270
|
sqlCast(qi, cast) {
|
|
271
|
+
const src = cast.e.sql || '';
|
|
281
272
|
if (cast.srcType === cast.dstType) {
|
|
282
|
-
return
|
|
273
|
+
return src;
|
|
283
274
|
}
|
|
284
275
|
if (cast.safe && typeof cast.srcType !== 'string') {
|
|
285
276
|
// safe cast is only supported for a few combinations of src -> dst types
|
|
@@ -291,35 +282,36 @@ ${(0, utils_1.indent)(sql)}
|
|
|
291
282
|
const tz = (0, dialect_1.qtz)(qi);
|
|
292
283
|
// casting timestamps and dates
|
|
293
284
|
if (cast.dstType === 'date' && cast.srcType === 'timestamp') {
|
|
294
|
-
let castExpr =
|
|
285
|
+
let castExpr = src;
|
|
295
286
|
if (tz) {
|
|
296
|
-
castExpr =
|
|
287
|
+
castExpr = `CONVERT_TIMEZONE('${tz}', ${castExpr})`;
|
|
297
288
|
}
|
|
298
|
-
return
|
|
289
|
+
return `TO_DATE(${castExpr})`;
|
|
299
290
|
}
|
|
300
291
|
else if (cast.dstType === 'timestamp' && cast.srcType === 'date') {
|
|
301
|
-
const retExpr =
|
|
292
|
+
const retExpr = `TO_TIMESTAMP(${src})`;
|
|
302
293
|
return this.atTz(retExpr, tz);
|
|
303
294
|
}
|
|
304
295
|
const dstType = typeof cast.dstType === 'string'
|
|
305
296
|
? this.malloyTypeToSQLType({ type: cast.dstType })
|
|
306
297
|
: cast.dstType.raw;
|
|
307
298
|
const castFunc = cast.safe ? 'TRY_CAST' : 'CAST';
|
|
308
|
-
return
|
|
299
|
+
return `${castFunc}(${src} AS ${dstType})`;
|
|
309
300
|
}
|
|
310
|
-
sqlLiteralTime(qi,
|
|
301
|
+
sqlLiteralTime(qi, lf) {
|
|
302
|
+
var _a;
|
|
311
303
|
const tz = (0, dialect_1.qtz)(qi);
|
|
312
304
|
// just making it explicit that timestring does not have timezone info
|
|
313
|
-
let ret = `'${
|
|
305
|
+
let ret = `'${lf.literal}'::TIMESTAMP_NTZ`;
|
|
314
306
|
// now do the hack to add timezone to a timestamp ntz
|
|
315
|
-
const targetTimeZone = timezone !== null &&
|
|
307
|
+
const targetTimeZone = (_a = lf.timezone) !== null && _a !== void 0 ? _a : tz;
|
|
316
308
|
if (targetTimeZone) {
|
|
317
309
|
const targetTimeZoneSuffix = `TO_CHAR(CONVERT_TIMEZONE('${targetTimeZone}', '1970-01-01 00:00:00'), 'TZHTZM')`;
|
|
318
310
|
const retTimeString = `TO_CHAR(${ret}, 'YYYY-MM-DD HH24:MI:SS.FF9')`;
|
|
319
311
|
ret = `${retTimeString} || ${targetTimeZoneSuffix}`;
|
|
320
312
|
ret = `(${ret})::TIMESTAMP_TZ`;
|
|
321
313
|
}
|
|
322
|
-
switch (
|
|
314
|
+
switch (lf.dataType) {
|
|
323
315
|
case 'date':
|
|
324
316
|
return `TO_DATE(${ret})`;
|
|
325
317
|
case 'timestamp': {
|
|
@@ -327,24 +319,25 @@ ${(0, utils_1.indent)(sql)}
|
|
|
327
319
|
}
|
|
328
320
|
}
|
|
329
321
|
}
|
|
330
|
-
|
|
322
|
+
sqlMeasureTimeExpr(df) {
|
|
323
|
+
const from = df.kids.left;
|
|
324
|
+
const to = df.kids.right;
|
|
331
325
|
let extractUnits = 'nanoseconds';
|
|
332
|
-
if (from.
|
|
326
|
+
if (from.dataType === 'date' || to.dataType === 'date') {
|
|
333
327
|
extractUnits = 'seconds';
|
|
334
328
|
}
|
|
335
|
-
return
|
|
336
|
-
'${units}',
|
|
329
|
+
return `TIMESTAMPDIFF(
|
|
330
|
+
'${df.units}',
|
|
337
331
|
'1970-01-01 00:00:00'::TIMESTAMP_NTZ,
|
|
338
332
|
TIMESTAMPADD(
|
|
339
333
|
'${extractUnits}',
|
|
340
|
-
EXTRACT('epoch_${extractUnits}', ${to.
|
|
334
|
+
EXTRACT('epoch_${extractUnits}', ${to.sql}) - EXTRACT('epoch_${extractUnits}', ${from.sql}),
|
|
341
335
|
'1970-01-01 00:00:00'::TIMESTAMP_NTZ
|
|
342
336
|
)
|
|
343
337
|
)`;
|
|
344
338
|
}
|
|
345
|
-
sqlRegexpMatch(
|
|
346
|
-
|
|
347
|
-
return (0, malloy_types_1.mkExpr) `(REGEXP_INSTR(${expr}, ${regexp}) != 0)`;
|
|
339
|
+
sqlRegexpMatch(compare) {
|
|
340
|
+
return `REGEXP_INSTR(${compare.kids.expr.sql}, ${compare.kids.regex.sql}) != 0`;
|
|
348
341
|
}
|
|
349
342
|
sqlSampleTable(tableSQL, sample) {
|
|
350
343
|
if (sample !== undefined) {
|
|
@@ -27,8 +27,8 @@ const util_1 = require("../../functions/util");
|
|
|
27
27
|
function fnStringAgg() {
|
|
28
28
|
const value = (0, util_1.makeParam)('value', (0, util_1.maxScalar)('string'));
|
|
29
29
|
const separator = (0, util_1.makeParam)('separator', (0, util_1.literal)((0, util_1.maxScalar)('string')));
|
|
30
|
-
const orderBy = {
|
|
31
|
-
const limit = {
|
|
30
|
+
const orderBy = { node: 'aggregate_order_by' };
|
|
31
|
+
const limit = { node: 'aggregate_limit' };
|
|
32
32
|
return [
|
|
33
33
|
(0, util_1.overload)((0, util_1.minAggregate)('string'), [value.param], (0, util_1.sql) `STRING_AGG(${value.arg}${orderBy}${limit})`, { supportsOrderBy: true, supportsLimit: true, defaultOrderByArgIndex: 0 }),
|
|
34
34
|
(0, util_1.overload)((0, util_1.minAggregate)('string'), [value.param, separator.param], (0, util_1.sql) `STRING_AGG(${value.arg}, ${separator.arg}${orderBy}${limit})`, { supportsOrderBy: true, supportsLimit: true, defaultOrderByArgIndex: 0 }),
|
|
@@ -38,8 +38,8 @@ exports.fnStringAgg = fnStringAgg;
|
|
|
38
38
|
function fnStringAggDistinct() {
|
|
39
39
|
const value = (0, util_1.makeParam)('value', (0, util_1.maxScalar)('string'));
|
|
40
40
|
const separator = (0, util_1.makeParam)('separator', (0, util_1.literal)((0, util_1.maxScalar)('string')));
|
|
41
|
-
const orderBy = {
|
|
42
|
-
const limit = {
|
|
41
|
+
const orderBy = { node: 'aggregate_order_by' };
|
|
42
|
+
const limit = { node: 'aggregate_limit' };
|
|
43
43
|
return [
|
|
44
44
|
(0, util_1.overload)((0, util_1.minAggregate)('string'), [value.param], (0, util_1.sql) `STRING_AGG(DISTINCT ${value.arg}${orderBy}${limit})`, {
|
|
45
45
|
isSymmetric: true,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Sampling, FieldAtomicTypeDef, TimeTruncExpr, TimeExtractExpr, TimeDeltaExpr, TypecastExpr, RegexMatchExpr, TimeLiteralNode, MeasureTimeExpr } from '../../model/malloy_types';
|
|
2
2
|
import { DialectFunctionOverloadDef } from '../functions';
|
|
3
3
|
import { Dialect, DialectFieldList, QueryInfo } from '../dialect';
|
|
4
4
|
export declare class StandardSQLDialect extends Dialect {
|
|
@@ -41,15 +41,15 @@ export declare class StandardSQLDialect extends Dialect {
|
|
|
41
41
|
sqlSelectAliasAsStruct(alias: string): string;
|
|
42
42
|
keywords: string[];
|
|
43
43
|
sqlMaybeQuoteIdentifier(identifier: string): string;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
sqlNowExpr(): string;
|
|
45
|
+
sqlTruncExpr(qi: QueryInfo, trunc: TimeTruncExpr): string;
|
|
46
|
+
sqlTimeExtractExpr(qi: QueryInfo, te: TimeExtractExpr): string;
|
|
47
|
+
sqlAlterTimeExpr(df: TimeDeltaExpr): string;
|
|
48
48
|
ignoreInProject(fieldName: string): boolean;
|
|
49
|
-
sqlCast(qi: QueryInfo, cast:
|
|
50
|
-
sqlRegexpMatch(
|
|
51
|
-
sqlLiteralTime(qi: QueryInfo,
|
|
52
|
-
|
|
49
|
+
sqlCast(qi: QueryInfo, cast: TypecastExpr): string;
|
|
50
|
+
sqlRegexpMatch(match: RegexMatchExpr): string;
|
|
51
|
+
sqlLiteralTime(qi: QueryInfo, lit: TimeLiteralNode): string;
|
|
52
|
+
sqlMeasureTimeExpr(measure: MeasureTimeExpr): string;
|
|
53
53
|
sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
|
|
54
54
|
sqlLiteralString(literal: string): string;
|
|
55
55
|
sqlLiteralRegexp(literal: string): string;
|