@malloydata/malloy 0.0.393 → 0.0.395
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/config.d.ts +2 -3
- package/dist/api/foundation/config.js +23 -11
- package/dist/api/foundation/core.d.ts +0 -4
- package/dist/api/foundation/core.js +14 -11
- package/dist/api/foundation/runtime.js +21 -1
- 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-compare.d.ts +15 -0
- package/dist/lang/ast/expressions/expr-compare.js +82 -2
- package/dist/lang/ast/source-elements/table-source.d.ts +1 -7
- package/dist/lang/ast/source-elements/table-source.js +20 -19
- package/dist/lang/ast/statements/define-given.d.ts +2 -1
- package/dist/lang/ast/statements/define-given.js +52 -1
- package/dist/lang/ast/types/malloy-element.js +2 -0
- package/dist/lang/lib/Malloy/MalloyParser.d.ts +188 -167
- package/dist/lang/lib/Malloy/MalloyParser.js +2582 -2442
- package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +24 -0
- package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +15 -0
- package/dist/lang/malloy-to-ast.d.ts +9 -2
- package/dist/lang/malloy-to-ast.js +37 -2
- package/dist/lang/parse-log.d.ts +23 -0
- package/dist/lang/parse-log.js +6 -0
- package/dist/lang/parse-malloy.js +37 -7
- 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/expr-to-str.js +3 -0
- package/dist/lang/translate-response.d.ts +1 -1
- package/dist/model/expression_compiler.js +38 -11
- package/dist/model/filter_compilers.js +1 -1
- package/dist/model/given_binding.d.ts +15 -0
- package/dist/model/given_binding.js +35 -0
- package/dist/model/inline_expr.d.ts +30 -0
- package/dist/model/inline_expr.js +184 -0
- package/dist/model/malloy_types.d.ts +19 -1
- package/dist/model/query_model_impl.js +7 -7
- package/dist/model/query_query.d.ts +1 -1
- package/dist/model/query_query.js +37 -33
- package/dist/model/sql_compiled.d.ts +2 -4
- package/dist/model/sql_compiled.js +14 -15
- 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
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright Contributors to the Malloy project
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.INLINE_LEAVES = exports.INLINE_OPS = void 0;
|
|
8
|
+
exports.inlineExpr = inlineExpr;
|
|
9
|
+
/**
|
|
10
|
+
* Operator node types allowed inside an `inline` given's default. Single
|
|
11
|
+
* source of truth — both the translator-side validator
|
|
12
|
+
* (`GivenDeclaration.execute`) and the bind-time evaluator below read
|
|
13
|
+
* this set when deciding whether an expression is reducible to a
|
|
14
|
+
* literal at bind time.
|
|
15
|
+
*
|
|
16
|
+
* Add a new operator here AND a corresponding `case` to `inlineExpr`'s
|
|
17
|
+
* switch in the same commit; the two are intentionally co-located so
|
|
18
|
+
* they can't drift apart.
|
|
19
|
+
*/
|
|
20
|
+
exports.INLINE_OPS = new Set([
|
|
21
|
+
'and',
|
|
22
|
+
'or',
|
|
23
|
+
'not',
|
|
24
|
+
'=',
|
|
25
|
+
'!=',
|
|
26
|
+
'>',
|
|
27
|
+
'<',
|
|
28
|
+
'>=',
|
|
29
|
+
'<=',
|
|
30
|
+
'inGiven',
|
|
31
|
+
'()',
|
|
32
|
+
]);
|
|
33
|
+
/**
|
|
34
|
+
* Leaf-shaped node types that are valid inside an inline expression but
|
|
35
|
+
* aren't "operators." Literals are returned as-is by the evaluator;
|
|
36
|
+
* `given` nodes resolve through the bound values map.
|
|
37
|
+
*/
|
|
38
|
+
exports.INLINE_LEAVES = new Set([
|
|
39
|
+
'stringLiteral',
|
|
40
|
+
'numberLiteral',
|
|
41
|
+
'true',
|
|
42
|
+
'false',
|
|
43
|
+
'null',
|
|
44
|
+
'arrayLiteral',
|
|
45
|
+
'given',
|
|
46
|
+
]);
|
|
47
|
+
/**
|
|
48
|
+
* Bind-time evaluator for `inline` given defaults. Walks the Expr tree,
|
|
49
|
+
* recursing on bound values for given-refs, and returns a literal Expr
|
|
50
|
+
* (string/number/boolean/null/arrayLiteral).
|
|
51
|
+
*
|
|
52
|
+
* Throws on any node outside `INLINE_OPS ∪ INLINE_LEAVES`. The
|
|
53
|
+
* translator's pre-flight check should have rejected such defaults
|
|
54
|
+
* already, so a throw here flags a compiler bug rather than a caller
|
|
55
|
+
* error.
|
|
56
|
+
*/
|
|
57
|
+
function inlineExpr(e, bound) {
|
|
58
|
+
switch (e.node) {
|
|
59
|
+
case 'stringLiteral':
|
|
60
|
+
case 'numberLiteral':
|
|
61
|
+
case 'true':
|
|
62
|
+
case 'false':
|
|
63
|
+
case 'null':
|
|
64
|
+
case 'arrayLiteral':
|
|
65
|
+
return e;
|
|
66
|
+
case 'given': {
|
|
67
|
+
const v = bound.get(e.id);
|
|
68
|
+
if (v === undefined) {
|
|
69
|
+
throw new Error(`inlineExpr: given '${e.refName}' has no bound value and no default — translator should have caught this earlier`);
|
|
70
|
+
}
|
|
71
|
+
return inlineExpr(v, bound);
|
|
72
|
+
}
|
|
73
|
+
case '()':
|
|
74
|
+
return inlineExpr(e.e, bound);
|
|
75
|
+
case 'not': {
|
|
76
|
+
const inner = inlineExpr(e.e, bound);
|
|
77
|
+
return toBoolLiteral(!exprAsBool(inner));
|
|
78
|
+
}
|
|
79
|
+
case 'and':
|
|
80
|
+
case 'or': {
|
|
81
|
+
const left = exprAsBool(inlineExpr(e.kids.left, bound));
|
|
82
|
+
const right = exprAsBool(inlineExpr(e.kids.right, bound));
|
|
83
|
+
return toBoolLiteral(e.node === 'and' ? left && right : left || right);
|
|
84
|
+
}
|
|
85
|
+
case '=':
|
|
86
|
+
case '!=':
|
|
87
|
+
case '>':
|
|
88
|
+
case '<':
|
|
89
|
+
case '>=':
|
|
90
|
+
case '<=': {
|
|
91
|
+
const left = inlineExpr(e.kids.left, bound);
|
|
92
|
+
const right = inlineExpr(e.kids.right, bound);
|
|
93
|
+
return toBoolLiteral(compareLiterals(e.node, left, right));
|
|
94
|
+
}
|
|
95
|
+
case 'inGiven': {
|
|
96
|
+
const lhs = inlineExpr(e.e, bound);
|
|
97
|
+
const arrBound = bound.get(e.givenRef.id);
|
|
98
|
+
if (arrBound === undefined) {
|
|
99
|
+
throw new Error(`inlineExpr: given '${e.givenRef.refName}' has no bound value and no default — translator should have caught this earlier`);
|
|
100
|
+
}
|
|
101
|
+
if (arrBound.node === 'null') {
|
|
102
|
+
return toBoolLiteral(e.not);
|
|
103
|
+
}
|
|
104
|
+
if (arrBound.node !== 'arrayLiteral') {
|
|
105
|
+
throw new Error(`inlineExpr: 'inGiven' bound to '${arrBound.node}', expected 'arrayLiteral'`);
|
|
106
|
+
}
|
|
107
|
+
const found = arrBound.kids.values.some(v => compareLiterals('=', lhs, inlineExpr(v, bound)));
|
|
108
|
+
return toBoolLiteral(e.not ? !found : found);
|
|
109
|
+
}
|
|
110
|
+
default:
|
|
111
|
+
throw new Error(`inlineExpr: unexpected node '${e.node}' — translator should have rejected this`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function toBoolLiteral(b) {
|
|
115
|
+
return { node: b ? 'true' : 'false' };
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Read a literal Expr as a JS boolean. The evaluator only ever produces
|
|
119
|
+
* 'true' / 'false' / 'null' / scalar literals here; anything else means
|
|
120
|
+
* we tried to use a non-boolean where a boolean was expected, which is a
|
|
121
|
+
* translator type-check bug.
|
|
122
|
+
*/
|
|
123
|
+
function exprAsBool(e) {
|
|
124
|
+
if (e.node === 'true')
|
|
125
|
+
return true;
|
|
126
|
+
if (e.node === 'false')
|
|
127
|
+
return false;
|
|
128
|
+
// `null` in boolean position is treated as false — matches the
|
|
129
|
+
// implicit SQL coalesce that Malloy does for filter expressions.
|
|
130
|
+
if (e.node === 'null')
|
|
131
|
+
return false;
|
|
132
|
+
throw new Error(`inlineExpr: expected boolean literal, got '${e.node}' — translator should have type-checked this`);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* JS-side comparison of two literal Exprs. Only the literal nodes
|
|
136
|
+
* produced by the evaluator are supported.
|
|
137
|
+
*
|
|
138
|
+
* SQL nullability: any operand being null produces false (matching
|
|
139
|
+
* Malloy's COALESCE-to-true / COALESCE-to-false behavior elsewhere).
|
|
140
|
+
*/
|
|
141
|
+
function compareLiterals(op, left, right) {
|
|
142
|
+
if (left.node === 'null' || right.node === 'null') {
|
|
143
|
+
// Mirror SQL: comparisons with NULL are unknown; treat as false for
|
|
144
|
+
// = / > / < / >= / <=, true for !=.
|
|
145
|
+
return op === '!=';
|
|
146
|
+
}
|
|
147
|
+
const l = literalToJS(left);
|
|
148
|
+
const r = literalToJS(right);
|
|
149
|
+
switch (op) {
|
|
150
|
+
case '=':
|
|
151
|
+
return l === r;
|
|
152
|
+
case '!=':
|
|
153
|
+
return l !== r;
|
|
154
|
+
case '>':
|
|
155
|
+
return l > r;
|
|
156
|
+
case '<':
|
|
157
|
+
return l < r;
|
|
158
|
+
case '>=':
|
|
159
|
+
return l >= r;
|
|
160
|
+
case '<=':
|
|
161
|
+
return l <= r;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Convert a literal Expr to a comparable JS value. Numbers come through
|
|
166
|
+
* `numberLiteral` as a string (full precision preserved); we parse to a
|
|
167
|
+
* JS number for ordering — bind-time precision loss here is fine
|
|
168
|
+
* because the result of an inline expression is a boolean for SQL.
|
|
169
|
+
*/
|
|
170
|
+
function literalToJS(e) {
|
|
171
|
+
switch (e.node) {
|
|
172
|
+
case 'stringLiteral':
|
|
173
|
+
return e.literal;
|
|
174
|
+
case 'numberLiteral':
|
|
175
|
+
return Number(e.literal);
|
|
176
|
+
case 'true':
|
|
177
|
+
return true;
|
|
178
|
+
case 'false':
|
|
179
|
+
return false;
|
|
180
|
+
default:
|
|
181
|
+
throw new Error(`inlineExpr: cannot compare non-literal node '${e.node}'`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=inline_expr.js.map
|
|
@@ -36,7 +36,7 @@ export type AnyExpr = ExprE | ExprOptionalE | ExprWithKids | ExprLeaf;
|
|
|
36
36
|
export declare function exprHasKids(e: AnyExpr): e is ExprWithKids;
|
|
37
37
|
export declare function exprHasE(e: AnyExpr): e is ExprE;
|
|
38
38
|
export declare function exprIsLeaf(e: AnyExpr): boolean;
|
|
39
|
-
export type Expr = BinaryExpr | UnaryExpr | FunctionCallNode | OutputFieldNode | FilterCondition | FilteredExpr | AggregateExpr | EmptyExpr | UngroupNode | FunctionParameterNode | SpreadExpr | AggregateOrderByNode | AggregateLimitNode | FieldnameNode | SourceReferenceNode | ParameterNode | GivenRefNode | NowNode | MeasureTimeExpr | TimeExtractExpr | TimeDeltaExpr | TimeTruncExpr | DateLiteralNode | TimestampLiteralNode | TimestamptzLiteralNode | TypecastExpr | RegexMatchExpr | RegexLiteralNode | FilterMatchExpr | FilterLiteralExpr | StringLiteralNode | NumberLiteralNode | BooleanLiteralNode | RecordLiteralNode | ArrayLiteralNode | FunctionOrderBy | GenericSQLExpr | NullNode | CaseExpr | InCompareExpr | CompositeFieldExpr | ErrorNode;
|
|
39
|
+
export type Expr = BinaryExpr | UnaryExpr | FunctionCallNode | OutputFieldNode | FilterCondition | FilteredExpr | AggregateExpr | EmptyExpr | UngroupNode | FunctionParameterNode | SpreadExpr | AggregateOrderByNode | AggregateLimitNode | FieldnameNode | SourceReferenceNode | ParameterNode | GivenRefNode | NowNode | MeasureTimeExpr | TimeExtractExpr | TimeDeltaExpr | TimeTruncExpr | DateLiteralNode | TimestampLiteralNode | TimestamptzLiteralNode | TypecastExpr | RegexMatchExpr | RegexLiteralNode | FilterMatchExpr | FilterLiteralExpr | StringLiteralNode | NumberLiteralNode | BooleanLiteralNode | RecordLiteralNode | ArrayLiteralNode | FunctionOrderBy | GenericSQLExpr | NullNode | CaseExpr | InCompareExpr | InGivenExpr | CompositeFieldExpr | ErrorNode;
|
|
40
40
|
export type BinaryOperator = '+' | '-' | '*' | '%' | '/' | 'and' | 'or' | '=' | '!=' | '>' | '<' | '>=' | '<=' | 'coalesce' | 'like' | '!like';
|
|
41
41
|
export interface BinaryExpr extends ExprWithKids {
|
|
42
42
|
node: BinaryOperator;
|
|
@@ -289,6 +289,19 @@ export interface InCompareExpr extends ExprWithKids {
|
|
|
289
289
|
oneOf: Expr[];
|
|
290
290
|
};
|
|
291
291
|
}
|
|
292
|
+
/**
|
|
293
|
+
* Test against a runtime-bound array given: `expr in $ARRAY_GIVEN`.
|
|
294
|
+
*
|
|
295
|
+
* Uses ExprE (one child `e`, the LHS). The given reference is embedded
|
|
296
|
+
* as a top-level field rather than a kid so the auto-visitor in
|
|
297
|
+
* `compileExpr` doesn't descend into it; resolution and per-element
|
|
298
|
+
* SQL emission happen in the `case 'inGiven':` handler.
|
|
299
|
+
*/
|
|
300
|
+
export interface InGivenExpr extends ExprE {
|
|
301
|
+
node: 'inGiven';
|
|
302
|
+
not: boolean;
|
|
303
|
+
givenRef: GivenRefNode;
|
|
304
|
+
}
|
|
292
305
|
export type ExpressionType = 'scalar' | 'aggregate' | 'scalar_analytic' | 'aggregate_analytic' | 'ungrouped_aggregate';
|
|
293
306
|
export interface Expression {
|
|
294
307
|
e?: Expr;
|
|
@@ -341,6 +354,11 @@ export interface Given extends HasLocation, HasAnnotation {
|
|
|
341
354
|
* its own default. Empty/undefined when the default is a closed
|
|
342
355
|
* literal. */
|
|
343
356
|
givenUsage?: GivenUsage;
|
|
357
|
+
/** Marked with the `inline` modifier — the default is eager-evaluated
|
|
358
|
+
* to a literal at bind time and substituted as that literal in SQL.
|
|
359
|
+
* Translator validates the default is eager-evaluable; bind-time
|
|
360
|
+
* evaluator (`model/inline_expr.ts`) performs the reduction. */
|
|
361
|
+
inline?: boolean;
|
|
344
362
|
}
|
|
345
363
|
export interface GivenEntry {
|
|
346
364
|
type: 'given';
|
|
@@ -107,12 +107,12 @@ class QueryModelImpl {
|
|
|
107
107
|
const fieldNames = [];
|
|
108
108
|
for (const f of ret.outputStruct.fields) {
|
|
109
109
|
if ((0, malloy_types_1.isAtomic)(f)) {
|
|
110
|
-
const quoted = q.parent.dialect.
|
|
110
|
+
const quoted = q.parent.dialect.sqlQuoteIdentifier(f.name);
|
|
111
111
|
fieldNames.push(quoted);
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
// const fieldNames = getAtomicFields(ret.outputStruct).map(fieldDef =>
|
|
115
|
-
// q.parent.dialect.
|
|
115
|
+
// q.parent.dialect.sqlQuoteIdentifier(fieldDef.name)
|
|
116
116
|
// );
|
|
117
117
|
ret.lastStageName = stageWriter.addStage(q.parent.dialect.sqlFinalStage(ret.lastStageName, fieldNames));
|
|
118
118
|
}
|
|
@@ -217,11 +217,11 @@ class QueryModelImpl {
|
|
|
217
217
|
},
|
|
218
218
|
],
|
|
219
219
|
};
|
|
220
|
-
const fieldNameColumn = d.
|
|
221
|
-
const fieldPathColumn = d.
|
|
222
|
-
const fieldValueColumn = d.
|
|
223
|
-
const fieldTypeColumn = d.
|
|
224
|
-
const weightColumn = d.
|
|
220
|
+
const fieldNameColumn = d.sqlQuoteIdentifier('fieldName');
|
|
221
|
+
const fieldPathColumn = d.sqlQuoteIdentifier('fieldPath');
|
|
222
|
+
const fieldValueColumn = d.sqlQuoteIdentifier('fieldValue');
|
|
223
|
+
const fieldTypeColumn = d.sqlQuoteIdentifier('fieldType');
|
|
224
|
+
const weightColumn = d.sqlQuoteIdentifier('weight');
|
|
225
225
|
// if we've compiled the SQL before use it otherwise
|
|
226
226
|
let sqlPDT = this.exploreSearchSQLMap.get(explore);
|
|
227
227
|
if (sqlPDT === undefined) {
|
|
@@ -103,7 +103,7 @@ export declare class QueryQuery extends QueryField {
|
|
|
103
103
|
generateTurtlePipelineSQL(fi: FieldInstanceResult, stageWriter: StageWriter, sourceSQLExpression: string): {
|
|
104
104
|
structDef: QueryResultDef;
|
|
105
105
|
pipeOut: any;
|
|
106
|
-
repeatedResultType: "
|
|
106
|
+
repeatedResultType: "inline" | "nested" | "inline_all_numbers";
|
|
107
107
|
};
|
|
108
108
|
generateComplexSQL(stageWriter: StageWriter): string;
|
|
109
109
|
generateSQL(stageWriter: StageWriter): string;
|
|
@@ -517,14 +517,17 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
517
517
|
var _a, _b, _c, _d;
|
|
518
518
|
switch (qs.structDef.type) {
|
|
519
519
|
case 'table':
|
|
520
|
-
|
|
520
|
+
// tablePath is canonical SQL — translator pre-validated.
|
|
521
|
+
return qs.structDef.tablePath;
|
|
521
522
|
case 'virtual': {
|
|
522
523
|
const virtualMap = (_a = qs.prepareResultOptions) === null || _a === void 0 ? void 0 : _a.virtualMap;
|
|
523
524
|
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
525
|
if (!tablePath) {
|
|
525
526
|
throw new Error(`No virtual map entry for '${qs.structDef.name}' on connection '${qs.structDef.connection}'`);
|
|
526
527
|
}
|
|
527
|
-
|
|
528
|
+
// virtualMap entries are application-supplied — assumed already
|
|
529
|
+
// canonical SQL.
|
|
530
|
+
return tablePath;
|
|
528
531
|
}
|
|
529
532
|
case 'composite':
|
|
530
533
|
// TODO: throw an error here; not simple because we call into this
|
|
@@ -533,7 +536,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
533
536
|
case 'finalize':
|
|
534
537
|
return qs.structDef.name;
|
|
535
538
|
case 'sql_select':
|
|
536
|
-
return `(${(0, sql_compiled_1.getCompiledSQL)(qs.structDef, (_c = qs.prepareResultOptions) !== null && _c !== void 0 ? _c : {},
|
|
539
|
+
return `(${(0, sql_compiled_1.getCompiledSQL)(qs.structDef, (_c = qs.prepareResultOptions) !== null && _c !== void 0 ? _c : {}, (query, opts) => {
|
|
537
540
|
// Compile query to isolated SQL (not into parent's stageWriter)
|
|
538
541
|
const ret = this.compileQueryToStages(query, opts !== null && opts !== void 0 ? opts : {}, undefined, false);
|
|
539
542
|
return ret.sql;
|
|
@@ -551,8 +554,9 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
551
554
|
const buildId = (0, source_def_utils_1.mkBuildID)(connDigest, fullRet.sql);
|
|
552
555
|
const entry = buildManifest.entries[buildId];
|
|
553
556
|
if (entry) {
|
|
554
|
-
// Found in manifest - use persisted table
|
|
555
|
-
|
|
557
|
+
// Found in manifest - use persisted table.
|
|
558
|
+
// entry.tableName comes from the manifest, assumed canonical.
|
|
559
|
+
return entry.tableName;
|
|
556
560
|
}
|
|
557
561
|
if (buildManifest.strict) {
|
|
558
562
|
const base = `Persist source '${qs.structDef.sourceID}' not found in manifest (buildId: ${buildId})`;
|
|
@@ -631,7 +635,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
631
635
|
}
|
|
632
636
|
if (ji.makeUniqueKey) {
|
|
633
637
|
const passKeys = this.generateSQLPassthroughKeys(qs);
|
|
634
|
-
structSQL = `(SELECT ${qs.dialect.sqlGenerateUUID()} as ${qs.dialect.
|
|
638
|
+
structSQL = `(SELECT ${qs.dialect.sqlGenerateUUID()} as ${qs.dialect.sqlQuoteIdentifier('__distinct_key')}, x.* ${passKeys} FROM ${structSQL} as x)`;
|
|
635
639
|
}
|
|
636
640
|
let onCondition = '';
|
|
637
641
|
if (qs.parent === undefined) {
|
|
@@ -764,7 +768,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
764
768
|
if ((0, malloy_types_1.isBaseTable)(qs.structDef)) {
|
|
765
769
|
if (ji.makeUniqueKey) {
|
|
766
770
|
const passKeys = this.generateSQLPassthroughKeys(qs);
|
|
767
|
-
structSQL = `(SELECT ${qs.dialect.sqlGenerateUUID()} as ${qs.dialect.
|
|
771
|
+
structSQL = `(SELECT ${qs.dialect.sqlGenerateUUID()} as ${qs.dialect.sqlQuoteIdentifier('__distinct_key')}, x.* ${passKeys} FROM ${structSQL} as x)`;
|
|
768
772
|
}
|
|
769
773
|
s += `FROM ${structSQL} as ${ji.alias}\n`;
|
|
770
774
|
}
|
|
@@ -846,7 +850,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
846
850
|
o.push(`${fi.fieldUsage.resultIndex} ${f.dir || 'ASC'}`);
|
|
847
851
|
}
|
|
848
852
|
else if (this.parent.dialect.orderByClause === 'output_name') {
|
|
849
|
-
o.push(`${this.parent.dialect.
|
|
853
|
+
o.push(`${this.parent.dialect.sqlQuoteIdentifier(f.field)} ${f.dir || 'ASC'}`);
|
|
850
854
|
}
|
|
851
855
|
else if (this.parent.dialect.orderByClause === 'expression') {
|
|
852
856
|
const fieldExpr = fi.getSQL();
|
|
@@ -863,7 +867,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
863
867
|
}
|
|
864
868
|
else if (this.parent.dialect.orderByClause === 'output_name') {
|
|
865
869
|
const orderingField = resultStruct.getFieldByNumber(f.field);
|
|
866
|
-
o.push(`${this.parent.dialect.
|
|
870
|
+
o.push(`${this.parent.dialect.sqlQuoteIdentifier(orderingField.name)} ${f.dir || 'ASC'}`);
|
|
867
871
|
}
|
|
868
872
|
else if (this.parent.dialect.orderByClause === 'expression') {
|
|
869
873
|
const orderingField = resultStruct.getFieldByNumber(f.field);
|
|
@@ -887,7 +891,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
887
891
|
const fields = [];
|
|
888
892
|
for (const [name, field] of this.rootResult.allFields) {
|
|
889
893
|
const fi = field;
|
|
890
|
-
const sqlName = this.parent.dialect.
|
|
894
|
+
const sqlName = this.parent.dialect.sqlQuoteIdentifier(name);
|
|
891
895
|
if (fi.fieldUsage.type === 'result') {
|
|
892
896
|
fields.push(` ${fi.generateExpression()} as ${sqlName}`);
|
|
893
897
|
}
|
|
@@ -937,7 +941,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
937
941
|
.map(o => `${o.pipelineSQL} as ${o.sqlFieldName}`)
|
|
938
942
|
.join(',\n');
|
|
939
943
|
const outputFields = outputPipelinedSQL.map(f => f.sqlFieldName);
|
|
940
|
-
const allFields = Array.from(this.rootResult.allFields.keys()).map(f => this.parent.dialect.
|
|
944
|
+
const allFields = Array.from(this.rootResult.allFields.keys()).map(f => this.parent.dialect.sqlQuoteIdentifier(f));
|
|
941
945
|
const fields = allFields.filter(f => outputFields.indexOf(f) === -1);
|
|
942
946
|
retSQL = `SELECT ${fields.length > 0 ? fields.join(', ') + ',' : ''} ${pipelinesSQL} FROM ${lastStageName}`;
|
|
943
947
|
}
|
|
@@ -956,7 +960,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
956
960
|
}
|
|
957
961
|
const orderedFields = [...scalarFields, ...otherFields];
|
|
958
962
|
for (const [name, fi] of orderedFields) {
|
|
959
|
-
const outputName = this.parent.dialect.
|
|
963
|
+
const outputName = this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultSet.groupSet}`);
|
|
960
964
|
if (fi instanceof field_instance_1.FieldInstanceField) {
|
|
961
965
|
if (fi.fieldUsage.type === 'result') {
|
|
962
966
|
const exp = fi.getSQL();
|
|
@@ -975,7 +979,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
975
979
|
});
|
|
976
980
|
output.sql.push(outputFieldName);
|
|
977
981
|
if (fi.f.fieldDef.type === 'number') {
|
|
978
|
-
const outputNameString = this.parent.dialect.
|
|
982
|
+
const outputNameString = this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultSet.groupSet}_string`);
|
|
979
983
|
const outputFieldNameString = `__lateral_join_bag.${outputNameString}`;
|
|
980
984
|
output.sql.push(outputFieldNameString);
|
|
981
985
|
output.dimensionIndexes.push(output.fieldIndex++);
|
|
@@ -1086,7 +1090,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1086
1090
|
let r = result;
|
|
1087
1091
|
while (r) {
|
|
1088
1092
|
for (const name of r.fieldNames(fi => (0, query_node_1.isScalarField)(fi.f))) {
|
|
1089
|
-
dimensions.push(this.parent.dialect.
|
|
1093
|
+
dimensions.push(this.parent.dialect.sqlQuoteIdentifier(`${name}__${r.groupSet}`));
|
|
1090
1094
|
}
|
|
1091
1095
|
r = r.parent;
|
|
1092
1096
|
}
|
|
@@ -1120,7 +1124,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1120
1124
|
orderingField = result.getFieldByNumber(ordering.field);
|
|
1121
1125
|
}
|
|
1122
1126
|
obSQL.push(' ' +
|
|
1123
|
-
this.parent.dialect.
|
|
1127
|
+
this.parent.dialect.sqlQuoteIdentifier(`${orderingField.name}__${result.groupSet}`) +
|
|
1124
1128
|
` ${ordering.dir || 'ASC'}`);
|
|
1125
1129
|
}
|
|
1126
1130
|
// partition for a row number is the parent if it exists.
|
|
@@ -1225,7 +1229,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1225
1229
|
generateDepthNFields(depth, resultSet, output, stageWriter) {
|
|
1226
1230
|
const groupsToMap = [];
|
|
1227
1231
|
for (const [name, fi] of resultSet.allFields) {
|
|
1228
|
-
const sqlFieldName = this.parent.dialect.
|
|
1232
|
+
const sqlFieldName = this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultSet.groupSet}`);
|
|
1229
1233
|
if (fi instanceof field_instance_1.FieldInstanceField) {
|
|
1230
1234
|
if (fi.fieldUsage.type === 'result') {
|
|
1231
1235
|
if ((0, query_node_1.isScalarField)(fi.f)) {
|
|
@@ -1329,15 +1333,15 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1329
1333
|
const outputPipelinedSQL = [];
|
|
1330
1334
|
const dimensionIndexes = [];
|
|
1331
1335
|
for (const [name, fi] of this.rootResult.allFields) {
|
|
1332
|
-
const sqlName = this.parent.dialect.
|
|
1336
|
+
const sqlName = this.parent.dialect.sqlQuoteIdentifier(name);
|
|
1333
1337
|
if (fi instanceof field_instance_1.FieldInstanceField) {
|
|
1334
1338
|
if (fi.fieldUsage.type === 'result') {
|
|
1335
1339
|
if ((0, query_node_1.isScalarField)(fi.f)) {
|
|
1336
|
-
fieldsSQL.push(this.parent.dialect.
|
|
1340
|
+
fieldsSQL.push(this.parent.dialect.sqlQuoteIdentifier(`${name}__${this.rootResult.groupSet}`) + ` as ${sqlName}`);
|
|
1337
1341
|
dimensionIndexes.push(fieldIndex++);
|
|
1338
1342
|
}
|
|
1339
1343
|
else if ((0, query_node_1.isBasicCalculation)(fi.f)) {
|
|
1340
|
-
fieldsSQL.push(this.parent.dialect.sqlAnyValueLastTurtle(this.parent.dialect.
|
|
1344
|
+
fieldsSQL.push(this.parent.dialect.sqlAnyValueLastTurtle(this.parent.dialect.sqlQuoteIdentifier(`${name}__${this.rootResult.groupSet}`), this.rootResult.groupSet, sqlName));
|
|
1341
1345
|
fieldIndex++;
|
|
1342
1346
|
}
|
|
1343
1347
|
}
|
|
@@ -1348,7 +1352,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1348
1352
|
fieldIndex++;
|
|
1349
1353
|
}
|
|
1350
1354
|
else if (fi.firstSegment.type === 'project') {
|
|
1351
|
-
fieldsSQL.push(this.parent.dialect.sqlAnyValueLastTurtle(this.parent.dialect.
|
|
1355
|
+
fieldsSQL.push(this.parent.dialect.sqlAnyValueLastTurtle(this.parent.dialect.sqlQuoteIdentifier(`${name}__${this.rootResult.groupSet}`), this.rootResult.groupSet, sqlName));
|
|
1352
1356
|
fieldIndex++;
|
|
1353
1357
|
}
|
|
1354
1358
|
}
|
|
@@ -1375,7 +1379,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1375
1379
|
buildDialectFieldList(resultStruct) {
|
|
1376
1380
|
const dialectFieldList = [];
|
|
1377
1381
|
for (const [name, field] of resultStruct.allFields) {
|
|
1378
|
-
const sqlName = this.parent.dialect.
|
|
1382
|
+
const sqlName = this.parent.dialect.sqlQuoteIdentifier(name);
|
|
1379
1383
|
//
|
|
1380
1384
|
if (resultStruct.firstSegment.type === 'reduce' &&
|
|
1381
1385
|
field instanceof field_instance_1.FieldInstanceResult) {
|
|
@@ -1390,7 +1394,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1390
1394
|
};
|
|
1391
1395
|
dialectFieldList.push({
|
|
1392
1396
|
typeDef: multiLineNest,
|
|
1393
|
-
sqlExpression: this.parent.dialect.
|
|
1397
|
+
sqlExpression: this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultStruct.groupSet}`),
|
|
1394
1398
|
rawName: name,
|
|
1395
1399
|
sqlOutputName: sqlName,
|
|
1396
1400
|
});
|
|
@@ -1404,7 +1408,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1404
1408
|
};
|
|
1405
1409
|
dialectFieldList.push({
|
|
1406
1410
|
typeDef: oneLineNest,
|
|
1407
|
-
sqlExpression: this.parent.dialect.
|
|
1411
|
+
sqlExpression: this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultStruct.groupSet}`),
|
|
1408
1412
|
rawName: name,
|
|
1409
1413
|
sqlOutputName: sqlName,
|
|
1410
1414
|
});
|
|
@@ -1415,7 +1419,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1415
1419
|
field.fieldUsage.type === 'result') {
|
|
1416
1420
|
pushDialectField(dialectFieldList, {
|
|
1417
1421
|
fieldDef: field.f.fieldDef,
|
|
1418
|
-
sqlExpression: this.parent.dialect.
|
|
1422
|
+
sqlExpression: this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultStruct.groupSet}`),
|
|
1419
1423
|
rawName: name,
|
|
1420
1424
|
sqlOutputName: sqlName,
|
|
1421
1425
|
});
|
|
@@ -1449,10 +1453,10 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1449
1453
|
else {
|
|
1450
1454
|
orderingField = resultStruct.getFieldByNumber(ordering.field);
|
|
1451
1455
|
}
|
|
1452
|
-
const structField = this.parent.dialect.
|
|
1456
|
+
const structField = this.parent.dialect.sqlQuoteIdentifier(orderingField.name);
|
|
1453
1457
|
if (resultStruct.firstSegment.type === 'reduce') {
|
|
1454
1458
|
compiledOrderBy.push({
|
|
1455
|
-
field: this.parent.dialect.
|
|
1459
|
+
field: this.parent.dialect.sqlQuoteIdentifier(`${orderingField.name}__${resultStruct.groupSet}`),
|
|
1456
1460
|
structField,
|
|
1457
1461
|
dir: ordering.dir || 'asc',
|
|
1458
1462
|
});
|
|
@@ -1636,12 +1640,12 @@ class QueryQueryIndexStage extends QueryQuery {
|
|
|
1636
1640
|
generateSQL(stageWriter) {
|
|
1637
1641
|
let measureSQL = 'COUNT(*)';
|
|
1638
1642
|
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.
|
|
1643
|
+
const fieldNameColumn = dialect.sqlQuoteIdentifier('fieldName');
|
|
1644
|
+
const fieldPathColumn = dialect.sqlQuoteIdentifier('fieldPath');
|
|
1645
|
+
const fieldValueColumn = dialect.sqlQuoteIdentifier('fieldValue');
|
|
1646
|
+
const fieldTypeColumn = dialect.sqlQuoteIdentifier('fieldType');
|
|
1647
|
+
const fieldRangeColumn = dialect.sqlQuoteIdentifier('fieldRange');
|
|
1648
|
+
const weightColumn = dialect.sqlQuoteIdentifier('weight');
|
|
1645
1649
|
const measureName = this.firstSegment.weightMeasure;
|
|
1646
1650
|
if (measureName) {
|
|
1647
1651
|
measureSQL = this.rootResult.getField(measureName).generateExpression();
|
|
@@ -1819,7 +1823,7 @@ class QueryQueryRaw extends QueryQuery {
|
|
|
1819
1823
|
if (this.parent.structDef.type !== 'sql_select') {
|
|
1820
1824
|
throw new Error('Invalid struct for QueryQueryRaw, currently only supports SQL');
|
|
1821
1825
|
}
|
|
1822
|
-
return stageWriter.addStage((0, sql_compiled_1.getCompiledSQL)(this.parent.structDef, (_a = this.parent.prepareResultOptions) !== null && _a !== void 0 ? _a : {},
|
|
1826
|
+
return stageWriter.addStage((0, sql_compiled_1.getCompiledSQL)(this.parent.structDef, (_a = this.parent.prepareResultOptions) !== null && _a !== void 0 ? _a : {}, (query, opts) => {
|
|
1823
1827
|
// Compile query to isolated SQL (not into parent's stageWriter)
|
|
1824
1828
|
const ret = this.compileQueryToStages(query, opts !== null && opts !== void 0 ? opts : {}, undefined, false);
|
|
1825
1829
|
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;
|
|
@@ -16,10 +16,9 @@ const source_def_utils_1 = require("./source_def_utils");
|
|
|
16
16
|
*
|
|
17
17
|
* @param src The SQLSourceDef to compile
|
|
18
18
|
* @param opts PrepareResultOptions with buildManifest and connectionDigests
|
|
19
|
-
* @param quoteTablePath Dialect function to safely quote a table path
|
|
20
19
|
* @param compileQuery Callback to compile a Query to SQL
|
|
21
20
|
*/
|
|
22
|
-
function getCompiledSQL(src, opts,
|
|
21
|
+
function getCompiledSQL(src, opts, compileQuery) {
|
|
23
22
|
// If no segments, just return the pre-computed selectStr
|
|
24
23
|
if (!src.selectSegments || src.selectSegments.length === 0) {
|
|
25
24
|
return src.selectStr;
|
|
@@ -27,42 +26,43 @@ function getCompiledSQL(src, opts, quoteTablePath, compileQuery) {
|
|
|
27
26
|
// Expand each segment
|
|
28
27
|
const parts = [];
|
|
29
28
|
for (const segment of src.selectSegments) {
|
|
30
|
-
parts.push(expandSegment(segment, opts,
|
|
29
|
+
parts.push(expandSegment(segment, opts, compileQuery));
|
|
31
30
|
}
|
|
32
31
|
return parts.join('');
|
|
33
32
|
}
|
|
34
33
|
/**
|
|
35
34
|
* Expand a single SQLPhraseSegment to SQL.
|
|
36
35
|
*/
|
|
37
|
-
function expandSegment(segment, opts,
|
|
36
|
+
function expandSegment(segment, opts, compileQuery) {
|
|
38
37
|
// Plain SQL string
|
|
39
38
|
if ((0, malloy_types_1.isSegmentSQL)(segment)) {
|
|
40
39
|
return segment.sql;
|
|
41
40
|
}
|
|
42
41
|
// PersistableSourceDef (sql_select or query_source)
|
|
43
42
|
if ((0, malloy_types_1.isSegmentSource)(segment)) {
|
|
44
|
-
return expandPersistableSource(segment, opts,
|
|
43
|
+
return expandPersistableSource(segment, opts, compileQuery);
|
|
45
44
|
}
|
|
46
45
|
// Query segment
|
|
47
|
-
return expandQuery(segment, opts,
|
|
46
|
+
return expandQuery(segment, opts, compileQuery);
|
|
48
47
|
}
|
|
49
48
|
/**
|
|
50
49
|
* Expand a PersistableSourceDef, checking manifest for pre-built table.
|
|
51
50
|
* Always returns a subquery form: (SELECT * FROM table) or (inline SQL)
|
|
52
51
|
*/
|
|
53
|
-
function expandPersistableSource(source, opts,
|
|
52
|
+
function expandPersistableSource(source, opts, compileQuery) {
|
|
54
53
|
const { buildManifest, connectionDigests } = opts;
|
|
55
54
|
// Try manifest lookup if we have the required info (only for persistent sources)
|
|
56
55
|
if (buildManifest && connectionDigests && source.persistent) {
|
|
57
56
|
const connDigest = (0, malloy_types_1.safeRecordGet)(connectionDigests, source.connection);
|
|
58
57
|
if (connDigest) {
|
|
59
58
|
// Get the SQL for this source to compute BuildID (no opts = full SQL)
|
|
60
|
-
const sql = getSourceSQL(source,
|
|
59
|
+
const sql = getSourceSQL(source, compileQuery);
|
|
61
60
|
const buildId = (0, source_def_utils_1.mkBuildID)(connDigest, sql);
|
|
62
61
|
const entry = buildManifest.entries[buildId];
|
|
63
62
|
if (entry) {
|
|
64
|
-
// Found in manifest - substitute with subquery from persisted table
|
|
65
|
-
|
|
63
|
+
// Found in manifest - substitute with subquery from persisted table.
|
|
64
|
+
// entry.tableName is canonical SQL, supplied by the manifest builder.
|
|
65
|
+
return `(SELECT * FROM ${entry.tableName})`;
|
|
66
66
|
}
|
|
67
67
|
// Not in manifest
|
|
68
68
|
if (buildManifest.strict) {
|
|
@@ -74,13 +74,13 @@ function expandPersistableSource(source, opts, quoteTablePath, compileQuery) {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
// No manifest or not found - expand inline as subquery
|
|
77
|
-
const sql = getSourceSQL(source,
|
|
77
|
+
const sql = getSourceSQL(source, compileQuery, opts);
|
|
78
78
|
return `(${sql})`;
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
81
81
|
* Expand a Query segment.
|
|
82
82
|
*/
|
|
83
|
-
function expandQuery(query, opts,
|
|
83
|
+
function expandQuery(query, opts, compileQuery) {
|
|
84
84
|
// Set isPartialQuery so CTEs aren't used (they can't be nested in subqueries)
|
|
85
85
|
const sql = compileQuery(query, { ...opts, isPartialQuery: true });
|
|
86
86
|
return `(${sql})`;
|
|
@@ -89,15 +89,14 @@ function expandQuery(query, opts, _quoteTablePath, compileQuery) {
|
|
|
89
89
|
* Get the SQL for a PersistableSourceDef.
|
|
90
90
|
*
|
|
91
91
|
* @param source The persistable source to compile
|
|
92
|
-
* @param quoteTablePath Dialect function to quote table paths
|
|
93
92
|
* @param compileQuery Callback to compile a Query to SQL
|
|
94
93
|
* @param opts Optional - if provided with manifest, nested sources may be substituted.
|
|
95
94
|
* Omit for "full SQL" (e.g., when computing BuildID).
|
|
96
95
|
*/
|
|
97
|
-
function getSourceSQL(source,
|
|
96
|
+
function getSourceSQL(source, compileQuery, opts) {
|
|
98
97
|
if (source.type === 'sql_select') {
|
|
99
98
|
// Recursive call for nested sql_select
|
|
100
|
-
return getCompiledSQL(source, opts !== null && opts !== void 0 ? opts : {},
|
|
99
|
+
return getCompiledSQL(source, opts !== null && opts !== void 0 ? opts : {}, compileQuery);
|
|
101
100
|
}
|
|
102
101
|
// query_source - compile the inner query
|
|
103
102
|
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.395";
|