@malloydata/malloy 0.0.433 → 0.0.434
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/compile.d.ts +2 -1
- package/dist/api/foundation/compile.js +8 -6
- package/dist/api/foundation/config.js +6 -15
- package/dist/api/foundation/runtime.d.ts +2 -7
- package/dist/api/foundation/runtime.js +10 -16
- package/dist/api/foundation/types.d.ts +1 -0
- package/dist/connection/validate_table_path.d.ts +1 -2
- package/dist/connection/validate_table_path.js +1 -2
- package/dist/dialect/databricks/databricks.js +6 -6
- package/dist/dialect/dialect.d.ts +21 -2
- package/dist/dialect/dialect.js +33 -3
- package/dist/dialect/duckdb/duckdb.js +7 -21
- package/dist/dialect/mysql/mysql.js +8 -8
- package/dist/dialect/pg_impl.js +12 -12
- package/dist/dialect/postgres/postgres.js +3 -3
- package/dist/dialect/snowflake/snowflake.js +12 -12
- package/dist/dialect/standardsql/standardsql.d.ts +1 -1
- package/dist/dialect/standardsql/standardsql.js +16 -13
- package/dist/dialect/trino/trino.d.ts +3 -3
- package/dist/dialect/trino/trino.js +32 -28
- package/dist/lang/ast/source-elements/refined-source.js +1 -1
- package/dist/lang/ast/source-elements/sql-source.js +2 -1
- package/dist/lang/ast/source-properties/timezone-statement.d.ts +4 -3
- package/dist/lang/ast/source-properties/timezone-statement.js +14 -12
- package/dist/lang/composite-source-utils.js +10 -3
- package/dist/lang/malloy-to-ast.js +2 -8
- package/dist/lang/parse-malloy.d.ts +3 -2
- package/dist/lang/parse-malloy.js +2 -1
- package/dist/lang/test/test-translator.d.ts +2 -1
- package/dist/lang/test/test-translator.js +1 -1
- package/dist/model/join_instance.d.ts +1 -0
- package/dist/model/join_instance.js +9 -1
- package/dist/model/query_query.d.ts +25 -0
- package/dist/model/query_query.js +142 -17
- package/dist/model/sql_block.d.ts +2 -2
- package/dist/model/sql_block.js +11 -47
- package/dist/model/sql_compiled.d.ts +3 -1
- package/dist/model/sql_compiled.js +8 -6
- package/dist/model/stage_writer.js +3 -3
- package/dist/model/utils.d.ts +2 -2
- package/dist/model/utils.js +2 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/femto-config.motly +2 -0
- package/package.json +4 -4
|
@@ -105,7 +105,7 @@ class SnowflakeDialect extends dialect_1.Dialect {
|
|
|
105
105
|
}
|
|
106
106
|
mapFields(fieldList) {
|
|
107
107
|
return fieldList
|
|
108
|
-
.map(f => `\n ${f.sqlExpression} as ${f.
|
|
108
|
+
.map(f => `\n ${f.sqlExpression} as ${this.sqlQuoteIdentifier(f.rawName)}`)
|
|
109
109
|
.join(', ');
|
|
110
110
|
}
|
|
111
111
|
mapFieldsForObjectConstruct(fieldList) {
|
|
@@ -138,7 +138,7 @@ class SnowflakeDialect extends dialect_1.Dialect {
|
|
|
138
138
|
sqlCoaleseMeasuresInline(groupSet, fieldList) {
|
|
139
139
|
const fields = this.mapFieldsForObjectConstruct(fieldList);
|
|
140
140
|
const nullValues = fieldList
|
|
141
|
-
.map(f =>
|
|
141
|
+
.map(f => `${this.sqlLiteralString(f.rawName)}, NULL`)
|
|
142
142
|
.join(', ');
|
|
143
143
|
return `COALESCE(ARRAY_AGG(CASE WHEN group_set=${groupSet} THEN OBJECT_CONSTRUCT_KEEP_NULL(${fields}) END)[0], OBJECT_CONSTRUCT_KEEP_NULL(${nullValues}))`;
|
|
144
144
|
}
|
|
@@ -254,21 +254,21 @@ ${(0, utils_1.indent)(sql)}
|
|
|
254
254
|
// Returns TIMESTAMP_TZ with timezone preserved
|
|
255
255
|
if (typeDef.type === 'timestamptz') {
|
|
256
256
|
return {
|
|
257
|
-
sql: `CONVERT_TIMEZONE(
|
|
257
|
+
sql: `CONVERT_TIMEZONE(${this.sqlTimezoneLiteral(timezone)}, ${expr})`,
|
|
258
258
|
typeDef: { type: 'timestamptz' },
|
|
259
259
|
};
|
|
260
260
|
}
|
|
261
261
|
// For plain timestamps (TIMESTAMP_NTZ): use 3-arg form
|
|
262
262
|
// Must cast to TIMESTAMP_NTZ first, returns TIMESTAMP_NTZ
|
|
263
263
|
return {
|
|
264
|
-
sql: `CONVERT_TIMEZONE('UTC',
|
|
264
|
+
sql: `CONVERT_TIMEZONE('UTC', ${this.sqlTimezoneLiteral(timezone)}, (${expr})::TIMESTAMP_NTZ)`,
|
|
265
265
|
typeDef: { type: 'timestamp' },
|
|
266
266
|
};
|
|
267
267
|
}
|
|
268
268
|
sqlConvertFromCivilTime(expr, timezone, _destTypeDef) {
|
|
269
269
|
// After civil time operations, we have a TIMESTAMP_NTZ in the target timezone
|
|
270
270
|
// Convert from timezone to UTC, returning TIMESTAMP_NTZ
|
|
271
|
-
return `CONVERT_TIMEZONE(
|
|
271
|
+
return `CONVERT_TIMEZONE(${this.sqlTimezoneLiteral(timezone)}, 'UTC', (${expr})::TIMESTAMP_NTZ)`;
|
|
272
272
|
}
|
|
273
273
|
sqlTruncate(expr, unit, _typeDef, _inCivilTime, _timezone) {
|
|
274
274
|
// Snowflake session is configured with WEEK_START=7 (Sunday)
|
|
@@ -287,7 +287,7 @@ ${(0, utils_1.indent)(sql)}
|
|
|
287
287
|
let extractFrom = from.e.sql;
|
|
288
288
|
const tz = (0, dialect_1.qtz)(qi);
|
|
289
289
|
if (tz && malloy_types_1.TD.isAnyTimestamp(from.e.typeDef)) {
|
|
290
|
-
extractFrom = `CONVERT_TIMEZONE(
|
|
290
|
+
extractFrom = `CONVERT_TIMEZONE(${this.sqlTimezoneLiteral(tz)}, ${extractFrom})`;
|
|
291
291
|
}
|
|
292
292
|
return `EXTRACT(${extractUnits} FROM ${extractFrom})`;
|
|
293
293
|
}
|
|
@@ -295,7 +295,7 @@ ${(0, utils_1.indent)(sql)}
|
|
|
295
295
|
if (tz !== undefined) {
|
|
296
296
|
return `(
|
|
297
297
|
TO_CHAR(${sqlExpr}::TIMESTAMP_NTZ, 'YYYY-MM-DD HH24:MI:SS.FF9') ||
|
|
298
|
-
TO_CHAR(CONVERT_TIMEZONE(
|
|
298
|
+
TO_CHAR(CONVERT_TIMEZONE(${this.sqlTimezoneLiteral(tz)}, '1970-01-01 00:00:00'), 'TZHTZM')
|
|
299
299
|
)::TIMESTAMP_TZ`;
|
|
300
300
|
}
|
|
301
301
|
return `${sqlExpr}::TIMESTAMP_NTZ`;
|
|
@@ -321,11 +321,11 @@ ${(0, utils_1.indent)(sql)}
|
|
|
321
321
|
if (tz && srcTypeDef && dstTypeDef) {
|
|
322
322
|
// TIMESTAMP → DATE: convert to query timezone, then to date
|
|
323
323
|
if (malloy_types_1.TD.isTimestamp(srcTypeDef) && malloy_types_1.TD.isDate(dstTypeDef)) {
|
|
324
|
-
return `TO_DATE(CONVERT_TIMEZONE(
|
|
324
|
+
return `TO_DATE(CONVERT_TIMEZONE(${this.sqlTimezoneLiteral(tz)}, ${src}))`;
|
|
325
325
|
}
|
|
326
326
|
// TIMESTAMPTZ → DATE: convert to query timezone, then to date
|
|
327
327
|
if (malloy_types_1.TD.isTimestamptz(srcTypeDef) && malloy_types_1.TD.isDate(dstTypeDef)) {
|
|
328
|
-
return `TO_DATE(CONVERT_TIMEZONE(
|
|
328
|
+
return `TO_DATE(CONVERT_TIMEZONE(${this.sqlTimezoneLiteral(tz)}, ${src}))`;
|
|
329
329
|
}
|
|
330
330
|
// DATE → TIMESTAMP: interpret date in query timezone, return UTC timestamp
|
|
331
331
|
if (malloy_types_1.TD.isDate(srcTypeDef) && malloy_types_1.TD.isTimestamp(dstTypeDef)) {
|
|
@@ -339,7 +339,7 @@ ${(0, utils_1.indent)(sql)}
|
|
|
339
339
|
}
|
|
340
340
|
// TIMESTAMPTZ → TIMESTAMP: convert to query timezone, get UTC wall clock
|
|
341
341
|
if (malloy_types_1.TD.isTimestamptz(srcTypeDef) && malloy_types_1.TD.isTimestamp(dstTypeDef)) {
|
|
342
|
-
return `CONVERT_TIMEZONE(
|
|
342
|
+
return `CONVERT_TIMEZONE(${this.sqlTimezoneLiteral(tz)}, ${src})::TIMESTAMP_NTZ`;
|
|
343
343
|
}
|
|
344
344
|
// TIMESTAMP → TIMESTAMPTZ: interpret as UTC, convert to TIMESTAMPTZ
|
|
345
345
|
if (malloy_types_1.TD.isTimestamp(srcTypeDef) && malloy_types_1.TD.isTimestamptz(dstTypeDef)) {
|
|
@@ -357,7 +357,7 @@ ${(0, utils_1.indent)(sql)}
|
|
|
357
357
|
let ret = `'${literal}'::TIMESTAMP_NTZ`;
|
|
358
358
|
if (tz) {
|
|
359
359
|
// Interpret the literal as being in query timezone, convert to UTC
|
|
360
|
-
ret = `CONVERT_TIMEZONE(
|
|
360
|
+
ret = `CONVERT_TIMEZONE(${this.sqlTimezoneLiteral(tz)}, 'UTC', ${ret})`;
|
|
361
361
|
}
|
|
362
362
|
return ret;
|
|
363
363
|
}
|
|
@@ -374,7 +374,7 @@ ${(0, utils_1.indent)(sql)}
|
|
|
374
374
|
const minute = dt.minute;
|
|
375
375
|
const second = dt.second;
|
|
376
376
|
const nanosecond = dt.millisecond * 1000000;
|
|
377
|
-
return `TIMESTAMP_TZ_FROM_PARTS(${year}, ${month}, ${day}, ${hour}, ${minute}, ${second}, ${nanosecond},
|
|
377
|
+
return `TIMESTAMP_TZ_FROM_PARTS(${year}, ${month}, ${day}, ${hour}, ${minute}, ${second}, ${nanosecond}, ${this.sqlTimezoneLiteral(timezone)})`;
|
|
378
378
|
}
|
|
379
379
|
sqlMeasureTimeExpr(df) {
|
|
380
380
|
const from = df.kids.left;
|
|
@@ -55,7 +55,7 @@ export declare class StandardSQLDialect extends Dialect {
|
|
|
55
55
|
sqlCreateFunction(id: string, funcText: string): string;
|
|
56
56
|
sqlCreateTableAsSelect(tableName: string, sql: string): string;
|
|
57
57
|
sqlCreateFunctionCombineLastStage(lastStageName: string): string;
|
|
58
|
-
sqlSelectAliasAsStruct(alias: string): string;
|
|
58
|
+
sqlSelectAliasAsStruct(alias: string, dialectFieldList: DialectFieldList): string;
|
|
59
59
|
sqlNowExpr(): string;
|
|
60
60
|
sqlTimeExtractExpr(qi: QueryInfo, te: TimeExtractExpr): string;
|
|
61
61
|
sqlConvertToCivilTime(expr: string, timezone: string, _typeDef: AtomicTypeDef): {
|
|
@@ -150,7 +150,7 @@ class StandardSQLDialect extends dialect_1.Dialect {
|
|
|
150
150
|
// can array agg or any_value a struct...
|
|
151
151
|
sqlAggregateTurtle(groupSet, fieldList, orderBy, limit, filterSQL) {
|
|
152
152
|
const fields = fieldList
|
|
153
|
-
.map(f => `\n ${f.sqlExpression} as ${f.
|
|
153
|
+
.map(f => `\n ${f.sqlExpression} as ${this.sqlQuoteIdentifier(f.rawName)}`)
|
|
154
154
|
.join(', ');
|
|
155
155
|
const orderByClause = orderBy ? this.sqlTurtleOrderByClause(orderBy) : '';
|
|
156
156
|
// BigQuery ARRAY_AGG takes LIMIT as its final sub-clause, after ORDER BY.
|
|
@@ -162,7 +162,7 @@ class StandardSQLDialect extends dialect_1.Dialect {
|
|
|
162
162
|
}
|
|
163
163
|
sqlAnyValueTurtle(groupSet, fieldList) {
|
|
164
164
|
const fields = fieldList
|
|
165
|
-
.map(f => `${f.sqlExpression} as ${f.
|
|
165
|
+
.map(f => `${f.sqlExpression} as ${this.sqlQuoteIdentifier(f.rawName)}`)
|
|
166
166
|
.join(', ');
|
|
167
167
|
return `ANY_VALUE(CASE WHEN group_set=${groupSet} THEN STRUCT(${fields}) END)`;
|
|
168
168
|
}
|
|
@@ -171,10 +171,10 @@ class StandardSQLDialect extends dialect_1.Dialect {
|
|
|
171
171
|
}
|
|
172
172
|
sqlCoaleseMeasuresInline(groupSet, fieldList) {
|
|
173
173
|
const fields = fieldList
|
|
174
|
-
.map(f => `${f.sqlExpression} as ${f.
|
|
174
|
+
.map(f => `${f.sqlExpression} as ${this.sqlQuoteIdentifier(f.rawName)}`)
|
|
175
175
|
.join(', ');
|
|
176
176
|
const nullValues = fieldList
|
|
177
|
-
.map(f => `NULL as ${f.
|
|
177
|
+
.map(f => `NULL as ${this.sqlQuoteIdentifier(f.rawName)}`)
|
|
178
178
|
.join(', ');
|
|
179
179
|
return `COALESCE(ANY_VALUE(CASE WHEN group_set=${groupSet} THEN STRUCT(${fields}) END), STRUCT(${nullValues}))`;
|
|
180
180
|
}
|
|
@@ -240,8 +240,11 @@ ${(0, utils_1.indent)(sql)}
|
|
|
240
240
|
sqlCreateFunctionCombineLastStage(lastStageName) {
|
|
241
241
|
return `SELECT ARRAY((SELECT AS STRUCT * FROM ${lastStageName}))\n`;
|
|
242
242
|
}
|
|
243
|
-
sqlSelectAliasAsStruct(alias) {
|
|
244
|
-
|
|
243
|
+
sqlSelectAliasAsStruct(alias, dialectFieldList) {
|
|
244
|
+
const fields = dialectFieldList
|
|
245
|
+
.map(d => `${alias}.${this.sqlQuoteIdentifier(d.rawName)}`)
|
|
246
|
+
.join(', ');
|
|
247
|
+
return `(SELECT AS STRUCT ${fields})`;
|
|
245
248
|
}
|
|
246
249
|
sqlNowExpr() {
|
|
247
250
|
return 'CURRENT_TIMESTAMP()';
|
|
@@ -249,18 +252,18 @@ ${(0, utils_1.indent)(sql)}
|
|
|
249
252
|
sqlTimeExtractExpr(qi, te) {
|
|
250
253
|
const extractTo = extractMap[te.units] || te.units;
|
|
251
254
|
const tz = malloy_types_1.TD.isAnyTimestamp(te.e.typeDef) && qtz(qi);
|
|
252
|
-
const tzAdd = tz ? ` AT TIME ZONE
|
|
255
|
+
const tzAdd = tz ? ` AT TIME ZONE ${this.sqlTimezoneLiteral(tz)}` : '';
|
|
253
256
|
return `EXTRACT(${extractTo} FROM ${te.e.sql}${tzAdd})`;
|
|
254
257
|
}
|
|
255
258
|
sqlConvertToCivilTime(expr, timezone, _typeDef) {
|
|
256
259
|
// BigQuery has no timestamptz type, so typeDef.timestamptz will never be true
|
|
257
260
|
return {
|
|
258
|
-
sql: `DATETIME(${expr},
|
|
261
|
+
sql: `DATETIME(${expr}, ${this.sqlTimezoneLiteral(timezone)})`,
|
|
259
262
|
typeDef: { type: 'timestamp' },
|
|
260
263
|
};
|
|
261
264
|
}
|
|
262
265
|
sqlConvertFromCivilTime(expr, timezone, _destTypeDef) {
|
|
263
|
-
return `TIMESTAMP(${expr},
|
|
266
|
+
return `TIMESTAMP(${expr}, ${this.sqlTimezoneLiteral(timezone)})`;
|
|
264
267
|
}
|
|
265
268
|
sqlTruncate(expr, unit, typeDef, inCivilTime, timezone) {
|
|
266
269
|
if (inCivilTime) {
|
|
@@ -272,7 +275,7 @@ ${(0, utils_1.indent)(sql)}
|
|
|
272
275
|
return `DATE_TRUNC(${expr}, ${unit})`;
|
|
273
276
|
}
|
|
274
277
|
// TIMESTAMP truncation with optional timezone
|
|
275
|
-
const tzParam = timezone ? `,
|
|
278
|
+
const tzParam = timezone ? `, ${this.sqlTimezoneLiteral(timezone)}` : '';
|
|
276
279
|
return `TIMESTAMP_TRUNC(${expr}, ${unit}${tzParam})`;
|
|
277
280
|
}
|
|
278
281
|
sqlOffsetTime(expr, op, magnitude, unit, typeDef, inCivilTime, _timezone) {
|
|
@@ -299,10 +302,10 @@ ${(0, utils_1.indent)(sql)}
|
|
|
299
302
|
const tz = qtz(qi);
|
|
300
303
|
const src = cast.e.sql || '';
|
|
301
304
|
if (op === 'timestamp::date' && tz) {
|
|
302
|
-
return `DATE(${src}
|
|
305
|
+
return `DATE(${src},${this.sqlTimezoneLiteral(tz)})`;
|
|
303
306
|
}
|
|
304
307
|
if (op === 'date::timestamp' && tz) {
|
|
305
|
-
return `TIMESTAMP(${src},
|
|
308
|
+
return `TIMESTAMP(${src}, ${this.sqlTimezoneLiteral(tz)})`;
|
|
306
309
|
}
|
|
307
310
|
if (!malloy_types_1.TD.eq(srcTypeDef, dstTypeDef)) {
|
|
308
311
|
const castFunc = cast.safe ? 'SAFE_CAST' : 'CAST';
|
|
@@ -320,7 +323,7 @@ ${(0, utils_1.indent)(sql)}
|
|
|
320
323
|
let timestampArgs = `'${literal}'`;
|
|
321
324
|
const tz = timezone || qtz(qi);
|
|
322
325
|
if (tz && tz !== 'UTC') {
|
|
323
|
-
timestampArgs +=
|
|
326
|
+
timestampArgs += `,${this.sqlTimezoneLiteral(tz)}`;
|
|
324
327
|
}
|
|
325
328
|
return `TIMESTAMP(${timestampArgs})`;
|
|
326
329
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Expr, Sampling, AtomicTypeDef, ATimestampTypeDef, TypecastExpr, RegexMatchExpr, MeasureTimeExpr, TimeExtractExpr, BasicAtomicTypeDef, RecordLiteralNode } from '../../model/malloy_types';
|
|
1
|
+
import type { Expr, Sampling, AtomicTypeDef, ATimestampTypeDef, TypecastExpr, RegexMatchExpr, MeasureTimeExpr, TimeExtractExpr, BasicAtomicTypeDef, RecordLiteralNode, OrderBy } from '../../model/malloy_types';
|
|
2
2
|
import type { DialectFunctionOverloadDef } from '../functions';
|
|
3
3
|
import type { CompiledOrderBy, DialectFieldList, OrderByClauseType, QueryInfo } from '../dialect';
|
|
4
4
|
import { PostgresBase } from '../pg_impl';
|
|
@@ -49,8 +49,8 @@ export declare class TrinoDialect extends PostgresBase {
|
|
|
49
49
|
sqlUnnestPipelineHead(isSingleton: boolean, sourceSQLExpression: string): string;
|
|
50
50
|
sqlCreateFunction(id: string, funcText: string): string;
|
|
51
51
|
sqlCreateTableAsSelect(tableName: string, sql: string): string;
|
|
52
|
-
sqlCreateFunctionCombineLastStage(lastStageName: string, fieldList: DialectFieldList): string;
|
|
53
|
-
sqlSelectAliasAsStruct(alias: string, fieldList:
|
|
52
|
+
sqlCreateFunctionCombineLastStage(lastStageName: string, fieldList: DialectFieldList, orderBy: OrderBy[] | undefined): string;
|
|
53
|
+
sqlSelectAliasAsStruct(alias: string, fieldList: DialectFieldList): string;
|
|
54
54
|
keywords: string[];
|
|
55
55
|
sqlConvertToCivilTime(expr: string, timezone: string, typeDef: AtomicTypeDef): {
|
|
56
56
|
sql: string;
|
|
@@ -82,7 +82,7 @@ class TrinoDialect extends pg_impl_1.PostgresBase {
|
|
|
82
82
|
this.orderByClause = 'output_name';
|
|
83
83
|
this.nullMatchesFunctionSignature = false;
|
|
84
84
|
this.supportsSelectReplace = false;
|
|
85
|
-
this.supportsComplexFilteredSources =
|
|
85
|
+
this.supportsComplexFilteredSources = true;
|
|
86
86
|
this.supportsTempTables = false;
|
|
87
87
|
this.supportsCountApprox = true;
|
|
88
88
|
this.supportsHyperLogLog = true;
|
|
@@ -223,7 +223,8 @@ class TrinoDialect extends pg_impl_1.PostgresBase {
|
|
|
223
223
|
}
|
|
224
224
|
buildTypeExpression(fieldList) {
|
|
225
225
|
return fieldList
|
|
226
|
-
.map(dlf => `${
|
|
226
|
+
.map(dlf => `${this.sqlQuoteIdentifier(dlf.rawName)} ` +
|
|
227
|
+
this.malloyTypeToSQLType(dlf.typeDef))
|
|
227
228
|
.join(', \n');
|
|
228
229
|
}
|
|
229
230
|
// can array agg or any_value a struct...
|
|
@@ -325,15 +326,18 @@ ${(0, utils_1.indent)(sql)}
|
|
|
325
326
|
);
|
|
326
327
|
`;
|
|
327
328
|
}
|
|
328
|
-
sqlCreateFunctionCombineLastStage(lastStageName, fieldList) {
|
|
329
|
+
sqlCreateFunctionCombineLastStage(lastStageName, fieldList, orderBy) {
|
|
329
330
|
const fields = fieldList.map(f => f.sqlExpression).join(', ');
|
|
330
331
|
const definitions = this.buildTypeExpression(fieldList);
|
|
331
|
-
|
|
332
|
+
const o = this.sqlCombineLastStageOrderBy(orderBy, fieldList);
|
|
333
|
+
return `SELECT ARRAY_AGG(CAST(ROW(${fields}) as ROW(${definitions}))${o}) FROM ${lastStageName}\n`;
|
|
332
334
|
}
|
|
333
335
|
sqlSelectAliasAsStruct(alias, fieldList) {
|
|
334
|
-
const fields = fieldList
|
|
336
|
+
const fields = fieldList
|
|
337
|
+
.map(f => `${alias}.${this.sqlQuoteIdentifier(f.rawName)}`)
|
|
338
|
+
.join(', ');
|
|
335
339
|
const definitions = this.buildTypeExpression(fieldList);
|
|
336
|
-
return `CAST(ROW(${fields}) as ROW(${definitions})`;
|
|
340
|
+
return `CAST(ROW(${fields}) as ROW(${definitions}))`;
|
|
337
341
|
}
|
|
338
342
|
sqlConvertToCivilTime(expr, timezone, typeDef) {
|
|
339
343
|
// Trino civil time = TIMESTAMPTZ with query timezone as stored timezone
|
|
@@ -341,13 +345,13 @@ ${(0, utils_1.indent)(sql)}
|
|
|
341
345
|
if (typeDef.type === 'timestamp') {
|
|
342
346
|
// TIMESTAMP (UTC wall clock) → TIMESTAMPTZ in query timezone
|
|
343
347
|
return {
|
|
344
|
-
sql: `at_timezone(with_timezone(${expr}, 'UTC'),
|
|
348
|
+
sql: `at_timezone(with_timezone(${expr}, 'UTC'), ${this.sqlTimezoneLiteral(timezone)})`,
|
|
345
349
|
typeDef: { type: 'timestamptz' },
|
|
346
350
|
};
|
|
347
351
|
}
|
|
348
352
|
// TIMESTAMPTZ → TIMESTAMPTZ in query timezone (same instant, different stored tz)
|
|
349
353
|
return {
|
|
350
|
-
sql: `at_timezone(${expr},
|
|
354
|
+
sql: `at_timezone(${expr}, ${this.sqlTimezoneLiteral(timezone)})`,
|
|
351
355
|
typeDef: { type: 'timestamptz' },
|
|
352
356
|
};
|
|
353
357
|
}
|
|
@@ -392,27 +396,27 @@ ${(0, utils_1.indent)(sql)}
|
|
|
392
396
|
if (tz && srcTypeDef && dstTypeDef) {
|
|
393
397
|
// TIMESTAMP → DATE: interpret as UTC, convert to query timezone
|
|
394
398
|
if (malloy_types_1.TD.isTimestamp(srcTypeDef) && malloy_types_1.TD.isDate(dstTypeDef)) {
|
|
395
|
-
return `CAST(at_timezone(with_timezone(${expr}, 'UTC'),
|
|
399
|
+
return `CAST(at_timezone(with_timezone(${expr}, 'UTC'), ${this.sqlTimezoneLiteral(tz)}) AS DATE)`;
|
|
396
400
|
}
|
|
397
401
|
// TIMESTAMPTZ → DATE: convert to query timezone
|
|
398
402
|
if (malloy_types_1.TD.isTimestamptz(srcTypeDef) && malloy_types_1.TD.isDate(dstTypeDef)) {
|
|
399
|
-
return `CAST(at_timezone(${expr},
|
|
403
|
+
return `CAST(at_timezone(${expr}, ${this.sqlTimezoneLiteral(tz)}) AS DATE)`;
|
|
400
404
|
}
|
|
401
405
|
// DATE → TIMESTAMP: interpret date in query timezone, return UTC wall clock
|
|
402
406
|
if (malloy_types_1.TD.isDate(srcTypeDef) && malloy_types_1.TD.isTimestamp(dstTypeDef)) {
|
|
403
|
-
return `CAST(at_timezone(with_timezone(CAST(${expr} AS TIMESTAMP),
|
|
407
|
+
return `CAST(at_timezone(with_timezone(CAST(${expr} AS TIMESTAMP), ${this.sqlTimezoneLiteral(tz)}), 'UTC') AS TIMESTAMP)`;
|
|
404
408
|
}
|
|
405
409
|
// DATE → TIMESTAMPTZ: interpret date in query timezone
|
|
406
410
|
if (malloy_types_1.TD.isDate(srcTypeDef) && malloy_types_1.TD.isTimestamptz(dstTypeDef)) {
|
|
407
|
-
return `with_timezone(CAST(${expr} AS TIMESTAMP),
|
|
411
|
+
return `with_timezone(CAST(${expr} AS TIMESTAMP), ${this.sqlTimezoneLiteral(tz)})`;
|
|
408
412
|
}
|
|
409
413
|
// TIMESTAMPTZ → TIMESTAMP: convert to query timezone wall clock
|
|
410
414
|
if (malloy_types_1.TD.isTimestamptz(srcTypeDef) && malloy_types_1.TD.isTimestamp(dstTypeDef)) {
|
|
411
|
-
return `CAST(at_timezone(${expr},
|
|
415
|
+
return `CAST(at_timezone(${expr}, ${this.sqlTimezoneLiteral(tz)}) AS TIMESTAMP)`;
|
|
412
416
|
}
|
|
413
417
|
// TIMESTAMP → TIMESTAMPTZ: interpret TIMESTAMP as being in query timezone
|
|
414
418
|
if (malloy_types_1.TD.isTimestamp(srcTypeDef) && malloy_types_1.TD.isTimestamptz(dstTypeDef)) {
|
|
415
|
-
return `with_timezone(${expr},
|
|
419
|
+
return `with_timezone(${expr}, ${this.sqlTimezoneLiteral(tz)})`;
|
|
416
420
|
}
|
|
417
421
|
}
|
|
418
422
|
// No special handling needed, or no query timezone
|
|
@@ -567,13 +571,13 @@ ${(0, utils_1.indent)(sql)}
|
|
|
567
571
|
const tz = timezone || qtz(qi);
|
|
568
572
|
if (tz) {
|
|
569
573
|
// Interpret wall clock time in timezone, convert to UTC wall clock, cast to TIMESTAMP
|
|
570
|
-
return `CAST(at_timezone(with_timezone(TIMESTAMP '${literal}',
|
|
574
|
+
return `CAST(at_timezone(with_timezone(TIMESTAMP '${literal}', ${this.sqlTimezoneLiteral(tz)}), 'UTC') AS TIMESTAMP)`;
|
|
571
575
|
}
|
|
572
576
|
return `TIMESTAMP '${literal}'`;
|
|
573
577
|
}
|
|
574
578
|
sqlTimestamptzLiteral(_qi, literal, timezone) {
|
|
575
579
|
// Use with_timezone to create a TIMESTAMP WITH TIME ZONE
|
|
576
|
-
return `with_timezone(TIMESTAMP '${literal}',
|
|
580
|
+
return `with_timezone(TIMESTAMP '${literal}', ${this.sqlTimezoneLiteral(timezone)})`;
|
|
577
581
|
}
|
|
578
582
|
sqlTimeExtractExpr(qi, from) {
|
|
579
583
|
const pgUnits = pg_impl_1.timeExtractMap[from.units] || from.units;
|
|
@@ -584,11 +588,11 @@ ${(0, utils_1.indent)(sql)}
|
|
|
584
588
|
// Convert both TIMESTAMP and TIMESTAMPTZ to query timezone for extraction
|
|
585
589
|
if (from.e.typeDef.type === 'timestamp') {
|
|
586
590
|
// TIMESTAMP: interpret as UTC, convert to query timezone
|
|
587
|
-
extractFrom = `at_timezone(with_timezone(${extractFrom}, 'UTC'),
|
|
591
|
+
extractFrom = `at_timezone(with_timezone(${extractFrom}, 'UTC'), ${this.sqlTimezoneLiteral(tz)})`;
|
|
588
592
|
}
|
|
589
593
|
else {
|
|
590
594
|
// TIMESTAMPTZ: convert to query timezone
|
|
591
|
-
extractFrom = `at_timezone(${extractFrom},
|
|
595
|
+
extractFrom = `at_timezone(${extractFrom}, ${this.sqlTimezoneLiteral(tz)})`;
|
|
592
596
|
}
|
|
593
597
|
}
|
|
594
598
|
}
|
|
@@ -628,18 +632,18 @@ class PrestoDialect extends TrinoDialect {
|
|
|
628
632
|
sqlTimestampLiteral(qi, literal, timezone) {
|
|
629
633
|
const tz = timezone || qtz(qi);
|
|
630
634
|
if (tz) {
|
|
631
|
-
return `CAST(TIMESTAMP '${literal} ${tz}' AT TIME ZONE 'UTC' AS TIMESTAMP)`;
|
|
635
|
+
return `CAST(TIMESTAMP '${literal} ${this.checkedTimezoneName(tz)}' AT TIME ZONE 'UTC' AS TIMESTAMP)`;
|
|
632
636
|
}
|
|
633
637
|
return `TIMESTAMP '${literal}'`;
|
|
634
638
|
}
|
|
635
639
|
sqlTimestamptzLiteral(_qi, literal, timezone) {
|
|
636
|
-
return `TIMESTAMP '${literal} ${timezone}'`;
|
|
640
|
+
return `TIMESTAMP '${literal} ${this.checkedTimezoneName(timezone)}'`;
|
|
637
641
|
}
|
|
638
642
|
sqlConvertToCivilTime(expr, timezone, _typeDef) {
|
|
639
643
|
// Presto's AT TIME ZONE operator (not function) produces TIMESTAMPTZ
|
|
640
644
|
// Reinterprets the instant in the target timezone
|
|
641
645
|
return {
|
|
642
|
-
sql: `${expr} AT TIME ZONE
|
|
646
|
+
sql: `${expr} AT TIME ZONE ${this.sqlTimezoneLiteral(timezone)}`,
|
|
643
647
|
typeDef: { type: 'timestamptz' },
|
|
644
648
|
};
|
|
645
649
|
}
|
|
@@ -658,26 +662,26 @@ class PrestoDialect extends TrinoDialect {
|
|
|
658
662
|
if (tz && srcTypeDef && dstTypeDef) {
|
|
659
663
|
// TIMESTAMP → DATE: interpret as UTC, convert to query timezone
|
|
660
664
|
if (malloy_types_1.TD.isTimestamp(srcTypeDef) && malloy_types_1.TD.isDate(dstTypeDef)) {
|
|
661
|
-
return `CAST((${expr} AT TIME ZONE 'UTC') AT TIME ZONE
|
|
665
|
+
return `CAST((${expr} AT TIME ZONE 'UTC') AT TIME ZONE ${this.sqlTimezoneLiteral(tz)} AS DATE)`;
|
|
662
666
|
}
|
|
663
667
|
// TIMESTAMPTZ → DATE: convert to query timezone
|
|
664
668
|
if (malloy_types_1.TD.isTimestamptz(srcTypeDef) && malloy_types_1.TD.isDate(dstTypeDef)) {
|
|
665
|
-
return `CAST(${expr} AT TIME ZONE
|
|
669
|
+
return `CAST(${expr} AT TIME ZONE ${this.sqlTimezoneLiteral(tz)} AS DATE)`;
|
|
666
670
|
}
|
|
667
671
|
// DATE → TIMESTAMP: interpret date in query timezone, return UTC wall clock
|
|
668
672
|
// Presto doesn't have a way to interpret TIMESTAMP in a non-UTC timezone,
|
|
669
673
|
// so we build a TIMESTAMPTZ literal string and cast it
|
|
670
674
|
if (malloy_types_1.TD.isDate(srcTypeDef) && malloy_types_1.TD.isTimestamp(dstTypeDef)) {
|
|
671
|
-
const tstzLiteral = `CAST(CAST(${expr} AS VARCHAR) || ' 00:00:00 ${tz}' AS TIMESTAMP WITH TIME ZONE)`;
|
|
675
|
+
const tstzLiteral = `CAST(CAST(${expr} AS VARCHAR) || ' 00:00:00 ${this.checkedTimezoneName(tz)}' AS TIMESTAMP WITH TIME ZONE)`;
|
|
672
676
|
return `CAST(${tstzLiteral} AS TIMESTAMP)`;
|
|
673
677
|
}
|
|
674
678
|
// DATE → TIMESTAMPTZ: interpret date in query timezone
|
|
675
679
|
if (malloy_types_1.TD.isDate(srcTypeDef) && malloy_types_1.TD.isTimestamptz(dstTypeDef)) {
|
|
676
|
-
return `CAST(CAST(${expr} AS VARCHAR) || ' 00:00:00 ${tz}' AS TIMESTAMP WITH TIME ZONE)`;
|
|
680
|
+
return `CAST(CAST(${expr} AS VARCHAR) || ' 00:00:00 ${this.checkedTimezoneName(tz)}' AS TIMESTAMP WITH TIME ZONE)`;
|
|
677
681
|
}
|
|
678
682
|
// TIMESTAMPTZ → TIMESTAMP: convert to query timezone wall clock
|
|
679
683
|
if (malloy_types_1.TD.isTimestamptz(srcTypeDef) && malloy_types_1.TD.isTimestamp(dstTypeDef)) {
|
|
680
|
-
return `CAST(${expr} AT TIME ZONE
|
|
684
|
+
return `CAST(${expr} AT TIME ZONE ${this.sqlTimezoneLiteral(tz)} AS TIMESTAMP)`;
|
|
681
685
|
}
|
|
682
686
|
// TIMESTAMP → TIMESTAMPTZ: interpret TIMESTAMP as UTC
|
|
683
687
|
if (malloy_types_1.TD.isTimestamp(srcTypeDef) && malloy_types_1.TD.isTimestamptz(dstTypeDef)) {
|
|
@@ -701,11 +705,11 @@ class PrestoDialect extends TrinoDialect {
|
|
|
701
705
|
if (from.e.typeDef.type === 'timestamp') {
|
|
702
706
|
// TIMESTAMP: interpret as UTC, convert to query timezone
|
|
703
707
|
// Presto uses AT TIME ZONE operator
|
|
704
|
-
extractFrom = `(${extractFrom} AT TIME ZONE 'UTC') AT TIME ZONE
|
|
708
|
+
extractFrom = `(${extractFrom} AT TIME ZONE 'UTC') AT TIME ZONE ${this.sqlTimezoneLiteral(tz)}`;
|
|
705
709
|
}
|
|
706
710
|
else {
|
|
707
711
|
// TIMESTAMPTZ: convert to query timezone
|
|
708
|
-
extractFrom = `${extractFrom} AT TIME ZONE
|
|
712
|
+
extractFrom = `${extractFrom} AT TIME ZONE ${this.sqlTimezoneLiteral(tz)}`;
|
|
709
713
|
}
|
|
710
714
|
}
|
|
711
715
|
}
|
|
@@ -81,7 +81,7 @@ class RefinedSource extends source_1.Source {
|
|
|
81
81
|
filters.push(el);
|
|
82
82
|
}
|
|
83
83
|
else if (el instanceof timezone_statement_1.TimezoneStatement) {
|
|
84
|
-
newTimezone = el.
|
|
84
|
+
newTimezone = el.timezoneName();
|
|
85
85
|
}
|
|
86
86
|
else {
|
|
87
87
|
errTo.logError('unexpected-source-property', `Unexpected source property: '${errTo.elementType}'`);
|
|
@@ -19,12 +19,13 @@ class SQLSource extends source_1.Source {
|
|
|
19
19
|
this.connectionNameInvalid = false;
|
|
20
20
|
}
|
|
21
21
|
sqlSourceRequest(doc) {
|
|
22
|
+
var _a;
|
|
22
23
|
const partialModel = this.select.containsQueries
|
|
23
24
|
? doc.modelDef()
|
|
24
25
|
: undefined;
|
|
25
26
|
const [valid, phrases] = this.select.sqlPhrases(this.connectionName.refString);
|
|
26
27
|
if (valid) {
|
|
27
|
-
return (0, sql_block_1.getSourceRequest)(phrases, this.connectionName.refString, partialModel);
|
|
28
|
+
return (0, sql_block_1.getSourceRequest)(phrases, this.connectionName.refString, partialModel, (_a = this.translator()) === null || _a === void 0 ? void 0 : _a.root.virtualMap);
|
|
28
29
|
}
|
|
29
30
|
return undefined;
|
|
30
31
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import type { ExprString } from '../expressions/expr-string';
|
|
1
2
|
import type { QueryBuilder } from '../types/query-builder';
|
|
2
3
|
import { MalloyElement } from '../types/malloy-element';
|
|
3
4
|
import type { QueryPropertyInterface } from '../types/query-property-interface';
|
|
4
5
|
export declare class TimezoneStatement extends MalloyElement implements QueryPropertyInterface {
|
|
5
|
-
readonly
|
|
6
|
+
private readonly timezone;
|
|
6
7
|
elementType: string;
|
|
7
8
|
forceQueryClass: undefined;
|
|
8
9
|
queryRefinementStage: undefined;
|
|
9
|
-
constructor(
|
|
10
|
-
|
|
10
|
+
constructor(timezone: ExprString);
|
|
11
|
+
timezoneName(): string | undefined;
|
|
11
12
|
queryExecute(executeFor: QueryBuilder): void;
|
|
12
13
|
}
|
|
@@ -5,27 +5,29 @@
|
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.TimezoneStatement = void 0;
|
|
8
|
+
const dialect_1 = require("../../../dialect/dialect");
|
|
8
9
|
const malloy_element_1 = require("../types/malloy-element");
|
|
9
|
-
const luxon_1 = require("luxon");
|
|
10
10
|
class TimezoneStatement extends malloy_element_1.MalloyElement {
|
|
11
|
-
constructor(
|
|
12
|
-
super();
|
|
13
|
-
this.
|
|
11
|
+
constructor(timezone) {
|
|
12
|
+
super({ timezone });
|
|
13
|
+
this.timezone = timezone;
|
|
14
14
|
this.elementType = 'timezone';
|
|
15
15
|
this.forceQueryClass = undefined;
|
|
16
16
|
this.queryRefinementStage = undefined;
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
catch {
|
|
24
|
-
return false;
|
|
18
|
+
timezoneName() {
|
|
19
|
+
const name = this.timezone.value;
|
|
20
|
+
if (!dialect_1.Dialect.isSafeTimezoneName(name)) {
|
|
21
|
+
this.logError('invalid-timezone', { timezone: name }, { at: this.timezone.location });
|
|
22
|
+
return undefined;
|
|
25
23
|
}
|
|
24
|
+
return name;
|
|
26
25
|
}
|
|
27
26
|
queryExecute(executeFor) {
|
|
28
|
-
|
|
27
|
+
const timezone = this.timezoneName();
|
|
28
|
+
if (timezone !== undefined) {
|
|
29
|
+
executeFor.resultFS.setTimezone(timezone);
|
|
30
|
+
}
|
|
29
31
|
}
|
|
30
32
|
}
|
|
31
33
|
exports.TimezoneStatement = TimezoneStatement;
|
|
@@ -407,9 +407,11 @@ function expandRefUsage(seed, fields, alwaysJoinNames = []) {
|
|
|
407
407
|
// given usage into the accumulator. Used both in-loop (joins reached
|
|
408
408
|
// via reference paths) and upfront (always-on segment-level joins).
|
|
409
409
|
function activateJoin(joinDef, joinPath) {
|
|
410
|
+
if (!(0, malloy_types_1.isJoined)(joinDef))
|
|
411
|
+
return;
|
|
410
412
|
const joinKey = (0, utils_2.pathToKey)('join', joinPath);
|
|
411
413
|
const thisDep = getJoin(activeJoinGraph, joinKey, joinPath);
|
|
412
|
-
if (
|
|
414
|
+
if (thisDep.checked)
|
|
413
415
|
return;
|
|
414
416
|
thisDep.checked = true;
|
|
415
417
|
const joinFieldUsage = getJoinFieldUsage(joinDef, joinPath);
|
|
@@ -462,8 +464,13 @@ function expandRefUsage(seed, fields, alwaysJoinNames = []) {
|
|
|
462
464
|
ungroupings.push(...joinedUngroupings(refPath, def.ungroupings));
|
|
463
465
|
}
|
|
464
466
|
}
|
|
465
|
-
//
|
|
466
|
-
|
|
467
|
+
// Track the joins along the path. A path which ends at a join and carries
|
|
468
|
+
// a unique key requirement is an aggregate computed over that join's rows,
|
|
469
|
+
// which should then include the join's on-clause fields in the field usage.
|
|
470
|
+
// A path which merely names a join-typed value does not.
|
|
471
|
+
const endsInTraversedJoin = reference.uniqueKeyRequirement !== undefined;
|
|
472
|
+
const joinDepth = reference.path.length - (endsInTraversedJoin ? 0 : 1);
|
|
473
|
+
for (let joinLen = 1; joinLen <= joinDepth; joinLen++) {
|
|
467
474
|
const joinPath = reference.path.slice(0, joinLen);
|
|
468
475
|
const joinDef = inNamespace(joinPath, fieldNameSpace);
|
|
469
476
|
if (!joinDef)
|
|
@@ -803,14 +803,8 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
|
|
|
803
803
|
return this.visitTimezoneStatement(cx.timezoneStatement());
|
|
804
804
|
}
|
|
805
805
|
visitTimezoneStatement(cx) {
|
|
806
|
-
const timezone = this.getPlainStringFrom(cx);
|
|
807
|
-
|
|
808
|
-
if (!timezoneStatement.isValid) {
|
|
809
|
-
this.astError(timezoneStatement, 'invalid-timezone', {
|
|
810
|
-
timezone: timezoneStatement.tz,
|
|
811
|
-
});
|
|
812
|
-
}
|
|
813
|
-
return this.astAt(timezoneStatement, cx);
|
|
806
|
+
const timezone = this.astAt(new ast.ExprString(this.getPlainStringFrom(cx)), cx.string());
|
|
807
|
+
return this.astAt(new ast.TimezoneStatement(timezone), cx);
|
|
814
808
|
}
|
|
815
809
|
visitQueryProperties(pcx) {
|
|
816
810
|
const qProps = this.only(pcx.queryStatement().map(qcx => this.astAt(this.visit(qcx), qcx)), x => ast.isQueryProperty(x) && x, 'query statement');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DocumentLocation, DocumentPosition, DocumentReference, ImportLocation, ModelDef, SourceDef, SQLSourceDef, DependencyTree, DocumentRange } from '../model/malloy_types';
|
|
1
|
+
import type { DocumentLocation, DocumentPosition, DocumentReference, ImportLocation, ModelDef, SourceDef, SQLSourceDef, DependencyTree, DocumentRange, VirtualMap } from '../model/malloy_types';
|
|
2
2
|
import type { LogMessage, LogMessageOptions, MessageCode, MessageParameterType } from './parse-log';
|
|
3
3
|
import { BaseMessageLogger } from './parse-log';
|
|
4
4
|
import type { ZoneData } from './zone';
|
|
@@ -186,6 +186,7 @@ export declare class MalloyChildTranslator extends MalloyTranslation {
|
|
|
186
186
|
export declare class MalloyTranslator extends MalloyTranslation {
|
|
187
187
|
private readonly eventStream;
|
|
188
188
|
readonly restrictedMode: boolean;
|
|
189
|
+
virtualMap?: VirtualMap | undefined;
|
|
189
190
|
schemaZone: Zone<SourceDef>;
|
|
190
191
|
importZone: Zone<string>;
|
|
191
192
|
pretranslatedModels: Map<string, ModelDef>;
|
|
@@ -193,7 +194,7 @@ export declare class MalloyTranslator extends MalloyTranslation {
|
|
|
193
194
|
connectionDialectZone: Zone<string>;
|
|
194
195
|
logger: BaseMessageLogger;
|
|
195
196
|
readonly root: MalloyTranslator;
|
|
196
|
-
constructor(rootURL: string, importURL?: string | null, preload?: ParseUpdate | null, eventStream?: EventStream | null, restrictedMode?: boolean);
|
|
197
|
+
constructor(rootURL: string, importURL?: string | null, preload?: ParseUpdate | null, eventStream?: EventStream | null, restrictedMode?: boolean, virtualMap?: VirtualMap | undefined);
|
|
197
198
|
update(dd: ParseUpdate): void;
|
|
198
199
|
private lockZonesIfRestricted;
|
|
199
200
|
translate(extendingModel?: ModelDef): TranslateResponse;
|
|
@@ -780,10 +780,11 @@ exports.MalloyChildTranslator = MalloyChildTranslator;
|
|
|
780
780
|
* no need to call again, the translation is finished or error'd.
|
|
781
781
|
*/
|
|
782
782
|
class MalloyTranslator extends MalloyTranslation {
|
|
783
|
-
constructor(rootURL, importURL = null, preload = null, eventStream = null, restrictedMode = false) {
|
|
783
|
+
constructor(rootURL, importURL = null, preload = null, eventStream = null, restrictedMode = false, virtualMap) {
|
|
784
784
|
super(rootURL, importURL);
|
|
785
785
|
this.eventStream = eventStream;
|
|
786
786
|
this.restrictedMode = restrictedMode;
|
|
787
|
+
this.virtualMap = virtualMap;
|
|
787
788
|
this.schemaZone = new zone_1.Zone();
|
|
788
789
|
this.importZone = new zone_1.Zone();
|
|
789
790
|
this.pretranslatedModels = new Map();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DocumentLocation, FieldDef, ModelDef, NamedModelObject, PipeSegment, Query, QueryFieldDef, StructDef, TurtleDef, SourceDef, TableSourceDef, SQLSourceDef, UserTypeDef } from '../../model/malloy_types';
|
|
1
|
+
import type { DocumentLocation, FieldDef, ModelDef, NamedModelObject, PipeSegment, Query, QueryFieldDef, StructDef, TurtleDef, SourceDef, TableSourceDef, SQLSourceDef, UserTypeDef, VirtualMap } from '../../model/malloy_types';
|
|
2
2
|
import { MalloyElement } from '../ast';
|
|
3
3
|
import type { NameSpace } from '../ast/types/name-space';
|
|
4
4
|
import type { ModelEntry } from '../ast/types/model-entry';
|
|
@@ -56,6 +56,7 @@ export interface TestTranslatorOptions {
|
|
|
56
56
|
eventStream?: EventStream | null;
|
|
57
57
|
internalModel?: ModelDef;
|
|
58
58
|
restrictedMode?: boolean;
|
|
59
|
+
virtualMap?: VirtualMap;
|
|
59
60
|
/**
|
|
60
61
|
* Each entry is a compiler-flag tag fragment — the content that
|
|
61
62
|
* would follow `##! ` in a Malloy source annotation. Rendered to
|
|
@@ -339,7 +339,7 @@ const testURI = 'internal://test/langtests/root.malloy';
|
|
|
339
339
|
class TestTranslator extends parse_malloy_1.MalloyTranslator {
|
|
340
340
|
constructor(testSrc, options = {}) {
|
|
341
341
|
var _a, _b, _c, _d, _e;
|
|
342
|
-
super(testURI, (_a = options.importBaseURL) !== null && _a !== void 0 ? _a : null, null, (_b = options.eventStream) !== null && _b !== void 0 ? _b : null, (_c = options.restrictedMode) !== null && _c !== void 0 ? _c : false);
|
|
342
|
+
super(testURI, (_a = options.importBaseURL) !== null && _a !== void 0 ? _a : null, null, (_b = options.eventStream) !== null && _b !== void 0 ? _b : null, (_c = options.restrictedMode) !== null && _c !== void 0 ? _c : false, options.virtualMap);
|
|
343
343
|
this.testSrc = testSrc;
|
|
344
344
|
this.allDialectsEnabled = true;
|
|
345
345
|
/*
|
|
@@ -12,6 +12,7 @@ export declare class JoinInstance {
|
|
|
12
12
|
joinFilterConditions?: QueryFieldBoolean[];
|
|
13
13
|
children: JoinInstance[];
|
|
14
14
|
constructor(queryStruct: QueryStruct, alias: string, parent: JoinInstance | undefined);
|
|
15
|
+
isSubquery(): boolean;
|
|
15
16
|
parentRelationship(): 'root' | JoinRelationship;
|
|
16
17
|
forceAllSymmetricCalculations(): boolean;
|
|
17
18
|
getDialectFieldList(): DialectFieldList;
|