@malloydata/malloy 0.0.394 → 0.0.396
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 +7 -6
- package/dist/api/foundation/compile.js +22 -6
- package/dist/api/foundation/config.d.ts +2 -3
- package/dist/api/foundation/config.js +23 -11
- package/dist/api/foundation/core.js +1 -1
- package/dist/api/foundation/runtime.d.ts +85 -5
- package/dist/api/foundation/runtime.js +204 -14
- package/dist/api/foundation/types.d.ts +2 -0
- package/dist/api/util.js +4 -0
- package/dist/connection/base_connection.js +6 -0
- package/dist/connection/validate_table_path.d.ts +10 -0
- package/dist/connection/validate_table_path.js +56 -0
- package/dist/dialect/databricks/databricks.d.ts +4 -4
- package/dist/dialect/databricks/databricks.js +17 -22
- package/dist/dialect/dialect.d.ts +100 -4
- package/dist/dialect/dialect.js +145 -1
- package/dist/dialect/duckdb/duckdb.d.ts +2 -3
- package/dist/dialect/duckdb/duckdb.js +12 -14
- package/dist/dialect/duckdb/table-path-parser.d.ts +2 -0
- package/dist/dialect/duckdb/table-path-parser.js +57 -0
- package/dist/dialect/index.d.ts +2 -0
- package/dist/dialect/index.js +4 -1
- package/dist/dialect/mysql/mysql.d.ts +4 -4
- package/dist/dialect/mysql/mysql.js +25 -20
- package/dist/dialect/pg_impl.d.ts +3 -1
- package/dist/dialect/pg_impl.js +6 -3
- package/dist/dialect/postgres/postgres.d.ts +1 -3
- package/dist/dialect/postgres/postgres.js +8 -16
- package/dist/dialect/snowflake/snowflake.d.ts +4 -4
- package/dist/dialect/snowflake/snowflake.js +11 -27
- package/dist/dialect/standardsql/standardsql.d.ts +6 -4
- package/dist/dialect/standardsql/standardsql.js +36 -15
- package/dist/dialect/table-path.d.ts +54 -0
- package/dist/dialect/table-path.js +144 -0
- package/dist/dialect/trino/trino.d.ts +0 -3
- package/dist/dialect/trino/trino.js +7 -20
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -2
- package/dist/lang/ast/expressions/expr-func.js +30 -11
- package/dist/lang/ast/expressions/expr-given.js +1 -0
- package/dist/lang/ast/field-space/reference-field.js +1 -1
- package/dist/lang/ast/source-elements/sql-source.js +4 -0
- package/dist/lang/ast/source-elements/table-source.d.ts +1 -7
- package/dist/lang/ast/source-elements/table-source.js +24 -19
- package/dist/lang/ast/statements/define-given.d.ts +1 -0
- package/dist/lang/ast/statements/define-given.js +7 -0
- package/dist/lang/ast/statements/import-statement.js +4 -0
- package/dist/lang/ast/types/annotation-elements.d.ts +1 -0
- package/dist/lang/ast/types/annotation-elements.js +10 -3
- package/dist/lang/ast/types/malloy-element.d.ts +1 -0
- package/dist/lang/ast/types/malloy-element.js +4 -0
- package/dist/lang/malloy-to-ast.d.ts +2 -1
- package/dist/lang/malloy-to-ast.js +11 -1
- package/dist/lang/parse-log.d.ts +2 -0
- package/dist/lang/parse-log.js +4 -0
- package/dist/lang/parse-malloy.d.ts +4 -1
- package/dist/lang/parse-malloy.js +63 -11
- package/dist/lang/parse-tree-walkers/find-external-references.d.ts +2 -15
- package/dist/lang/parse-tree-walkers/find-external-references.js +6 -23
- package/dist/lang/test/test-translator.d.ts +19 -5
- package/dist/lang/test/test-translator.js +15 -12
- package/dist/lang/translate-response.d.ts +1 -1
- package/dist/lang/zone.d.ts +2 -0
- package/dist/lang/zone.js +10 -0
- package/dist/model/constant_expression_compiler.js +14 -5
- package/dist/model/expression_compiler.js +19 -17
- package/dist/model/field_instance.js +7 -3
- package/dist/model/filter_compilers.js +1 -1
- package/dist/model/given_binding.js +26 -21
- package/dist/model/index.d.ts +1 -0
- package/dist/model/index.js +3 -1
- package/dist/model/malloy_compile_error.d.ts +13 -0
- package/dist/model/malloy_compile_error.js +23 -0
- package/dist/model/malloy_types.d.ts +2 -0
- package/dist/model/query_model_impl.js +9 -8
- package/dist/model/query_node.d.ts +5 -5
- package/dist/model/query_node.js +21 -16
- package/dist/model/query_query.js +60 -44
- package/dist/model/sql_compiled.d.ts +2 -4
- package/dist/model/sql_compiled.js +20 -18
- package/dist/test/test-models.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -13,6 +13,7 @@ const stage_writer_1 = require("./stage_writer");
|
|
|
13
13
|
const field_instance_1 = require("./field_instance");
|
|
14
14
|
const sql_compiled_1 = require("./sql_compiled");
|
|
15
15
|
const source_def_utils_1 = require("./source_def_utils");
|
|
16
|
+
const malloy_compile_error_1 = require("./malloy_compile_error");
|
|
16
17
|
function pathToCol(path) {
|
|
17
18
|
return path.map(el => encodeURIComponent(el)).join('/');
|
|
18
19
|
}
|
|
@@ -142,7 +143,8 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
142
143
|
for (const pathSegment of ungrouping.path) {
|
|
143
144
|
const nextStruct = destResult.allFields.get(pathSegment);
|
|
144
145
|
if (!(nextStruct instanceof field_instance_1.FieldInstanceResult)) {
|
|
145
|
-
throw new
|
|
146
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Ungrouping path '${ungrouping.path.join('.')}' references ` +
|
|
147
|
+
`'${pathSegment}', which is not a nested view at this level.`, 'compiler-ungrouped-invalid-path', this.fieldDef.location);
|
|
146
148
|
}
|
|
147
149
|
destResult = nextStruct;
|
|
148
150
|
}
|
|
@@ -192,7 +194,9 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
192
194
|
const drillExpression = this.getDrillExpression(f);
|
|
193
195
|
if (field instanceof QueryQuery) {
|
|
194
196
|
if (this.firstSegment.type === 'project') {
|
|
195
|
-
throw new
|
|
197
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Cannot include nested view '${field.fieldDef.name}' in a ` +
|
|
198
|
+
"'select:' stage. Nested views require `group_by:` or " +
|
|
199
|
+
'`aggregate:` to be included in output.', 'compiler-nested-view-in-select', field.fieldDef.location);
|
|
196
200
|
}
|
|
197
201
|
const fir = new field_instance_1.FieldInstanceResult(field.fieldDef, resultStruct);
|
|
198
202
|
this.expandFields(fir);
|
|
@@ -212,7 +216,8 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
212
216
|
}
|
|
213
217
|
if ((0, query_node_1.isBasicAggregate)(field)) {
|
|
214
218
|
if (this.firstSegment.type === 'project') {
|
|
215
|
-
throw new
|
|
219
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Cannot include aggregate field '${field.fieldDef.name}' in ` +
|
|
220
|
+
"a 'select:' stage. Use `aggregate:` instead to compute aggregates.", 'compiler-aggregate-in-select', field.fieldDef.location);
|
|
216
221
|
}
|
|
217
222
|
}
|
|
218
223
|
}
|
|
@@ -517,14 +522,19 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
517
522
|
var _a, _b, _c, _d;
|
|
518
523
|
switch (qs.structDef.type) {
|
|
519
524
|
case 'table':
|
|
520
|
-
|
|
525
|
+
// tablePath is canonical SQL — translator pre-validated.
|
|
526
|
+
return qs.structDef.tablePath;
|
|
521
527
|
case 'virtual': {
|
|
522
528
|
const virtualMap = (_a = qs.prepareResultOptions) === null || _a === void 0 ? void 0 : _a.virtualMap;
|
|
523
529
|
const tablePath = (_b = virtualMap === null || virtualMap === void 0 ? void 0 : virtualMap.get(qs.structDef.connection)) === null || _b === void 0 ? void 0 : _b.get(qs.structDef.name);
|
|
524
530
|
if (!tablePath) {
|
|
525
|
-
throw new
|
|
531
|
+
throw new malloy_compile_error_1.MalloyCompileError(`No virtual-map entry for virtual source '${qs.structDef.name}' ` +
|
|
532
|
+
`on connection '${qs.structDef.connection}'. ` +
|
|
533
|
+
'Add a virtual-map entry via the `virtualMap` runtime option.', 'runtime-virtual-map-missing', qs.structDef.location);
|
|
526
534
|
}
|
|
527
|
-
|
|
535
|
+
// virtualMap entries are application-supplied — assumed already
|
|
536
|
+
// canonical SQL.
|
|
537
|
+
return tablePath;
|
|
528
538
|
}
|
|
529
539
|
case 'composite':
|
|
530
540
|
// TODO: throw an error here; not simple because we call into this
|
|
@@ -533,7 +543,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
533
543
|
case 'finalize':
|
|
534
544
|
return qs.structDef.name;
|
|
535
545
|
case 'sql_select':
|
|
536
|
-
return `(${(0, sql_compiled_1.getCompiledSQL)(qs.structDef, (_c = qs.prepareResultOptions) !== null && _c !== void 0 ? _c : {},
|
|
546
|
+
return `(${(0, sql_compiled_1.getCompiledSQL)(qs.structDef, (_c = qs.prepareResultOptions) !== null && _c !== void 0 ? _c : {}, (query, opts) => {
|
|
537
547
|
// Compile query to isolated SQL (not into parent's stageWriter)
|
|
538
548
|
const ret = this.compileQueryToStages(query, opts !== null && opts !== void 0 ? opts : {}, undefined, false);
|
|
539
549
|
return ret.sql;
|
|
@@ -551,14 +561,17 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
551
561
|
const buildId = (0, source_def_utils_1.mkBuildID)(connDigest, fullRet.sql);
|
|
552
562
|
const entry = buildManifest.entries[buildId];
|
|
553
563
|
if (entry) {
|
|
554
|
-
// Found in manifest - use persisted table
|
|
555
|
-
|
|
564
|
+
// Found in manifest - use persisted table.
|
|
565
|
+
// entry.tableName comes from the manifest, assumed canonical.
|
|
566
|
+
return entry.tableName;
|
|
556
567
|
}
|
|
557
568
|
if (buildManifest.strict) {
|
|
558
|
-
const base = `Persist source '${qs.structDef.sourceID}' not found
|
|
559
|
-
|
|
569
|
+
const base = `Persist source '${qs.structDef.sourceID}' not found ` +
|
|
570
|
+
`in manifest (buildId: ${buildId}); strict manifest mode ` +
|
|
571
|
+
'forbids fallback to live compilation.';
|
|
572
|
+
throw new malloy_compile_error_1.MalloyCompileError(buildManifest.loadError
|
|
560
573
|
? `${base}\n ${buildManifest.loadError}`
|
|
561
|
-
: base);
|
|
574
|
+
: base, 'runtime-manifest-strict-miss', qs.structDef.location);
|
|
562
575
|
}
|
|
563
576
|
}
|
|
564
577
|
}
|
|
@@ -594,7 +607,8 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
594
607
|
if (typeof structRef === 'string') {
|
|
595
608
|
const struct = this.structRefToQueryStruct(structRef);
|
|
596
609
|
if (!struct) {
|
|
597
|
-
throw new
|
|
610
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Query references source '${structRef}', ` +
|
|
611
|
+
'which is not defined in this model.', 'compiler-undefined-source', undefined);
|
|
598
612
|
}
|
|
599
613
|
sourceStruct = struct;
|
|
600
614
|
}
|
|
@@ -631,7 +645,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
631
645
|
}
|
|
632
646
|
if (ji.makeUniqueKey) {
|
|
633
647
|
const passKeys = this.generateSQLPassthroughKeys(qs);
|
|
634
|
-
structSQL = `(SELECT ${qs.dialect.sqlGenerateUUID()} as ${qs.dialect.
|
|
648
|
+
structSQL = `(SELECT ${qs.dialect.sqlGenerateUUID()} as ${qs.dialect.sqlQuoteIdentifier('__distinct_key')}, x.* ${passKeys} FROM ${structSQL} as x)`;
|
|
635
649
|
}
|
|
636
650
|
let onCondition = '';
|
|
637
651
|
if (qs.parent === undefined) {
|
|
@@ -764,7 +778,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
764
778
|
if ((0, malloy_types_1.isBaseTable)(qs.structDef)) {
|
|
765
779
|
if (ji.makeUniqueKey) {
|
|
766
780
|
const passKeys = this.generateSQLPassthroughKeys(qs);
|
|
767
|
-
structSQL = `(SELECT ${qs.dialect.sqlGenerateUUID()} as ${qs.dialect.
|
|
781
|
+
structSQL = `(SELECT ${qs.dialect.sqlGenerateUUID()} as ${qs.dialect.sqlQuoteIdentifier('__distinct_key')}, x.* ${passKeys} FROM ${structSQL} as x)`;
|
|
768
782
|
}
|
|
769
783
|
s += `FROM ${structSQL} as ${ji.alias}\n`;
|
|
770
784
|
}
|
|
@@ -846,7 +860,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
846
860
|
o.push(`${fi.fieldUsage.resultIndex} ${f.dir || 'ASC'}`);
|
|
847
861
|
}
|
|
848
862
|
else if (this.parent.dialect.orderByClause === 'output_name') {
|
|
849
|
-
o.push(`${this.parent.dialect.
|
|
863
|
+
o.push(`${this.parent.dialect.sqlQuoteIdentifier(f.field)} ${f.dir || 'ASC'}`);
|
|
850
864
|
}
|
|
851
865
|
else if (this.parent.dialect.orderByClause === 'expression') {
|
|
852
866
|
const fieldExpr = fi.getSQL();
|
|
@@ -854,7 +868,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
854
868
|
}
|
|
855
869
|
}
|
|
856
870
|
else {
|
|
857
|
-
throw new
|
|
871
|
+
throw new malloy_compile_error_1.MalloyCompileError(`ORDER BY references unknown field '${f.field}'.`, 'compiler-orderby-field-not-found', queryDef.referencedAt);
|
|
858
872
|
}
|
|
859
873
|
}
|
|
860
874
|
else {
|
|
@@ -863,7 +877,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
863
877
|
}
|
|
864
878
|
else if (this.parent.dialect.orderByClause === 'output_name') {
|
|
865
879
|
const orderingField = resultStruct.getFieldByNumber(f.field);
|
|
866
|
-
o.push(`${this.parent.dialect.
|
|
880
|
+
o.push(`${this.parent.dialect.sqlQuoteIdentifier(orderingField.name)} ${f.dir || 'ASC'}`);
|
|
867
881
|
}
|
|
868
882
|
else if (this.parent.dialect.orderByClause === 'expression') {
|
|
869
883
|
const orderingField = resultStruct.getFieldByNumber(f.field);
|
|
@@ -887,7 +901,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
887
901
|
const fields = [];
|
|
888
902
|
for (const [name, field] of this.rootResult.allFields) {
|
|
889
903
|
const fi = field;
|
|
890
|
-
const sqlName = this.parent.dialect.
|
|
904
|
+
const sqlName = this.parent.dialect.sqlQuoteIdentifier(name);
|
|
891
905
|
if (fi.fieldUsage.type === 'result') {
|
|
892
906
|
fields.push(` ${fi.generateExpression()} as ${sqlName}`);
|
|
893
907
|
}
|
|
@@ -937,7 +951,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
937
951
|
.map(o => `${o.pipelineSQL} as ${o.sqlFieldName}`)
|
|
938
952
|
.join(',\n');
|
|
939
953
|
const outputFields = outputPipelinedSQL.map(f => f.sqlFieldName);
|
|
940
|
-
const allFields = Array.from(this.rootResult.allFields.keys()).map(f => this.parent.dialect.
|
|
954
|
+
const allFields = Array.from(this.rootResult.allFields.keys()).map(f => this.parent.dialect.sqlQuoteIdentifier(f));
|
|
941
955
|
const fields = allFields.filter(f => outputFields.indexOf(f) === -1);
|
|
942
956
|
retSQL = `SELECT ${fields.length > 0 ? fields.join(', ') + ',' : ''} ${pipelinesSQL} FROM ${lastStageName}`;
|
|
943
957
|
}
|
|
@@ -956,7 +970,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
956
970
|
}
|
|
957
971
|
const orderedFields = [...scalarFields, ...otherFields];
|
|
958
972
|
for (const [name, fi] of orderedFields) {
|
|
959
|
-
const outputName = this.parent.dialect.
|
|
973
|
+
const outputName = this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultSet.groupSet}`);
|
|
960
974
|
if (fi instanceof field_instance_1.FieldInstanceField) {
|
|
961
975
|
if (fi.fieldUsage.type === 'result') {
|
|
962
976
|
const exp = fi.getSQL();
|
|
@@ -975,7 +989,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
975
989
|
});
|
|
976
990
|
output.sql.push(outputFieldName);
|
|
977
991
|
if (fi.f.fieldDef.type === 'number') {
|
|
978
|
-
const outputNameString = this.parent.dialect.
|
|
992
|
+
const outputNameString = this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultSet.groupSet}_string`);
|
|
979
993
|
const outputFieldNameString = `__lateral_join_bag.${outputNameString}`;
|
|
980
994
|
output.sql.push(outputFieldNameString);
|
|
981
995
|
output.dimensionIndexes.push(output.fieldIndex++);
|
|
@@ -1086,7 +1100,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1086
1100
|
let r = result;
|
|
1087
1101
|
while (r) {
|
|
1088
1102
|
for (const name of r.fieldNames(fi => (0, query_node_1.isScalarField)(fi.f))) {
|
|
1089
|
-
dimensions.push(this.parent.dialect.
|
|
1103
|
+
dimensions.push(this.parent.dialect.sqlQuoteIdentifier(`${name}__${r.groupSet}`));
|
|
1090
1104
|
}
|
|
1091
1105
|
r = r.parent;
|
|
1092
1106
|
}
|
|
@@ -1120,7 +1134,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1120
1134
|
orderingField = result.getFieldByNumber(ordering.field);
|
|
1121
1135
|
}
|
|
1122
1136
|
obSQL.push(' ' +
|
|
1123
|
-
this.parent.dialect.
|
|
1137
|
+
this.parent.dialect.sqlQuoteIdentifier(`${orderingField.name}__${result.groupSet}`) +
|
|
1124
1138
|
` ${ordering.dir || 'ASC'}`);
|
|
1125
1139
|
}
|
|
1126
1140
|
// partition for a row number is the parent if it exists.
|
|
@@ -1206,7 +1220,9 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1206
1220
|
this.generateStage0Fields(this.rootResult, f, stageWriter);
|
|
1207
1221
|
if (this.firstSegment.type === 'project' &&
|
|
1208
1222
|
!this.parent.modelCompilerFlags().has('unsafe_complex_select_query')) {
|
|
1209
|
-
throw new
|
|
1223
|
+
throw new malloy_compile_error_1.MalloyCompileError("Cannot use 'select:' in a stage that contains nested views. " +
|
|
1224
|
+
'Use `group_by:` or restructure the pipeline. ' +
|
|
1225
|
+
'Set `##! unsafe_complex_select_query` to bypass at your own risk.', 'compiler-project-with-turtles', this.fieldDef.location);
|
|
1210
1226
|
}
|
|
1211
1227
|
const groupBy = 'GROUP BY ' + f.dimensionIndexes.join(',') + '\n';
|
|
1212
1228
|
from += this.parent.dialect.sqlGroupSetTable(this.maxGroupSet) + '\n';
|
|
@@ -1225,7 +1241,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1225
1241
|
generateDepthNFields(depth, resultSet, output, stageWriter) {
|
|
1226
1242
|
const groupsToMap = [];
|
|
1227
1243
|
for (const [name, fi] of resultSet.allFields) {
|
|
1228
|
-
const sqlFieldName = this.parent.dialect.
|
|
1244
|
+
const sqlFieldName = this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultSet.groupSet}`);
|
|
1229
1245
|
if (fi instanceof field_instance_1.FieldInstanceField) {
|
|
1230
1246
|
if (fi.fieldUsage.type === 'result') {
|
|
1231
1247
|
if ((0, query_node_1.isScalarField)(fi.f)) {
|
|
@@ -1329,15 +1345,15 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1329
1345
|
const outputPipelinedSQL = [];
|
|
1330
1346
|
const dimensionIndexes = [];
|
|
1331
1347
|
for (const [name, fi] of this.rootResult.allFields) {
|
|
1332
|
-
const sqlName = this.parent.dialect.
|
|
1348
|
+
const sqlName = this.parent.dialect.sqlQuoteIdentifier(name);
|
|
1333
1349
|
if (fi instanceof field_instance_1.FieldInstanceField) {
|
|
1334
1350
|
if (fi.fieldUsage.type === 'result') {
|
|
1335
1351
|
if ((0, query_node_1.isScalarField)(fi.f)) {
|
|
1336
|
-
fieldsSQL.push(this.parent.dialect.
|
|
1352
|
+
fieldsSQL.push(this.parent.dialect.sqlQuoteIdentifier(`${name}__${this.rootResult.groupSet}`) + ` as ${sqlName}`);
|
|
1337
1353
|
dimensionIndexes.push(fieldIndex++);
|
|
1338
1354
|
}
|
|
1339
1355
|
else if ((0, query_node_1.isBasicCalculation)(fi.f)) {
|
|
1340
|
-
fieldsSQL.push(this.parent.dialect.sqlAnyValueLastTurtle(this.parent.dialect.
|
|
1356
|
+
fieldsSQL.push(this.parent.dialect.sqlAnyValueLastTurtle(this.parent.dialect.sqlQuoteIdentifier(`${name}__${this.rootResult.groupSet}`), this.rootResult.groupSet, sqlName));
|
|
1341
1357
|
fieldIndex++;
|
|
1342
1358
|
}
|
|
1343
1359
|
}
|
|
@@ -1348,7 +1364,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1348
1364
|
fieldIndex++;
|
|
1349
1365
|
}
|
|
1350
1366
|
else if (fi.firstSegment.type === 'project') {
|
|
1351
|
-
fieldsSQL.push(this.parent.dialect.sqlAnyValueLastTurtle(this.parent.dialect.
|
|
1367
|
+
fieldsSQL.push(this.parent.dialect.sqlAnyValueLastTurtle(this.parent.dialect.sqlQuoteIdentifier(`${name}__${this.rootResult.groupSet}`), this.rootResult.groupSet, sqlName));
|
|
1352
1368
|
fieldIndex++;
|
|
1353
1369
|
}
|
|
1354
1370
|
}
|
|
@@ -1375,7 +1391,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1375
1391
|
buildDialectFieldList(resultStruct) {
|
|
1376
1392
|
const dialectFieldList = [];
|
|
1377
1393
|
for (const [name, field] of resultStruct.allFields) {
|
|
1378
|
-
const sqlName = this.parent.dialect.
|
|
1394
|
+
const sqlName = this.parent.dialect.sqlQuoteIdentifier(name);
|
|
1379
1395
|
//
|
|
1380
1396
|
if (resultStruct.firstSegment.type === 'reduce' &&
|
|
1381
1397
|
field instanceof field_instance_1.FieldInstanceResult) {
|
|
@@ -1390,7 +1406,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1390
1406
|
};
|
|
1391
1407
|
dialectFieldList.push({
|
|
1392
1408
|
typeDef: multiLineNest,
|
|
1393
|
-
sqlExpression: this.parent.dialect.
|
|
1409
|
+
sqlExpression: this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultStruct.groupSet}`),
|
|
1394
1410
|
rawName: name,
|
|
1395
1411
|
sqlOutputName: sqlName,
|
|
1396
1412
|
});
|
|
@@ -1404,7 +1420,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1404
1420
|
};
|
|
1405
1421
|
dialectFieldList.push({
|
|
1406
1422
|
typeDef: oneLineNest,
|
|
1407
|
-
sqlExpression: this.parent.dialect.
|
|
1423
|
+
sqlExpression: this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultStruct.groupSet}`),
|
|
1408
1424
|
rawName: name,
|
|
1409
1425
|
sqlOutputName: sqlName,
|
|
1410
1426
|
});
|
|
@@ -1415,7 +1431,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1415
1431
|
field.fieldUsage.type === 'result') {
|
|
1416
1432
|
pushDialectField(dialectFieldList, {
|
|
1417
1433
|
fieldDef: field.f.fieldDef,
|
|
1418
|
-
sqlExpression: this.parent.dialect.
|
|
1434
|
+
sqlExpression: this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultStruct.groupSet}`),
|
|
1419
1435
|
rawName: name,
|
|
1420
1436
|
sqlOutputName: sqlName,
|
|
1421
1437
|
});
|
|
@@ -1449,10 +1465,10 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1449
1465
|
else {
|
|
1450
1466
|
orderingField = resultStruct.getFieldByNumber(ordering.field);
|
|
1451
1467
|
}
|
|
1452
|
-
const structField = this.parent.dialect.
|
|
1468
|
+
const structField = this.parent.dialect.sqlQuoteIdentifier(orderingField.name);
|
|
1453
1469
|
if (resultStruct.firstSegment.type === 'reduce') {
|
|
1454
1470
|
compiledOrderBy.push({
|
|
1455
|
-
field: this.parent.dialect.
|
|
1471
|
+
field: this.parent.dialect.sqlQuoteIdentifier(`${orderingField.name}__${resultStruct.groupSet}`),
|
|
1456
1472
|
structField,
|
|
1457
1473
|
dir: ordering.dir || 'asc',
|
|
1458
1474
|
});
|
|
@@ -1607,7 +1623,7 @@ class QueryQueryIndexStage extends QueryQuery {
|
|
|
1607
1623
|
}
|
|
1608
1624
|
expandField(f) {
|
|
1609
1625
|
const as = f.path.join('.');
|
|
1610
|
-
const field = this.parent.getQueryFieldByName(f.path);
|
|
1626
|
+
const field = this.parent.getQueryFieldByName(f.path, f.at);
|
|
1611
1627
|
return { as, field };
|
|
1612
1628
|
}
|
|
1613
1629
|
expandFields(resultStruct) {
|
|
@@ -1636,12 +1652,12 @@ class QueryQueryIndexStage extends QueryQuery {
|
|
|
1636
1652
|
generateSQL(stageWriter) {
|
|
1637
1653
|
let measureSQL = 'COUNT(*)';
|
|
1638
1654
|
const dialect = this.parent.dialect;
|
|
1639
|
-
const fieldNameColumn = dialect.
|
|
1640
|
-
const fieldPathColumn = dialect.
|
|
1641
|
-
const fieldValueColumn = dialect.
|
|
1642
|
-
const fieldTypeColumn = dialect.
|
|
1643
|
-
const fieldRangeColumn = dialect.
|
|
1644
|
-
const weightColumn = dialect.
|
|
1655
|
+
const fieldNameColumn = dialect.sqlQuoteIdentifier('fieldName');
|
|
1656
|
+
const fieldPathColumn = dialect.sqlQuoteIdentifier('fieldPath');
|
|
1657
|
+
const fieldValueColumn = dialect.sqlQuoteIdentifier('fieldValue');
|
|
1658
|
+
const fieldTypeColumn = dialect.sqlQuoteIdentifier('fieldType');
|
|
1659
|
+
const fieldRangeColumn = dialect.sqlQuoteIdentifier('fieldRange');
|
|
1660
|
+
const weightColumn = dialect.sqlQuoteIdentifier('weight');
|
|
1645
1661
|
const measureName = this.firstSegment.weightMeasure;
|
|
1646
1662
|
if (measureName) {
|
|
1647
1663
|
measureSQL = this.rootResult.getField(measureName).generateExpression();
|
|
@@ -1819,7 +1835,7 @@ class QueryQueryRaw extends QueryQuery {
|
|
|
1819
1835
|
if (this.parent.structDef.type !== 'sql_select') {
|
|
1820
1836
|
throw new Error('Invalid struct for QueryQueryRaw, currently only supports SQL');
|
|
1821
1837
|
}
|
|
1822
|
-
return stageWriter.addStage((0, sql_compiled_1.getCompiledSQL)(this.parent.structDef, (_a = this.parent.prepareResultOptions) !== null && _a !== void 0 ? _a : {},
|
|
1838
|
+
return stageWriter.addStage((0, sql_compiled_1.getCompiledSQL)(this.parent.structDef, (_a = this.parent.prepareResultOptions) !== null && _a !== void 0 ? _a : {}, (query, opts) => {
|
|
1823
1839
|
// Compile query to isolated SQL (not into parent's stageWriter)
|
|
1824
1840
|
const ret = this.compileQueryToStages(query, opts !== null && opts !== void 0 ? opts : {}, undefined, false);
|
|
1825
1841
|
return ret.sql;
|
|
@@ -13,17 +13,15 @@ export type CompileQueryCallback = (query: Query, opts?: PrepareResultOptions) =
|
|
|
13
13
|
*
|
|
14
14
|
* @param src The SQLSourceDef to compile
|
|
15
15
|
* @param opts PrepareResultOptions with buildManifest and connectionDigests
|
|
16
|
-
* @param quoteTablePath Dialect function to safely quote a table path
|
|
17
16
|
* @param compileQuery Callback to compile a Query to SQL
|
|
18
17
|
*/
|
|
19
|
-
export declare function getCompiledSQL(src: SQLSourceDef, opts: PrepareResultOptions,
|
|
18
|
+
export declare function getCompiledSQL(src: SQLSourceDef, opts: PrepareResultOptions, compileQuery: CompileQueryCallback): string;
|
|
20
19
|
/**
|
|
21
20
|
* Get the SQL for a PersistableSourceDef.
|
|
22
21
|
*
|
|
23
22
|
* @param source The persistable source to compile
|
|
24
|
-
* @param quoteTablePath Dialect function to quote table paths
|
|
25
23
|
* @param compileQuery Callback to compile a Query to SQL
|
|
26
24
|
* @param opts Optional - if provided with manifest, nested sources may be substituted.
|
|
27
25
|
* Omit for "full SQL" (e.g., when computing BuildID).
|
|
28
26
|
*/
|
|
29
|
-
export declare function getSourceSQL(source: PersistableSourceDef,
|
|
27
|
+
export declare function getSourceSQL(source: PersistableSourceDef, compileQuery: CompileQueryCallback, opts?: PrepareResultOptions): string;
|
|
@@ -8,6 +8,7 @@ exports.getCompiledSQL = getCompiledSQL;
|
|
|
8
8
|
exports.getSourceSQL = getSourceSQL;
|
|
9
9
|
const malloy_types_1 = require("./malloy_types");
|
|
10
10
|
const source_def_utils_1 = require("./source_def_utils");
|
|
11
|
+
const malloy_compile_error_1 = require("./malloy_compile_error");
|
|
11
12
|
/**
|
|
12
13
|
* Compile a SQLSourceDef to its final SQL string.
|
|
13
14
|
*
|
|
@@ -16,10 +17,9 @@ const source_def_utils_1 = require("./source_def_utils");
|
|
|
16
17
|
*
|
|
17
18
|
* @param src The SQLSourceDef to compile
|
|
18
19
|
* @param opts PrepareResultOptions with buildManifest and connectionDigests
|
|
19
|
-
* @param quoteTablePath Dialect function to safely quote a table path
|
|
20
20
|
* @param compileQuery Callback to compile a Query to SQL
|
|
21
21
|
*/
|
|
22
|
-
function getCompiledSQL(src, opts,
|
|
22
|
+
function getCompiledSQL(src, opts, compileQuery) {
|
|
23
23
|
// If no segments, just return the pre-computed selectStr
|
|
24
24
|
if (!src.selectSegments || src.selectSegments.length === 0) {
|
|
25
25
|
return src.selectStr;
|
|
@@ -27,60 +27,63 @@ function getCompiledSQL(src, opts, quoteTablePath, compileQuery) {
|
|
|
27
27
|
// Expand each segment
|
|
28
28
|
const parts = [];
|
|
29
29
|
for (const segment of src.selectSegments) {
|
|
30
|
-
parts.push(expandSegment(segment, opts,
|
|
30
|
+
parts.push(expandSegment(segment, opts, compileQuery));
|
|
31
31
|
}
|
|
32
32
|
return parts.join('');
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
35
|
* Expand a single SQLPhraseSegment to SQL.
|
|
36
36
|
*/
|
|
37
|
-
function expandSegment(segment, opts,
|
|
37
|
+
function expandSegment(segment, opts, compileQuery) {
|
|
38
38
|
// Plain SQL string
|
|
39
39
|
if ((0, malloy_types_1.isSegmentSQL)(segment)) {
|
|
40
40
|
return segment.sql;
|
|
41
41
|
}
|
|
42
42
|
// PersistableSourceDef (sql_select or query_source)
|
|
43
43
|
if ((0, malloy_types_1.isSegmentSource)(segment)) {
|
|
44
|
-
return expandPersistableSource(segment, opts,
|
|
44
|
+
return expandPersistableSource(segment, opts, compileQuery);
|
|
45
45
|
}
|
|
46
46
|
// Query segment
|
|
47
|
-
return expandQuery(segment, opts,
|
|
47
|
+
return expandQuery(segment, opts, compileQuery);
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* Expand a PersistableSourceDef, checking manifest for pre-built table.
|
|
51
51
|
* Always returns a subquery form: (SELECT * FROM table) or (inline SQL)
|
|
52
52
|
*/
|
|
53
|
-
function expandPersistableSource(source, opts,
|
|
53
|
+
function expandPersistableSource(source, opts, compileQuery) {
|
|
54
54
|
const { buildManifest, connectionDigests } = opts;
|
|
55
55
|
// Try manifest lookup if we have the required info (only for persistent sources)
|
|
56
56
|
if (buildManifest && connectionDigests && source.persistent) {
|
|
57
57
|
const connDigest = (0, malloy_types_1.safeRecordGet)(connectionDigests, source.connection);
|
|
58
58
|
if (connDigest) {
|
|
59
59
|
// Get the SQL for this source to compute BuildID (no opts = full SQL)
|
|
60
|
-
const sql = getSourceSQL(source,
|
|
60
|
+
const sql = getSourceSQL(source, compileQuery);
|
|
61
61
|
const buildId = (0, source_def_utils_1.mkBuildID)(connDigest, sql);
|
|
62
62
|
const entry = buildManifest.entries[buildId];
|
|
63
63
|
if (entry) {
|
|
64
|
-
// Found in manifest - substitute with subquery from persisted table
|
|
65
|
-
|
|
64
|
+
// Found in manifest - substitute with subquery from persisted table.
|
|
65
|
+
// entry.tableName is canonical SQL, supplied by the manifest builder.
|
|
66
|
+
return `(SELECT * FROM ${entry.tableName})`;
|
|
66
67
|
}
|
|
67
68
|
// Not in manifest
|
|
68
69
|
if (buildManifest.strict) {
|
|
69
|
-
const base = `Persist source '${source.sourceID}' not found in manifest
|
|
70
|
-
|
|
70
|
+
const base = `Persist source '${source.sourceID}' not found in manifest ` +
|
|
71
|
+
`(buildId: ${buildId}); strict manifest mode forbids fallback ` +
|
|
72
|
+
'to live compilation.';
|
|
73
|
+
throw new malloy_compile_error_1.MalloyCompileError(buildManifest.loadError
|
|
71
74
|
? `${base}\n ${buildManifest.loadError}`
|
|
72
|
-
: base);
|
|
75
|
+
: base, 'runtime-manifest-strict-miss', source.location);
|
|
73
76
|
}
|
|
74
77
|
}
|
|
75
78
|
}
|
|
76
79
|
// No manifest or not found - expand inline as subquery
|
|
77
|
-
const sql = getSourceSQL(source,
|
|
80
|
+
const sql = getSourceSQL(source, compileQuery, opts);
|
|
78
81
|
return `(${sql})`;
|
|
79
82
|
}
|
|
80
83
|
/**
|
|
81
84
|
* Expand a Query segment.
|
|
82
85
|
*/
|
|
83
|
-
function expandQuery(query, opts,
|
|
86
|
+
function expandQuery(query, opts, compileQuery) {
|
|
84
87
|
// Set isPartialQuery so CTEs aren't used (they can't be nested in subqueries)
|
|
85
88
|
const sql = compileQuery(query, { ...opts, isPartialQuery: true });
|
|
86
89
|
return `(${sql})`;
|
|
@@ -89,15 +92,14 @@ function expandQuery(query, opts, _quoteTablePath, compileQuery) {
|
|
|
89
92
|
* Get the SQL for a PersistableSourceDef.
|
|
90
93
|
*
|
|
91
94
|
* @param source The persistable source to compile
|
|
92
|
-
* @param quoteTablePath Dialect function to quote table paths
|
|
93
95
|
* @param compileQuery Callback to compile a Query to SQL
|
|
94
96
|
* @param opts Optional - if provided with manifest, nested sources may be substituted.
|
|
95
97
|
* Omit for "full SQL" (e.g., when computing BuildID).
|
|
96
98
|
*/
|
|
97
|
-
function getSourceSQL(source,
|
|
99
|
+
function getSourceSQL(source, compileQuery, opts) {
|
|
98
100
|
if (source.type === 'sql_select') {
|
|
99
101
|
// Recursive call for nested sql_select
|
|
100
|
-
return getCompiledSQL(source, opts !== null && opts !== void 0 ? opts : {},
|
|
102
|
+
return getCompiledSQL(source, opts !== null && opts !== void 0 ? opts : {}, compileQuery);
|
|
101
103
|
}
|
|
102
104
|
// query_source - compile the inner query
|
|
103
105
|
return compileQuery(source.query, opts);
|
package/dist/test/test-models.js
CHANGED
|
@@ -194,7 +194,7 @@ function generateSQL(dialect, rows) {
|
|
|
194
194
|
const sql = exprToSQL(typedValue.expr, dialect);
|
|
195
195
|
if (idx === 0) {
|
|
196
196
|
// First row: include column aliases and explicit casts if needed
|
|
197
|
-
const quotedName = dialect.
|
|
197
|
+
const quotedName = dialect.sqlQuoteIdentifier(colName);
|
|
198
198
|
if (typedValue.needsCast) {
|
|
199
199
|
const sqlType = dialect.malloyTypeToSQLType(typedValue.malloyType);
|
|
200
200
|
fields.push(`CAST(${sql} AS ${sqlType}) AS ${quotedName}`);
|
|
@@ -225,7 +225,7 @@ function generateSQL(dialect, rows) {
|
|
|
225
225
|
}
|
|
226
226
|
// Multiple rows: wrap for sorting
|
|
227
227
|
const quotedColumns = columnList
|
|
228
|
-
.map(col => dialect.
|
|
228
|
+
.map(col => dialect.sqlQuoteIdentifier(col))
|
|
229
229
|
.join(', ');
|
|
230
230
|
const innerQuery = selects.join('\nUNION ALL ');
|
|
231
231
|
// Generate ORDER BY based on dialect preference
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const MALLOY_VERSION = "0.0.
|
|
1
|
+
export declare const MALLOY_VERSION = "0.0.396";
|
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.396';
|
|
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.396",
|
|
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.396",
|
|
55
|
+
"@malloydata/malloy-interfaces": "0.0.396",
|
|
56
|
+
"@malloydata/malloy-tag": "0.0.396",
|
|
57
57
|
"@noble/hashes": "^1.8.0",
|
|
58
58
|
"antlr4ts": "^0.5.0-alpha.4",
|
|
59
59
|
"assert": "^2.0.0",
|