@malloydata/malloy 0.0.305 → 0.0.307
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/lang/malloy-to-stable-query.js +12 -0
- package/dist/model/constant_expression_compiler.d.ts +22 -0
- package/dist/model/constant_expression_compiler.js +144 -0
- package/dist/model/expression_compiler.d.ts +20 -21
- package/dist/model/expression_compiler.js +82 -88
- package/dist/model/field_instance.d.ts +2 -2
- package/dist/model/field_instance.js +3 -3
- package/dist/model/index.d.ts +1 -0
- package/dist/model/index.js +3 -1
- package/dist/model/query_query.js +3 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -885,6 +885,18 @@ class MalloyToQuery extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor
|
|
|
885
885
|
else if (literalCx instanceof parse.ExprNULLContext) {
|
|
886
886
|
return { kind: 'null_literal' };
|
|
887
887
|
}
|
|
888
|
+
else if (literalCx instanceof parse.FilterString_stubContext) {
|
|
889
|
+
const filterContext = literalCx.getChild(0);
|
|
890
|
+
if (filterContext instanceof parse.FilterStringContext) {
|
|
891
|
+
const filterString = this.getFilterString(filterContext);
|
|
892
|
+
if (filterString) {
|
|
893
|
+
return {
|
|
894
|
+
kind: 'filter_expression_literal',
|
|
895
|
+
filter_expression_value: filterString,
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}
|
|
888
900
|
return null;
|
|
889
901
|
}
|
|
890
902
|
getDrill(drillCx) {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Expr, Parameter } from './malloy_types';
|
|
2
|
+
import type { Dialect } from '../dialect';
|
|
3
|
+
import type { EventStream } from '../runtime_types';
|
|
4
|
+
type ConstantExpressionResult = {
|
|
5
|
+
sql: string;
|
|
6
|
+
error?: undefined;
|
|
7
|
+
} | {
|
|
8
|
+
sql?: undefined;
|
|
9
|
+
error: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Compiles an IR expression containing only constants and parameters to SQL.
|
|
13
|
+
* This is useful for expressions that don't reference source fields.
|
|
14
|
+
*
|
|
15
|
+
* @param expr The expression to compile (should contain only literals, parameters, and operations on them)
|
|
16
|
+
* @param dialect The SQL dialect to use for generation
|
|
17
|
+
* @param parameters Parameters that can be referenced in the expression
|
|
18
|
+
* @param eventStream Optional event stream for debugging/tracking
|
|
19
|
+
* @returns Either {sql: string} on success or {error: string} on failure
|
|
20
|
+
*/
|
|
21
|
+
export declare function constantExprToSQL(expr: Expr, dialect: Dialect, parameters?: Record<string, Parameter>, eventStream?: EventStream): ConstantExpressionResult;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,144 @@
|
|
|
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.constantExprToSQL = constantExprToSQL;
|
|
8
|
+
const expression_compiler_1 = require("./expression_compiler");
|
|
9
|
+
const utils_1 = require("./utils");
|
|
10
|
+
const query_node_1 = require("./query_node");
|
|
11
|
+
const field_instance_1 = require("./field_instance");
|
|
12
|
+
/**
|
|
13
|
+
* Custom error class for constant expression compilation errors.
|
|
14
|
+
* Used to distinguish expected errors from unexpected ones.
|
|
15
|
+
*/
|
|
16
|
+
class ConstantExpressionError extends Error {
|
|
17
|
+
constructor(message) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = 'ConstantExpressionError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Minimal FieldInstanceResultRoot for constant expressions.
|
|
24
|
+
* This serves as both the result set and its own root, providing
|
|
25
|
+
* only what's needed by exprToSQL for constants.
|
|
26
|
+
*/
|
|
27
|
+
class ConstantFieldInstanceResultRoot extends field_instance_1.FieldInstanceResultRoot {
|
|
28
|
+
constructor() {
|
|
29
|
+
// Create a minimal TurtleDef
|
|
30
|
+
const minimalTurtleDef = {
|
|
31
|
+
type: 'turtle',
|
|
32
|
+
name: '__constant__',
|
|
33
|
+
pipeline: [],
|
|
34
|
+
};
|
|
35
|
+
super(minimalTurtleDef);
|
|
36
|
+
this.joins = new Map();
|
|
37
|
+
this.havings = new utils_1.AndChain();
|
|
38
|
+
this.isComplexQuery = false;
|
|
39
|
+
this.queryUsesPartitioning = false;
|
|
40
|
+
this.computeOnlyGroups = [];
|
|
41
|
+
this.elimatedComputeGroups = false;
|
|
42
|
+
// Create minimal SourceDef for outputStruct
|
|
43
|
+
const minimalOutputStruct = {
|
|
44
|
+
type: 'table',
|
|
45
|
+
name: '__constant_output__',
|
|
46
|
+
fields: [],
|
|
47
|
+
tablePath: '__constant__',
|
|
48
|
+
connection: '__constant__',
|
|
49
|
+
dialect: 'standardsql',
|
|
50
|
+
};
|
|
51
|
+
// Create minimal QuerySegment
|
|
52
|
+
const minimalSegment = {
|
|
53
|
+
type: 'project',
|
|
54
|
+
filterList: [],
|
|
55
|
+
queryFields: [],
|
|
56
|
+
outputStruct: minimalOutputStruct,
|
|
57
|
+
isRepeated: false,
|
|
58
|
+
};
|
|
59
|
+
this.firstSegment = minimalSegment;
|
|
60
|
+
}
|
|
61
|
+
root() {
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
getQueryInfo() {
|
|
65
|
+
// Return minimal query info - constants don't need timezone
|
|
66
|
+
return {
|
|
67
|
+
queryTimezone: 'UTC',
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Minimal QueryStruct subclass for constant expression compilation.
|
|
73
|
+
* This provides only what's needed to compile expressions containing
|
|
74
|
+
* literals and parameters, without requiring a full query structure.
|
|
75
|
+
*/
|
|
76
|
+
class ConstantQueryStruct extends query_node_1.QueryStruct {
|
|
77
|
+
constructor(dialect, parameters, eventStream) {
|
|
78
|
+
// Create a minimal StructDef that satisfies the constructor requirements
|
|
79
|
+
const minimalStructDef = {
|
|
80
|
+
type: 'table',
|
|
81
|
+
name: '__constant__',
|
|
82
|
+
fields: [],
|
|
83
|
+
tablePath: '__constant__',
|
|
84
|
+
connection: dialect.name,
|
|
85
|
+
dialect: dialect.name,
|
|
86
|
+
};
|
|
87
|
+
// Create a minimal model interface that only provides eventStream
|
|
88
|
+
const minimalModel = { eventStream };
|
|
89
|
+
// Create minimal prepare result options
|
|
90
|
+
const minimalPrepareOptions = {};
|
|
91
|
+
// Call parent constructor with minimal requirements
|
|
92
|
+
super(minimalStructDef, undefined, // no source arguments initially
|
|
93
|
+
{ model: minimalModel }, minimalPrepareOptions);
|
|
94
|
+
this.dialect = dialect;
|
|
95
|
+
this._constantArguments = parameters;
|
|
96
|
+
if (eventStream) {
|
|
97
|
+
this.model.eventStream = eventStream;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Override arguments() to return our parameters
|
|
102
|
+
*/
|
|
103
|
+
arguments() {
|
|
104
|
+
return this._constantArguments;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* These methods should not be called for constant expressions
|
|
108
|
+
*/
|
|
109
|
+
getFieldByName(path) {
|
|
110
|
+
throw new ConstantExpressionError(`Illegal reference to '${path.join('.')}' in constant expressions`);
|
|
111
|
+
}
|
|
112
|
+
getStructByName(path) {
|
|
113
|
+
throw new ConstantExpressionError(`Illegal reference to '${path.join('.')}' in constant expressions`);
|
|
114
|
+
}
|
|
115
|
+
getSQLIdentifier() {
|
|
116
|
+
throw new ConstantExpressionError('Constant expressions do not need SQL identifiers');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Compiles an IR expression containing only constants and parameters to SQL.
|
|
121
|
+
* This is useful for expressions that don't reference source fields.
|
|
122
|
+
*
|
|
123
|
+
* @param expr The expression to compile (should contain only literals, parameters, and operations on them)
|
|
124
|
+
* @param dialect The SQL dialect to use for generation
|
|
125
|
+
* @param parameters Parameters that can be referenced in the expression
|
|
126
|
+
* @param eventStream Optional event stream for debugging/tracking
|
|
127
|
+
* @returns Either {sql: string} on success or {error: string} on failure
|
|
128
|
+
*/
|
|
129
|
+
function constantExprToSQL(expr, dialect, parameters = {}, eventStream) {
|
|
130
|
+
try {
|
|
131
|
+
const context = new ConstantQueryStruct(dialect, parameters, eventStream);
|
|
132
|
+
const resultSet = new ConstantFieldInstanceResultRoot();
|
|
133
|
+
const sql = (0, expression_compiler_1.exprToSQL)(resultSet, context, expr);
|
|
134
|
+
return { sql };
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
if (error instanceof ConstantExpressionError) {
|
|
138
|
+
return { error: error.message };
|
|
139
|
+
}
|
|
140
|
+
// Re-throw unexpected errors
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=constant_expression_compiler.js.map
|
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
import type { Expr, FunctionCallNode, FunctionOverloadDef, FunctionOrderBy, FieldnameNode, OutputFieldNode, GenericSQLExpr, FilteredExpr, UngroupNode, ParameterNode,
|
|
1
|
+
import type { Expr, FunctionCallNode, FunctionOverloadDef, FunctionOrderBy, FieldnameNode, OutputFieldNode, GenericSQLExpr, FilteredExpr, UngroupNode, ParameterNode, AggregateExpr, SourceReferenceNode, CaseExpr } from './malloy_types';
|
|
2
2
|
import { type FieldInstanceResult } from './field_instance';
|
|
3
3
|
import { GenerateState } from './utils';
|
|
4
|
-
import type { QueryStruct
|
|
4
|
+
import type { QueryStruct } from './query_node';
|
|
5
5
|
/**
|
|
6
6
|
* Converts an expression to SQL.
|
|
7
7
|
* This function was extracted from QueryField.exprToSQL to break circular dependencies.
|
|
8
8
|
*/
|
|
9
|
-
export declare function exprToSQL(
|
|
10
|
-
export declare function generateFunctionCallExpression(
|
|
11
|
-
export declare function generateFieldFragment(
|
|
12
|
-
export declare function generateOutputFieldFragment(
|
|
13
|
-
export declare function generateParameterFragment(
|
|
14
|
-
export declare function generateFilterFragment(
|
|
15
|
-
export declare function generateDimFragment(
|
|
16
|
-
export declare function generateUngroupedFragment(
|
|
17
|
-
export declare function generateDistinctKeyIfNecessary(
|
|
18
|
-
export declare function generateSumFragment(
|
|
19
|
-
export declare function generateSymmetricFragment(
|
|
20
|
-
export declare function generateAvgFragment(
|
|
21
|
-
export declare function generateCountFragment(
|
|
22
|
-
export declare function
|
|
23
|
-
export declare function
|
|
24
|
-
export declare function
|
|
25
|
-
export declare function
|
|
26
|
-
export declare function
|
|
27
|
-
export declare function stringsFromSQLExpression(field: QueryField, resultSet: FieldInstanceResult, context: QueryStruct, e: GenericSQLExpr, state: GenerateState): Generator<string, void, unknown>;
|
|
9
|
+
export declare function exprToSQL(resultSet: FieldInstanceResult, context: QueryStruct, exprToTranslate: Expr, state?: GenerateState): string;
|
|
10
|
+
export declare function generateFunctionCallExpression(resultSet: FieldInstanceResult, context: QueryStruct, frag: FunctionCallNode, state: GenerateState): string;
|
|
11
|
+
export declare function generateFieldFragment(resultSet: FieldInstanceResult, context: QueryStruct, expr: FieldnameNode, state: GenerateState): string;
|
|
12
|
+
export declare function generateOutputFieldFragment(resultSet: FieldInstanceResult, _context: QueryStruct, frag: OutputFieldNode, _state: GenerateState): string;
|
|
13
|
+
export declare function generateParameterFragment(resultSet: FieldInstanceResult, context: QueryStruct, expr: ParameterNode, state: GenerateState): string;
|
|
14
|
+
export declare function generateFilterFragment(resultSet: FieldInstanceResult, context: QueryStruct, expr: FilteredExpr, state: GenerateState): string;
|
|
15
|
+
export declare function generateDimFragment(resultSet: FieldInstanceResult, context: QueryStruct, expr: Expr, state: GenerateState): string;
|
|
16
|
+
export declare function generateUngroupedFragment(resultSet: FieldInstanceResult, context: QueryStruct, expr: UngroupNode, state: GenerateState): string;
|
|
17
|
+
export declare function generateDistinctKeyIfNecessary(resultSet: FieldInstanceResult, context: QueryStruct, structPath: string[] | undefined): string | undefined;
|
|
18
|
+
export declare function generateSumFragment(resultSet: FieldInstanceResult, context: QueryStruct, expr: AggregateExpr, state: GenerateState): string;
|
|
19
|
+
export declare function generateSymmetricFragment(resultSet: FieldInstanceResult, context: QueryStruct, expr: AggregateExpr, state: GenerateState): string;
|
|
20
|
+
export declare function generateAvgFragment(resultSet: FieldInstanceResult, context: QueryStruct, expr: AggregateExpr, state: GenerateState): string;
|
|
21
|
+
export declare function generateCountFragment(resultSet: FieldInstanceResult, context: QueryStruct, expr: AggregateExpr, state: GenerateState): string;
|
|
22
|
+
export declare function generateSourceReference(resultSet: FieldInstanceResult, context: QueryStruct, expr: SourceReferenceNode): string;
|
|
23
|
+
export declare function generateCaseSQL(pf: CaseExpr): string;
|
|
24
|
+
export declare function getFunctionOrderBy(resultSet: FieldInstanceResult, context: QueryStruct, state: GenerateState, orderBy: FunctionOrderBy[], args: Expr[], overload: FunctionOverloadDef): string | undefined;
|
|
25
|
+
export declare function getAnalyticPartitions(resultStruct: FieldInstanceResult, extraPartitionFields?: string[]): string[];
|
|
26
|
+
export declare function stringsFromSQLExpression(resultSet: FieldInstanceResult, context: QueryStruct, e: GenericSQLExpr, state: GenerateState): Generator<string, void, unknown>;
|
|
@@ -17,7 +17,6 @@ exports.generateSumFragment = generateSumFragment;
|
|
|
17
17
|
exports.generateSymmetricFragment = generateSymmetricFragment;
|
|
18
18
|
exports.generateAvgFragment = generateAvgFragment;
|
|
19
19
|
exports.generateCountFragment = generateCountFragment;
|
|
20
|
-
exports.generateSpread = generateSpread;
|
|
21
20
|
exports.generateSourceReference = generateSourceReference;
|
|
22
21
|
exports.generateCaseSQL = generateCaseSQL;
|
|
23
22
|
exports.getFunctionOrderBy = getFunctionOrderBy;
|
|
@@ -51,11 +50,11 @@ function sqlSumDistinct(dialect, sqlExp, sqlDistintKey) {
|
|
|
51
50
|
* Converts an expression to SQL.
|
|
52
51
|
* This function was extracted from QueryField.exprToSQL to break circular dependencies.
|
|
53
52
|
*/
|
|
54
|
-
function exprToSQL(
|
|
53
|
+
function exprToSQL(resultSet, context, exprToTranslate, state = new utils_1.GenerateState()) {
|
|
55
54
|
var _a;
|
|
56
55
|
// Wrap non leaf sub expressions in parenthesis
|
|
57
|
-
const subExpr = function (
|
|
58
|
-
const sql = exprToSQL(
|
|
56
|
+
const subExpr = function (e) {
|
|
57
|
+
const sql = exprToSQL(resultSet, context, e, state);
|
|
59
58
|
if ((0, malloy_types_1.exprHasKids)(e)) {
|
|
60
59
|
return `(${sql})`;
|
|
61
60
|
}
|
|
@@ -69,7 +68,7 @@ function exprToSQL(field, resultSet, context, exprToTranslate, state = new utils
|
|
|
69
68
|
let expr = exprToTranslate;
|
|
70
69
|
if ((0, malloy_types_1.exprHasE)(exprToTranslate)) {
|
|
71
70
|
expr = { ...exprToTranslate };
|
|
72
|
-
const eSql = subExpr(
|
|
71
|
+
const eSql = subExpr(expr.e);
|
|
73
72
|
expr.e = { ...expr.e, sql: eSql };
|
|
74
73
|
}
|
|
75
74
|
else if ((0, malloy_types_1.exprHasKids)(exprToTranslate)) {
|
|
@@ -80,11 +79,11 @@ function exprToSQL(field, resultSet, context, exprToTranslate, state = new utils
|
|
|
80
79
|
continue;
|
|
81
80
|
if (Array.isArray(kidExpr)) {
|
|
82
81
|
expr.kids[name] = kidExpr.map(e => {
|
|
83
|
-
return { ...e, sql: subExpr(
|
|
82
|
+
return { ...e, sql: subExpr(e) };
|
|
84
83
|
});
|
|
85
84
|
}
|
|
86
85
|
else {
|
|
87
|
-
expr.kids[name] = { ...oldKids[name], sql: subExpr(
|
|
86
|
+
expr.kids[name] = { ...oldKids[name], sql: subExpr(kidExpr) };
|
|
88
87
|
}
|
|
89
88
|
}
|
|
90
89
|
}
|
|
@@ -92,37 +91,37 @@ function exprToSQL(field, resultSet, context, exprToTranslate, state = new utils
|
|
|
92
91
|
* Give the dialect a chance to translate this node
|
|
93
92
|
*/
|
|
94
93
|
const qi = resultSet.getQueryInfo();
|
|
95
|
-
const dialectSQL =
|
|
94
|
+
const dialectSQL = context.dialect.exprToSQL(qi, expr);
|
|
96
95
|
if (dialectSQL) {
|
|
97
96
|
return dialectSQL;
|
|
98
97
|
}
|
|
99
98
|
switch (expr.node) {
|
|
100
99
|
case 'field':
|
|
101
|
-
return generateFieldFragment(
|
|
100
|
+
return generateFieldFragment(resultSet, context, expr, state);
|
|
102
101
|
case 'parameter':
|
|
103
|
-
return generateParameterFragment(
|
|
102
|
+
return generateParameterFragment(resultSet, context, expr, state);
|
|
104
103
|
case 'filteredExpr':
|
|
105
|
-
return generateFilterFragment(
|
|
104
|
+
return generateFilterFragment(resultSet, context, expr, state);
|
|
106
105
|
case 'all':
|
|
107
106
|
case 'exclude':
|
|
108
|
-
return generateUngroupedFragment(
|
|
107
|
+
return generateUngroupedFragment(resultSet, context, expr, state);
|
|
109
108
|
case 'genericSQLExpr':
|
|
110
|
-
return Array.from(stringsFromSQLExpression(
|
|
109
|
+
return Array.from(stringsFromSQLExpression(resultSet, context, expr, state)).join('');
|
|
111
110
|
case 'aggregate': {
|
|
112
111
|
let agg = '';
|
|
113
112
|
if (expr.function === 'sum') {
|
|
114
|
-
agg = generateSumFragment(
|
|
113
|
+
agg = generateSumFragment(resultSet, context, expr, state);
|
|
115
114
|
}
|
|
116
115
|
else if (expr.function === 'avg') {
|
|
117
|
-
agg = generateAvgFragment(
|
|
116
|
+
agg = generateAvgFragment(resultSet, context, expr, state);
|
|
118
117
|
}
|
|
119
118
|
else if (expr.function === 'count') {
|
|
120
|
-
agg = generateCountFragment(
|
|
119
|
+
agg = generateCountFragment(resultSet, context, expr, state);
|
|
121
120
|
}
|
|
122
121
|
else if (expr.function === 'min' ||
|
|
123
122
|
expr.function === 'max' ||
|
|
124
123
|
expr.function === 'distinct') {
|
|
125
|
-
agg = generateSymmetricFragment(
|
|
124
|
+
agg = generateSymmetricFragment(resultSet, context, expr, state);
|
|
126
125
|
}
|
|
127
126
|
else {
|
|
128
127
|
throw new Error(`Internal Error: Unknown aggregate function ${expr.function}`);
|
|
@@ -139,13 +138,13 @@ function exprToSQL(field, resultSet, context, exprToTranslate, state = new utils
|
|
|
139
138
|
case 'function_parameter':
|
|
140
139
|
throw new Error('Internal Error: Function parameter fragment remaining during SQL generation');
|
|
141
140
|
case 'outputField':
|
|
142
|
-
return generateOutputFieldFragment(
|
|
141
|
+
return generateOutputFieldFragment(resultSet, context, expr, state);
|
|
143
142
|
case 'function_call':
|
|
144
|
-
return generateFunctionCallExpression(
|
|
143
|
+
return generateFunctionCallExpression(resultSet, context, expr, state);
|
|
145
144
|
case 'spread':
|
|
146
|
-
|
|
145
|
+
throw new Error("Internal Error: expandFunctionCall() failed to process node: 'spread'");
|
|
147
146
|
case 'source-reference':
|
|
148
|
-
return generateSourceReference(
|
|
147
|
+
return generateSourceReference(resultSet, context, expr);
|
|
149
148
|
case '+':
|
|
150
149
|
case '-':
|
|
151
150
|
case '*':
|
|
@@ -175,7 +174,7 @@ function exprToSQL(field, resultSet, context, exprToTranslate, state = new utils
|
|
|
175
174
|
case '!like': {
|
|
176
175
|
const likeIt = expr.node === 'like' ? 'LIKE' : 'NOT LIKE';
|
|
177
176
|
const compare = expr.kids.right.node === 'stringLiteral'
|
|
178
|
-
?
|
|
177
|
+
? context.dialect.sqlLike(likeIt, (_a = expr.kids.left.sql) !== null && _a !== void 0 ? _a : '', expr.kids.right.literal)
|
|
179
178
|
: `${expr.kids.left.sql} ${likeIt} ${expr.kids.right.sql}`;
|
|
180
179
|
return expr.node === 'like' ? compare : `COALESCE(${compare},true)`;
|
|
181
180
|
}
|
|
@@ -196,7 +195,7 @@ function exprToSQL(field, resultSet, context, exprToTranslate, state = new utils
|
|
|
196
195
|
case 'null':
|
|
197
196
|
return 'NULL';
|
|
198
197
|
case 'case':
|
|
199
|
-
return generateCaseSQL(
|
|
198
|
+
return generateCaseSQL(expr);
|
|
200
199
|
case '':
|
|
201
200
|
return '';
|
|
202
201
|
case 'filterCondition':
|
|
@@ -214,14 +213,14 @@ function exprToSQL(field, resultSet, context, exprToTranslate, state = new utils
|
|
|
214
213
|
case 'compositeField':
|
|
215
214
|
return '{COMPOSITE_FIELD}';
|
|
216
215
|
case 'filterMatch':
|
|
217
|
-
return generateAppliedFilter(
|
|
216
|
+
return generateAppliedFilter(context, expr);
|
|
218
217
|
case 'filterLiteral':
|
|
219
218
|
return 'INTERNAL ERROR FILTER EXPRESSION VALUE SHOULD NOT BE USED';
|
|
220
219
|
default:
|
|
221
220
|
throw new Error(`Internal Error: Unknown expression node '${expr.node}' ${JSON.stringify(expr, undefined, 2)}`);
|
|
222
221
|
}
|
|
223
222
|
}
|
|
224
|
-
function generateAppliedFilter(
|
|
223
|
+
function generateAppliedFilter(context, filterMatchExpr) {
|
|
225
224
|
var _a;
|
|
226
225
|
let filterExpr = filterMatchExpr.kids.filterExpr;
|
|
227
226
|
while (filterExpr.node === '()') {
|
|
@@ -335,19 +334,19 @@ function getParamForArgIndex(params, argIndex) {
|
|
|
335
334
|
const prevVariadic = params.slice(0, argIndex).find(p => p.isVariadic);
|
|
336
335
|
return prevVariadic !== null && prevVariadic !== void 0 ? prevVariadic : params[argIndex];
|
|
337
336
|
}
|
|
338
|
-
function generateAsymmetricStringAggExpression(
|
|
337
|
+
function generateAsymmetricStringAggExpression(resultSet, context, value, separator, distinctKey, orderBy, dialectName, state) {
|
|
339
338
|
if (orderBy) {
|
|
340
339
|
throw new Error(`Function \`string_agg\` does not support fanning out with an order by in ${dialectName}`);
|
|
341
340
|
}
|
|
342
|
-
const valueSQL = generateDimFragment(
|
|
341
|
+
const valueSQL = generateDimFragment(resultSet, context, value, state);
|
|
343
342
|
const separatorSQL = separator
|
|
344
|
-
? generateDimFragment(
|
|
343
|
+
? generateDimFragment(resultSet, context, separator, state)
|
|
345
344
|
: '';
|
|
346
|
-
return
|
|
345
|
+
return context.dialect.sqlStringAggDistinct(distinctKey, valueSQL, separatorSQL);
|
|
347
346
|
}
|
|
348
|
-
function generateAnalyticFragment(
|
|
347
|
+
function generateAnalyticFragment(dialect, resultStruct, context, expr, overload, state, args, partitionByFields, funcOrdering) {
|
|
349
348
|
const isComplex = resultStruct.root().isComplexQuery;
|
|
350
|
-
const partitionFields = getAnalyticPartitions(
|
|
349
|
+
const partitionFields = getAnalyticPartitions(resultStruct, partitionByFields);
|
|
351
350
|
const allPartitions = [
|
|
352
351
|
...(isComplex ? ['group_set'] : []),
|
|
353
352
|
...partitionFields,
|
|
@@ -396,7 +395,7 @@ function generateAnalyticFragment(field, dialect, resultStruct, context, expr, o
|
|
|
396
395
|
}
|
|
397
396
|
}
|
|
398
397
|
if (obSQL.length > 0) {
|
|
399
|
-
orderBy = ' ' +
|
|
398
|
+
orderBy = ' ' + context.dialect.sqlOrderBy(obSQL, 'analytical');
|
|
400
399
|
}
|
|
401
400
|
}
|
|
402
401
|
let between = '';
|
|
@@ -421,41 +420,41 @@ function generateAnalyticFragment(field, dialect, resultStruct, context, expr, o
|
|
|
421
420
|
});
|
|
422
421
|
between = `ROWS BETWEEN ${preceding} PRECEDING AND ${following} FOLLOWING`;
|
|
423
422
|
}
|
|
424
|
-
const funcSQL = exprToSQL(
|
|
423
|
+
const funcSQL = exprToSQL(resultStruct, context, expr, state);
|
|
425
424
|
let retExpr = `${funcSQL} OVER(${partitionBy} ${orderBy} ${between})`;
|
|
426
425
|
if (isComplex) {
|
|
427
426
|
retExpr = `CASE WHEN group_set=${resultStruct.groupSet} THEN ${retExpr} END`;
|
|
428
427
|
}
|
|
429
428
|
return retExpr;
|
|
430
429
|
}
|
|
431
|
-
function generateFunctionCallExpression(
|
|
430
|
+
function generateFunctionCallExpression(resultSet, context, frag, state) {
|
|
432
431
|
var _a, _b, _c;
|
|
433
432
|
const overload = frag.overload;
|
|
434
433
|
const args = frag.kids.args;
|
|
435
434
|
const isSymmetric = (_a = frag.overload.isSymmetric) !== null && _a !== void 0 ? _a : false;
|
|
436
435
|
const distinctKey = (0, malloy_types_1.expressionIsAggregate)(overload.returnType.expressionType) &&
|
|
437
436
|
!isSymmetric &&
|
|
438
|
-
generateDistinctKeyIfNecessary(
|
|
437
|
+
generateDistinctKeyIfNecessary(resultSet, context, frag.structPath);
|
|
439
438
|
const aggregateLimit = frag.limit ? `LIMIT ${frag.limit}` : undefined;
|
|
440
439
|
if (frag.name === 'string_agg' &&
|
|
441
440
|
distinctKey &&
|
|
442
441
|
!context.dialect.supportsAggDistinct &&
|
|
443
442
|
context.dialect.name !== 'snowflake') {
|
|
444
|
-
return generateAsymmetricStringAggExpression(
|
|
443
|
+
return generateAsymmetricStringAggExpression(resultSet, context, args[0], args[1], distinctKey, frag.kids.orderBy, context.dialect.name, state);
|
|
445
444
|
}
|
|
446
445
|
if (distinctKey) {
|
|
447
446
|
if (!context.dialect.supportsAggDistinct) {
|
|
448
447
|
throw new Error(`Function \`${frag.name}\` does not support fanning out in ${context.dialect.name}`);
|
|
449
448
|
}
|
|
450
449
|
const argsExpressions = args.map(arg => {
|
|
451
|
-
return generateDimFragment(
|
|
450
|
+
return generateDimFragment(resultSet, context, arg, state);
|
|
452
451
|
});
|
|
453
452
|
const orderBys = (_b = frag.kids.orderBy) !== null && _b !== void 0 ? _b : [];
|
|
454
453
|
const orderByExpressions = orderBys.map(ob => {
|
|
455
454
|
var _a;
|
|
456
455
|
const defaultOrderByArgIndex = (_a = overload.dialect[context.dialect.name].defaultOrderByArgIndex) !== null && _a !== void 0 ? _a : 0;
|
|
457
456
|
const expr = ob.node === 'functionOrderBy' ? ob.e : args[defaultOrderByArgIndex];
|
|
458
|
-
return generateDimFragment(
|
|
457
|
+
return generateDimFragment(resultSet, context, expr, state);
|
|
459
458
|
});
|
|
460
459
|
return context.dialect.sqlAggDistinct(distinctKey, [...argsExpressions, ...orderByExpressions], valNames => {
|
|
461
460
|
const vals = valNames.map((v, i) => {
|
|
@@ -476,9 +475,9 @@ function generateFunctionCallExpression(field, resultSet, context, frag, state)
|
|
|
476
475
|
.map((e, i) => {
|
|
477
476
|
return { node: 'functionOrderBy', e, dir: orderBys[i].dir };
|
|
478
477
|
});
|
|
479
|
-
const orderBySQL = getFunctionOrderBy(
|
|
478
|
+
const orderBySQL = getFunctionOrderBy(resultSet, context, state, orderBy, newArgs, overload);
|
|
480
479
|
const funcCall = expandFunctionCall(context.dialect.name, overload, newArgs, orderBySQL, aggregateLimit);
|
|
481
|
-
return exprToSQL(
|
|
480
|
+
return exprToSQL(resultSet, context, funcCall, state);
|
|
482
481
|
});
|
|
483
482
|
}
|
|
484
483
|
else {
|
|
@@ -500,28 +499,28 @@ function generateFunctionCallExpression(field, resultSet, context, frag, state)
|
|
|
500
499
|
return param.allowedTypes.every(t => (0, malloy_types_1.isLiteral)(t.evalSpace))
|
|
501
500
|
? arg
|
|
502
501
|
: (0, utils_1.composeSQLExpr)([
|
|
503
|
-
generateDimFragment(
|
|
502
|
+
generateDimFragment(resultSet, context, arg, state),
|
|
504
503
|
]);
|
|
505
504
|
})
|
|
506
505
|
: args;
|
|
507
506
|
const orderBySql = frag.kids.orderBy
|
|
508
|
-
? getFunctionOrderBy(
|
|
507
|
+
? getFunctionOrderBy(resultSet, context, state, frag.kids.orderBy, args, overload)
|
|
509
508
|
: '';
|
|
510
509
|
const funcCall = expandFunctionCall(context.dialect.name, overload, mappedArgs, orderBySql, aggregateLimit);
|
|
511
510
|
if ((0, malloy_types_1.expressionIsAnalytic)(overload.returnType.expressionType)) {
|
|
512
511
|
const extraPartitions = ((_c = frag.partitionBy) !== null && _c !== void 0 ? _c : []).map(outputName => {
|
|
513
512
|
return `(${resultSet.getField(outputName).getAnalyticalSQL(false)})`;
|
|
514
513
|
});
|
|
515
|
-
return generateAnalyticFragment(
|
|
514
|
+
return generateAnalyticFragment(context.dialect.name, resultSet, context, funcCall, overload, state, args, extraPartitions, orderBySql);
|
|
516
515
|
}
|
|
517
|
-
return exprToSQL(
|
|
516
|
+
return exprToSQL(resultSet, context, funcCall, state);
|
|
518
517
|
}
|
|
519
518
|
}
|
|
520
|
-
function generateFieldFragment(
|
|
519
|
+
function generateFieldFragment(resultSet, context, expr, state) {
|
|
521
520
|
// find the structDef and return the path to the field...
|
|
522
521
|
const fieldRef = context.getFieldByName(expr.path);
|
|
523
522
|
if ((0, malloy_types_1.hasExpression)(fieldRef.fieldDef)) {
|
|
524
|
-
const ret = exprToSQL(
|
|
523
|
+
const ret = exprToSQL(resultSet, fieldRef.parent, fieldRef.fieldDef.e, state);
|
|
525
524
|
return `(${ret})`;
|
|
526
525
|
}
|
|
527
526
|
else {
|
|
@@ -541,34 +540,34 @@ function generateFieldFragment(field, resultSet, context, expr, state) {
|
|
|
541
540
|
: undefined);
|
|
542
541
|
}
|
|
543
542
|
}
|
|
544
|
-
function generateOutputFieldFragment(
|
|
543
|
+
function generateOutputFieldFragment(resultSet, _context, frag, _state) {
|
|
545
544
|
return `(${resultSet.getField(frag.name).getAnalyticalSQL(false)})`;
|
|
546
545
|
}
|
|
547
|
-
function generateParameterFragment(
|
|
546
|
+
function generateParameterFragment(resultSet, context, expr, state) {
|
|
548
547
|
var _a;
|
|
549
548
|
const name = expr.path[0];
|
|
550
549
|
(_a = context.eventStream) === null || _a === void 0 ? void 0 : _a.emit('source-argument-compiled', { name });
|
|
551
550
|
const argument = context.arguments()[name];
|
|
552
551
|
if (argument.value) {
|
|
553
|
-
return exprToSQL(
|
|
552
|
+
return exprToSQL(resultSet, context, argument.value, state);
|
|
554
553
|
}
|
|
555
554
|
throw new Error(`Can't generate SQL, no value for ${expr.path}`);
|
|
556
555
|
}
|
|
557
|
-
function generateFilterFragment(
|
|
556
|
+
function generateFilterFragment(resultSet, context, expr, state) {
|
|
558
557
|
const allWhere = new utils_1.AndChain(state.whereSQL);
|
|
559
558
|
for (const cond of expr.kids.filterList) {
|
|
560
|
-
allWhere.add(exprToSQL(
|
|
559
|
+
allWhere.add(exprToSQL(resultSet, context, cond.e, state.withWhere()));
|
|
561
560
|
}
|
|
562
|
-
return exprToSQL(
|
|
561
|
+
return exprToSQL(resultSet, context, expr.kids.e, state.withWhere(allWhere.sql()));
|
|
563
562
|
}
|
|
564
|
-
function generateDimFragment(
|
|
565
|
-
let dim = exprToSQL(
|
|
563
|
+
function generateDimFragment(resultSet, context, expr, state) {
|
|
564
|
+
let dim = exprToSQL(resultSet, context, expr, state);
|
|
566
565
|
if (state.whereSQL) {
|
|
567
566
|
dim = `CASE WHEN ${state.whereSQL} THEN ${dim} END`;
|
|
568
567
|
}
|
|
569
568
|
return dim;
|
|
570
569
|
}
|
|
571
|
-
function generateUngroupedFragment(
|
|
570
|
+
function generateUngroupedFragment(resultSet, context, expr, state) {
|
|
572
571
|
if (state.totalGroupSet !== -1) {
|
|
573
572
|
throw new Error('Already in ALL. Cannot nest within an all calcuation.');
|
|
574
573
|
}
|
|
@@ -585,7 +584,7 @@ function generateUngroupedFragment(field, resultSet, context, expr, state) {
|
|
|
585
584
|
else {
|
|
586
585
|
totalGroupSet = resultSet.parent ? resultSet.parent.groupSet : 0;
|
|
587
586
|
}
|
|
588
|
-
const s = exprToSQL(
|
|
587
|
+
const s = exprToSQL(resultSet, context, expr.e, state.withTotal(totalGroupSet));
|
|
589
588
|
const fields = resultSet.getUngroupPartitions(ungroupSet);
|
|
590
589
|
let partitionBy = '';
|
|
591
590
|
const fieldsString = fields.map(f => f.getAnalyticalSQL(true)).join(', ');
|
|
@@ -598,10 +597,10 @@ function getDistinctKeySQL(struct, resultSet) {
|
|
|
598
597
|
const distinctKeyField = struct.getDistinctKey();
|
|
599
598
|
return generateDistinctKeySQL(distinctKeyField, resultSet);
|
|
600
599
|
}
|
|
601
|
-
function generateDistinctKeyIfNecessary(
|
|
600
|
+
function generateDistinctKeyIfNecessary(resultSet, context, structPath) {
|
|
602
601
|
let struct = context;
|
|
603
602
|
if (structPath) {
|
|
604
|
-
struct =
|
|
603
|
+
struct = context.getStructByName(structPath);
|
|
605
604
|
}
|
|
606
605
|
if (needsSymetricCalculation(struct, resultSet)) {
|
|
607
606
|
return getDistinctKeySQL(struct, resultSet);
|
|
@@ -610,16 +609,16 @@ function generateDistinctKeyIfNecessary(field, resultSet, context, structPath) {
|
|
|
610
609
|
return undefined;
|
|
611
610
|
}
|
|
612
611
|
}
|
|
613
|
-
function generateSumFragment(
|
|
614
|
-
const dimSQL = generateDimFragment(
|
|
615
|
-
const distinctKeySQL = generateDistinctKeyIfNecessary(
|
|
612
|
+
function generateSumFragment(resultSet, context, expr, state) {
|
|
613
|
+
const dimSQL = generateDimFragment(resultSet, context, expr.e, state);
|
|
614
|
+
const distinctKeySQL = generateDistinctKeyIfNecessary(resultSet, context, expr.structPath);
|
|
616
615
|
let ret;
|
|
617
616
|
if (distinctKeySQL) {
|
|
618
|
-
if (
|
|
619
|
-
ret =
|
|
617
|
+
if (context.dialect.supportsSumDistinctFunction) {
|
|
618
|
+
ret = context.dialect.sqlSumDistinct(distinctKeySQL, dimSQL, 'SUM');
|
|
620
619
|
}
|
|
621
620
|
else {
|
|
622
|
-
ret = sqlSumDistinct(
|
|
621
|
+
ret = sqlSumDistinct(context.dialect, dimSQL, distinctKeySQL);
|
|
623
622
|
}
|
|
624
623
|
}
|
|
625
624
|
else {
|
|
@@ -627,14 +626,14 @@ function generateSumFragment(field, resultSet, context, expr, state) {
|
|
|
627
626
|
}
|
|
628
627
|
return `COALESCE(${ret},0)`;
|
|
629
628
|
}
|
|
630
|
-
function generateSymmetricFragment(
|
|
631
|
-
const dimSQL = generateDimFragment(
|
|
629
|
+
function generateSymmetricFragment(resultSet, context, expr, state) {
|
|
630
|
+
const dimSQL = generateDimFragment(resultSet, context, expr.e, state);
|
|
632
631
|
const f = expr.function === 'distinct' ? 'count(distinct ' : expr.function + '(';
|
|
633
632
|
return `${f}${dimSQL})`;
|
|
634
633
|
}
|
|
635
|
-
function generateAvgFragment(
|
|
636
|
-
const dimSQL = generateDimFragment(
|
|
637
|
-
const distinctKeySQL = generateDistinctKeyIfNecessary(
|
|
634
|
+
function generateAvgFragment(resultSet, context, expr, state) {
|
|
635
|
+
const dimSQL = generateDimFragment(resultSet, context, expr.e, state);
|
|
636
|
+
const distinctKeySQL = generateDistinctKeyIfNecessary(resultSet, context, expr.structPath);
|
|
638
637
|
if (distinctKeySQL) {
|
|
639
638
|
let countDistinctKeySQL = distinctKeySQL;
|
|
640
639
|
if (state.whereSQL) {
|
|
@@ -642,11 +641,11 @@ function generateAvgFragment(field, resultSet, context, expr, state) {
|
|
|
642
641
|
}
|
|
643
642
|
let sumDistinctSQL;
|
|
644
643
|
let avgDistinctSQL;
|
|
645
|
-
if (
|
|
646
|
-
avgDistinctSQL =
|
|
644
|
+
if (context.dialect.supportsSumDistinctFunction) {
|
|
645
|
+
avgDistinctSQL = context.dialect.sqlSumDistinct(distinctKeySQL, dimSQL, 'AVG');
|
|
647
646
|
}
|
|
648
647
|
else {
|
|
649
|
-
sumDistinctSQL = sqlSumDistinct(
|
|
648
|
+
sumDistinctSQL = sqlSumDistinct(context.dialect, dimSQL, distinctKeySQL);
|
|
650
649
|
avgDistinctSQL = `(${sumDistinctSQL})/NULLIF(COUNT(DISTINCT CASE WHEN ${dimSQL} IS NOT NULL THEN ${countDistinctKeySQL} END),0)`;
|
|
651
650
|
}
|
|
652
651
|
return avgDistinctSQL;
|
|
@@ -655,12 +654,12 @@ function generateAvgFragment(field, resultSet, context, expr, state) {
|
|
|
655
654
|
return `AVG(${dimSQL})`;
|
|
656
655
|
}
|
|
657
656
|
}
|
|
658
|
-
function generateCountFragment(
|
|
657
|
+
function generateCountFragment(resultSet, context, expr, state) {
|
|
659
658
|
let func = 'COUNT(';
|
|
660
659
|
let thing = '1';
|
|
661
660
|
let struct = context;
|
|
662
661
|
if (expr.structPath) {
|
|
663
|
-
struct =
|
|
662
|
+
struct = context.getStructByName(expr.structPath);
|
|
664
663
|
}
|
|
665
664
|
const joinName = struct.getJoinableParent().getIdentifier();
|
|
666
665
|
const join = resultSet.root().joins.get(joinName);
|
|
@@ -678,10 +677,7 @@ function generateCountFragment(field, resultSet, context, expr, state) {
|
|
|
678
677
|
return `${func}${thing})`;
|
|
679
678
|
}
|
|
680
679
|
}
|
|
681
|
-
function
|
|
682
|
-
throw new Error(`Unexpanded spread encountered during SQL generation for ${field.getIdentifier()}`);
|
|
683
|
-
}
|
|
684
|
-
function generateSourceReference(field, resultSet, context, expr) {
|
|
680
|
+
function generateSourceReference(resultSet, context, expr) {
|
|
685
681
|
if (expr.path === undefined) {
|
|
686
682
|
return context.getSQLIdentifier();
|
|
687
683
|
}
|
|
@@ -689,7 +685,7 @@ function generateSourceReference(field, resultSet, context, expr) {
|
|
|
689
685
|
return context.getFieldByName(expr.path).getIdentifier();
|
|
690
686
|
}
|
|
691
687
|
}
|
|
692
|
-
function generateCaseSQL(
|
|
688
|
+
function generateCaseSQL(pf) {
|
|
693
689
|
const caseStmt = ['CASE'];
|
|
694
690
|
if (pf.kids.caseValue !== undefined) {
|
|
695
691
|
caseStmt.push(`${pf.kids.caseValue.sql}`);
|
|
@@ -703,7 +699,7 @@ function generateCaseSQL(field, pf) {
|
|
|
703
699
|
caseStmt.push('END');
|
|
704
700
|
return caseStmt.join(' ');
|
|
705
701
|
}
|
|
706
|
-
function getFunctionOrderBy(
|
|
702
|
+
function getFunctionOrderBy(resultSet, context, state, orderBy, args, overload) {
|
|
707
703
|
if (orderBy.length === 0)
|
|
708
704
|
return undefined;
|
|
709
705
|
return ('ORDER BY ' +
|
|
@@ -712,13 +708,13 @@ function getFunctionOrderBy(field, resultSet, context, state, orderBy, args, ove
|
|
|
712
708
|
var _a;
|
|
713
709
|
const defaultOrderByArgIndex = (_a = overload.dialect[context.dialect.name].defaultOrderByArgIndex) !== null && _a !== void 0 ? _a : 0;
|
|
714
710
|
const expr = ob.node === 'functionOrderBy' ? ob.e : args[defaultOrderByArgIndex];
|
|
715
|
-
const osql = generateDimFragment(
|
|
711
|
+
const osql = generateDimFragment(resultSet, context, expr, state);
|
|
716
712
|
const dirsql = ob.dir === 'asc' ? ' ASC' : ob.dir === 'desc' ? ' DESC' : '';
|
|
717
713
|
return `${osql}${dirsql}`;
|
|
718
714
|
})
|
|
719
715
|
.join(', '));
|
|
720
716
|
}
|
|
721
|
-
function getAnalyticPartitions(
|
|
717
|
+
function getAnalyticPartitions(resultStruct, extraPartitionFields) {
|
|
722
718
|
const ret = [];
|
|
723
719
|
let p = resultStruct.parent;
|
|
724
720
|
while (p !== undefined) {
|
|
@@ -732,7 +728,7 @@ function getAnalyticPartitions(field, resultStruct, extraPartitionFields) {
|
|
|
732
728
|
}
|
|
733
729
|
return ret;
|
|
734
730
|
}
|
|
735
|
-
function* stringsFromSQLExpression(
|
|
731
|
+
function* stringsFromSQLExpression(resultSet, context, e, state) {
|
|
736
732
|
/*
|
|
737
733
|
* Like template strings, the array of strings is paired with template insertions,
|
|
738
734
|
* each string is followed by at most one expression to be inserted
|
|
@@ -742,7 +738,7 @@ function* stringsFromSQLExpression(field, resultSet, context, e, state) {
|
|
|
742
738
|
yield str;
|
|
743
739
|
const expr = subExprList.shift();
|
|
744
740
|
if (expr) {
|
|
745
|
-
yield exprToSQL(
|
|
741
|
+
yield exprToSQL(resultSet, context, expr, state);
|
|
746
742
|
}
|
|
747
743
|
}
|
|
748
744
|
}
|
|
@@ -753,15 +749,13 @@ function generateDistinctKeySQL(fieldRef, resultSet) {
|
|
|
753
749
|
if (parent.primaryKey()) {
|
|
754
750
|
const pk = parent.getPrimaryKeyField(fieldRef.fieldDef);
|
|
755
751
|
// Recursively generate the primary key SQL
|
|
756
|
-
return generateFieldFragment(
|
|
757
|
-
resultSet, parent, { node: 'field', path: [pk.getIdentifier()] }, new utils_1.GenerateState());
|
|
752
|
+
return generateFieldFragment(resultSet, parent, { node: 'field', path: [pk.getIdentifier()] }, new utils_1.GenerateState());
|
|
758
753
|
}
|
|
759
754
|
else if (parent.structDef.type === 'array') {
|
|
760
755
|
const parentDistinctKey = (_a = parent.parent) === null || _a === void 0 ? void 0 : _a.getDistinctKey();
|
|
761
756
|
let parentKeySQL = '';
|
|
762
757
|
if (parentDistinctKey && parent.parent) {
|
|
763
|
-
parentKeySQL = generateFieldFragment(
|
|
764
|
-
resultSet, parent.parent, { node: 'field', path: ['__distinct_key'] }, new utils_1.GenerateState());
|
|
758
|
+
parentKeySQL = generateFieldFragment(resultSet, parent.parent, { node: 'field', path: ['__distinct_key'] }, new utils_1.GenerateState());
|
|
765
759
|
}
|
|
766
760
|
return parent.dialect.sqlMakeUnnestKey(parentKeySQL, parent.dialect.sqlFieldReference(parent.getIdentifier(), 'table', '__row_id', 'string'));
|
|
767
761
|
}
|
|
@@ -24,8 +24,8 @@ export declare class FieldInstanceField implements FieldInstance {
|
|
|
24
24
|
partitionSQL: string | undefined;
|
|
25
25
|
constructor(f: QueryField, fieldUsage: InstanceFieldUsage, parent: FieldInstanceResult, drillExpression: Malloy.Expression | undefined);
|
|
26
26
|
root(): FieldInstanceResultRoot;
|
|
27
|
-
static exprCompiler?: (
|
|
28
|
-
static registerExpressionCompiler(compiler: (
|
|
27
|
+
static exprCompiler?: (resultSet: FieldInstanceResult, context: QueryStruct, expr: Expr, state?: GenerateState) => string;
|
|
28
|
+
static registerExpressionCompiler(compiler: (resultSet: FieldInstanceResult, context: QueryStruct, expr: Expr, state?: GenerateState) => string): void;
|
|
29
29
|
getSQL(): string;
|
|
30
30
|
generateExpression(): string;
|
|
31
31
|
private generateDistinctKeyExpression;
|
|
@@ -45,7 +45,7 @@ class FieldInstanceField {
|
|
|
45
45
|
}
|
|
46
46
|
// Normal field expression generation
|
|
47
47
|
if ((0, malloy_types_1.hasExpression)(this.f.fieldDef)) {
|
|
48
|
-
return FieldInstanceField.exprCompiler(this.
|
|
48
|
+
return FieldInstanceField.exprCompiler(this.parent, this.f.parent, this.f.fieldDef.e);
|
|
49
49
|
}
|
|
50
50
|
// Walk the tree and compute record aliases if needed
|
|
51
51
|
for (let ancestor = this.f.parent; ancestor !== undefined; ancestor = ancestor.parent) {
|
|
@@ -55,7 +55,7 @@ class FieldInstanceField {
|
|
|
55
55
|
if (!ancestor.parent) {
|
|
56
56
|
throw new Error('Inconceivable record ancestor with expression but no parent');
|
|
57
57
|
}
|
|
58
|
-
const aliasValue = FieldInstanceField.exprCompiler(this.
|
|
58
|
+
const aliasValue = FieldInstanceField.exprCompiler(this.parent, ancestor.parent, ancestor.structDef.e);
|
|
59
59
|
ancestor.informOfAliasValue(aliasValue);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -498,7 +498,7 @@ function sqlFullChildReference(struct, name, expand) {
|
|
|
498
498
|
if (!FieldInstanceField.exprCompiler) {
|
|
499
499
|
throw new Error('Expression compiler not registered with FieldInstanceField');
|
|
500
500
|
}
|
|
501
|
-
parentRef = FieldInstanceField.exprCompiler(expand.
|
|
501
|
+
parentRef = FieldInstanceField.exprCompiler(expand.result, struct.parent, struct.structDef.e);
|
|
502
502
|
}
|
|
503
503
|
let refType = 'table';
|
|
504
504
|
if (struct.structDef.type === 'record') {
|
package/dist/model/index.d.ts
CHANGED
|
@@ -5,3 +5,4 @@ import { QueryModelImpl } from './query_model_impl';
|
|
|
5
5
|
export { QueryField, QueryStruct, QueryQuery, QueryModelImpl as QueryModel };
|
|
6
6
|
export { getResultStructDefForQuery, getResultStructDefForView, } from './query_model_impl';
|
|
7
7
|
export { indent, composeSQLExpr } from './utils';
|
|
8
|
+
export { constantExprToSQL } from './constant_expression_compiler';
|
package/dist/model/index.js
CHANGED
|
@@ -36,7 +36,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
36
36
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.composeSQLExpr = exports.indent = exports.getResultStructDefForView = exports.getResultStructDefForQuery = exports.QueryModel = exports.QueryQuery = exports.QueryStruct = exports.QueryField = void 0;
|
|
39
|
+
exports.constantExprToSQL = exports.composeSQLExpr = exports.indent = exports.getResultStructDefForView = exports.getResultStructDefForQuery = exports.QueryModel = exports.QueryQuery = exports.QueryStruct = exports.QueryField = void 0;
|
|
40
40
|
__exportStar(require("./malloy_types"), exports);
|
|
41
41
|
const query_node_1 = require("./query_node");
|
|
42
42
|
Object.defineProperty(exports, "QueryField", { enumerable: true, get: function () { return query_node_1.QueryField; } });
|
|
@@ -65,4 +65,6 @@ Object.defineProperty(exports, "getResultStructDefForView", { enumerable: true,
|
|
|
65
65
|
var utils_1 = require("./utils");
|
|
66
66
|
Object.defineProperty(exports, "indent", { enumerable: true, get: function () { return utils_1.indent; } });
|
|
67
67
|
Object.defineProperty(exports, "composeSQLExpr", { enumerable: true, get: function () { return utils_1.composeSQLExpr; } });
|
|
68
|
+
var constant_expression_compiler_1 = require("./constant_expression_compiler");
|
|
69
|
+
Object.defineProperty(exports, "constantExprToSQL", { enumerable: true, get: function () { return constant_expression_compiler_1.constantExprToSQL; } });
|
|
68
70
|
//# sourceMappingURL=index.js.map
|
|
@@ -225,7 +225,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
225
225
|
if (qs.structDef.type === 'record' &&
|
|
226
226
|
(0, malloy_types_1.hasExpression)(qs.structDef) &&
|
|
227
227
|
qs.parent) {
|
|
228
|
-
qs.informOfAliasValue((0, expression_compiler_1.exprToSQL)(this
|
|
228
|
+
qs.informOfAliasValue((0, expression_compiler_1.exprToSQL)(this.rootResult, qs.parent, qs.structDef.e));
|
|
229
229
|
}
|
|
230
230
|
context = qs;
|
|
231
231
|
}
|
|
@@ -299,7 +299,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
299
299
|
const context = this.parent;
|
|
300
300
|
if ((which === 'having' && (0, malloy_types_1.expressionIsCalculation)(cond.expressionType)) ||
|
|
301
301
|
(which === 'where' && (0, malloy_types_1.expressionIsScalar)(cond.expressionType))) {
|
|
302
|
-
const sqlClause = (0, expression_compiler_1.exprToSQL)(
|
|
302
|
+
const sqlClause = (0, expression_compiler_1.exprToSQL)(resultStruct, context, cond.e, undefined);
|
|
303
303
|
resultFilters.add(sqlClause);
|
|
304
304
|
}
|
|
305
305
|
}
|
|
@@ -671,7 +671,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
671
671
|
// If this array is NOT contained in the parent, but a computed entity
|
|
672
672
|
// then the thing we are joining is not "parent.childName", but
|
|
673
673
|
// the expression which is built in that namespace
|
|
674
|
-
arrayExpression = (0, expression_compiler_1.exprToSQL)(this
|
|
674
|
+
arrayExpression = (0, expression_compiler_1.exprToSQL)(this.rootResult, qs.parent, qsDef.e);
|
|
675
675
|
}
|
|
676
676
|
else {
|
|
677
677
|
// If this is a reference through an expression at the top level,
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const MALLOY_VERSION = "0.0.
|
|
1
|
+
export declare const MALLOY_VERSION = "0.0.307";
|
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.307';
|
|
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.307",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"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"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@malloydata/malloy-filter": "0.0.
|
|
45
|
-
"@malloydata/malloy-interfaces": "0.0.
|
|
46
|
-
"@malloydata/malloy-tag": "0.0.
|
|
44
|
+
"@malloydata/malloy-filter": "0.0.307",
|
|
45
|
+
"@malloydata/malloy-interfaces": "0.0.307",
|
|
46
|
+
"@malloydata/malloy-tag": "0.0.307",
|
|
47
47
|
"antlr4ts": "^0.5.0-alpha.4",
|
|
48
48
|
"assert": "^2.0.0",
|
|
49
49
|
"jaro-winkler": "^0.2.8",
|