@malloydata/malloy 0.0.190 → 0.0.191-dev240925232958
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
|
@@ -51,11 +51,11 @@ class SQReference extends source_query_element_1.SourceQueryElement {
|
|
|
51
51
|
return query;
|
|
52
52
|
}
|
|
53
53
|
else {
|
|
54
|
-
this.sqLog(`Illegal reference to '${entry.as || entry.name}', query expected`);
|
|
54
|
+
this.sqLog(`cannot-use-${entry.type}-as-query`, `Illegal reference to '${entry.as || entry.name}', query expected`);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
else {
|
|
58
|
-
this.ref.
|
|
58
|
+
this.ref.logError('source-or-query-not-found', `Reference to undefined object '${this.ref.refString}'`);
|
|
59
59
|
this.errored = true;
|
|
60
60
|
}
|
|
61
61
|
return;
|
|
@@ -70,13 +70,13 @@ class SQReference extends source_query_element_1.SourceQueryElement {
|
|
|
70
70
|
}
|
|
71
71
|
const entry = this.ref.getNamed();
|
|
72
72
|
if (!entry) {
|
|
73
|
-
this.ref.
|
|
73
|
+
this.ref.logError('source-not-found', `Reference to undefined object '${this.ref.refString}'`);
|
|
74
74
|
this.errored = true;
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
77
|
if (entry.type === 'query') {
|
|
78
78
|
if (this.args !== undefined) {
|
|
79
|
-
this.ref.
|
|
79
|
+
this.ref.logError('illegal-query-argument', 'Arguments cannot be passed to queries');
|
|
80
80
|
}
|
|
81
81
|
const existingQuery = new query_reference_1.QueryReference(this.ref);
|
|
82
82
|
this.asSource = new query_source_1.QuerySource(existingQuery);
|
|
@@ -85,7 +85,7 @@ class SQReference extends source_query_element_1.SourceQueryElement {
|
|
|
85
85
|
this.asSource = new named_source_1.NamedSource(this.ref, undefined, this.args);
|
|
86
86
|
}
|
|
87
87
|
else {
|
|
88
|
-
this.sqLog(`Expected '${this.ref.refString}' to be of type query or source, not '${entry.type}'`);
|
|
88
|
+
this.sqLog(`cannot-use-${entry.type}-as-source`, `Expected '${this.ref.refString}' to be of type query or source, not '${entry.type}'`);
|
|
89
89
|
return;
|
|
90
90
|
}
|
|
91
91
|
this.has({ asSource: this.asSource });
|
|
@@ -43,10 +43,10 @@ class SQRefine extends source_query_element_1.SourceQueryElement {
|
|
|
43
43
|
getQuery() {
|
|
44
44
|
if (this.toRefine.isSource()) {
|
|
45
45
|
if (this.toRefine instanceof sq_reference_1.SQReference) {
|
|
46
|
-
this.sqLog(`Cannot add view refinements to '${this.toRefine.ref.refString}' because it is a source`);
|
|
46
|
+
this.sqLog('illegal-refinement-of-source', `Cannot add view refinements to '${this.toRefine.ref.refString}' because it is a source`);
|
|
47
47
|
}
|
|
48
48
|
else {
|
|
49
|
-
this.sqLog('Cannot add view refinements to a source');
|
|
49
|
+
this.sqLog('illegal-refinement-of-source', 'Cannot add view refinements to a source');
|
|
50
50
|
}
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
@@ -49,7 +49,7 @@ class SQLString extends malloy_element_1.MalloyElement {
|
|
|
49
49
|
el.parent = this;
|
|
50
50
|
}
|
|
51
51
|
else {
|
|
52
|
-
el.
|
|
52
|
+
el.logError('invalid-sql-source-interpolation', 'This element is not legal inside an SQL string');
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
sqlPhrases() {
|
|
@@ -64,7 +64,7 @@ class SQLString extends malloy_element_1.MalloyElement {
|
|
|
64
64
|
ret.push(queryObject.query());
|
|
65
65
|
}
|
|
66
66
|
else {
|
|
67
|
-
el.sqLog('Cannot expand into a query');
|
|
67
|
+
el.sqLog('failed-to-expand-sql-source', 'Cannot expand into a query');
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
}
|
|
@@ -37,12 +37,12 @@ class DefineQuery extends malloy_element_1.MalloyElement {
|
|
|
37
37
|
execute(doc) {
|
|
38
38
|
const existing = doc.getEntry(this.name);
|
|
39
39
|
if (existing) {
|
|
40
|
-
this.
|
|
40
|
+
this.logError('query-definition-name-conflict', `'${this.name}' is already defined, cannot redefine`);
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
43
|
const queryEl = this.queryExpr.getQuery();
|
|
44
44
|
if (!queryEl) {
|
|
45
|
-
this.queryExpr.sqLog('Cannot define a query from this expression');
|
|
45
|
+
this.queryExpr.sqLog('query-definition-from-non-query', 'Cannot define a query from this expression');
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
48
|
const entry = {
|
|
@@ -46,7 +46,7 @@ class DefineSource extends malloy_element_1.MalloyElement {
|
|
|
46
46
|
execute(doc) {
|
|
47
47
|
var _a;
|
|
48
48
|
if (doc.modelEntry(this.name)) {
|
|
49
|
-
this.
|
|
49
|
+
this.logError('source-definition-name-conflict', `Cannot redefine '${this.name}'`);
|
|
50
50
|
}
|
|
51
51
|
else {
|
|
52
52
|
const theSource = (_a = this.sourceExpr) === null || _a === void 0 ? void 0 : _a.getSource();
|
|
@@ -79,7 +79,7 @@ class DefineSource extends malloy_element_1.MalloyElement {
|
|
|
79
79
|
const out = [];
|
|
80
80
|
for (const parameter of this.parameters) {
|
|
81
81
|
if (parameter.name in exists) {
|
|
82
|
-
parameter.
|
|
82
|
+
parameter.logError('parameter-name-conflict', `Cannot redefine parameter \`${parameter.name}\``);
|
|
83
83
|
}
|
|
84
84
|
exists[parameter.name] = true;
|
|
85
85
|
out.push(parameter);
|
|
@@ -89,7 +89,7 @@ class DefineSource extends malloy_element_1.MalloyElement {
|
|
|
89
89
|
validateParameterShadowing(parameters, structDef) {
|
|
90
90
|
for (const parameter of parameters) {
|
|
91
91
|
if (structDef.fields.find(field => { var _a; return ((_a = field.as) !== null && _a !== void 0 ? _a : field.name) === parameter.name; })) {
|
|
92
|
-
parameter.
|
|
92
|
+
parameter.logError('parameter-shadowing-field', `Illegal shadowing of field \`${parameter.name}\` by parameter with the same name`);
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
}
|
|
@@ -61,7 +61,7 @@ class ImportStatement extends malloy_element_1.ListOf {
|
|
|
61
61
|
this.fullURL = decodeURI(new URL(url, baseURL).toString());
|
|
62
62
|
}
|
|
63
63
|
catch (e) {
|
|
64
|
-
this.
|
|
64
|
+
this.logError('invalid-import-url', 'Invalid URL in import statement');
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
needs() {
|
|
@@ -79,7 +79,7 @@ class ImportStatement extends malloy_element_1.ListOf {
|
|
|
79
79
|
execute(doc) {
|
|
80
80
|
const trans = this.translator();
|
|
81
81
|
if (!trans) {
|
|
82
|
-
this.
|
|
82
|
+
this.logError('no-translator-for-import', 'Cannot import without translation context');
|
|
83
83
|
}
|
|
84
84
|
else if (this.fullURL) {
|
|
85
85
|
const src = trans.root.importZone.getEntry(this.fullURL);
|
|
@@ -90,7 +90,7 @@ class ImportStatement extends malloy_element_1.ListOf {
|
|
|
90
90
|
for (const importOne of this.list) {
|
|
91
91
|
const fetchName = importOne.from || importOne;
|
|
92
92
|
if (doc.getEntry(importOne.text)) {
|
|
93
|
-
importOne.
|
|
93
|
+
importOne.logError('name-conflict-on-selective-import', `Cannot redefine '${importOne.text}'`);
|
|
94
94
|
}
|
|
95
95
|
else if (importable[fetchName.text]) {
|
|
96
96
|
const importMe = { ...importable[fetchName.text] };
|
|
@@ -100,7 +100,7 @@ class ImportStatement extends malloy_element_1.ListOf {
|
|
|
100
100
|
doc.setEntry(importOne.text, { entry: importMe, exported: false });
|
|
101
101
|
}
|
|
102
102
|
else {
|
|
103
|
-
fetchName.
|
|
103
|
+
fetchName.logError('selective-import-not-found', `Cannot find '${fetchName.text}', not imported`);
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
}
|
|
@@ -108,7 +108,7 @@ class ImportStatement extends malloy_element_1.ListOf {
|
|
|
108
108
|
// import everything
|
|
109
109
|
for (const [importing, entry] of Object.entries(trans.getChildExports(this.fullURL))) {
|
|
110
110
|
if (doc.getEntry(importing)) {
|
|
111
|
-
this.
|
|
111
|
+
this.logError('name-conflict-on-indiscriminate-import', `Cannot redefine '${importing}'`);
|
|
112
112
|
}
|
|
113
113
|
else {
|
|
114
114
|
doc.setEntry(importing, { entry, exported: false });
|
|
@@ -117,10 +117,10 @@ class ImportStatement extends malloy_element_1.ListOf {
|
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
else if (src.status === 'error') {
|
|
120
|
-
this.
|
|
120
|
+
this.logError('failed-import', `import failed: '${src.message}'`);
|
|
121
121
|
}
|
|
122
122
|
else {
|
|
123
|
-
this.
|
|
123
|
+
this.logError('failed-import', `import failed with status: '${src.status}'`);
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
}
|
|
@@ -40,7 +40,7 @@ function opOutputStruct(logTo, inputStruct, opDesc) {
|
|
|
40
40
|
return malloy_query_1.Segment.nextStructDef(inputStruct, opDesc);
|
|
41
41
|
}
|
|
42
42
|
catch (e) {
|
|
43
|
-
logTo.
|
|
43
|
+
logTo.logError('failed-to-compute-output-schema', `INTERNAL ERROR model/Segment.nextStructDef: ${e.message}\n` +
|
|
44
44
|
`QUERY: ${(0, util_1.inspect)(opDesc, { breakLength: 72, depth: Infinity })}`);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -66,9 +66,14 @@ class ExpressionDef extends malloy_element_1.MalloyElement {
|
|
|
66
66
|
*/
|
|
67
67
|
typeCheck(eNode, eVal) {
|
|
68
68
|
if (eVal.dataType !== 'error' && !fragtype_utils_1.FT.in(eVal, this.legalChildTypes)) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
if (eVal.dataType === 'sql native') {
|
|
70
|
+
eNode.logError('sql-native-not-allowed-in-expression', {
|
|
71
|
+
rawType: eVal.rawType,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
eNode.logError('expression-type-error', `'${this.elementType}' Can't use type ${fragtype_utils_1.FT.inspect(eVal)}`);
|
|
76
|
+
}
|
|
72
77
|
return false;
|
|
73
78
|
}
|
|
74
79
|
return true;
|
|
@@ -114,7 +119,7 @@ class ExprDuration extends ExpressionDef {
|
|
|
114
119
|
if ((0, malloy_types_1.isTimeFieldType)(lhs.dataType) && (op === '+' || op === '-')) {
|
|
115
120
|
const num = this.n.getExpression(fs);
|
|
116
121
|
if (!fragtype_utils_1.FT.typeEq(num, fragtype_utils_1.FT.numberT)) {
|
|
117
|
-
this.
|
|
122
|
+
this.logError('invalid-duration-quantity', `Duration quantity needs number not '${num.dataType}`);
|
|
118
123
|
return (0, ast_utils_1.errorFor)('illegal unit expression');
|
|
119
124
|
}
|
|
120
125
|
let resultGranularity;
|
|
@@ -142,8 +147,7 @@ class ExprDuration extends ExpressionDef {
|
|
|
142
147
|
}, resultGranularity);
|
|
143
148
|
}
|
|
144
149
|
else {
|
|
145
|
-
this.
|
|
146
|
-
return (0, ast_utils_1.errorFor)('ofsset date error');
|
|
150
|
+
return this.loggedErrorExpr('invalid-timeframe-for-time-offset', `Cannot offset date by ${this.timeframe}`);
|
|
147
151
|
}
|
|
148
152
|
}
|
|
149
153
|
return super.apply(fs, op, left);
|
|
@@ -196,7 +200,7 @@ function timeCompare(left, lhs, op, rhs) {
|
|
|
196
200
|
if ((leftIsTime || rightIsTime) &&
|
|
197
201
|
lhs.dataType !== 'null' &&
|
|
198
202
|
rhs.dataType !== 'null') {
|
|
199
|
-
left.
|
|
203
|
+
left.logError('time-comparison-type-mismatch', `Cannot compare a ${lhs.dataType} to a ${rhs.dataType}`);
|
|
200
204
|
return { node: 'false' };
|
|
201
205
|
}
|
|
202
206
|
return undefined;
|
|
@@ -319,15 +323,14 @@ function numeric(fs, left, op, right) {
|
|
|
319
323
|
if (err)
|
|
320
324
|
return err;
|
|
321
325
|
const noGo = unsupportError(left, lhs, right, rhs);
|
|
322
|
-
if (noGo)
|
|
326
|
+
if (noGo)
|
|
323
327
|
return noGo;
|
|
324
|
-
}
|
|
325
328
|
const expressionType = (0, malloy_types_1.maxExpressionType)(lhs.expressionType, rhs.expressionType);
|
|
326
329
|
if (lhs.dataType !== 'number') {
|
|
327
|
-
left.
|
|
330
|
+
left.logError('arithmetic-operation-type-mismatch', `The '${op}' operator requires a number, not a '${lhs.dataType}'`);
|
|
328
331
|
}
|
|
329
332
|
else if (rhs.dataType !== 'number') {
|
|
330
|
-
right.
|
|
333
|
+
right.logError('arithmetic-operation-type-mismatch', `The '${op}' operator requires a number, not a '${rhs.dataType}'`);
|
|
331
334
|
}
|
|
332
335
|
else {
|
|
333
336
|
return {
|
|
@@ -360,8 +363,7 @@ function delta(fs, left, op, right) {
|
|
|
360
363
|
duration = new ExprDuration(right, 'day');
|
|
361
364
|
}
|
|
362
365
|
else {
|
|
363
|
-
left.
|
|
364
|
-
return (0, ast_utils_1.errorFor)(`time plus ${rhs.dataType}`);
|
|
366
|
+
return left.loggedErrorExpr('time-offset-type-mismatch', `Can not offset time by '${rhs.dataType}'`);
|
|
365
367
|
}
|
|
366
368
|
}
|
|
367
369
|
return duration.apply(fs, op, left);
|
|
@@ -396,18 +398,16 @@ function applyBinary(fs, left, op, right) {
|
|
|
396
398
|
const num = left.getExpression(fs);
|
|
397
399
|
const denom = right.getExpression(fs);
|
|
398
400
|
const noGo = unsupportError(left, num, right, denom);
|
|
399
|
-
if (noGo)
|
|
400
|
-
left.log(`Cannot use '${op}' with sql native type`);
|
|
401
|
+
if (noGo)
|
|
401
402
|
return noGo;
|
|
402
|
-
}
|
|
403
403
|
const err = errorCascade('number', num, denom);
|
|
404
404
|
if (err)
|
|
405
405
|
return err;
|
|
406
406
|
if (num.dataType !== 'number') {
|
|
407
|
-
left.
|
|
407
|
+
left.logError('arithmetic-operation-type-mismatch', 'Numerator must be a number');
|
|
408
408
|
}
|
|
409
409
|
else if (denom.dataType !== 'number') {
|
|
410
|
-
right.
|
|
410
|
+
right.logError('arithmetic-operation-type-mismatch', 'Denominator must be a number');
|
|
411
411
|
}
|
|
412
412
|
else {
|
|
413
413
|
const divmod = {
|
|
@@ -423,8 +423,7 @@ function applyBinary(fs, left, op, right) {
|
|
|
423
423
|
}
|
|
424
424
|
return (0, ast_utils_1.errorFor)('divide type mismatch');
|
|
425
425
|
}
|
|
426
|
-
left.
|
|
427
|
-
return (0, ast_utils_1.errorFor)('applybinary bad operator');
|
|
426
|
+
return left.loggedErrorExpr('unexpected-binary-operator', `Cannot use ${op} operator here`);
|
|
428
427
|
}
|
|
429
428
|
exports.applyBinary = applyBinary;
|
|
430
429
|
function errorCascade(dataType, ...es) {
|
|
@@ -448,12 +447,12 @@ function unsupportError(l, lhs, r, rhs) {
|
|
|
448
447
|
evalSpace: (0, malloy_types_1.mergeEvalSpaces)(lhs.evalSpace, rhs.evalSpace),
|
|
449
448
|
};
|
|
450
449
|
if (lhs.dataType === 'sql native') {
|
|
451
|
-
l.
|
|
450
|
+
l.logError('sql-native-not-allowed-in-expression', { rawType: lhs.rawType });
|
|
452
451
|
ret.dataType = rhs.dataType;
|
|
453
452
|
return ret;
|
|
454
453
|
}
|
|
455
454
|
if (rhs.dataType === 'sql native') {
|
|
456
|
-
r.
|
|
455
|
+
r.logError('sql-native-not-allowed-in-expression', { rawType: rhs.rawType });
|
|
457
456
|
return ret;
|
|
458
457
|
}
|
|
459
458
|
return undefined;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { StructRelationship } from '../../../model';
|
|
2
|
+
import { MessageCode } from '../../parse-log';
|
|
2
3
|
import { SpaceEntry } from './space-entry';
|
|
3
4
|
export interface LookupFound {
|
|
4
5
|
found: SpaceEntry;
|
|
@@ -10,7 +11,10 @@ export interface LookupFound {
|
|
|
10
11
|
isOutputField: boolean;
|
|
11
12
|
}
|
|
12
13
|
export interface LookupError {
|
|
13
|
-
error:
|
|
14
|
+
error: {
|
|
15
|
+
message: string;
|
|
16
|
+
code: MessageCode;
|
|
17
|
+
};
|
|
14
18
|
found: undefined;
|
|
15
19
|
}
|
|
16
20
|
export type LookupResult = LookupFound | LookupError;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Annotation, DocumentLocation, DocumentReference, ModelDef, ModelAnnotation, NamedModelObject, Query, SQLBlockStructDef, StructDef } from '../../../model/malloy_types';
|
|
2
2
|
import { Tag } from '../../../tags';
|
|
3
|
-
import {
|
|
3
|
+
import { LogMessageOptions, MessageLogger, MessageParameterType, MessageCode } from '../../parse-log';
|
|
4
4
|
import { MalloyTranslation } from '../../parse-malloy';
|
|
5
5
|
import { ModelDataRequest } from '../../translate-response';
|
|
6
6
|
import { DocumentCompileResult } from './document-compile-result';
|
|
7
|
+
import { ExprValue } from './expr-value';
|
|
7
8
|
import { ModelEntry } from './model-entry';
|
|
8
9
|
import { NameSpace } from './name-space';
|
|
9
10
|
import { Noteable, extendNoteMethod } from './noteable';
|
|
@@ -38,10 +39,12 @@ export declare abstract class MalloyElement {
|
|
|
38
39
|
setTranslator(x: MalloyTranslation): void;
|
|
39
40
|
addReference(reference: DocumentReference): void;
|
|
40
41
|
private get sourceURL();
|
|
41
|
-
errorsExist(): boolean;
|
|
42
42
|
private readonly logged;
|
|
43
|
-
log
|
|
44
|
-
|
|
43
|
+
private log;
|
|
44
|
+
logError<T extends MessageCode>(code: T, parameters: MessageParameterType<T>, options?: Omit<LogMessageOptions, 'severity'>): T;
|
|
45
|
+
logWarning<T extends MessageCode>(code: T, parameters: MessageParameterType<T>, options?: Omit<LogMessageOptions, 'severity'>): T;
|
|
46
|
+
loggedErrorExpr<T extends MessageCode>(code: T, parameters: MessageParameterType<T>, options?: LogMessageOptions): ExprValue;
|
|
47
|
+
get logger(): MessageLogger;
|
|
45
48
|
/**
|
|
46
49
|
* Mostly for debugging / testing. A string-y version of this object which
|
|
47
50
|
* is used to ask "are these two AST segments equal". Formatted so that
|
|
@@ -54,7 +57,7 @@ export declare abstract class MalloyElement {
|
|
|
54
57
|
private varInfo;
|
|
55
58
|
protected internalError(msg: string): Error;
|
|
56
59
|
needs(doc: Document): ModelDataRequest | undefined;
|
|
57
|
-
inExperiment(
|
|
60
|
+
inExperiment(experimentId: string, silent?: boolean): boolean;
|
|
58
61
|
}
|
|
59
62
|
export declare class Unimplemented extends MalloyElement {
|
|
60
63
|
elementType: string;
|
|
@@ -26,6 +26,8 @@ exports.Document = exports.DocStatementList = exports.ListOf = exports.isDocStat
|
|
|
26
26
|
const dialect_1 = require("../../../dialect");
|
|
27
27
|
const malloy_types_1 = require("../../../model/malloy_types");
|
|
28
28
|
const tags_1 = require("../../../tags");
|
|
29
|
+
const parse_log_1 = require("../../parse-log");
|
|
30
|
+
const ast_utils_1 = require("../ast-utils");
|
|
29
31
|
const dialect_name_space_1 = require("./dialect-name-space");
|
|
30
32
|
const global_name_space_1 = require("./global-name-space");
|
|
31
33
|
const noteable_1 = require("./noteable");
|
|
@@ -166,35 +168,40 @@ class MalloyElement {
|
|
|
166
168
|
const trans = this.translator();
|
|
167
169
|
return (trans === null || trans === void 0 ? void 0 : trans.sourceURL) || '(missing)';
|
|
168
170
|
}
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
return false;
|
|
175
|
-
}
|
|
176
|
-
log(message, severity = 'error') {
|
|
171
|
+
log(code, parameters, options) {
|
|
172
|
+
const log = (0, parse_log_1.makeLogMessage)(code, parameters, {
|
|
173
|
+
at: this.location,
|
|
174
|
+
...options,
|
|
175
|
+
});
|
|
177
176
|
if (this.codeLocation) {
|
|
178
177
|
/*
|
|
179
178
|
* If this element has a location, then don't report the same
|
|
180
179
|
* error message at the same location more than once
|
|
181
180
|
*/
|
|
182
|
-
if (this.logged.has(message)) {
|
|
183
|
-
return;
|
|
181
|
+
if (this.logged.has(log.message)) {
|
|
182
|
+
return code;
|
|
184
183
|
}
|
|
185
|
-
this.logged.add(message);
|
|
186
|
-
}
|
|
187
|
-
const msg = { at: this.location, message, severity };
|
|
188
|
-
const logTo = this.logger();
|
|
189
|
-
if (logTo) {
|
|
190
|
-
logTo.log(msg);
|
|
191
|
-
return;
|
|
184
|
+
this.logged.add(log.message);
|
|
192
185
|
}
|
|
193
|
-
|
|
186
|
+
this.logger.log(log);
|
|
187
|
+
return code;
|
|
194
188
|
}
|
|
195
|
-
|
|
189
|
+
logError(code, parameters, options) {
|
|
190
|
+
return this.log(code, parameters, { severity: 'error', ...options });
|
|
191
|
+
}
|
|
192
|
+
logWarning(code, parameters, options) {
|
|
193
|
+
return this.log(code, parameters, { severity: 'warn', ...options });
|
|
194
|
+
}
|
|
195
|
+
loggedErrorExpr(code, parameters, options) {
|
|
196
|
+
return (0, ast_utils_1.errorFor)(this.logError(code, parameters, options));
|
|
197
|
+
}
|
|
198
|
+
get logger() {
|
|
196
199
|
var _a;
|
|
197
|
-
|
|
200
|
+
const logger = (_a = this.translator()) === null || _a === void 0 ? void 0 : _a.root.logger;
|
|
201
|
+
if (logger === undefined) {
|
|
202
|
+
throw new Error('Attempted to access logger without a translator');
|
|
203
|
+
}
|
|
204
|
+
return logger;
|
|
198
205
|
}
|
|
199
206
|
/**
|
|
200
207
|
* Mostly for debugging / testing. A string-y version of this object which
|
|
@@ -254,8 +261,7 @@ class MalloyElement {
|
|
|
254
261
|
return extra;
|
|
255
262
|
}
|
|
256
263
|
internalError(msg) {
|
|
257
|
-
|
|
258
|
-
return new Error(msg);
|
|
264
|
+
return new Error(`INTERNAL ERROR IN TRANSLATION: ${msg}`);
|
|
259
265
|
}
|
|
260
266
|
needs(doc) {
|
|
261
267
|
for (const child of this.walk()) {
|
|
@@ -264,15 +270,15 @@ class MalloyElement {
|
|
|
264
270
|
return childNeeds;
|
|
265
271
|
}
|
|
266
272
|
}
|
|
267
|
-
inExperiment(
|
|
273
|
+
inExperiment(experimentId, silent = false) {
|
|
268
274
|
var _a;
|
|
269
275
|
const experimental = (_a = this.translator()) === null || _a === void 0 ? void 0 : _a.compilerFlags.tag('experimental');
|
|
270
|
-
const enabled = experimental && (experimental.bare() || experimental.has(
|
|
276
|
+
const enabled = experimental && (experimental.bare() || experimental.has(experimentId));
|
|
271
277
|
if (enabled) {
|
|
272
278
|
return true;
|
|
273
279
|
}
|
|
274
280
|
if (!silent) {
|
|
275
|
-
this.
|
|
281
|
+
this.logError('experiment-not-enabled', { experimentId });
|
|
276
282
|
}
|
|
277
283
|
return false;
|
|
278
284
|
}
|
|
@@ -551,7 +557,7 @@ class Document extends MalloyElement {
|
|
|
551
557
|
setEntry(str, ent) {
|
|
552
558
|
// TODO this error message is going to be in the wrong place everywhere...
|
|
553
559
|
if (this.globalNameSpace.getEntry(str) !== undefined) {
|
|
554
|
-
this.
|
|
560
|
+
this.logError('name-conflict-with-global', `Cannot redefine '${str}', which is in global namespace`);
|
|
555
561
|
}
|
|
556
562
|
if (ent.entry.type === 'struct') {
|
|
557
563
|
this.checkExperimentalDialect(this, ent.entry.dialect);
|
|
@@ -570,7 +576,7 @@ class Document extends MalloyElement {
|
|
|
570
576
|
t.firstReferenceToDialect(dialect) &&
|
|
571
577
|
(0, dialect_1.getDialect)(dialect).experimental &&
|
|
572
578
|
!t.experimentalDialectEnabled(dialect)) {
|
|
573
|
-
me.
|
|
579
|
+
me.logError('experimental-dialect-not-enabled', { dialect });
|
|
574
580
|
}
|
|
575
581
|
}
|
|
576
582
|
getDialectNamespace(dialectName) {
|
|
@@ -49,7 +49,7 @@ class QOpDescView extends view_1.View {
|
|
|
49
49
|
}
|
|
50
50
|
getOp(inputFS, isNestIn, qOpDesc, refineThis) {
|
|
51
51
|
if ((0, malloy_types_1.isRawSegment)(refineThis)) {
|
|
52
|
-
this.
|
|
52
|
+
this.logError('refinement-of-raw-query', 'A raw query cannot be refined');
|
|
53
53
|
return refineThis;
|
|
54
54
|
}
|
|
55
55
|
qOpDesc.refineFrom(refineThis);
|
|
@@ -72,13 +72,13 @@ class QOpDescView extends view_1.View {
|
|
|
72
72
|
headRefinements.push(qop);
|
|
73
73
|
break;
|
|
74
74
|
case query_property_interface_1.LegalRefinementStage.Single:
|
|
75
|
-
qop.
|
|
75
|
+
qop.logError('illegal-multistage-refinement-operation', 'Illegal in refinement of a query with more than one stage');
|
|
76
76
|
break;
|
|
77
77
|
case query_property_interface_1.LegalRefinementStage.Tail:
|
|
78
78
|
tailRefinements.push(qop);
|
|
79
79
|
break;
|
|
80
80
|
default:
|
|
81
|
-
qop.
|
|
81
|
+
qop.logError('illegal-refinement-operation', 'Illegal query refinement');
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
if (headRefinements.notEmpty()) {
|
|
@@ -60,7 +60,7 @@ class ReferenceView extends view_1.View {
|
|
|
60
60
|
};
|
|
61
61
|
};
|
|
62
62
|
if (!lookup.found) {
|
|
63
|
-
this.
|
|
63
|
+
this.logError('view-not-found', `\`${this.reference.refString}\` is not defined`);
|
|
64
64
|
return oops();
|
|
65
65
|
}
|
|
66
66
|
if (!(lookup.found instanceof space_field_1.SpaceField)) {
|
|
@@ -95,10 +95,10 @@ class ReferenceView extends view_1.View {
|
|
|
95
95
|
else if ((0, malloy_types_1.isTurtleDef)(fieldDef)) {
|
|
96
96
|
if (this.reference.list.length > 1) {
|
|
97
97
|
if (forRefinement) {
|
|
98
|
-
this.
|
|
98
|
+
this.logError('refinement-with-joined-view', 'Cannot use view from join as refinement');
|
|
99
99
|
}
|
|
100
100
|
else {
|
|
101
|
-
this.
|
|
101
|
+
this.logError('nest-of-joined-view', 'Cannot use view from join');
|
|
102
102
|
}
|
|
103
103
|
return oops();
|
|
104
104
|
}
|
|
@@ -111,10 +111,10 @@ class ReferenceView extends view_1.View {
|
|
|
111
111
|
}
|
|
112
112
|
else {
|
|
113
113
|
if (forRefinement) {
|
|
114
|
-
this.reference.
|
|
114
|
+
this.reference.logError('refinement-with-source', `named refinement \`${this.reference.refString}\` must be a view, found a ${fieldDef.type}`);
|
|
115
115
|
}
|
|
116
116
|
else {
|
|
117
|
-
this.reference.
|
|
117
|
+
this.reference.logError('nest-of-source', 'This operation is not supported');
|
|
118
118
|
}
|
|
119
119
|
return oops();
|
|
120
120
|
}
|
|
@@ -126,7 +126,7 @@ class ReferenceView extends view_1.View {
|
|
|
126
126
|
if (error)
|
|
127
127
|
return;
|
|
128
128
|
if (pipeline.length !== 1) {
|
|
129
|
-
this.reference.
|
|
129
|
+
this.reference.logError('refinement-with-multistage-view', `named refinement \`${this.reference.refString}\` must have exactly one stage`);
|
|
130
130
|
return;
|
|
131
131
|
}
|
|
132
132
|
return pipeline[0];
|
|
@@ -29,14 +29,14 @@ function refine(logTo, refineTo, refineFrom) {
|
|
|
29
29
|
var _a, _b;
|
|
30
30
|
// TODO we should probably support this
|
|
31
31
|
if (refineTo.length !== 1) {
|
|
32
|
-
logTo.
|
|
32
|
+
logTo.logError('refinement-with-multistage-view', 'Named refinements of multi-stage views are not supported');
|
|
33
33
|
// TODO better error pipeline?
|
|
34
34
|
return refineTo;
|
|
35
35
|
}
|
|
36
36
|
const to = { ...refineTo[0] };
|
|
37
37
|
const from = refineFrom;
|
|
38
38
|
if ((0, model_1.isRawSegment)(to)) {
|
|
39
|
-
logTo.
|
|
39
|
+
logTo.logError('refinement-of-raw-query', 'Cannot refine raw query, must add an explicit query stage');
|
|
40
40
|
}
|
|
41
41
|
else {
|
|
42
42
|
// TODO need to disallow partial + index for now to make the types happy
|
|
@@ -44,7 +44,7 @@ function refine(logTo, refineTo, refineFrom) {
|
|
|
44
44
|
to.type = from.type;
|
|
45
45
|
}
|
|
46
46
|
else if (from.type !== to.type) {
|
|
47
|
-
logTo.
|
|
47
|
+
logTo.logError('mismatched-view-types-for-refinement', `cannot refine ${to.type} view with ${from.type} view`);
|
|
48
48
|
}
|
|
49
49
|
if (from.type !== 'index' && to.type !== 'index' && from.type !== 'raw') {
|
|
50
50
|
if (from.orderBy !== undefined || from.by !== undefined) {
|
|
@@ -57,7 +57,7 @@ function refine(logTo, refineTo, refineFrom) {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
else {
|
|
60
|
-
logTo.
|
|
60
|
+
logTo.logError('ordering-overridden-in-refinement', 'refinement cannot override existing ordering');
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
if (from.limit !== undefined) {
|
|
@@ -65,7 +65,7 @@ function refine(logTo, refineTo, refineFrom) {
|
|
|
65
65
|
to.limit = from.limit;
|
|
66
66
|
}
|
|
67
67
|
else {
|
|
68
|
-
logTo.
|
|
68
|
+
logTo.logError('limit-overridden-in-refinement', 'refinement cannot override existing limit');
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
}
|
|
@@ -90,7 +90,7 @@ function refine(logTo, refineTo, refineFrom) {
|
|
|
90
90
|
}
|
|
91
91
|
to.queryFields = [...to.queryFields, ...nonOverlappingFields];
|
|
92
92
|
if (overlappingFields.length > 0) {
|
|
93
|
-
logTo.
|
|
93
|
+
logTo.logError('name-conflict-in-refinement', `overlapping fields in refinement: ${overlappingFields.map(field_utils_1.nameFromDef)}`);
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
else if (from.type === 'index' && to.type === 'index') {
|
|
@@ -48,7 +48,7 @@ class ViewArrow extends view_1.View {
|
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
50
|
refine(_inputFS, _pipeline, _isNestIn) {
|
|
51
|
-
this.
|
|
51
|
+
this.logError('refinement-with-multistage-view', 'A multi-segment view cannot be used as a refinement');
|
|
52
52
|
return [];
|
|
53
53
|
}
|
|
54
54
|
getImplicitName() {
|
|
@@ -54,7 +54,7 @@ class ViewRefine extends view_1.View {
|
|
|
54
54
|
refine(inputFS, pipeline, isNestIn) {
|
|
55
55
|
const refineFrom = this.pipeline(inputFS, isNestIn);
|
|
56
56
|
if (refineFrom.length !== 1) {
|
|
57
|
-
this.refinement.
|
|
57
|
+
this.refinement.logError('refinement-with-multistage-view', 'refinement must have exactly one stage');
|
|
58
58
|
// TODO better error pipeline?
|
|
59
59
|
return pipeline;
|
|
60
60
|
}
|