@malloydata/malloy 0.0.395 → 0.0.397
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/annotation.d.ts +85 -1
- package/dist/annotation.js +133 -47
- package/dist/api/core.js +2 -7
- package/dist/api/foundation/compile.d.ts +7 -6
- package/dist/api/foundation/compile.js +22 -6
- package/dist/api/foundation/core.d.ts +10 -0
- package/dist/api/foundation/core.js +32 -9
- package/dist/api/foundation/runtime.d.ts +85 -5
- package/dist/api/foundation/runtime.js +184 -14
- package/dist/api/foundation/types.d.ts +2 -0
- package/dist/lang/ast/expressions/expr-func.js +30 -11
- package/dist/lang/ast/expressions/expr-given.js +1 -0
- package/dist/lang/ast/field-space/reference-field.js +1 -1
- package/dist/lang/ast/source-elements/sql-source.js +4 -0
- package/dist/lang/ast/source-elements/table-source.js +4 -0
- package/dist/lang/ast/statements/define-given.d.ts +1 -0
- package/dist/lang/ast/statements/define-given.js +7 -0
- package/dist/lang/ast/statements/import-statement.js +4 -0
- package/dist/lang/ast/types/annotation-elements.d.ts +1 -0
- package/dist/lang/ast/types/annotation-elements.js +10 -3
- package/dist/lang/ast/types/malloy-element.d.ts +1 -0
- package/dist/lang/ast/types/malloy-element.js +4 -0
- package/dist/lang/composite-source-utils.js +1 -1
- package/dist/lang/malloy-to-ast.d.ts +9 -1
- package/dist/lang/malloy-to-ast.js +37 -11
- package/dist/lang/malloy-to-stable-query.js +3 -3
- package/dist/lang/parse-log.d.ts +7 -1
- package/dist/lang/parse-log.js +12 -0
- package/dist/lang/parse-malloy.d.ts +4 -1
- package/dist/lang/parse-malloy.js +26 -4
- package/dist/lang/parse-tree-walkers/model-annotation-walker.js +3 -11
- package/dist/lang/parse-utils.d.ts +10 -2
- package/dist/lang/parse-utils.js +89 -29
- package/dist/lang/test/test-translator.d.ts +19 -5
- package/dist/lang/test/test-translator.js +15 -12
- package/dist/lang/zone.d.ts +2 -0
- package/dist/lang/zone.js +10 -0
- package/dist/model/constant_expression_compiler.js +14 -5
- package/dist/model/expression_compiler.js +19 -17
- package/dist/model/field_instance.js +7 -3
- package/dist/model/given_binding.js +26 -21
- package/dist/model/index.d.ts +1 -0
- package/dist/model/index.js +3 -1
- package/dist/model/malloy_compile_error.d.ts +13 -0
- package/dist/model/malloy_compile_error.js +23 -0
- package/dist/model/malloy_types.d.ts +9 -0
- package/dist/model/persist_utils.js +1 -1
- package/dist/model/query_model_impl.js +2 -1
- package/dist/model/query_node.d.ts +5 -5
- package/dist/model/query_node.js +22 -17
- package/dist/model/query_query.js +23 -11
- package/dist/model/sql_compiled.js +6 -3
- package/dist/prefix.d.ts +51 -0
- package/dist/prefix.js +99 -0
- package/dist/taggable.d.ts +17 -1
- package/dist/test/resultMatchers.js +2 -1
- package/dist/to_stable.d.ts +7 -1
- package/dist/to_stable.js +13 -16
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -29,6 +29,7 @@ const field_instance_1 = require("./field_instance");
|
|
|
29
29
|
const filter_compilers_1 = require("./filter_compilers");
|
|
30
30
|
const utils_1 = require("./utils");
|
|
31
31
|
const query_node_1 = require("./query_node");
|
|
32
|
+
const malloy_compile_error_1 = require("./malloy_compile_error");
|
|
32
33
|
const NUMERIC_DECIMAL_PRECISION = 9;
|
|
33
34
|
function sqlSumDistinct(dialect, sqlExp, sqlDistintKey) {
|
|
34
35
|
const precision = 9;
|
|
@@ -186,7 +187,7 @@ function compileExpr(resultSet, context, expr, state = new utils_1.GenerateState
|
|
|
186
187
|
return `${expr.kids.e.sql} ${expr.not ? 'NOT IN' : 'IN'} (${oneOf})`;
|
|
187
188
|
}
|
|
188
189
|
case 'inGiven': {
|
|
189
|
-
const bound = resolveGivenBoundExpr(context, expr.givenRef
|
|
190
|
+
const bound = resolveGivenBoundExpr(context, expr.givenRef);
|
|
190
191
|
// null binding collapses to empty-set semantics — not the SQL
|
|
191
192
|
// `IN (NULL)` shape, which has confusing NULL-membership rules.
|
|
192
193
|
if (bound.node === 'null') {
|
|
@@ -280,27 +281,27 @@ function generateAppliedFilter(context, filterMatchExpr, qi) {
|
|
|
280
281
|
filterExpr = argument.value;
|
|
281
282
|
}
|
|
282
283
|
else {
|
|
283
|
-
throw new
|
|
284
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Parameter '${name}' has no value, but a filter expression is required here.`, 'compiler-filter-parameter-no-value', filterExpr.at);
|
|
284
285
|
}
|
|
285
286
|
}
|
|
286
287
|
if (filterExpr.node === 'given') {
|
|
287
|
-
const
|
|
288
|
-
const supplied = (_c = (_b = context.prepareResultOptions) === null || _b === void 0 ? void 0 : _b.resolvedGivens) === null || _c === void 0 ? void 0 : _c.get(id);
|
|
288
|
+
const supplied = (_c = (_b = context.prepareResultOptions) === null || _b === void 0 ? void 0 : _b.resolvedGivens) === null || _c === void 0 ? void 0 : _c.get(filterExpr.id);
|
|
289
289
|
if (supplied !== undefined) {
|
|
290
290
|
filterExpr = supplied;
|
|
291
291
|
}
|
|
292
292
|
else {
|
|
293
|
-
const decl = context.getModel().givens[id];
|
|
293
|
+
const decl = context.getModel().givens[filterExpr.id];
|
|
294
294
|
if ((decl === null || decl === void 0 ? void 0 : decl.default) !== undefined) {
|
|
295
295
|
filterExpr = decl.default;
|
|
296
296
|
}
|
|
297
297
|
else {
|
|
298
|
-
throw new
|
|
298
|
+
throw new malloy_compile_error_1.MalloyCompileError(unsatisfiedGivenMessage(filterExpr.refName), 'compiler-given-no-value', filterExpr.at);
|
|
299
299
|
}
|
|
300
300
|
}
|
|
301
301
|
}
|
|
302
302
|
if (filterExpr.node !== 'filterLiteral') {
|
|
303
|
-
throw new
|
|
303
|
+
throw new malloy_compile_error_1.MalloyCompileError("Filter context requires a filter-expression literal (e.g., `f'...'`) " +
|
|
304
|
+
`or a parameter that resolves to one; got node '${filterExpr.node}'.`, 'compiler-filter-not-literal', undefined);
|
|
304
305
|
}
|
|
305
306
|
const filterSrc = filterExpr.filterSrc;
|
|
306
307
|
let fParse;
|
|
@@ -320,10 +321,11 @@ function generateAppliedFilter(context, filterMatchExpr, qi) {
|
|
|
320
321
|
fParse = malloy_filter_1.TemporalFilterExpression.parse(filterSrc);
|
|
321
322
|
break;
|
|
322
323
|
default:
|
|
323
|
-
throw new
|
|
324
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Filter type '${filterMatchExpr.dataType}' is not supported. ` +
|
|
325
|
+
'Supported filter types: string, number, boolean, date, timestamp, timestamptz.', 'compiler-filter-type-unsupported', undefined);
|
|
324
326
|
}
|
|
325
327
|
if (fParse.log.length > 0) {
|
|
326
|
-
throw new
|
|
328
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Filter expression parse error: ${fParse.log[0]}.`, 'compiler-filter-parse-error', undefined);
|
|
327
329
|
}
|
|
328
330
|
return filter_compilers_1.FilterCompilers.compile(filterMatchExpr.dataType, fParse.parsed, filterMatchExpr.kids.expr.sql || '', context.dialect, qi);
|
|
329
331
|
}
|
|
@@ -581,7 +583,7 @@ function generateFunctionCallExpression(resultSet, context, frag, state) {
|
|
|
581
583
|
}
|
|
582
584
|
function generateFieldFragment(resultSet, context, expr, state) {
|
|
583
585
|
// find the structDef and return the path to the field...
|
|
584
|
-
const fieldRef = context.getFieldByName(expr.path);
|
|
586
|
+
const fieldRef = context.getFieldByName(expr.path, expr.at);
|
|
585
587
|
if ((0, malloy_types_1.hasExpression)(fieldRef.fieldDef)) {
|
|
586
588
|
const ret = exprToSQL(resultSet, fieldRef.parent, fieldRef.fieldDef.e, state);
|
|
587
589
|
return `(${ret})`;
|
|
@@ -614,7 +616,7 @@ function generateParameterFragment(resultSet, context, expr, state) {
|
|
|
614
616
|
if (argument === null || argument === void 0 ? void 0 : argument.value) {
|
|
615
617
|
return exprToSQL(resultSet, context, argument.value, state);
|
|
616
618
|
}
|
|
617
|
-
throw new
|
|
619
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Parameter '${expr.path.join('.')}' has no value supplied.`, 'compiler-parameter-no-value', expr.at);
|
|
618
620
|
}
|
|
619
621
|
/**
|
|
620
622
|
* Resolve a given to the Expr that should stand in for it at SQL emit:
|
|
@@ -625,20 +627,20 @@ function generateParameterFragment(resultSet, context, expr, state) {
|
|
|
625
627
|
* Shared by `generateGivenFragment` ($NAME directly in an expression)
|
|
626
628
|
* and the `'inGiven'` SQL-emit case ($ARR in `expr in $ARR`).
|
|
627
629
|
*/
|
|
628
|
-
function resolveGivenBoundExpr(context,
|
|
630
|
+
function resolveGivenBoundExpr(context, ref) {
|
|
629
631
|
var _a, _b;
|
|
630
|
-
const supplied = (_b = (_a = context.prepareResultOptions) === null || _a === void 0 ? void 0 : _a.resolvedGivens) === null || _b === void 0 ? void 0 : _b.get(id);
|
|
632
|
+
const supplied = (_b = (_a = context.prepareResultOptions) === null || _a === void 0 ? void 0 : _a.resolvedGivens) === null || _b === void 0 ? void 0 : _b.get(ref.id);
|
|
631
633
|
if (supplied !== undefined)
|
|
632
634
|
return supplied;
|
|
633
|
-
const decl = context.getModel().givens[id];
|
|
635
|
+
const decl = context.getModel().givens[ref.id];
|
|
634
636
|
if ((decl === null || decl === void 0 ? void 0 : decl.default) !== undefined)
|
|
635
637
|
return decl.default;
|
|
636
|
-
throw new
|
|
638
|
+
throw new malloy_compile_error_1.MalloyCompileError(unsatisfiedGivenMessage(ref.refName), 'compiler-given-no-value', ref.at);
|
|
637
639
|
}
|
|
638
640
|
function generateGivenFragment(resultSet, context, expr, state) {
|
|
639
641
|
// The bound expr may itself be a `$OTHER`-bearing expression; recursive
|
|
640
642
|
// compile handles default chains.
|
|
641
|
-
const bound = resolveGivenBoundExpr(context, expr
|
|
643
|
+
const bound = resolveGivenBoundExpr(context, expr);
|
|
642
644
|
return exprToSQL(resultSet, context, bound, state);
|
|
643
645
|
}
|
|
644
646
|
function unsatisfiedGivenMessage(refName) {
|
|
@@ -663,7 +665,7 @@ function generateDimFragment(resultSet, context, expr, state) {
|
|
|
663
665
|
}
|
|
664
666
|
function generateUngroupedFragment(resultSet, context, expr, state) {
|
|
665
667
|
if (state.totalGroupSet !== -1) {
|
|
666
|
-
throw new
|
|
668
|
+
throw new malloy_compile_error_1.MalloyCompileError("Cannot nest 'all()' or 'exclude()' inside another 'all()' calculation.", 'compiler-nested-ungroup', undefined);
|
|
667
669
|
}
|
|
668
670
|
let totalGroupSet;
|
|
669
671
|
let ungroupSet;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.FieldInstanceResultRoot = exports.FieldInstanceResult = exports.FieldInstanceField = void 0;
|
|
8
8
|
exports.sqlFullChildReference = sqlFullChildReference;
|
|
9
|
+
const malloy_compile_error_1 = require("./malloy_compile_error");
|
|
9
10
|
const malloy_types_1 = require("./malloy_types");
|
|
10
11
|
const utils_1 = require("./utils");
|
|
11
12
|
const join_instance_1 = require("./join_instance");
|
|
@@ -139,7 +140,8 @@ class FieldInstanceResult {
|
|
|
139
140
|
const fi = this.allFields.get(as);
|
|
140
141
|
if (fi) {
|
|
141
142
|
if (fi.type === 'query') {
|
|
142
|
-
throw new
|
|
143
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Field '${field.fieldDef.name}' is already defined as a nested view; ` +
|
|
144
|
+
'cannot also use it as a scalar field in this output.', 'compiler-field-redefined-as-struct', field.fieldDef.location);
|
|
143
145
|
}
|
|
144
146
|
const fif = fi;
|
|
145
147
|
if (fif.fieldUsage.type === 'result') {
|
|
@@ -148,7 +150,8 @@ class FieldInstanceResult {
|
|
|
148
150
|
return;
|
|
149
151
|
}
|
|
150
152
|
else {
|
|
151
|
-
throw new
|
|
153
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Output field name '${field.fieldDef.name}' is ambiguous — ` +
|
|
154
|
+
'defined more than once at the query output level.', 'compiler-ambiguous-output-name', field.fieldDef.location);
|
|
152
155
|
}
|
|
153
156
|
}
|
|
154
157
|
}
|
|
@@ -373,7 +376,8 @@ class FieldInstanceResult {
|
|
|
373
376
|
// verify that all names specified are available in the current scope.
|
|
374
377
|
for (const fieldName of (ungroupSet === null || ungroupSet === void 0 ? void 0 : ungroupSet.fields) || []) {
|
|
375
378
|
if (inScopeFieldNames.indexOf(fieldName) === -1) {
|
|
376
|
-
throw new
|
|
379
|
+
throw new malloy_compile_error_1.MalloyCompileError(`'${ungroupSet === null || ungroupSet === void 0 ? void 0 : ungroupSet.type}()' references field '${fieldName}', ` +
|
|
380
|
+
'which is not defined or not in scope at this nesting level.', 'compiler-ungroup-field-unknown', undefined);
|
|
377
381
|
}
|
|
378
382
|
}
|
|
379
383
|
return ret;
|
|
@@ -10,6 +10,7 @@ const luxon_1 = require("luxon");
|
|
|
10
10
|
const closest_match_1 = require("../util/closest_match");
|
|
11
11
|
const inline_expr_1 = require("./inline_expr");
|
|
12
12
|
const malloy_types_1 = require("./malloy_types");
|
|
13
|
+
const malloy_compile_error_1 = require("./malloy_compile_error");
|
|
13
14
|
function resolveSuppliedGivens(supplied, modelDef) {
|
|
14
15
|
var _a;
|
|
15
16
|
const out = new Map();
|
|
@@ -20,9 +21,9 @@ function resolveSuppliedGivens(supplied, modelDef) {
|
|
|
20
21
|
// prototype pollution from e.g. an Object.create(...)-derived input.
|
|
21
22
|
for (const [name, value] of Object.entries(supplied)) {
|
|
22
23
|
if (value === undefined) {
|
|
23
|
-
throw new
|
|
24
|
+
throw new malloy_compile_error_1.MalloyCompileError(`givens.${name}: explicit undefined is not a valid value. ` +
|
|
24
25
|
'Omit the key to defer to declaration default or a lower supply ' +
|
|
25
|
-
'layer; use null for an explicit null value.');
|
|
26
|
+
'layer; use null for an explicit null value.', 'runtime-given-undefined', undefined);
|
|
26
27
|
}
|
|
27
28
|
const entry = modelDef.contents[name];
|
|
28
29
|
if (!entry || entry.type !== 'given') {
|
|
@@ -33,7 +34,8 @@ function resolveSuppliedGivens(supplied, modelDef) {
|
|
|
33
34
|
}
|
|
34
35
|
const suggestion = (0, closest_match_1.closestMatch)(name, surfaceNames);
|
|
35
36
|
const hint = suggestion ? ` (did you mean '${suggestion}'?)` : '';
|
|
36
|
-
throw new
|
|
37
|
+
throw new malloy_compile_error_1.MalloyCompileError(`givens: unknown given '${name}'${hint}. ` +
|
|
38
|
+
`Model surfaces [${surfaceNames.join(', ')}]`, 'runtime-given-unknown', undefined);
|
|
37
39
|
}
|
|
38
40
|
const decl = givens[entry.id];
|
|
39
41
|
if (!decl) {
|
|
@@ -83,10 +85,13 @@ function valueToExpr(path, type, value) {
|
|
|
83
85
|
if (value === null) {
|
|
84
86
|
return { node: 'null' };
|
|
85
87
|
}
|
|
88
|
+
function bad(msg, code = 'runtime-given-bad-value') {
|
|
89
|
+
throw new malloy_compile_error_1.MalloyCompileError(`givens.${path}: ${msg}`, code, undefined);
|
|
90
|
+
}
|
|
86
91
|
switch (type.type) {
|
|
87
92
|
case 'string': {
|
|
88
93
|
if (typeof value !== 'string') {
|
|
89
|
-
|
|
94
|
+
bad(`expected string, got ${describeJs(value)}`);
|
|
90
95
|
}
|
|
91
96
|
return { node: 'stringLiteral', literal: value };
|
|
92
97
|
}
|
|
@@ -94,7 +99,7 @@ function valueToExpr(path, type, value) {
|
|
|
94
99
|
let lit;
|
|
95
100
|
if (typeof value === 'number') {
|
|
96
101
|
if (!Number.isFinite(value)) {
|
|
97
|
-
|
|
102
|
+
bad(`number must be finite, got ${value}`);
|
|
98
103
|
}
|
|
99
104
|
lit = String(value);
|
|
100
105
|
}
|
|
@@ -103,27 +108,27 @@ function valueToExpr(path, type, value) {
|
|
|
103
108
|
}
|
|
104
109
|
else if (typeof value === 'string') {
|
|
105
110
|
if (!/^-?(\d+(\.\d+)?|\.\d+)([eE][+-]?\d+)?$/.test(value)) {
|
|
106
|
-
|
|
111
|
+
bad(`number-as-string must be numeric, got '${value}'`);
|
|
107
112
|
}
|
|
108
113
|
lit = value;
|
|
109
114
|
}
|
|
110
115
|
else {
|
|
111
|
-
|
|
116
|
+
bad(`expected number | bigint | string, got ${describeJs(value)}`);
|
|
112
117
|
}
|
|
113
118
|
return { node: 'numberLiteral', literal: lit };
|
|
114
119
|
}
|
|
115
120
|
case 'boolean': {
|
|
116
121
|
if (typeof value !== 'boolean') {
|
|
117
|
-
|
|
122
|
+
bad(`expected boolean, got ${describeJs(value)}`);
|
|
118
123
|
}
|
|
119
124
|
return { node: value ? 'true' : 'false' };
|
|
120
125
|
}
|
|
121
126
|
case 'date': {
|
|
122
127
|
if (typeof value !== 'string') {
|
|
123
|
-
|
|
128
|
+
bad(`expected ISO date string 'YYYY-MM-DD', got ${describeJs(value)}`);
|
|
124
129
|
}
|
|
125
130
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
126
|
-
|
|
131
|
+
bad(`date must match 'YYYY-MM-DD', got '${value}'`);
|
|
127
132
|
}
|
|
128
133
|
return { node: 'dateLiteral', literal: value, typeDef: { type: 'date' } };
|
|
129
134
|
}
|
|
@@ -133,17 +138,17 @@ function valueToExpr(path, type, value) {
|
|
|
133
138
|
// strings (those want 'timestamptz'). Parse the rest with Luxon and
|
|
134
139
|
// emit canonical "YYYY-MM-DD HH:MM:SS.sss" for the dialect.
|
|
135
140
|
if (typeof value !== 'string') {
|
|
136
|
-
|
|
141
|
+
bad(`expected ISO timestamp string (no offset), got ${describeJs(value)}`);
|
|
137
142
|
}
|
|
138
143
|
if (/Z$|[+-]\d{2}:?\d{2}$/.test(value)) {
|
|
139
|
-
|
|
144
|
+
bad(`'timestamp' is naive — use 'timestamptz' for offset/zoned values, got '${value}'`);
|
|
140
145
|
}
|
|
141
146
|
// ISO uses T-separator; SQL form uses space. Accept both.
|
|
142
147
|
let dt = luxon_1.DateTime.fromISO(value, { zone: 'utc' });
|
|
143
148
|
if (!dt.isValid)
|
|
144
149
|
dt = luxon_1.DateTime.fromSQL(value, { zone: 'utc' });
|
|
145
150
|
if (!dt.isValid) {
|
|
146
|
-
|
|
151
|
+
bad(`invalid timestamp value '${value}': ${(_a = dt.invalidReason) !== null && _a !== void 0 ? _a : 'unknown'}`);
|
|
147
152
|
}
|
|
148
153
|
return {
|
|
149
154
|
node: 'timestampLiteral',
|
|
@@ -162,10 +167,10 @@ function valueToExpr(path, type, value) {
|
|
|
162
167
|
dt = dt.toUTC();
|
|
163
168
|
}
|
|
164
169
|
else {
|
|
165
|
-
|
|
170
|
+
bad(`expected JS Date or ISO timestamptz string, got ${describeJs(value)}`);
|
|
166
171
|
}
|
|
167
172
|
if (!dt.isValid) {
|
|
168
|
-
|
|
173
|
+
bad(`invalid timestamptz value '${value}': ${(_b = dt.invalidReason) !== null && _b !== void 0 ? _b : 'unknown'}`);
|
|
169
174
|
}
|
|
170
175
|
return {
|
|
171
176
|
node: 'timestamptzLiteral',
|
|
@@ -176,13 +181,13 @@ function valueToExpr(path, type, value) {
|
|
|
176
181
|
}
|
|
177
182
|
case 'filter expression': {
|
|
178
183
|
if (typeof value !== 'string') {
|
|
179
|
-
|
|
184
|
+
bad(`filter<T> givens require a JS string of Malloy filter source, got ${describeJs(value)}`);
|
|
180
185
|
}
|
|
181
186
|
return { node: 'filterLiteral', filterSrc: value };
|
|
182
187
|
}
|
|
183
188
|
case 'array': {
|
|
184
189
|
if (!Array.isArray(value)) {
|
|
185
|
-
|
|
190
|
+
bad(`expected array, got ${describeJs(value)}`);
|
|
186
191
|
}
|
|
187
192
|
// RepeatedRecord (array of records) carries `record_element` as its
|
|
188
193
|
// element type and the record's schema in `fields`. Each element is
|
|
@@ -198,19 +203,19 @@ function valueToExpr(path, type, value) {
|
|
|
198
203
|
if (typeof value !== 'object' ||
|
|
199
204
|
Array.isArray(value) ||
|
|
200
205
|
value instanceof Date) {
|
|
201
|
-
|
|
206
|
+
bad(`expected object, got ${describeJs(value)}`);
|
|
202
207
|
}
|
|
203
208
|
const obj = value;
|
|
204
209
|
const declared = new Set(type.fields.map(f => f.name));
|
|
205
210
|
for (const k of Object.keys(obj)) {
|
|
206
211
|
if (!declared.has(k)) {
|
|
207
|
-
throw new
|
|
212
|
+
throw new malloy_compile_error_1.MalloyCompileError(`givens.${path}.${k}: unexpected key (not in record type [${[...declared].join(', ')}])`, 'runtime-given-record-extra-key', undefined);
|
|
208
213
|
}
|
|
209
214
|
}
|
|
210
215
|
const kids = (0, malloy_types_1.mkSafeRecord)();
|
|
211
216
|
for (const field of type.fields) {
|
|
212
217
|
if (!(field.name in obj)) {
|
|
213
|
-
throw new
|
|
218
|
+
throw new malloy_compile_error_1.MalloyCompileError(`givens.${path}.${field.name}: missing required key`, 'runtime-given-record-missing-key', undefined);
|
|
214
219
|
}
|
|
215
220
|
kids[field.name] = valueToExpr(`${path}.${field.name}`, malloy_types_1.TD.atomicDef(field), obj[field.name]);
|
|
216
221
|
}
|
|
@@ -219,7 +224,7 @@ function valueToExpr(path, type, value) {
|
|
|
219
224
|
case 'json':
|
|
220
225
|
case 'sql native':
|
|
221
226
|
case 'error':
|
|
222
|
-
throw new
|
|
227
|
+
throw new malloy_compile_error_1.MalloyCompileError(`givens.${path}: type '${type.type}' is not bindable as a given value.`, 'runtime-given-type-not-bindable', undefined);
|
|
223
228
|
default: {
|
|
224
229
|
// Exhaustiveness: future GivenTypeDef additions will trip this.
|
|
225
230
|
const _x = type;
|
package/dist/model/index.d.ts
CHANGED
|
@@ -7,4 +7,5 @@ export { getResultStructDefForQuery, getResultStructDefForView, } from './query_
|
|
|
7
7
|
export { indent, composeSQLExpr, makeDigest, mkModelDef, pathToKey, typeDefToString, } from './utils';
|
|
8
8
|
export { constantExprToSQL } from './constant_expression_compiler';
|
|
9
9
|
export { getCompiledSQL } from './sql_compiled';
|
|
10
|
+
export { MalloyCompileError } from './malloy_compile_error';
|
|
10
11
|
export { mkSourceID, mkBuildID, mkQuerySourceDef, mkSQLSourceDef, mkTableSourceDef, resolveSourceID, registerSource, hasSourceRegistryEntry, } from './source_def_utils';
|
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.hasSourceRegistryEntry = exports.registerSource = exports.resolveSourceID = exports.mkTableSourceDef = exports.mkSQLSourceDef = exports.mkQuerySourceDef = exports.mkBuildID = exports.mkSourceID = exports.getCompiledSQL = exports.constantExprToSQL = exports.typeDefToString = exports.pathToKey = exports.mkModelDef = exports.makeDigest = exports.composeSQLExpr = exports.indent = exports.getResultStructDefForView = exports.getResultStructDefForQuery = exports.QueryModel = exports.QueryQuery = exports.QueryStruct = exports.QueryField = void 0;
|
|
39
|
+
exports.hasSourceRegistryEntry = exports.registerSource = exports.resolveSourceID = exports.mkTableSourceDef = exports.mkSQLSourceDef = exports.mkQuerySourceDef = exports.mkBuildID = exports.mkSourceID = exports.MalloyCompileError = exports.getCompiledSQL = exports.constantExprToSQL = exports.typeDefToString = exports.pathToKey = exports.mkModelDef = exports.makeDigest = 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; } });
|
|
@@ -66,6 +66,8 @@ var constant_expression_compiler_1 = require("./constant_expression_compiler");
|
|
|
66
66
|
Object.defineProperty(exports, "constantExprToSQL", { enumerable: true, get: function () { return constant_expression_compiler_1.constantExprToSQL; } });
|
|
67
67
|
var sql_compiled_1 = require("./sql_compiled");
|
|
68
68
|
Object.defineProperty(exports, "getCompiledSQL", { enumerable: true, get: function () { return sql_compiled_1.getCompiledSQL; } });
|
|
69
|
+
var malloy_compile_error_1 = require("./malloy_compile_error");
|
|
70
|
+
Object.defineProperty(exports, "MalloyCompileError", { enumerable: true, get: function () { return malloy_compile_error_1.MalloyCompileError; } });
|
|
69
71
|
var source_def_utils_1 = require("./source_def_utils");
|
|
70
72
|
Object.defineProperty(exports, "mkSourceID", { enumerable: true, get: function () { return source_def_utils_1.mkSourceID; } });
|
|
71
73
|
Object.defineProperty(exports, "mkBuildID", { enumerable: true, get: function () { return source_def_utils_1.mkBuildID; } });
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DocumentLocation } from './malloy_types';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by the SQL compiler (`src/model/`) for user-actionable errors the
|
|
4
|
+
* translator didn't catch. Caught at the materializer boundary and turned
|
|
5
|
+
* into a `LogMessage`. Singular `at` reflects the fail-fast contract — the
|
|
6
|
+
* first such error stops compilation. Invariant violations stay as bare
|
|
7
|
+
* `Error` and surface as `code: 'compiler-bug'` instead.
|
|
8
|
+
*/
|
|
9
|
+
export declare class MalloyCompileError extends Error {
|
|
10
|
+
readonly code: string;
|
|
11
|
+
readonly at: DocumentLocation | undefined;
|
|
12
|
+
constructor(message: string, code: string, at: DocumentLocation | undefined);
|
|
13
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
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.MalloyCompileError = void 0;
|
|
8
|
+
/**
|
|
9
|
+
* Thrown by the SQL compiler (`src/model/`) for user-actionable errors the
|
|
10
|
+
* translator didn't catch. Caught at the materializer boundary and turned
|
|
11
|
+
* into a `LogMessage`. Singular `at` reflects the fail-fast contract — the
|
|
12
|
+
* first such error stops compilation. Invariant violations stay as bare
|
|
13
|
+
* `Error` and surface as `code: 'compiler-bug'` instead.
|
|
14
|
+
*/
|
|
15
|
+
class MalloyCompileError extends Error {
|
|
16
|
+
constructor(message, code, at) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.code = code;
|
|
19
|
+
this.at = at;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.MalloyCompileError = MalloyCompileError;
|
|
23
|
+
//# sourceMappingURL=malloy_compile_error.js.map
|
|
@@ -127,11 +127,13 @@ export interface SourceReferenceNode extends ExprLeaf {
|
|
|
127
127
|
export interface ParameterNode extends ExprLeaf {
|
|
128
128
|
node: 'parameter';
|
|
129
129
|
path: string[];
|
|
130
|
+
at?: DocumentLocation;
|
|
130
131
|
}
|
|
131
132
|
export interface GivenRefNode extends ExprLeaf {
|
|
132
133
|
node: 'given';
|
|
133
134
|
id: GivenID;
|
|
134
135
|
refName: string;
|
|
136
|
+
at?: DocumentLocation;
|
|
135
137
|
}
|
|
136
138
|
export interface NowNode extends ExprLeaf {
|
|
137
139
|
node: 'now';
|
|
@@ -1136,6 +1138,13 @@ export interface Annotation {
|
|
|
1136
1138
|
export interface Note {
|
|
1137
1139
|
text: string;
|
|
1138
1140
|
at: DocumentLocation;
|
|
1141
|
+
/**
|
|
1142
|
+
* For block annotations: characters of leading whitespace removed from each
|
|
1143
|
+
* body line by the dedent pass. Used to map payload-parser error columns
|
|
1144
|
+
* back to source (`source_col = indentStripped + parser_col` for body lines).
|
|
1145
|
+
* Omitted for single-line notes and blocks with no common indent.
|
|
1146
|
+
*/
|
|
1147
|
+
indentStripped?: number;
|
|
1139
1148
|
}
|
|
1140
1149
|
/** Annotations with a uuid to make it easier to stream */
|
|
1141
1150
|
export interface ModelAnnotation extends Annotation {
|
|
@@ -24,7 +24,7 @@ function resolveSource(modelDef, name) {
|
|
|
24
24
|
function checkPersistAnnotation(source) {
|
|
25
25
|
if (!source.annotation)
|
|
26
26
|
return { persist: false, log: [] };
|
|
27
|
-
const { tag, log } =
|
|
27
|
+
const { tag, log } = new annotation_1.Annotations(source.annotation).parseAsTag('@');
|
|
28
28
|
return { persist: tag.has('persist'), log };
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
@@ -14,6 +14,7 @@ const stage_writer_1 = require("./stage_writer");
|
|
|
14
14
|
const dialect_1 = require("../dialect");
|
|
15
15
|
const query_node_1 = require("./query_node");
|
|
16
16
|
const row_data_utils_1 = require("../api/row_data_utils");
|
|
17
|
+
const malloy_compile_error_1 = require("./malloy_compile_error");
|
|
17
18
|
function makeQueryModel(modelDef) {
|
|
18
19
|
return new QueryModelImpl(modelDef);
|
|
19
20
|
}
|
|
@@ -66,7 +67,7 @@ class QueryModelImpl {
|
|
|
66
67
|
if (s) {
|
|
67
68
|
return s;
|
|
68
69
|
}
|
|
69
|
-
throw new
|
|
70
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Source '${name}' is not defined in this model.`, 'compiler-undefined-source', undefined);
|
|
70
71
|
}
|
|
71
72
|
getStructFromRef(structRef, sourceArguments, prepareResultOptions) {
|
|
72
73
|
prepareResultOptions !== null && prepareResultOptions !== void 0 ? prepareResultOptions : (prepareResultOptions = {});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FieldDef, BooleanFieldDef, DateFieldDef, StringFieldDef, JSONFieldDef, NumberFieldDef, ATimestampFieldDef, NativeUnsupportedFieldDef, JoinFieldDef, Argument, Given, GivenID, PrepareResultOptions, AtomicFieldDef, BasicAtomicDef, FilterCondition, RefToField, StructDef, TurtleDef, TurtleDefPlusFilters, SourceDef, Query } from './malloy_types';
|
|
1
|
+
import type { FieldDef, BooleanFieldDef, DateFieldDef, DocumentLocation, StringFieldDef, JSONFieldDef, NumberFieldDef, ATimestampFieldDef, NativeUnsupportedFieldDef, JoinFieldDef, Argument, Given, GivenID, PrepareResultOptions, AtomicFieldDef, BasicAtomicDef, FilterCondition, RefToField, StructDef, TurtleDef, TurtleDefPlusFilters, SourceDef, Query } from './malloy_types';
|
|
2
2
|
import type { EventStream } from '../runtime_types';
|
|
3
3
|
import type { Tag } from '@malloydata/malloy-tag';
|
|
4
4
|
import type { Dialect } from '../dialect';
|
|
@@ -106,7 +106,7 @@ export declare class QueryStruct {
|
|
|
106
106
|
getFullOutputName(): string;
|
|
107
107
|
unnestWithNumbers(): boolean;
|
|
108
108
|
getJoinableParent(): QueryStruct;
|
|
109
|
-
addFieldToNameMap(as: string, n: QueryField): void;
|
|
109
|
+
addFieldToNameMap(as: string, n: QueryField, at?: DocumentLocation): void;
|
|
110
110
|
/** the the primary key or throw an error. */
|
|
111
111
|
getPrimaryKeyField(fieldDef: FieldDef): QueryBasicField;
|
|
112
112
|
/**
|
|
@@ -126,14 +126,14 @@ export declare class QueryStruct {
|
|
|
126
126
|
primaryKey(): QueryBasicField | undefined;
|
|
127
127
|
getChildByName(name: string): QueryField | undefined;
|
|
128
128
|
/** convert a path into a field reference */
|
|
129
|
-
getFieldByName(path: string[]): QueryField;
|
|
130
|
-
getQueryFieldByName(name: string[]): QueryField;
|
|
129
|
+
getFieldByName(path: string[], at?: DocumentLocation): QueryField;
|
|
130
|
+
getQueryFieldByName(name: string[], at?: DocumentLocation): QueryField;
|
|
131
131
|
getQueryFieldReference(f: RefToField): QueryField;
|
|
132
132
|
getDimensionOrMeasureByName(name: string[]): QueryField;
|
|
133
133
|
/** returns a query object for the given name */
|
|
134
134
|
getDimensionByName(name: string[]): QueryBasicField;
|
|
135
135
|
/** returns a query object for the given name */
|
|
136
|
-
getStructByName(name: string[]): QueryStruct;
|
|
136
|
+
getStructByName(name: string[], at?: DocumentLocation): QueryStruct;
|
|
137
137
|
getDistinctKey(): QueryBasicField;
|
|
138
138
|
applyStructFiltersToTurtleDef(turtleDef: TurtleDef | TurtleDefPlusFilters): TurtleDef;
|
|
139
139
|
}
|
package/dist/model/query_node.js
CHANGED
|
@@ -12,6 +12,7 @@ exports.isBasicAggregate = isBasicAggregate;
|
|
|
12
12
|
exports.isBasicCalculation = isBasicCalculation;
|
|
13
13
|
exports.isBasicScalar = isBasicScalar;
|
|
14
14
|
const uuid_1 = require("uuid");
|
|
15
|
+
const malloy_compile_error_1 = require("./malloy_compile_error");
|
|
15
16
|
const malloy_types_1 = require("./malloy_types");
|
|
16
17
|
const annotation_1 = require("../annotation");
|
|
17
18
|
const dialect_1 = require("../dialect");
|
|
@@ -205,7 +206,7 @@ class QueryStruct {
|
|
|
205
206
|
modelCompilerFlags() {
|
|
206
207
|
if (this._modelTag === undefined) {
|
|
207
208
|
const annotation = this.structDef.modelAnnotation;
|
|
208
|
-
const { tag } =
|
|
209
|
+
const { tag } = new annotation_1.Annotations(annotation).parseAsTag('!');
|
|
209
210
|
this._modelTag = tag;
|
|
210
211
|
}
|
|
211
212
|
return this._modelTag;
|
|
@@ -245,7 +246,8 @@ class QueryStruct {
|
|
|
245
246
|
? this.parent.resolveParentParameterReferences(resolved1)
|
|
246
247
|
: resolved1;
|
|
247
248
|
if (resolved2.value === null) {
|
|
248
|
-
throw new
|
|
249
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Parameter '${frag.path[0]}' resolves to a null value chain; ` +
|
|
250
|
+
'this parameter was not supplied.', 'compiler-parameter-no-value', undefined);
|
|
249
251
|
}
|
|
250
252
|
else {
|
|
251
253
|
return resolved2.value;
|
|
@@ -284,10 +286,10 @@ class QueryStruct {
|
|
|
284
286
|
if (!QueryStruct.turtleFieldMaker) {
|
|
285
287
|
throw new Error('INTERNAL ERROR: QueryQuery must initialize QueryStruct nested factory method');
|
|
286
288
|
}
|
|
287
|
-
this.addFieldToNameMap(as, QueryStruct.turtleFieldMaker(field, this));
|
|
289
|
+
this.addFieldToNameMap(as, QueryStruct.turtleFieldMaker(field, this), field.location);
|
|
288
290
|
}
|
|
289
291
|
else if ((0, malloy_types_1.isAtomic)(field) || (0, malloy_types_1.isJoinedSource)(field)) {
|
|
290
|
-
this.addFieldToNameMap(as, this.makeQueryField(field));
|
|
292
|
+
this.addFieldToNameMap(as, this.makeQueryField(field), field.location);
|
|
291
293
|
}
|
|
292
294
|
else {
|
|
293
295
|
// According to the type system this should be impossible, but we have seen this happen
|
|
@@ -413,9 +415,9 @@ class QueryStruct {
|
|
|
413
415
|
}
|
|
414
416
|
return this;
|
|
415
417
|
}
|
|
416
|
-
addFieldToNameMap(as, n) {
|
|
418
|
+
addFieldToNameMap(as, n, at) {
|
|
417
419
|
if (this.nameMap.has(as)) {
|
|
418
|
-
throw new
|
|
420
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Field name '${as}' is defined more than once in this scope.`, 'compiler-name-redefined', at);
|
|
419
421
|
}
|
|
420
422
|
this.nameMap.set(as, n);
|
|
421
423
|
}
|
|
@@ -426,7 +428,9 @@ class QueryStruct {
|
|
|
426
428
|
return pk;
|
|
427
429
|
}
|
|
428
430
|
else {
|
|
429
|
-
throw new
|
|
431
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Source '${(0, malloy_types_1.getIdentifier)(this.structDef)}' has no primary key; ` +
|
|
432
|
+
`cannot compute a unique key for field '${(0, malloy_types_1.getIdentifier)(fieldDef)}'. ` +
|
|
433
|
+
'Add `primary_key: <field>` to the source definition.', 'compiler-missing-primary-key', fieldDef.location);
|
|
430
434
|
}
|
|
431
435
|
}
|
|
432
436
|
/**
|
|
@@ -528,7 +532,7 @@ class QueryStruct {
|
|
|
528
532
|
return this.nameMap.get(name);
|
|
529
533
|
}
|
|
530
534
|
/** convert a path into a field reference */
|
|
531
|
-
getFieldByName(path) {
|
|
535
|
+
getFieldByName(path, at) {
|
|
532
536
|
let found = undefined;
|
|
533
537
|
let lookIn = this;
|
|
534
538
|
let notFound = path[0];
|
|
@@ -542,22 +546,23 @@ class QueryStruct {
|
|
|
542
546
|
found instanceof QueryFieldStruct ? found.queryStruct : undefined;
|
|
543
547
|
}
|
|
544
548
|
if (found === undefined) {
|
|
545
|
-
const pathErr = path.length > 1 ? ` in ${path.join('.')}` : '';
|
|
546
|
-
throw new
|
|
549
|
+
const pathErr = path.length > 1 ? ` in path '${path.join('.')}'` : '';
|
|
550
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Field '${notFound}' not found${pathErr}.`, 'compiler-field-not-found', at);
|
|
547
551
|
}
|
|
548
552
|
return found;
|
|
549
553
|
}
|
|
550
554
|
// structs referenced in queries are converted to fields.
|
|
551
|
-
getQueryFieldByName(name) {
|
|
552
|
-
const field = this.getFieldByName(name);
|
|
555
|
+
getQueryFieldByName(name, at) {
|
|
556
|
+
const field = this.getFieldByName(name, at);
|
|
553
557
|
if (field instanceof QueryFieldStruct) {
|
|
554
|
-
throw new
|
|
558
|
+
throw new malloy_compile_error_1.MalloyCompileError(`'${name.join('.')}' refers to a source or join, not a scalar field. ` +
|
|
559
|
+
'Use `source.field` to reference fields inside it.', 'compiler-cannot-reference-as-scalar', at);
|
|
555
560
|
}
|
|
556
561
|
return field;
|
|
557
562
|
}
|
|
558
563
|
getQueryFieldReference(f) {
|
|
559
564
|
const { path, annotation, drillExpression } = f;
|
|
560
|
-
const field = this.getFieldByName(path);
|
|
565
|
+
const field = this.getFieldByName(path, f.at);
|
|
561
566
|
if (annotation || drillExpression) {
|
|
562
567
|
if (field.parent === undefined) {
|
|
563
568
|
throw new Error('Inconcievable, field reference to orphaned query field');
|
|
@@ -591,15 +596,15 @@ class QueryStruct {
|
|
|
591
596
|
throw new Error(`${name} is not an atomic scalar field? Inconceivable!`);
|
|
592
597
|
}
|
|
593
598
|
/** returns a query object for the given name */
|
|
594
|
-
getStructByName(name) {
|
|
599
|
+
getStructByName(name, at) {
|
|
595
600
|
if (name.length === 0) {
|
|
596
601
|
return this;
|
|
597
602
|
}
|
|
598
|
-
const struct = this.getFieldByName(name);
|
|
603
|
+
const struct = this.getFieldByName(name, at);
|
|
599
604
|
if (struct instanceof QueryFieldStruct) {
|
|
600
605
|
return struct.queryStruct;
|
|
601
606
|
}
|
|
602
|
-
throw new
|
|
607
|
+
throw new malloy_compile_error_1.MalloyCompileError(`'${name.join('.')}' is not a source or join.`, 'compiler-struct-not-found', at);
|
|
603
608
|
}
|
|
604
609
|
getDistinctKey() {
|
|
605
610
|
if (this.structDef.type !== 'record') {
|