@malloydata/malloy 0.0.191-dev240925183459 → 0.0.191-dev240927163326
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/ast/expressions/constant-expression.js +4 -1
- package/dist/lang/ast/expressions/expr-aggregate-function.js +25 -14
- package/dist/lang/ast/expressions/expr-alternation-tree.js +1 -3
- package/dist/lang/ast/expressions/expr-cast.js +1 -1
- package/dist/lang/ast/expressions/expr-coalesce.js +1 -1
- package/dist/lang/ast/expressions/expr-func.js +20 -31
- package/dist/lang/ast/expressions/expr-granular-time.js +1 -1
- package/dist/lang/ast/expressions/expr-id-reference.js +1 -3
- package/dist/lang/ast/expressions/expr-props.js +8 -8
- package/dist/lang/ast/expressions/expr-time-extract.js +7 -13
- package/dist/lang/ast/expressions/expr-ungroup.js +4 -8
- package/dist/lang/ast/expressions/for-range.js +2 -3
- package/dist/lang/ast/expressions/function-ordering.js +6 -6
- package/dist/lang/ast/expressions/partial-compare.js +1 -3
- package/dist/lang/ast/expressions/pick-when.js +30 -20
- package/dist/lang/ast/expressions/range.js +1 -1
- package/dist/lang/ast/expressions/top-by.js +1 -1
- package/dist/lang/ast/field-space/dynamic-space.js +1 -1
- package/dist/lang/ast/field-space/index-field-space.js +6 -6
- package/dist/lang/ast/field-space/parameter-space.js +14 -3
- package/dist/lang/ast/field-space/project-field-space.js +1 -1
- package/dist/lang/ast/field-space/query-spaces.d.ts +2 -1
- package/dist/lang/ast/field-space/query-spaces.js +7 -6
- package/dist/lang/ast/field-space/reference-field.js +1 -1
- package/dist/lang/ast/field-space/refined-space.js +3 -3
- package/dist/lang/ast/field-space/static-space.js +11 -2
- package/dist/lang/ast/parameters/has-parameter.js +4 -4
- package/dist/lang/ast/query-builders/index-builder.js +4 -4
- package/dist/lang/ast/query-builders/project-builder.js +2 -2
- package/dist/lang/ast/query-builders/reduce-builder.js +5 -5
- package/dist/lang/ast/query-elements/anonymous-query.js +1 -1
- package/dist/lang/ast/query-elements/query-reference.js +2 -2
- package/dist/lang/ast/query-items/field-declaration.js +7 -4
- package/dist/lang/ast/query-items/field-references.js +1 -1
- package/dist/lang/ast/query-items/typecheck_utils.js +31 -11
- package/dist/lang/ast/query-properties/filters.js +4 -4
- package/dist/lang/ast/query-properties/ordering.js +3 -3
- package/dist/lang/ast/query-properties/qop-desc.js +2 -2
- package/dist/lang/ast/query-properties/top.js +5 -5
- package/dist/lang/ast/query-utils.js +1 -1
- package/dist/lang/ast/source-elements/named-source.d.ts +2 -2
- package/dist/lang/ast/source-elements/named-source.js +12 -13
- package/dist/lang/ast/source-elements/refined-source.js +9 -7
- package/dist/lang/ast/source-elements/sql-source.js +5 -5
- package/dist/lang/ast/source-elements/table-source.js +2 -2
- package/dist/lang/ast/source-properties/joins.js +6 -6
- package/dist/lang/ast/source-properties/renames.js +3 -3
- package/dist/lang/ast/source-query-elements/source-query-element.d.ts +2 -1
- package/dist/lang/ast/source-query-elements/source-query-element.js +3 -2
- package/dist/lang/ast/source-query-elements/sq-arrow.js +2 -2
- package/dist/lang/ast/source-query-elements/sq-extend.js +1 -1
- package/dist/lang/ast/source-query-elements/sq-reference.js +5 -5
- package/dist/lang/ast/source-query-elements/sq-refine.js +2 -2
- package/dist/lang/ast/source-query-elements/sq-source.js +1 -1
- package/dist/lang/ast/sql-elements/sql-string.js +2 -2
- package/dist/lang/ast/statements/define-query.js +2 -2
- package/dist/lang/ast/statements/define-source.js +3 -3
- package/dist/lang/ast/statements/import-statement.js +7 -7
- package/dist/lang/ast/struct-utils.js +1 -1
- package/dist/lang/ast/types/expression-def.js +21 -22
- package/dist/lang/ast/types/lookup-result.d.ts +5 -1
- package/dist/lang/ast/types/malloy-element.d.ts +8 -5
- package/dist/lang/ast/types/malloy-element.js +33 -27
- package/dist/lang/ast/view-elements/qop-desc-view.js +3 -3
- package/dist/lang/ast/view-elements/reference-view.js +6 -6
- package/dist/lang/ast/view-elements/refine-utils.js +6 -6
- package/dist/lang/ast/view-elements/view-arrow.js +1 -1
- package/dist/lang/ast/view-elements/view-refine.js +1 -1
- package/dist/lang/malloy-to-ast.d.ts +7 -7
- package/dist/lang/malloy-to-ast.js +56 -55
- package/dist/lang/parse-log.d.ts +323 -6
- package/dist/lang/parse-log.js +62 -16
- package/dist/lang/parse-malloy.d.ts +5 -3
- package/dist/lang/parse-malloy.js +22 -31
- package/dist/lang/test/annotation.spec.js +4 -4
- package/dist/lang/test/expressions.spec.js +93 -74
- package/dist/lang/test/imports.spec.js +5 -5
- package/dist/lang/test/lenses.spec.js +18 -18
- package/dist/lang/test/literals.spec.js +1 -1
- package/dist/lang/test/locations.spec.js +5 -5
- package/dist/lang/test/parameters.spec.js +34 -34
- package/dist/lang/test/parse-expects.d.ts +10 -28
- package/dist/lang/test/parse-expects.js +38 -33
- package/dist/lang/test/parse.spec.js +49 -49
- package/dist/lang/test/query.spec.js +82 -82
- package/dist/lang/test/source.spec.js +6 -6
- package/dist/lang/test/test-translator.d.ts +19 -0
- package/dist/lang/test/test-translator.js +20 -1
- package/dist/tags.js +4 -2
- package/package.json +1 -1
|
@@ -36,7 +36,10 @@ class ConstantFieldSpace {
|
|
|
36
36
|
}
|
|
37
37
|
lookup(_name) {
|
|
38
38
|
return {
|
|
39
|
-
error:
|
|
39
|
+
error: {
|
|
40
|
+
message: 'Only constants allowed in parameter default values',
|
|
41
|
+
code: 'illegal-reference-in-parameter-default',
|
|
42
|
+
},
|
|
40
43
|
found: undefined,
|
|
41
44
|
};
|
|
42
45
|
}
|
|
@@ -49,7 +49,7 @@ class ExprAggregateFunction extends expression_def_1.ExpressionDef {
|
|
|
49
49
|
return 'number';
|
|
50
50
|
}
|
|
51
51
|
getExpression(fs) {
|
|
52
|
-
var _a, _b;
|
|
52
|
+
var _a, _b, _c;
|
|
53
53
|
// It is never useful to use output fields in an aggregate expression
|
|
54
54
|
// so we don't even allow them to be referenced at all
|
|
55
55
|
const inputFS = fs.isQueryFieldSpace() ? fs.inputSpace() : fs;
|
|
@@ -88,23 +88,19 @@ class ExprAggregateFunction extends expression_def_1.ExpressionDef {
|
|
|
88
88
|
}
|
|
89
89
|
else {
|
|
90
90
|
if (!(sourceFoot instanceof struct_space_field_base_1.StructSpaceFieldBase)) {
|
|
91
|
-
this.
|
|
92
|
-
return (0, ast_utils_1.errorFor)(`Aggregate source cannot be a ${footType.dataType}`);
|
|
91
|
+
return this.loggedErrorExpr('invalid-aggregate-source', `Aggregate source cannot be a ${footType.dataType}`);
|
|
93
92
|
}
|
|
94
93
|
}
|
|
95
94
|
}
|
|
96
95
|
else {
|
|
97
|
-
this.
|
|
98
|
-
return (0, ast_utils_1.errorFor)(`Reference to undefined value ${this.source.refString}`);
|
|
96
|
+
return this.loggedErrorExpr('aggregate-source-not-found', `Reference to undefined value ${this.source.refString}`);
|
|
99
97
|
}
|
|
100
98
|
}
|
|
101
99
|
if (exprVal === undefined) {
|
|
102
|
-
this.
|
|
103
|
-
return (0, ast_utils_1.errorFor)('agggregate without expression');
|
|
100
|
+
return this.loggedErrorExpr('missing-aggregate-expression', 'Missing expression for aggregate function');
|
|
104
101
|
}
|
|
105
102
|
if ((0, malloy_types_1.expressionIsAggregate)(exprVal.expressionType)) {
|
|
106
|
-
this.
|
|
107
|
-
return (0, ast_utils_1.errorFor)('reagggregate');
|
|
103
|
+
return this.loggedErrorExpr('aggregate-of-aggregate', 'Aggregate expression cannot be aggregate');
|
|
108
104
|
}
|
|
109
105
|
const isAnError = exprVal.dataType === 'error';
|
|
110
106
|
if (!isAnError) {
|
|
@@ -118,11 +114,17 @@ class ExprAggregateFunction extends expression_def_1.ExpressionDef {
|
|
|
118
114
|
const usagePaths = getJoinUsagePaths(sourceRelationship, joinUsage);
|
|
119
115
|
const joinError = validateUsagePaths(this.elementType, usagePaths);
|
|
120
116
|
const message = sourceSpecified
|
|
121
|
-
? joinError
|
|
117
|
+
? joinError === null || joinError === void 0 ? void 0 : joinError.message
|
|
122
118
|
: 'Join path is required for this calculation';
|
|
123
119
|
if (message) {
|
|
124
120
|
const errorWithSuggestion = suggestNewVersion(message, joinUsage, expr, this.elementType);
|
|
125
|
-
|
|
121
|
+
const code = (_c = joinError === null || joinError === void 0 ? void 0 : joinError.code) !== null && _c !== void 0 ? _c : 'bad-join-usage';
|
|
122
|
+
if (joinError) {
|
|
123
|
+
this.logError(code, errorWithSuggestion);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
this.logWarning(code, errorWithSuggestion);
|
|
127
|
+
}
|
|
126
128
|
}
|
|
127
129
|
}
|
|
128
130
|
}
|
|
@@ -269,13 +271,22 @@ function validateUsagePaths(functionName, usagePaths) {
|
|
|
269
271
|
for (const path of usagePaths) {
|
|
270
272
|
for (const step of path) {
|
|
271
273
|
if (step.structRelationship.type === 'cross') {
|
|
272
|
-
return
|
|
274
|
+
return {
|
|
275
|
+
code: 'aggregate-traverses-join-cross',
|
|
276
|
+
message: `Cannot compute \`${functionName}\` across \`join_cross\` relationship \`${step.name}\``,
|
|
277
|
+
};
|
|
273
278
|
}
|
|
274
279
|
else if (step.structRelationship.type === 'many' && !step.reverse) {
|
|
275
|
-
return
|
|
280
|
+
return {
|
|
281
|
+
code: 'aggregate-traverses-join-many',
|
|
282
|
+
message: `Cannot compute \`${functionName}\` across \`join_many\` relationship \`${step.name}\``,
|
|
283
|
+
};
|
|
276
284
|
}
|
|
277
285
|
else if (step.structRelationship.type === 'nested' && !step.reverse) {
|
|
278
|
-
return
|
|
286
|
+
return {
|
|
287
|
+
code: 'aggregate-traverses-repeated-relationship',
|
|
288
|
+
message: `Cannot compute \`${functionName}\` across repeated relationship \`${step.name}\``,
|
|
289
|
+
};
|
|
279
290
|
}
|
|
280
291
|
}
|
|
281
292
|
}
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.ExprAlternationTree = void 0;
|
|
26
26
|
const malloy_types_1 = require("../../../model/malloy_types");
|
|
27
|
-
const ast_utils_1 = require("../ast-utils");
|
|
28
27
|
const expression_def_1 = require("../types/expression-def");
|
|
29
28
|
class ExprAlternationTree extends expression_def_1.ExpressionDef {
|
|
30
29
|
constructor(left, op, right) {
|
|
@@ -52,8 +51,7 @@ class ExprAlternationTree extends expression_def_1.ExpressionDef {
|
|
|
52
51
|
return undefined;
|
|
53
52
|
}
|
|
54
53
|
getExpression(_fs) {
|
|
55
|
-
this.
|
|
56
|
-
return (0, ast_utils_1.errorFor)('no value from alternation tree');
|
|
54
|
+
return this.loggedErrorExpr('alternation-as-value', 'Alternation tree has no value');
|
|
57
55
|
}
|
|
58
56
|
}
|
|
59
57
|
exports.ExprAlternationTree = ExprAlternationTree;
|
|
@@ -50,7 +50,7 @@ class ExprCast extends expression_def_1.ExpressionDef {
|
|
|
50
50
|
(_c = (_b = (_a = fs.dialectObj()) === null || _a === void 0 ? void 0 : _a.sqlTypeToMalloyType(this.castType.raw)) === null || _b === void 0 ? void 0 : _b.type) !== null && _c !== void 0 ? _c : 'sql native';
|
|
51
51
|
}
|
|
52
52
|
else {
|
|
53
|
-
this.
|
|
53
|
+
this.logError('invalid-sql-native-type', `Cast type \`${this.castType.raw}\` is invalid for ${dialect.name} dialect`);
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
}
|
|
@@ -49,7 +49,7 @@ class ExprCoalesce extends expression_def_1.ExpressionDef {
|
|
|
49
49
|
* trees" rewrite happens.
|
|
50
50
|
*/
|
|
51
51
|
if (!fragtype_utils_1.FT.typeEq(maybeNull, whenNull)) {
|
|
52
|
-
this.
|
|
52
|
+
this.logError('mismatched-coalesce-types', `Mismatched types for coalesce (${maybeNull.dataType}, ${whenNull.dataType})`);
|
|
53
53
|
}
|
|
54
54
|
return {
|
|
55
55
|
...whenNull,
|
|
@@ -62,15 +62,15 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
62
62
|
: undefined;
|
|
63
63
|
const func = dialectFunc !== null && dialectFunc !== void 0 ? dialectFunc : (_c = this.modelEntry(normalizedName)) === null || _c === void 0 ? void 0 : _c.entry;
|
|
64
64
|
if (func === undefined) {
|
|
65
|
-
this.
|
|
65
|
+
this.logError('function-not-found', `Unknown function '${this.name}'. Use '${this.name}!(...)' to call a SQL function directly.`);
|
|
66
66
|
return { found: undefined, error: 'unknown function' };
|
|
67
67
|
}
|
|
68
68
|
else if (func.type !== 'function') {
|
|
69
|
-
this.
|
|
69
|
+
this.logError(`${func.type}-not-callable`, `Cannot call '${this.name}', which is of type ${func.type}`);
|
|
70
70
|
return { found: undefined, error: 'called non function' };
|
|
71
71
|
}
|
|
72
72
|
if (func.name !== this.name) {
|
|
73
|
-
this.
|
|
73
|
+
this.logWarning('case-insensitive-function', `Case insensitivity for function names is deprecated, use '${func.name}' instead`);
|
|
74
74
|
}
|
|
75
75
|
return { found: func, error: undefined };
|
|
76
76
|
}
|
|
@@ -124,16 +124,12 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
124
124
|
}
|
|
125
125
|
else {
|
|
126
126
|
if (!(sourceFoot instanceof struct_space_field_base_1.StructSpaceFieldBase)) {
|
|
127
|
-
|
|
128
|
-
this.log(message);
|
|
129
|
-
return (0, ast_utils_1.errorFor)(message);
|
|
127
|
+
return this.loggedErrorExpr('invalid-aggregate-source', `Aggregate source cannot be a ${footType.dataType}`);
|
|
130
128
|
}
|
|
131
129
|
}
|
|
132
130
|
}
|
|
133
131
|
else {
|
|
134
|
-
|
|
135
|
-
this.log(message);
|
|
136
|
-
return (0, ast_utils_1.errorFor)(message);
|
|
132
|
+
this.loggedErrorExpr('aggregate-source-not-found', `Reference to undefined value ${this.source.refString}`);
|
|
137
133
|
}
|
|
138
134
|
}
|
|
139
135
|
// Construct the full args list including the implicit arg.
|
|
@@ -143,10 +139,9 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
143
139
|
];
|
|
144
140
|
const result = findOverload(func, argExprs);
|
|
145
141
|
if (result === undefined) {
|
|
146
|
-
this.
|
|
142
|
+
return this.loggedErrorExpr('no-matching-function-overload', `No matching overload for function ${this.name}(${argExprs
|
|
147
143
|
.map(e => e.dataType)
|
|
148
144
|
.join(', ')})`);
|
|
149
|
-
return (0, ast_utils_1.errorFor)('no matching overload');
|
|
150
145
|
}
|
|
151
146
|
const { overload, expressionTypeErrors, evalSpaceErrors, nullabilityErrors } = result;
|
|
152
147
|
// Report errors for expression type mismatch
|
|
@@ -156,7 +151,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
156
151
|
? 'scalar'
|
|
157
152
|
: 'scalar or aggregate';
|
|
158
153
|
const arg = this.args[adjustedIndex];
|
|
159
|
-
arg.
|
|
154
|
+
arg.logError('invalid-function-argument-expression-type', `Parameter ${error.argIndex + 1} ('${error.param.name}') of ${this.name} must be ${allowed}, but received ${error.actualExpressionType}`);
|
|
160
155
|
}
|
|
161
156
|
// Report errors for eval space mismatch
|
|
162
157
|
for (const error of evalSpaceErrors) {
|
|
@@ -167,13 +162,13 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
167
162
|
? 'literal or constant'
|
|
168
163
|
: 'literal, constant or output';
|
|
169
164
|
const arg = this.args[adjustedIndex];
|
|
170
|
-
arg.
|
|
165
|
+
arg.logError('invalid-function-argument-evaluation-space', `Parameter ${error.argIndex + 1} ('${error.param.name}') of ${this.name} must be ${allowed}, but received ${error.actualEvalSpace}`);
|
|
171
166
|
}
|
|
172
167
|
// Report nullability errors
|
|
173
168
|
for (const error of nullabilityErrors) {
|
|
174
169
|
const adjustedIndex = error.argIndex - (implicitExpr ? 1 : 0);
|
|
175
170
|
const arg = this.args[adjustedIndex];
|
|
176
|
-
arg.
|
|
171
|
+
arg.logError('literal-null-function-argument', `Parameter ${error.argIndex + 1} ('${error.param.name}') of ${this.name} must not be a literal null`);
|
|
177
172
|
}
|
|
178
173
|
const type = overload.returnType;
|
|
179
174
|
const expressionType = (0, malloy_types_1.maxOfExpressionTypes)([
|
|
@@ -182,10 +177,9 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
182
177
|
]);
|
|
183
178
|
if (!(0, malloy_types_1.expressionIsAggregate)(overload.returnType.expressionType) &&
|
|
184
179
|
this.source !== undefined) {
|
|
185
|
-
this.
|
|
180
|
+
return this.loggedErrorExpr('non-aggregate-function-with-source', `Cannot call function ${this.name}(${argExprs
|
|
186
181
|
.map(e => e.dataType)
|
|
187
182
|
.join(', ')}) with source`);
|
|
188
|
-
return (0, ast_utils_1.errorFor)('cannot call with source');
|
|
189
183
|
}
|
|
190
184
|
const frag = {
|
|
191
185
|
node: 'function_call',
|
|
@@ -203,7 +197,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
203
197
|
const isAnalytic = (0, malloy_types_1.expressionIsAnalytic)(overload.returnType.expressionType);
|
|
204
198
|
if (!isAnalytic) {
|
|
205
199
|
if (!this.inExperiment('aggregate_order_by', true)) {
|
|
206
|
-
props.orderBys[0].
|
|
200
|
+
props.orderBys[0].logError('aggregate-order-by-experiment-not-enabled', 'Enable experiment `aggregate_order_by` to use `order_by` with an aggregate function');
|
|
207
201
|
}
|
|
208
202
|
}
|
|
209
203
|
if (overload.supportsOrderBy || isAnalytic) {
|
|
@@ -214,7 +208,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
214
208
|
frag.kids.orderBy = allObs;
|
|
215
209
|
}
|
|
216
210
|
else {
|
|
217
|
-
props.orderBys[0].
|
|
211
|
+
props.orderBys[0].logError('function-does-not-support-order-by', `Function \`${this.name}\` does not support \`order_by\``);
|
|
218
212
|
}
|
|
219
213
|
}
|
|
220
214
|
if ((props === null || props === void 0 ? void 0 : props.limit) !== undefined) {
|
|
@@ -222,7 +216,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
222
216
|
frag.limit = props.limit.limit;
|
|
223
217
|
}
|
|
224
218
|
else {
|
|
225
|
-
this.
|
|
219
|
+
this.logError('function-does-not-support-limit', `Function ${this.name} does not support limit`);
|
|
226
220
|
}
|
|
227
221
|
}
|
|
228
222
|
if ((props === null || props === void 0 ? void 0 : props.partitionBys) && props.partitionBys.length > 0) {
|
|
@@ -231,11 +225,11 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
231
225
|
for (const partitionField of partitionBy.partitionFields) {
|
|
232
226
|
const e = partitionField.getField(fs);
|
|
233
227
|
if (e.found === undefined) {
|
|
234
|
-
partitionField.
|
|
228
|
+
partitionField.logError('partition-by-not-found', `${partitionField.refString} is not defined`);
|
|
235
229
|
}
|
|
236
230
|
else if ((0, malloy_types_1.expressionIsAnalytic)(e.found.typeDesc().expressionType) ||
|
|
237
231
|
(0, malloy_types_1.expressionIsUngroupedAggregate)(e.found.typeDesc().expressionType)) {
|
|
238
|
-
partitionField.
|
|
232
|
+
partitionField.logError('non-scalar-or-aggregate-partition-by', 'Partition expression must be scalar or aggregate');
|
|
239
233
|
}
|
|
240
234
|
else {
|
|
241
235
|
partitionByFields.push(partitionField.nameString);
|
|
@@ -252,13 +246,11 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
252
246
|
'sql_boolean',
|
|
253
247
|
].includes(func.name)) {
|
|
254
248
|
if (!this.inExperiment('sql_functions', true)) {
|
|
255
|
-
|
|
256
|
-
this.log(message);
|
|
257
|
-
return (0, ast_utils_1.errorFor)('sql_function used without enabling');
|
|
249
|
+
return this.loggedErrorExpr('sql-functions-experiment-not-enabled', `Cannot use sql_function \`${func.name}\`; use \`sql_functions\` experiment to enable this behavior`);
|
|
258
250
|
}
|
|
259
251
|
const str = argExprs[0].value;
|
|
260
252
|
if (str.node !== 'stringLiteral') {
|
|
261
|
-
this.
|
|
253
|
+
this.logError('invalid-sql-function-argument', `Invalid string literal for \`${func.name}\``);
|
|
262
254
|
}
|
|
263
255
|
else {
|
|
264
256
|
const literal = str.literal;
|
|
@@ -272,8 +264,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
272
264
|
const unsupportedInterpolationMsg = unsupportedInterpolations.length === 1
|
|
273
265
|
? `'.' paths are not yet supported in sql interpolations, found ${unsupportedInterpolations.at(0)}`
|
|
274
266
|
: `'.' paths are not yet supported in sql interpolations, found (${unsupportedInterpolations.join(', ')})`;
|
|
275
|
-
this.
|
|
276
|
-
return (0, ast_utils_1.errorFor)(`${unsupportedInterpolationMsg}. See LookML \${...} documentation at https://cloud.google.com/looker/docs/reference/param-field-sql#sql_for_dimensions`);
|
|
267
|
+
return this.loggedErrorExpr('unsupported-sql-function-interpolation', unsupportedInterpolationMsg);
|
|
277
268
|
}
|
|
278
269
|
const expr = [];
|
|
279
270
|
for (const part of parts) {
|
|
@@ -288,8 +279,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
288
279
|
this.has({ name });
|
|
289
280
|
const result = fs.lookup([name]);
|
|
290
281
|
if (result.found === undefined) {
|
|
291
|
-
this.
|
|
292
|
-
return (0, ast_utils_1.errorFor)('invalid interpolated field');
|
|
282
|
+
return this.loggedErrorExpr('sql-function-interpolation-not-found', `Invalid interpolation: ${result.error.message}`);
|
|
293
283
|
}
|
|
294
284
|
if (result.found.refType === 'parameter') {
|
|
295
285
|
expr.push({ node: 'parameter', path: [part.name] });
|
|
@@ -303,8 +293,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
303
293
|
}
|
|
304
294
|
}
|
|
305
295
|
if (type.dataType === 'any') {
|
|
306
|
-
this.
|
|
307
|
-
return (0, ast_utils_1.errorFor)('invalid return type');
|
|
296
|
+
return this.loggedErrorExpr('function-returns-any', `Invalid return type ${type.dataType} for function '${this.name}'`);
|
|
308
297
|
}
|
|
309
298
|
const maxEvalSpace = (0, malloy_types_1.mergeEvalSpaces)(...argExprs.map(e => e.evalSpace));
|
|
310
299
|
// If the merged eval space of all args is constant, the result is constant.
|
|
@@ -68,7 +68,7 @@ class ExprGranularTime extends expression_def_1.ExpressionDef {
|
|
|
68
68
|
return tsVal;
|
|
69
69
|
}
|
|
70
70
|
if (exprVal.dataType !== 'error') {
|
|
71
|
-
this.
|
|
71
|
+
this.logError('unsupported-type-for-time-truncation', `Cannot do time truncation on type '${exprVal.dataType}'`);
|
|
72
72
|
}
|
|
73
73
|
const returnType = exprVal.dataType === 'error'
|
|
74
74
|
? (0, malloy_types_1.isDateUnit)(timeframe)
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.ExprIdReference = void 0;
|
|
26
26
|
const malloy_types_1 = require("../../../model/malloy_types");
|
|
27
|
-
const ast_utils_1 = require("../ast-utils");
|
|
28
27
|
const expression_def_1 = require("../types/expression-def");
|
|
29
28
|
class ExprIdReference extends expression_def_1.ExpressionDef {
|
|
30
29
|
constructor(fieldReference) {
|
|
@@ -54,8 +53,7 @@ class ExprIdReference extends expression_def_1.ExpressionDef {
|
|
|
54
53
|
: td.evalSpace;
|
|
55
54
|
return { ...td, value, evalSpace };
|
|
56
55
|
}
|
|
57
|
-
this.
|
|
58
|
-
return (0, ast_utils_1.errorFor)(def.error);
|
|
56
|
+
return this.loggedErrorExpr(def.error.code, def.error.message);
|
|
59
57
|
}
|
|
60
58
|
}
|
|
61
59
|
exports.ExprIdReference = ExprIdReference;
|
|
@@ -42,14 +42,14 @@ class ExprProps extends expression_def_1.ExpressionDef {
|
|
|
42
42
|
getFilteredExpression(fs, expr, wheres) {
|
|
43
43
|
if (wheres.length > 0) {
|
|
44
44
|
if (!this.expr.supportsWhere(expr)) {
|
|
45
|
-
this.expr.
|
|
45
|
+
this.expr.logError('filter-of-non-aggregate', 'Filtered expression requires an aggregate computation');
|
|
46
46
|
return expr;
|
|
47
47
|
}
|
|
48
48
|
const filterList = [];
|
|
49
49
|
for (const where of wheres) {
|
|
50
50
|
const testList = where.getFilterList(fs);
|
|
51
51
|
if (testList.find(cond => (0, malloy_types_1.expressionIsCalculation)(cond.expressionType))) {
|
|
52
|
-
where.
|
|
52
|
+
where.logError('aggregate-filter-expression-not-scalar', 'Cannot filter an expresion with an aggregate or analytical computation');
|
|
53
53
|
return expr;
|
|
54
54
|
}
|
|
55
55
|
filterList.push(...testList);
|
|
@@ -63,7 +63,7 @@ class ExprProps extends expression_def_1.ExpressionDef {
|
|
|
63
63
|
},
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
|
-
this.expr.
|
|
66
|
+
this.expr.logError('filter-of-non-aggregate', `Cannot filter '${expr.expressionType}' data`);
|
|
67
67
|
return (0, ast_utils_1.errorFor)('cannot filter type');
|
|
68
68
|
}
|
|
69
69
|
return expr;
|
|
@@ -76,7 +76,7 @@ class ExprProps extends expression_def_1.ExpressionDef {
|
|
|
76
76
|
for (const statement of this.statements) {
|
|
77
77
|
if (statement instanceof partition_by_1.PartitionBy) {
|
|
78
78
|
if (!this.expr.canSupportPartitionBy()) {
|
|
79
|
-
statement.
|
|
79
|
+
statement.logError('partition-by-of-non-window-function', '`partition_by` is not supported for this kind of expression');
|
|
80
80
|
}
|
|
81
81
|
else {
|
|
82
82
|
partitionBys.push(statement);
|
|
@@ -84,18 +84,18 @@ class ExprProps extends expression_def_1.ExpressionDef {
|
|
|
84
84
|
}
|
|
85
85
|
else if (statement instanceof limit_1.Limit) {
|
|
86
86
|
if (limit) {
|
|
87
|
-
statement.
|
|
87
|
+
statement.logError('expression-limit-already-specified', 'limit already specified');
|
|
88
88
|
}
|
|
89
89
|
else if (!this.expr.canSupportLimit()) {
|
|
90
|
-
statement.
|
|
90
|
+
statement.logError('limit-of-non-aggregate-function', '`limit` is not supported for this kind of expression');
|
|
91
91
|
}
|
|
92
92
|
else {
|
|
93
93
|
limit = statement;
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
else if (statement instanceof function_ordering_1.FunctionOrdering) {
|
|
97
|
-
if (!this.expr.
|
|
98
|
-
statement.
|
|
97
|
+
if (!this.expr.canSupportOrderBy()) {
|
|
98
|
+
statement.logError('order-by-of-non-aggregate-function', '`order_by` is not supported for this kind of expression');
|
|
99
99
|
}
|
|
100
100
|
else {
|
|
101
101
|
orderBys.push(statement);
|
|
@@ -47,8 +47,7 @@ class ExprTimeExtract extends expression_def_1.ExpressionDef {
|
|
|
47
47
|
const extractTo = ExprTimeExtract.extractor(this.extractText);
|
|
48
48
|
if (extractTo) {
|
|
49
49
|
if (this.args.length !== 1) {
|
|
50
|
-
this.
|
|
51
|
-
return (0, ast_utils_1.errorFor)('{this.name} arg count');
|
|
50
|
+
return this.loggedErrorExpr('too-many-arguments-for-time-extraction', `Extraction function ${extractTo} requires one argument`);
|
|
52
51
|
}
|
|
53
52
|
const from = this.args[0];
|
|
54
53
|
if (from instanceof range_1.Range) {
|
|
@@ -65,12 +64,10 @@ class ExprTimeExtract extends expression_def_1.ExpressionDef {
|
|
|
65
64
|
};
|
|
66
65
|
}
|
|
67
66
|
if (!(0, malloy_types_1.isTimeFieldType)(first.dataType)) {
|
|
68
|
-
from.first.
|
|
69
|
-
return (0, ast_utils_1.errorFor)(`${extractTo} bad type ${first.dataType}`);
|
|
67
|
+
return from.first.loggedErrorExpr('invalid-type-for-time-extraction', `Can't extract ${extractTo} from '${first.dataType}'`);
|
|
70
68
|
}
|
|
71
69
|
if (!(0, malloy_types_1.isTimeFieldType)(last.dataType)) {
|
|
72
|
-
from.last.
|
|
73
|
-
return (0, ast_utils_1.errorFor)(`${extractTo} bad type ${last.dataType}`);
|
|
70
|
+
return from.last.loggedErrorExpr('invalid-type-for-time-extraction', `Cannot extract ${extractTo} from '${last.dataType}'`);
|
|
74
71
|
}
|
|
75
72
|
let valueType = first.dataType;
|
|
76
73
|
if (first.dataType !== last.dataType) {
|
|
@@ -91,17 +88,14 @@ class ExprTimeExtract extends expression_def_1.ExpressionDef {
|
|
|
91
88
|
}
|
|
92
89
|
}
|
|
93
90
|
if (cannotMeasure) {
|
|
94
|
-
from.first.
|
|
95
|
-
return (0, ast_utils_1.errorFor)(`${extractTo} range mismatch`);
|
|
91
|
+
return from.first.loggedErrorExpr('invalid-types-for-time-measurement', `Cannot measure from ${first.dataType} to ${last.dataType}`);
|
|
96
92
|
}
|
|
97
93
|
}
|
|
98
94
|
if (['week', 'month', 'quarter', 'year'].includes(extractTo)) {
|
|
99
|
-
this.
|
|
100
|
-
return (0, ast_utils_1.errorFor)(`${extractTo} civil extraction`);
|
|
95
|
+
return this.loggedErrorExpr('invalid-timeframe-for-time-measurement', `Cannot measure interval using '${extractTo}'`);
|
|
101
96
|
}
|
|
102
97
|
if (!(0, malloy_types_1.isTimestampUnit)(extractTo)) {
|
|
103
|
-
this.
|
|
104
|
-
return (0, ast_utils_1.errorFor)(`${extractTo} bad extraction`);
|
|
98
|
+
return this.loggedErrorExpr('invalid-time-extraction-unit', `Cannot extract ${extractTo} from a range`);
|
|
105
99
|
}
|
|
106
100
|
return {
|
|
107
101
|
dataType: 'number',
|
|
@@ -132,7 +126,7 @@ class ExprTimeExtract extends expression_def_1.ExpressionDef {
|
|
|
132
126
|
};
|
|
133
127
|
}
|
|
134
128
|
if (argV.dataType !== 'error') {
|
|
135
|
-
this.
|
|
129
|
+
this.logError('unsupported-type-for-time-extraction', `${this.extractText}() requires time type, not '${argV.dataType}'`);
|
|
136
130
|
}
|
|
137
131
|
return {
|
|
138
132
|
dataType: 'number',
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.ExprUngroup = void 0;
|
|
26
26
|
const malloy_types_1 = require("../../../model/malloy_types");
|
|
27
|
-
const ast_utils_1 = require("../ast-utils");
|
|
28
27
|
const query_spaces_1 = require("../field-space/query-spaces");
|
|
29
28
|
const fragtype_utils_1 = require("../fragtype-utils");
|
|
30
29
|
const expression_def_1 = require("../types/expression-def");
|
|
@@ -43,12 +42,10 @@ class ExprUngroup extends expression_def_1.ExpressionDef {
|
|
|
43
42
|
getExpression(fs) {
|
|
44
43
|
const exprVal = this.expr.getExpression(fs);
|
|
45
44
|
if (!(0, malloy_types_1.expressionIsAggregate)(exprVal.expressionType)) {
|
|
46
|
-
this.expr.
|
|
47
|
-
return (0, ast_utils_1.errorFor)('ungrouped scalar');
|
|
45
|
+
return this.expr.loggedErrorExpr('ungroup-of-non-aggregate', `${this.control}() expression must be an aggregate`);
|
|
48
46
|
}
|
|
49
47
|
if ((0, malloy_types_1.expressionIsUngroupedAggregate)(exprVal.expressionType)) {
|
|
50
|
-
this.expr.
|
|
51
|
-
return (0, ast_utils_1.errorFor)('doubly-ungrouped aggregate');
|
|
48
|
+
return this.expr.loggedErrorExpr('ungroup-of-ungrouped-aggregate', `${this.control}() expression must not already be ungrouped`);
|
|
52
49
|
}
|
|
53
50
|
const ungroup = {
|
|
54
51
|
node: this.control,
|
|
@@ -79,7 +76,7 @@ class ExprUngroup extends expression_def_1.ExpressionDef {
|
|
|
79
76
|
}
|
|
80
77
|
if (notFound) {
|
|
81
78
|
const uName = isExclude ? 'exclude()' : 'all()';
|
|
82
|
-
mentionedField.
|
|
79
|
+
mentionedField.logError('ungroup-field-not-in-output', `${uName} '${mentionedField.refString}' is missing from query output`);
|
|
83
80
|
}
|
|
84
81
|
}
|
|
85
82
|
ungroup.fields = dstFields;
|
|
@@ -91,8 +88,7 @@ class ExprUngroup extends expression_def_1.ExpressionDef {
|
|
|
91
88
|
evalSpace: 'output',
|
|
92
89
|
};
|
|
93
90
|
}
|
|
94
|
-
this.
|
|
95
|
-
return (0, ast_utils_1.errorFor)('ungrouped type check');
|
|
91
|
+
return this.loggedErrorExpr('ungroup-with-non-scalar', `${this.control}() incompatible type`);
|
|
96
92
|
}
|
|
97
93
|
}
|
|
98
94
|
exports.ExprUngroup = ExprUngroup;
|
|
@@ -48,7 +48,7 @@ class ForRange extends expression_def_1.ExpressionDef {
|
|
|
48
48
|
const nV = this.duration.getExpression(fs);
|
|
49
49
|
if (nV.dataType !== 'number') {
|
|
50
50
|
if (nV.dataType !== 'error') {
|
|
51
|
-
this.
|
|
51
|
+
this.logError('invalid-duration-quantity', `FOR duration count must be a number, not '${nV.dataType}'`);
|
|
52
52
|
}
|
|
53
53
|
return {
|
|
54
54
|
dataType: 'boolean',
|
|
@@ -96,8 +96,7 @@ class ForRange extends expression_def_1.ExpressionDef {
|
|
|
96
96
|
return undefined;
|
|
97
97
|
}
|
|
98
98
|
getExpression(_fs) {
|
|
99
|
-
this.
|
|
100
|
-
return (0, ast_utils_1.errorFor)('range has no value');
|
|
99
|
+
return this.loggedErrorExpr('range-as-value', 'A Range is not a value');
|
|
101
100
|
}
|
|
102
101
|
}
|
|
103
102
|
exports.ForRange = ForRange;
|
|
@@ -37,7 +37,7 @@ class FunctionOrderBy extends malloy_element_1.MalloyElement {
|
|
|
37
37
|
}
|
|
38
38
|
getAnalyticOrderBy(fs) {
|
|
39
39
|
if (!this.field) {
|
|
40
|
-
this.
|
|
40
|
+
this.logError('analytic-order-by-missing-field', 'analytic `order_by` must specify an aggregate expression or output field reference');
|
|
41
41
|
return { node: 'functionOrderBy', e: { node: 'error' }, dir: this.dir };
|
|
42
42
|
}
|
|
43
43
|
const expr = this.field.getExpression(fs);
|
|
@@ -47,11 +47,11 @@ class FunctionOrderBy extends malloy_element_1.MalloyElement {
|
|
|
47
47
|
else if ((0, malloy_types_1.expressionIsScalar)(expr.expressionType)) {
|
|
48
48
|
if (!(this.field instanceof expr_id_reference_1.ExprIdReference) ||
|
|
49
49
|
expr.evalSpace === 'input') {
|
|
50
|
-
this.field.
|
|
50
|
+
this.field.logError('analytic-order-by-not-output', 'analytic `order_by` must be an aggregate or an output field reference');
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
else {
|
|
54
|
-
this.field.
|
|
54
|
+
this.field.logError('analytic-order-by-not-aggregate-or-output', 'analytic `order_by` must be scalar or aggregate');
|
|
55
55
|
}
|
|
56
56
|
return { node: 'functionOrderBy', e: expr.value, dir: this.dir };
|
|
57
57
|
}
|
|
@@ -59,17 +59,17 @@ class FunctionOrderBy extends malloy_element_1.MalloyElement {
|
|
|
59
59
|
if (this.field) {
|
|
60
60
|
const expr = this.field.getExpression(fs);
|
|
61
61
|
if (!(0, malloy_types_1.expressionIsScalar)(expr.expressionType)) {
|
|
62
|
-
this.field.
|
|
62
|
+
this.field.logError('aggregate-order-by-not-scalar', 'aggregate `order_by` must be scalar');
|
|
63
63
|
}
|
|
64
64
|
if (!allowExpression) {
|
|
65
|
-
this.field.
|
|
65
|
+
this.field.logError('aggregate-order-by-expression-not-allowed', '`order_by` must be only `asc` or `desc` with no expression');
|
|
66
66
|
}
|
|
67
67
|
return { node: 'functionOrderBy', e: expr.value, dir: this.dir };
|
|
68
68
|
}
|
|
69
69
|
else {
|
|
70
70
|
if (this.dir === undefined) {
|
|
71
71
|
// This error should technically never happen because it can't parse this way
|
|
72
|
-
this.
|
|
72
|
+
this.logError('aggregate-order-by-without-field-or-direction', 'field or order direction must be specified');
|
|
73
73
|
return { node: 'functionDefaultOrderBy', dir: 'asc' };
|
|
74
74
|
}
|
|
75
75
|
return { node: 'functionDefaultOrderBy', dir: this.dir };
|
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.PartialCompare = void 0;
|
|
26
|
-
const ast_utils_1 = require("../ast-utils");
|
|
27
26
|
const expression_def_1 = require("../types/expression-def");
|
|
28
27
|
class PartialCompare extends expression_def_1.ExpressionDef {
|
|
29
28
|
constructor(op, right) {
|
|
@@ -42,8 +41,7 @@ class PartialCompare extends expression_def_1.ExpressionDef {
|
|
|
42
41
|
return undefined;
|
|
43
42
|
}
|
|
44
43
|
getExpression(_fs) {
|
|
45
|
-
this.
|
|
46
|
-
return (0, ast_utils_1.errorFor)('no value for partial compare');
|
|
44
|
+
return this.loggedErrorExpr('partial-as-value', 'Partial comparison does not have a value');
|
|
47
45
|
}
|
|
48
46
|
}
|
|
49
47
|
exports.PartialCompare = PartialCompare;
|