@malloydata/malloy 0.0.435 → 0.0.436
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +4 -12
- 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/pick-when.js +7 -0
- 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/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/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/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
|
@@ -33,6 +33,7 @@ function refine(logTo, refineTo, refineFrom) {
|
|
|
33
33
|
if (from.orderBy !== undefined && !from.defaultOrderBy) {
|
|
34
34
|
if (to.orderBy === undefined || to.defaultOrderBy) {
|
|
35
35
|
to.orderBy = from.orderBy;
|
|
36
|
+
delete to.defaultOrderBy;
|
|
36
37
|
}
|
|
37
38
|
else {
|
|
38
39
|
logTo.logError('ordering-overridden-in-refinement', 'refinement cannot override existing ordering');
|
|
@@ -28,6 +28,7 @@ exports.pathBegins = pathBegins;
|
|
|
28
28
|
exports.hasCompositesAnywhere = hasCompositesAnywhere;
|
|
29
29
|
exports.logCompositeError = logCompositeError;
|
|
30
30
|
const malloy_filter_1 = require("@malloydata/malloy-filter");
|
|
31
|
+
const sql_compiled_1 = require("../model/sql_compiled");
|
|
31
32
|
const malloy_types_1 = require("../model/malloy_types");
|
|
32
33
|
const utils_1 = require("./utils");
|
|
33
34
|
const utils_2 = require("../model/utils");
|
|
@@ -1214,9 +1215,12 @@ function computeQueryGivenUsage(pipeline) {
|
|
|
1214
1215
|
return result;
|
|
1215
1216
|
}
|
|
1216
1217
|
// Returns every given a SourceDef references — its own filterList plus any
|
|
1217
|
-
// givens hiding inside an embedded Query.
|
|
1218
|
-
//
|
|
1219
|
-
//
|
|
1218
|
+
// givens hiding inside an embedded Query. For a persistable source the
|
|
1219
|
+
// embedded part is `givenUsageOfRelation` (model/sql_compiled.ts), which is
|
|
1220
|
+
// also what persistence keys a table on; the filterList is added here because
|
|
1221
|
+
// a query over the source applies it, but a table built from the source does
|
|
1222
|
+
// not. When a future SourceDef variant grows an embedded Query, teach that
|
|
1223
|
+
// helper or this one.
|
|
1220
1224
|
//
|
|
1221
1225
|
// Composite sources: composite-source support across the codebase is
|
|
1222
1226
|
// partial; the givens work isn't chasing it. The `composite` arm here is
|
|
@@ -1226,23 +1230,12 @@ function computeQueryGivenUsage(pipeline) {
|
|
|
1226
1230
|
// reaches here (e.g. composites in join positions if/when those work),
|
|
1227
1231
|
// the conservative union over all branches is the safe fallback.
|
|
1228
1232
|
function givenUsageOfSource(sd) {
|
|
1229
|
-
var _a
|
|
1233
|
+
var _a;
|
|
1230
1234
|
const fromFilters = ((_a = sd.filterList) !== null && _a !== void 0 ? _a : []).flatMap(f => (0, malloy_types_1.givenUsageFrom)(f.refSummary));
|
|
1231
1235
|
switch (sd.type) {
|
|
1232
1236
|
case 'query_source':
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
const fromSegments = ((_c = sd.selectSegments) !== null && _c !== void 0 ? _c : []).flatMap(seg => {
|
|
1236
|
-
var _a;
|
|
1237
|
-
if ((0, malloy_types_1.isSegmentSQL)(seg))
|
|
1238
|
-
return [];
|
|
1239
|
-
if ((0, malloy_types_1.isSegmentSource)(seg))
|
|
1240
|
-
return givenUsageOfSource(seg);
|
|
1241
|
-
// Remaining variant of SQLPhraseSegment is `Query`
|
|
1242
|
-
return (_a = seg.givenUsage) !== null && _a !== void 0 ? _a : [];
|
|
1243
|
-
});
|
|
1244
|
-
return [...fromFilters, ...fromSegments];
|
|
1245
|
-
}
|
|
1237
|
+
case 'sql_select':
|
|
1238
|
+
return [...fromFilters, ...(0, sql_compiled_1.givenUsageOfRelation)(sd)];
|
|
1246
1239
|
case 'composite':
|
|
1247
1240
|
return [
|
|
1248
1241
|
...fromFilters,
|
package/dist/lang/parse-log.d.ts
CHANGED
|
@@ -64,6 +64,17 @@ type MessageParameterTypes = {
|
|
|
64
64
|
'nesting-unsupported': {
|
|
65
65
|
dialect: string;
|
|
66
66
|
};
|
|
67
|
+
'boolean-value-unsupported': {
|
|
68
|
+
dialect: string;
|
|
69
|
+
where: string;
|
|
70
|
+
hint: string;
|
|
71
|
+
};
|
|
72
|
+
'wildcard-omits-boolean': {
|
|
73
|
+
dialect: string;
|
|
74
|
+
wildcard: string;
|
|
75
|
+
name: string;
|
|
76
|
+
hint: string;
|
|
77
|
+
};
|
|
67
78
|
'nested-multi-stage-unsupported': {
|
|
68
79
|
dialect: string;
|
|
69
80
|
};
|
|
@@ -297,6 +308,7 @@ type MessageParameterTypes = {
|
|
|
297
308
|
'export-name-not-exportable': string;
|
|
298
309
|
'duplicate-export-name': string;
|
|
299
310
|
'unsatisfied-given-in-query': string;
|
|
311
|
+
'unsatisfied-given-in-persist-source': string;
|
|
300
312
|
'given-alias-collision': string;
|
|
301
313
|
'failed-to-compute-output-schema': string;
|
|
302
314
|
'invalid-timeframe-for-time-offset': string;
|
package/dist/lang/parse-log.js
CHANGED
|
@@ -56,6 +56,8 @@ exports.MESSAGE_FORMATTERS = {
|
|
|
56
56
|
}),
|
|
57
57
|
'experimental-dialect-not-enabled': e => `Requires compiler flag '##! experimental.dialect.${e.dialect}'`,
|
|
58
58
|
'nesting-unsupported': e => `'${e.dialect}' does not support nested queries`,
|
|
59
|
+
'boolean-value-unsupported': e => `'${e.dialect}' does not support a boolean ${e.where}; ${e.hint}`,
|
|
60
|
+
'wildcard-omits-boolean': e => `'${e.name}' is left out of '${e.wildcard}': '${e.dialect}' does not support a boolean as a result column; ${e.hint}`,
|
|
59
61
|
'nested-multi-stage-unsupported': e => `'${e.dialect}' does not support a multi-stage pipeline ('->') in a nested query`,
|
|
60
62
|
'nested-projection-limit-unsupported': e => `'${e.dialect}' does not support 'limit:' on a nested 'select:'`,
|
|
61
63
|
'pick-missing-else': "pick incomplete, missing 'else'",
|
|
@@ -29,6 +29,7 @@ export declare const aTableDef: TableSourceDef;
|
|
|
29
29
|
export declare const db2TableDef: TableSourceDef;
|
|
30
30
|
export declare const bqTableDef: SourceDef;
|
|
31
31
|
export declare const pgTableDef: SourceDef;
|
|
32
|
+
export declare const mssqlTableDef: SourceDef;
|
|
32
33
|
/**
|
|
33
34
|
* A TestTranlator never actually talks to connection, instead uses
|
|
34
35
|
* some mocked schema definitions.
|
|
@@ -69,7 +70,7 @@ export interface TestTranslatorOptions {
|
|
|
69
70
|
}
|
|
70
71
|
/**
|
|
71
72
|
* Every connection name a test mentions resolves to a dialect, as it would
|
|
72
|
-
* through a host's connection lookup: the
|
|
73
|
+
* through a host's connection lookup: the five listed below to theirs, and
|
|
73
74
|
* any other name to `TEST_DIALECT`.
|
|
74
75
|
*/
|
|
75
76
|
declare class TestConnectionDialectZone extends Zone<string> {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* SPDX-License-Identifier: MIT
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.BetaExpression = exports.TestTranslator = exports.TestChildTranslator = exports.mockSchema = exports.pgTableDef = exports.bqTableDef = exports.db2TableDef = exports.aTableDef = exports.TEST_DIALECT = void 0;
|
|
8
|
+
exports.BetaExpression = exports.TestTranslator = exports.TestChildTranslator = exports.mockSchema = exports.mssqlTableDef = exports.pgTableDef = exports.bqTableDef = exports.db2TableDef = exports.aTableDef = exports.TEST_DIALECT = void 0;
|
|
9
9
|
exports.pretty = pretty;
|
|
10
10
|
exports.humanify = humanify;
|
|
11
11
|
exports.getExplore = getExplore;
|
|
@@ -194,6 +194,16 @@ exports.pgTableDef = {
|
|
|
194
194
|
connection: '_pg_',
|
|
195
195
|
fields: baseFields,
|
|
196
196
|
};
|
|
197
|
+
// SQL Server has no boolean values (booleanType 'none'), so no column of
|
|
198
|
+
// its table is a boolean
|
|
199
|
+
exports.mssqlTableDef = {
|
|
200
|
+
type: 'table',
|
|
201
|
+
name: 'aTable',
|
|
202
|
+
dialect: 'sqlserver',
|
|
203
|
+
tablePath: 'aTable',
|
|
204
|
+
connection: '_mssql_',
|
|
205
|
+
fields: baseFields.filter(f => f.name !== 'abool'),
|
|
206
|
+
};
|
|
197
207
|
/**
|
|
198
208
|
* A TestTranlator never actually talks to connection, instead uses
|
|
199
209
|
* some mocked schema definitions.
|
|
@@ -203,6 +213,7 @@ exports.mockSchema = [
|
|
|
203
213
|
exports.db2TableDef,
|
|
204
214
|
exports.bqTableDef,
|
|
205
215
|
exports.pgTableDef,
|
|
216
|
+
exports.mssqlTableDef,
|
|
206
217
|
{
|
|
207
218
|
type: 'table',
|
|
208
219
|
name: 'carriers',
|
|
@@ -339,7 +350,7 @@ exports.TestChildTranslator = TestChildTranslator;
|
|
|
339
350
|
const testURI = 'internal://test/langtests/root.malloy';
|
|
340
351
|
/**
|
|
341
352
|
* Every connection name a test mentions resolves to a dialect, as it would
|
|
342
|
-
* through a host's connection lookup: the
|
|
353
|
+
* through a host's connection lookup: the five listed below to theirs, and
|
|
343
354
|
* any other name to `TEST_DIALECT`.
|
|
344
355
|
*/
|
|
345
356
|
class TestConnectionDialectZone extends zone_1.Zone {
|
|
@@ -357,7 +368,7 @@ class TestTranslator extends parse_malloy_1.MalloyTranslator {
|
|
|
357
368
|
this.testSrc = testSrc;
|
|
358
369
|
this.connectionDialectZone = new TestConnectionDialectZone();
|
|
359
370
|
/*
|
|
360
|
-
* There are
|
|
371
|
+
* There are five connections:
|
|
361
372
|
* _db_ - duckdb dialect, with the following tables ...
|
|
362
373
|
* aTable, malloytest.carriers, malloytest.flights, malloytest.airports
|
|
363
374
|
* _db2_ - duckdb dialect, with one table, aTable. A second connection
|
|
@@ -366,6 +377,8 @@ class TestTranslator extends parse_malloy_1.MalloyTranslator {
|
|
|
366
377
|
* aTable
|
|
367
378
|
* _pg_ - postgres dialect, with one table
|
|
368
379
|
* aTable
|
|
380
|
+
* _mssql_ - sqlserver dialect, which has no boolean values, with one
|
|
381
|
+
* table, aTable
|
|
369
382
|
*
|
|
370
383
|
* The "aTable" table is a mocked table with one column of each type.
|
|
371
384
|
* The _bq_ version does not have the timestamptz column, and when
|
|
@@ -394,6 +407,7 @@ class TestTranslator extends parse_malloy_1.MalloyTranslator {
|
|
|
394
407
|
_db2_: { type: 'connection', name: '_db2_' },
|
|
395
408
|
_bq_: { type: 'connection', name: '_bq_' },
|
|
396
409
|
_pg_: { type: 'connection', name: '_pg_' },
|
|
410
|
+
_mssql_: { type: 'connection', name: '_mssql_' },
|
|
397
411
|
a: { ...exports.aTableDef, primaryKey: 'astr', name: 'a' },
|
|
398
412
|
b: { ...exports.aTableDef, primaryKey: 'astr', name: 'b' },
|
|
399
413
|
bq_a: { ...exports.bqTableDef, primaryKey: 'astr', name: 'bq_a' },
|
|
@@ -451,6 +465,7 @@ class TestTranslator extends parse_malloy_1.MalloyTranslator {
|
|
|
451
465
|
this.connectionDialectZone.define('_db2_', exports.TEST_DIALECT);
|
|
452
466
|
this.connectionDialectZone.define('_bq_', 'standardsql');
|
|
453
467
|
this.connectionDialectZone.define('_pg_', 'postgres');
|
|
468
|
+
this.connectionDialectZone.define('_mssql_', 'sqlserver');
|
|
454
469
|
for (const flag of (_e = options.compilerFlags) !== null && _e !== void 0 ? _e : []) {
|
|
455
470
|
this.compilerFlagSrc.push(`##! ${flag}\n`);
|
|
456
471
|
}
|
|
@@ -658,10 +673,29 @@ function makeModelFunc(options) {
|
|
|
658
673
|
const { prefix, wrap, ...ttOptions } = options;
|
|
659
674
|
return {
|
|
660
675
|
...ms,
|
|
676
|
+
// A marked location is where the mark sits in the whole source, after
|
|
677
|
+
// the prefix. A wrap could put the code anywhere, so marks stay as
|
|
678
|
+
// they are.
|
|
679
|
+
locations: wrap ? ms.locations : ms.locations.map(l => after(prefix, l)),
|
|
661
680
|
translator: new TestTranslator((prefix !== null && prefix !== void 0 ? prefix : '') + (wrap ? wrap(ms.code) : ms.code), ttOptions),
|
|
662
681
|
};
|
|
663
682
|
};
|
|
664
683
|
}
|
|
684
|
+
function after(prefix, l) {
|
|
685
|
+
if (!prefix)
|
|
686
|
+
return l;
|
|
687
|
+
const lines = prefix.split('\n');
|
|
688
|
+
const dLine = lines.length - 1;
|
|
689
|
+
const dChar = lines[dLine].length;
|
|
690
|
+
const shift = (p) => ({
|
|
691
|
+
line: p.line + dLine,
|
|
692
|
+
character: p.line === 0 ? p.character + dChar : p.character,
|
|
693
|
+
});
|
|
694
|
+
return {
|
|
695
|
+
...l,
|
|
696
|
+
range: { start: shift(l.range.start), end: shift(l.range.end) },
|
|
697
|
+
};
|
|
698
|
+
}
|
|
665
699
|
function makeExprFunc(model, sourceName = 'ab', options = {}) {
|
|
666
700
|
return function expr(unmarked, ...marked) {
|
|
667
701
|
const ms = markSource(unmarked, ...marked);
|
|
@@ -109,7 +109,7 @@ function compileExpr(resultSet, context, expr, state = new utils_1.GenerateState
|
|
|
109
109
|
return expr;
|
|
110
110
|
}
|
|
111
111
|
const sql = (() => {
|
|
112
|
-
var _a;
|
|
112
|
+
var _a, _b;
|
|
113
113
|
switch (expr.node) {
|
|
114
114
|
case 'field':
|
|
115
115
|
return generateFieldFragment(resultSet, context, expr, state);
|
|
@@ -176,7 +176,7 @@ function compileExpr(resultSet, context, expr, state = new utils_1.GenerateState
|
|
|
176
176
|
// Malloy inequality comparisons always return a boolean
|
|
177
177
|
case '!=': {
|
|
178
178
|
const notEqual = `${expr.kids.left.sql}!=${expr.kids.right.sql}`;
|
|
179
|
-
return
|
|
179
|
+
return context.dialect.sqlNullIsTrue(notEqual);
|
|
180
180
|
}
|
|
181
181
|
case 'and':
|
|
182
182
|
case 'or':
|
|
@@ -192,13 +192,13 @@ function compileExpr(resultSet, context, expr, state = new utils_1.GenerateState
|
|
|
192
192
|
// null binding collapses to empty-set semantics — not the SQL
|
|
193
193
|
// `IN (NULL)` shape, which has confusing NULL-membership rules.
|
|
194
194
|
if (bound.node === 'null') {
|
|
195
|
-
return expr.not
|
|
195
|
+
return context.dialect.sqlBoolean(expr.not);
|
|
196
196
|
}
|
|
197
197
|
if (bound.node !== 'arrayLiteral') {
|
|
198
198
|
throw new Error(`Internal compiler error: 'inGiven' bound to '${bound.node}', expected 'arrayLiteral'. The translator should have rejected a non-array given here.`);
|
|
199
199
|
}
|
|
200
200
|
if (bound.kids.values.length === 0) {
|
|
201
|
-
return expr.not
|
|
201
|
+
return context.dialect.sqlBoolean(expr.not);
|
|
202
202
|
}
|
|
203
203
|
const elemSqls = bound.kids.values.map(v => exprToSQL(resultSet, context, v, state));
|
|
204
204
|
const verb = expr.not ? 'NOT IN' : 'IN';
|
|
@@ -210,13 +210,14 @@ function compileExpr(resultSet, context, expr, state = new utils_1.GenerateState
|
|
|
210
210
|
const compare = expr.kids.right.node === 'stringLiteral'
|
|
211
211
|
? context.dialect.sqlLike(likeIt, (_a = expr.kids.left.sql) !== null && _a !== void 0 ? _a : '', expr.kids.right.literal)
|
|
212
212
|
: `${expr.kids.left.sql} ${likeIt} ${expr.kids.right.sql}`;
|
|
213
|
-
return expr.node === 'like'
|
|
213
|
+
return expr.node === 'like'
|
|
214
|
+
? compare
|
|
215
|
+
: context.dialect.sqlNullIsTrue(compare);
|
|
214
216
|
}
|
|
215
217
|
case '()':
|
|
216
218
|
return `(${expr.e.sql})`;
|
|
217
219
|
case 'not':
|
|
218
|
-
|
|
219
|
-
return `COALESCE(NOT ${expr.e.sql},TRUE)`;
|
|
220
|
+
return context.dialect.sqlNot((_b = expr.e.sql) !== null && _b !== void 0 ? _b : '');
|
|
220
221
|
case 'unary-':
|
|
221
222
|
return `-${expr.e.sql}`;
|
|
222
223
|
case 'is-null':
|
|
@@ -34,13 +34,13 @@ function unlike(disLiked, x) {
|
|
|
34
34
|
// The `none` filter ("always false") compiles to a constant, independent of
|
|
35
35
|
// column type or value; `not none` is "always true". Shared by the top-level
|
|
36
36
|
// guard and every per-type compiler so the constant lives in one place.
|
|
37
|
-
function noneToSQL(not) {
|
|
38
|
-
return not
|
|
37
|
+
function noneToSQL(not, d) {
|
|
38
|
+
return d.sqlBoolean(not === true);
|
|
39
39
|
}
|
|
40
40
|
exports.FilterCompilers = {
|
|
41
41
|
compile(t, c, x, d, qi = {}) {
|
|
42
42
|
if (c === null) {
|
|
43
|
-
return
|
|
43
|
+
return d.sqlBoolean(true);
|
|
44
44
|
}
|
|
45
45
|
// `none` is the always-false filter (companion to the empty/`null` filter,
|
|
46
46
|
// which is always-true above). It compiles to a constant independent of
|
|
@@ -48,7 +48,7 @@ exports.FilterCompilers = {
|
|
|
48
48
|
// also the primary path for boolean, whose compiler has no switch and
|
|
49
49
|
// would otherwise route `none` through the null/false truth-table.
|
|
50
50
|
if (c.operator === 'none') {
|
|
51
|
-
return noneToSQL(c.not);
|
|
51
|
+
return noneToSQL(c.not, d);
|
|
52
52
|
}
|
|
53
53
|
if (t === 'string' && (0, malloy_filter_1.isStringFilter)(c)) {
|
|
54
54
|
return exports.FilterCompilers.stringCompile(c, x, d);
|
|
@@ -102,7 +102,7 @@ exports.FilterCompilers = {
|
|
|
102
102
|
case 'null':
|
|
103
103
|
return nc.not ? `${x} IS NOT NULL` : `${x} IS NULL`;
|
|
104
104
|
case 'none':
|
|
105
|
-
return noneToSQL(nc.not);
|
|
105
|
+
return noneToSQL(nc.not, d);
|
|
106
106
|
case '()': {
|
|
107
107
|
const wrapped = '(' + exports.FilterCompilers.numberCompile(nc.expr, x, d) + ')';
|
|
108
108
|
return nc.not ? `NOT ${wrapped}` : wrapped;
|
|
@@ -135,7 +135,7 @@ exports.FilterCompilers = {
|
|
|
135
135
|
// Normally intercepted by compile()'s top-level guard; handled here too so
|
|
136
136
|
// booleanCompile is self-safe (this if-chain has no default, and `none`
|
|
137
137
|
// must not fall through to the null/false truth-table below).
|
|
138
|
-
return noneToSQL(bc.not);
|
|
138
|
+
return noneToSQL(bc.not, d);
|
|
139
139
|
}
|
|
140
140
|
else if (bc.operator === '=true') {
|
|
141
141
|
return bc.not ? `NOT ${px}` : x;
|
|
@@ -172,7 +172,7 @@ exports.FilterCompilers = {
|
|
|
172
172
|
case 'null':
|
|
173
173
|
return sc.not ? `${x} IS NOT NULL` : `${x} IS NULL`;
|
|
174
174
|
case 'none':
|
|
175
|
-
return noneToSQL(sc.not);
|
|
175
|
+
return noneToSQL(sc.not, d);
|
|
176
176
|
case 'empty':
|
|
177
177
|
return sc.not ? `COALESCE(${x},'') != ''` : `COALESCE(${x},'') = ''`;
|
|
178
178
|
case '=': {
|
|
@@ -267,7 +267,7 @@ exports.FilterCompilers = {
|
|
|
267
267
|
}
|
|
268
268
|
}
|
|
269
269
|
if ((includeEmpty && excludeEmpty) || (includeNull && excludeNull)) {
|
|
270
|
-
return
|
|
270
|
+
return d.sqlBoolean(false);
|
|
271
271
|
}
|
|
272
272
|
let includeSQL = '';
|
|
273
273
|
if (includes.length > 0 || includeNull || includeEmpty) {
|
|
@@ -298,7 +298,7 @@ exports.FilterCompilers = {
|
|
|
298
298
|
? `(${includeSQL}) AND (${excludeSQL})`
|
|
299
299
|
: includeSQL;
|
|
300
300
|
}
|
|
301
|
-
return excludeSQL !== '' ? excludeSQL :
|
|
301
|
+
return excludeSQL !== '' ? excludeSQL : d.sqlBoolean(true);
|
|
302
302
|
}
|
|
303
303
|
}
|
|
304
304
|
},
|
|
@@ -331,7 +331,7 @@ class TemporalFilterCompiler {
|
|
|
331
331
|
if (this.timetype !== 'date') {
|
|
332
332
|
return timeSQL;
|
|
333
333
|
}
|
|
334
|
-
|
|
334
|
+
const toDate = {
|
|
335
335
|
node: 'cast',
|
|
336
336
|
e: {
|
|
337
337
|
node: 'genericSQLExpr',
|
|
@@ -342,7 +342,8 @@ class TemporalFilterCompiler {
|
|
|
342
342
|
srcType: { type: 'timestamp' },
|
|
343
343
|
dstType: { type: 'date' },
|
|
344
344
|
safe: false,
|
|
345
|
-
}
|
|
345
|
+
};
|
|
346
|
+
return this.d.sqlTimeCast(this.qi, toDate);
|
|
346
347
|
}
|
|
347
348
|
compile(tc) {
|
|
348
349
|
const x = this.expr;
|
|
@@ -421,7 +422,7 @@ class TemporalFilterCompiler {
|
|
|
421
422
|
case 'null':
|
|
422
423
|
return tc.not ? `${x} IS NOT NULL` : `${x} IS NULL`;
|
|
423
424
|
case 'none':
|
|
424
|
-
return noneToSQL(tc.not);
|
|
425
|
+
return noneToSQL(tc.not, this.d);
|
|
425
426
|
case '()': {
|
|
426
427
|
const wrapped = '(' + this.compile(tc.expr) + ')';
|
|
427
428
|
return tc.not ? `NOT ${wrapped}` : wrapped;
|
|
@@ -27,3 +27,11 @@ export declare function resolveSuppliedGivens(supplied: Record<string, GivenValu
|
|
|
27
27
|
* `resolveGiven`), which needs no ordering.
|
|
28
28
|
*/
|
|
29
29
|
export declare function evaluateInlineGivens(bound: Map<GivenID, Expr>, modelDef: ModelDef | undefined): Map<GivenID, Expr>;
|
|
30
|
+
/**
|
|
31
|
+
* Binds the givens a compile runs under: the supplied values, then each
|
|
32
|
+
* `inline` given's default folded against them. Queries and persistence builds
|
|
33
|
+
* both bind here, so the same values always compile to the same SQL and a
|
|
34
|
+
* persisted table's key is the key a query recomputes. Undefined when nothing
|
|
35
|
+
* binds, which the compiler reads as "no givens".
|
|
36
|
+
*/
|
|
37
|
+
export declare function bindGivens(supplied: Record<string, GivenValue> | undefined, modelDef: ModelDef | undefined): Map<GivenID, Expr> | undefined;
|
|
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.lookupGivenValue = lookupGivenValue;
|
|
8
8
|
exports.resolveSuppliedGivens = resolveSuppliedGivens;
|
|
9
9
|
exports.evaluateInlineGivens = evaluateInlineGivens;
|
|
10
|
+
exports.bindGivens = bindGivens;
|
|
10
11
|
const luxon_1 = require("luxon");
|
|
11
12
|
const closest_match_1 = require("../util/closest_match");
|
|
12
13
|
const inline_expr_1 = require("./inline_expr");
|
|
@@ -106,6 +107,18 @@ function evaluateInlineGivens(bound, modelDef) {
|
|
|
106
107
|
}
|
|
107
108
|
return bound;
|
|
108
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Binds the givens a compile runs under: the supplied values, then each
|
|
112
|
+
* `inline` given's default folded against them. Queries and persistence builds
|
|
113
|
+
* both bind here, so the same values always compile to the same SQL and a
|
|
114
|
+
* persisted table's key is the key a query recomputes. Undefined when nothing
|
|
115
|
+
* binds, which the compiler reads as "no givens".
|
|
116
|
+
*/
|
|
117
|
+
function bindGivens(supplied, modelDef) {
|
|
118
|
+
const bound = resolveSuppliedGivens(supplied, modelDef);
|
|
119
|
+
evaluateInlineGivens(bound, modelDef);
|
|
120
|
+
return bound.size > 0 ? bound : undefined;
|
|
121
|
+
}
|
|
109
122
|
function valueToExpr(path, type, value) {
|
|
110
123
|
var _a, _b;
|
|
111
124
|
if (value === null) {
|
package/dist/model/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export { getResultStructDefForQuery, getResultStructDefForView, } from './query_
|
|
|
7
7
|
export { indent, composeSQLExpr, makeDigest, mkModelDef, mkModelID, pathToKey, typeDefToString, } from './utils';
|
|
8
8
|
export { getModelAnnotations } from './annotation_utils';
|
|
9
9
|
export { constantExprToSQL } from './constant_expression_compiler';
|
|
10
|
-
export { getCompiledSQL, buildIdOptions } from './sql_compiled';
|
|
10
|
+
export { getCompiledSQL, buildIdOptions, givenUsageOfRelation, } from './sql_compiled';
|
|
11
11
|
export type { BuildIdOptions } from './sql_compiled';
|
|
12
12
|
export { MalloyCompileError } from './malloy_compile_error';
|
|
13
13
|
export { mkSourceID, mkBuildID, mkQuerySourceDef, mkSQLSourceDef, mkTableSourceDef, resolveSourceID, resolveSourceRef, sourceNamespaceReference, registerSource, hasSourceRegistryEntry, } from './source_def_utils';
|
package/dist/model/index.js
CHANGED
|
@@ -18,7 +18,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
18
18
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
19
19
|
};
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.hasSourceRegistryEntry = exports.registerSource = exports.sourceNamespaceReference = exports.resolveSourceRef = exports.resolveSourceID = exports.mkTableSourceDef = exports.mkSQLSourceDef = exports.mkQuerySourceDef = exports.mkBuildID = exports.mkSourceID = exports.MalloyCompileError = exports.buildIdOptions = exports.getCompiledSQL = exports.constantExprToSQL = exports.getModelAnnotations = exports.typeDefToString = exports.pathToKey = exports.mkModelID = exports.mkModelDef = exports.makeDigest = exports.composeSQLExpr = exports.indent = exports.getResultStructDefForView = exports.getResultStructDefForQuery = exports.QueryModel = exports.QueryQuery = exports.QueryStruct = exports.QueryField = void 0;
|
|
21
|
+
exports.hasSourceRegistryEntry = exports.registerSource = exports.sourceNamespaceReference = exports.resolveSourceRef = exports.resolveSourceID = exports.mkTableSourceDef = exports.mkSQLSourceDef = exports.mkQuerySourceDef = exports.mkBuildID = exports.mkSourceID = exports.MalloyCompileError = exports.givenUsageOfRelation = exports.buildIdOptions = exports.getCompiledSQL = exports.constantExprToSQL = exports.getModelAnnotations = exports.typeDefToString = exports.pathToKey = exports.mkModelID = exports.mkModelDef = exports.makeDigest = exports.composeSQLExpr = exports.indent = exports.getResultStructDefForView = exports.getResultStructDefForQuery = exports.QueryModel = exports.QueryQuery = exports.QueryStruct = exports.QueryField = void 0;
|
|
22
22
|
__exportStar(require("./malloy_types"), exports);
|
|
23
23
|
const query_node_1 = require("./query_node");
|
|
24
24
|
Object.defineProperty(exports, "QueryField", { enumerable: true, get: function () { return query_node_1.QueryField; } });
|
|
@@ -52,6 +52,7 @@ Object.defineProperty(exports, "constantExprToSQL", { enumerable: true, get: fun
|
|
|
52
52
|
var sql_compiled_1 = require("./sql_compiled");
|
|
53
53
|
Object.defineProperty(exports, "getCompiledSQL", { enumerable: true, get: function () { return sql_compiled_1.getCompiledSQL; } });
|
|
54
54
|
Object.defineProperty(exports, "buildIdOptions", { enumerable: true, get: function () { return sql_compiled_1.buildIdOptions; } });
|
|
55
|
+
Object.defineProperty(exports, "givenUsageOfRelation", { enumerable: true, get: function () { return sql_compiled_1.givenUsageOfRelation; } });
|
|
55
56
|
var malloy_compile_error_1 = require("./malloy_compile_error");
|
|
56
57
|
Object.defineProperty(exports, "MalloyCompileError", { enumerable: true, get: function () { return malloy_compile_error_1.MalloyCompileError; } });
|
|
57
58
|
var source_def_utils_1 = require("./source_def_utils");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PrepareResultOptions, SQLSourceDef, SQLPhraseSegment, PersistableSourceDef, Query, VirtualMap } from './malloy_types';
|
|
1
|
+
import type { Expr, GivenID, GivenUsage, PrepareResultOptions, SQLSourceDef, SQLPhraseSegment, PersistableSourceDef, Query, VirtualMap } from './malloy_types';
|
|
2
2
|
/**
|
|
3
3
|
* Callback type for compiling a Query to SQL.
|
|
4
4
|
* opts is optional - omit for "full SQL" (BuildID computation),
|
|
@@ -19,31 +19,23 @@ export declare function getCompiledSQL(src: SQLSourceDef, opts: PrepareResultOpt
|
|
|
19
19
|
/** Expand SQL text and interpolations for schema discovery or execution. */
|
|
20
20
|
export declare function expandSQLSegments(segments: SQLPhraseSegment[], opts: PrepareResultOptions, compileQuery: CompileQueryCallback): string;
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
23
|
-
* the compiler
|
|
22
|
+
* What a BuildID's SQL is generated under: everything that changes what the
|
|
23
|
+
* SQL computes and that the builder and the compiler can both know.
|
|
24
24
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
25
|
+
* No manifest. A BuildID must not depend on what has already been built, or
|
|
26
|
+
* build order would change the key, so this type cannot carry one;
|
|
27
27
|
* `mkBuildTargets` takes it for the same reason.
|
|
28
|
+
*
|
|
29
|
+
* `virtualMap` decides which table a virtual source reads. `resolvedGivens`
|
|
30
|
+
* is the value of every given the SQL reads, supplied or defaulted; both sides
|
|
31
|
+
* produce it through `bindGivens`, so equal values give the same key and
|
|
32
|
+
* different values give different keys.
|
|
28
33
|
*/
|
|
29
34
|
export interface BuildIdOptions {
|
|
30
35
|
virtualMap?: VirtualMap;
|
|
36
|
+
resolvedGivens?: Map<GivenID, Expr>;
|
|
31
37
|
}
|
|
32
|
-
/**
|
|
33
|
-
* Project compile options down to what a BuildID is computed under.
|
|
34
|
-
*
|
|
35
|
-
* `virtualMap` decides which table a virtual source reads, so it changes the
|
|
36
|
-
* SQL and has to be in the key; the builder supplies its own.
|
|
37
|
-
*
|
|
38
|
-
* `resolvedGivens` is deliberately absent even though it also changes the SQL.
|
|
39
|
-
* The builder has no way to produce one — `Runtime.getBuildTargets` takes no
|
|
40
|
-
* givens and `PersistSource.getSQL` never resolves them — so including it makes
|
|
41
|
-
* the two sides disagree: the compiler folds `$IS_ADMIN` to a literal while the
|
|
42
|
-
* builder re-derives it from the declaration and emits `'admin'='admin'`. Both
|
|
43
|
-
* sides therefore compile givens the same way, by not resolving them. The
|
|
44
|
-
* consequence — a source whose SQL depends on a supplied given cannot be
|
|
45
|
-
* persisted, and says so badly — is #3041.
|
|
46
|
-
*/
|
|
38
|
+
/** Project compile options down to what a BuildID is computed under. */
|
|
47
39
|
export declare function buildIdOptions(opts: PrepareResultOptions): BuildIdOptions;
|
|
48
40
|
/**
|
|
49
41
|
* Ask the manifest what table backs a persistable source.
|
|
@@ -57,6 +49,13 @@ export declare function buildIdOptions(opts: PrepareResultOptions): BuildIdOptio
|
|
|
57
49
|
* undefined when the caller should emit the source's own SQL.
|
|
58
50
|
*/
|
|
59
51
|
export declare function persistedTableFor(source: PersistableSourceDef, opts: PrepareResultOptions, compileQuery: CompileQueryCallback): string | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* The givens a persisted source's SQL reads — the relation, not the source.
|
|
54
|
+
* A `where:` added by `extend` is applied by the query that reads the table,
|
|
55
|
+
* so it is not here, and a given used only there does not split the table by
|
|
56
|
+
* value. Mirrors `getSourceSQL`: what that compiles, this reports on.
|
|
57
|
+
*/
|
|
58
|
+
export declare function givenUsageOfRelation(source: PersistableSourceDef): GivenUsage;
|
|
60
59
|
/**
|
|
61
60
|
* Get the SQL for a PersistableSourceDef.
|
|
62
61
|
*
|
|
@@ -8,6 +8,7 @@ exports.getCompiledSQL = getCompiledSQL;
|
|
|
8
8
|
exports.expandSQLSegments = expandSQLSegments;
|
|
9
9
|
exports.buildIdOptions = buildIdOptions;
|
|
10
10
|
exports.persistedTableFor = persistedTableFor;
|
|
11
|
+
exports.givenUsageOfRelation = givenUsageOfRelation;
|
|
11
12
|
exports.getSourceSQL = getSourceSQL;
|
|
12
13
|
const malloy_types_1 = require("./malloy_types");
|
|
13
14
|
const source_def_utils_1 = require("./source_def_utils");
|
|
@@ -50,23 +51,9 @@ function expandSegment(segment, opts, compileQuery) {
|
|
|
50
51
|
// Query segment
|
|
51
52
|
return expandQuery(segment, opts, compileQuery);
|
|
52
53
|
}
|
|
53
|
-
/**
|
|
54
|
-
* Project compile options down to what a BuildID is computed under.
|
|
55
|
-
*
|
|
56
|
-
* `virtualMap` decides which table a virtual source reads, so it changes the
|
|
57
|
-
* SQL and has to be in the key; the builder supplies its own.
|
|
58
|
-
*
|
|
59
|
-
* `resolvedGivens` is deliberately absent even though it also changes the SQL.
|
|
60
|
-
* The builder has no way to produce one — `Runtime.getBuildTargets` takes no
|
|
61
|
-
* givens and `PersistSource.getSQL` never resolves them — so including it makes
|
|
62
|
-
* the two sides disagree: the compiler folds `$IS_ADMIN` to a literal while the
|
|
63
|
-
* builder re-derives it from the declaration and emits `'admin'='admin'`. Both
|
|
64
|
-
* sides therefore compile givens the same way, by not resolving them. The
|
|
65
|
-
* consequence — a source whose SQL depends on a supplied given cannot be
|
|
66
|
-
* persisted, and says so badly — is #3041.
|
|
67
|
-
*/
|
|
54
|
+
/** Project compile options down to what a BuildID is computed under. */
|
|
68
55
|
function buildIdOptions(opts) {
|
|
69
|
-
return { virtualMap: opts.virtualMap };
|
|
56
|
+
return { virtualMap: opts.virtualMap, resolvedGivens: opts.resolvedGivens };
|
|
70
57
|
}
|
|
71
58
|
/**
|
|
72
59
|
* Ask the manifest what table backs a persistable source.
|
|
@@ -100,12 +87,37 @@ function persistedTableFor(source, opts, compileQuery) {
|
|
|
100
87
|
const named = source.sourceID
|
|
101
88
|
? `Persisted source '${source.sourceID}'`
|
|
102
89
|
: 'Persisted source';
|
|
90
|
+
const perValue = givenUsageOfRelation(source).length > 0
|
|
91
|
+
? ' This source reads givens, and no table was built for the given ' +
|
|
92
|
+
'values this query supplies.'
|
|
93
|
+
: '';
|
|
103
94
|
const base = `${named} not found in manifest (buildId: ${buildId}); ` +
|
|
104
|
-
'strict manifest mode forbids fallback to live compilation.'
|
|
95
|
+
'strict manifest mode forbids fallback to live compilation.' +
|
|
96
|
+
perValue;
|
|
105
97
|
throw new malloy_compile_error_1.MalloyCompileError(buildManifest.loadError ? `${base}\n ${buildManifest.loadError}` : base, 'runtime-manifest-strict-miss', source.location);
|
|
106
98
|
}
|
|
107
99
|
return undefined;
|
|
108
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* The givens a persisted source's SQL reads — the relation, not the source.
|
|
103
|
+
* A `where:` added by `extend` is applied by the query that reads the table,
|
|
104
|
+
* so it is not here, and a given used only there does not split the table by
|
|
105
|
+
* value. Mirrors `getSourceSQL`: what that compiles, this reports on.
|
|
106
|
+
*/
|
|
107
|
+
function givenUsageOfRelation(source) {
|
|
108
|
+
var _a, _b;
|
|
109
|
+
if (source.type === 'query_source') {
|
|
110
|
+
return (_a = source.query.givenUsage) !== null && _a !== void 0 ? _a : [];
|
|
111
|
+
}
|
|
112
|
+
return ((_b = source.selectSegments) !== null && _b !== void 0 ? _b : []).flatMap(segment => {
|
|
113
|
+
var _a;
|
|
114
|
+
if ((0, malloy_types_1.isSegmentSQL)(segment))
|
|
115
|
+
return [];
|
|
116
|
+
if ((0, malloy_types_1.isSegmentSource)(segment))
|
|
117
|
+
return givenUsageOfRelation(segment);
|
|
118
|
+
return (_a = segment.givenUsage) !== null && _a !== void 0 ? _a : [];
|
|
119
|
+
});
|
|
120
|
+
}
|
|
109
121
|
/**
|
|
110
122
|
* Expand a PersistableSourceDef as a `%{ }` segment.
|
|
111
123
|
* Always returns a subquery form: (SELECT * FROM table) or (inline SQL)
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const MALLOY_VERSION = "0.0.
|
|
1
|
+
export declare const MALLOY_VERSION = "0.0.436";
|
package/dist/version.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MALLOY_VERSION = void 0;
|
|
4
4
|
// generated with 'generate-version-file' script; do not edit manually
|
|
5
|
-
exports.MALLOY_VERSION = '0.0.
|
|
5
|
+
exports.MALLOY_VERSION = '0.0.436';
|
|
6
6
|
//# sourceMappingURL=version.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@malloydata/malloy",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.436",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js",
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"generate-version-file": "VERSION=$(npm pkg get version --workspaces=false | tr -d \\\")\necho \"// generated with 'generate-version-file' script; do not edit manually\\nexport const MALLOY_VERSION = '$VERSION';\" > src/version.ts"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@malloydata/malloy-filter": "0.0.
|
|
55
|
-
"@malloydata/malloy-interfaces": "0.0.
|
|
56
|
-
"@malloydata/malloy-tag": "0.0.
|
|
54
|
+
"@malloydata/malloy-filter": "0.0.436",
|
|
55
|
+
"@malloydata/malloy-interfaces": "0.0.436",
|
|
56
|
+
"@malloydata/malloy-tag": "0.0.436",
|
|
57
57
|
"@noble/hashes": "^1.8.0",
|
|
58
58
|
"antlr4ts": "^0.5.0-alpha.4",
|
|
59
59
|
"assert": "^2.0.0",
|