@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
|
@@ -28,51 +28,59 @@ function typecheckProject(type, logTo) {
|
|
|
28
28
|
if (type.dataType === 'turtle' || !(0, model_1.expressionIsScalar)(type.expressionType)) {
|
|
29
29
|
let useInstead;
|
|
30
30
|
let kind;
|
|
31
|
+
let code;
|
|
31
32
|
if (type.dataType === 'turtle') {
|
|
32
33
|
useInstead = 'a nest';
|
|
33
34
|
kind = 'a view';
|
|
35
|
+
code = 'select-of-view';
|
|
34
36
|
}
|
|
35
37
|
else if ((0, model_1.expressionIsAnalytic)(type.expressionType)) {
|
|
36
38
|
useInstead = 'a calculate';
|
|
37
39
|
kind = 'an analytic';
|
|
40
|
+
code = 'select-of-analytic';
|
|
38
41
|
}
|
|
39
42
|
else if ((0, model_1.expressionIsAggregate)(type.expressionType)) {
|
|
40
43
|
useInstead = 'an aggregate';
|
|
41
44
|
kind = 'an aggregate';
|
|
45
|
+
code = 'select-of-aggregate';
|
|
42
46
|
}
|
|
43
47
|
else {
|
|
44
48
|
throw new Error(`Unexpected expression type ${type.expressionType} not handled here`);
|
|
45
49
|
}
|
|
46
|
-
logTo.
|
|
50
|
+
logTo.logError(code, `Cannot use ${kind} field in a select operation, did you mean to use ${useInstead} operation instead?`);
|
|
47
51
|
}
|
|
48
52
|
}
|
|
49
53
|
exports.typecheckProject = typecheckProject;
|
|
50
54
|
function typecheckIndex(type, logTo) {
|
|
51
55
|
if (type.dataType === 'turtle' || !(0, model_1.expressionIsScalar)(type.expressionType)) {
|
|
52
56
|
let kind;
|
|
57
|
+
let code;
|
|
53
58
|
if (type.dataType === 'turtle') {
|
|
54
59
|
kind = 'a view';
|
|
60
|
+
code = 'index-of-view';
|
|
55
61
|
}
|
|
56
62
|
else if ((0, model_1.expressionIsAnalytic)(type.expressionType)) {
|
|
57
63
|
kind = 'an analytic';
|
|
64
|
+
code = 'index-of-analytic';
|
|
58
65
|
}
|
|
59
66
|
else if ((0, model_1.expressionIsAggregate)(type.expressionType)) {
|
|
60
67
|
kind = 'an aggregate';
|
|
68
|
+
code = 'index-of-aggregate';
|
|
61
69
|
}
|
|
62
70
|
else {
|
|
63
71
|
throw new Error(`Unexpected expression type ${type.expressionType} not handled here`);
|
|
64
72
|
}
|
|
65
|
-
logTo.
|
|
73
|
+
logTo.logError(code, `Cannot use ${kind} field in an index operation`);
|
|
66
74
|
}
|
|
67
75
|
}
|
|
68
76
|
exports.typecheckIndex = typecheckIndex;
|
|
69
77
|
function typecheckDimension(type, logTo) {
|
|
70
78
|
if (!(0, model_1.expressionIsScalar)(type.expressionType)) {
|
|
71
79
|
if ((0, model_1.expressionIsAggregate)(type.expressionType)) {
|
|
72
|
-
logTo.
|
|
80
|
+
logTo.logError('aggregate-in-dimension', 'Cannot use an aggregate field in a dimension declaration, did you mean to use a measure declaration instead?');
|
|
73
81
|
}
|
|
74
82
|
else if ((0, model_1.expressionIsAnalytic)(type.expressionType)) {
|
|
75
|
-
logTo.
|
|
83
|
+
logTo.logError('analytic-in-dimension', 'Cannot use an analytic field in a dimension declaration');
|
|
76
84
|
}
|
|
77
85
|
else {
|
|
78
86
|
throw new Error(`Unexpected expression type ${type.expressionType} not handled here`);
|
|
@@ -83,10 +91,10 @@ exports.typecheckDimension = typecheckDimension;
|
|
|
83
91
|
function typecheckMeasure(type, logTo) {
|
|
84
92
|
if (!(0, model_1.expressionIsAggregate)(type.expressionType)) {
|
|
85
93
|
if ((0, model_1.expressionIsScalar)(type.expressionType)) {
|
|
86
|
-
logTo.
|
|
94
|
+
logTo.logError('scalar-in-measure', 'Cannot use a scalar field in a measure declaration, did you mean to use a dimension declaration instead?');
|
|
87
95
|
}
|
|
88
96
|
else if ((0, model_1.expressionIsAnalytic)(type.expressionType)) {
|
|
89
|
-
logTo.
|
|
97
|
+
logTo.logError('analytic-in-measure', 'Cannot use an analytic field in a measure declaration');
|
|
90
98
|
}
|
|
91
99
|
else {
|
|
92
100
|
throw new Error(`Unexpected expression type ${type.expressionType} not handled here`);
|
|
@@ -96,10 +104,10 @@ function typecheckMeasure(type, logTo) {
|
|
|
96
104
|
exports.typecheckMeasure = typecheckMeasure;
|
|
97
105
|
function typecheckDeclare(type, logTo) {
|
|
98
106
|
if (type.dataType === 'turtle') {
|
|
99
|
-
logTo.
|
|
107
|
+
logTo.logError('view-in-declare', 'Views cannot be used in a declare block');
|
|
100
108
|
}
|
|
101
109
|
else if ((0, model_1.expressionIsAnalytic)(type.expressionType)) {
|
|
102
|
-
logTo.
|
|
110
|
+
logTo.logError('analytic-in-declare', 'Analytic expressions can not be used in a declare block');
|
|
103
111
|
}
|
|
104
112
|
}
|
|
105
113
|
exports.typecheckDeclare = typecheckDeclare;
|
|
@@ -108,22 +116,26 @@ function typecheckCalculate(type, logTo) {
|
|
|
108
116
|
!(0, model_1.expressionIsAnalytic)(type.expressionType)) {
|
|
109
117
|
let useInstead;
|
|
110
118
|
let kind;
|
|
119
|
+
let code;
|
|
111
120
|
if (type.dataType === 'turtle') {
|
|
112
121
|
useInstead = 'a nest';
|
|
113
122
|
kind = 'a view';
|
|
123
|
+
code = 'calculate-of-view';
|
|
114
124
|
}
|
|
115
125
|
else if ((0, model_1.expressionIsAggregate)(type.expressionType)) {
|
|
116
126
|
useInstead = 'an aggregate';
|
|
117
127
|
kind = 'an aggregate';
|
|
128
|
+
code = 'calculate-of-aggregate';
|
|
118
129
|
}
|
|
119
130
|
else if ((0, model_1.expressionIsScalar)(type.expressionType)) {
|
|
120
131
|
useInstead = 'a group_by or select';
|
|
121
132
|
kind = 'a scalar';
|
|
133
|
+
code = 'calculate-of-scalar';
|
|
122
134
|
}
|
|
123
135
|
else {
|
|
124
136
|
throw new Error(`Unexpected expression type ${type.expressionType} not handled here`);
|
|
125
137
|
}
|
|
126
|
-
logTo.
|
|
138
|
+
logTo.logError(code, `Cannot use ${kind} field in a calculate operation, did you mean to use ${useInstead} operation instead?`);
|
|
127
139
|
}
|
|
128
140
|
}
|
|
129
141
|
exports.typecheckCalculate = typecheckCalculate;
|
|
@@ -132,22 +144,26 @@ function typecheckAggregate(type, logTo) {
|
|
|
132
144
|
!(0, model_1.expressionIsAggregate)(type.expressionType)) {
|
|
133
145
|
let useInstead;
|
|
134
146
|
let kind;
|
|
147
|
+
let code;
|
|
135
148
|
if (type.dataType === 'turtle') {
|
|
136
149
|
useInstead = 'a nest';
|
|
137
150
|
kind = 'a view';
|
|
151
|
+
code = 'aggregate-of-view';
|
|
138
152
|
}
|
|
139
153
|
else if ((0, model_1.expressionIsAnalytic)(type.expressionType)) {
|
|
140
154
|
useInstead = 'a calculate';
|
|
141
155
|
kind = 'an analytic';
|
|
156
|
+
code = 'aggregate-of-analytic';
|
|
142
157
|
}
|
|
143
158
|
else if ((0, model_1.expressionIsScalar)(type.expressionType)) {
|
|
144
159
|
useInstead = 'a group_by or select';
|
|
145
160
|
kind = 'a scalar';
|
|
161
|
+
code = 'aggregate-of-scalar';
|
|
146
162
|
}
|
|
147
163
|
else {
|
|
148
164
|
throw new Error(`Unexpected expression type ${type} not handled here`);
|
|
149
165
|
}
|
|
150
|
-
logTo.
|
|
166
|
+
logTo.logError(code, `Cannot use ${kind} field in an aggregate operation, did you mean to use ${useInstead} operation instead?`);
|
|
151
167
|
}
|
|
152
168
|
}
|
|
153
169
|
exports.typecheckAggregate = typecheckAggregate;
|
|
@@ -155,22 +171,26 @@ function typecheckGroupBy(type, logTo) {
|
|
|
155
171
|
if (type.dataType === 'turtle' || !(0, model_1.expressionIsScalar)(type.expressionType)) {
|
|
156
172
|
let useInstead;
|
|
157
173
|
let kind;
|
|
174
|
+
let code;
|
|
158
175
|
if (type.dataType === 'turtle') {
|
|
159
176
|
useInstead = 'a nest';
|
|
160
177
|
kind = 'a view';
|
|
178
|
+
code = 'group-by-view';
|
|
161
179
|
}
|
|
162
180
|
else if ((0, model_1.expressionIsAnalytic)(type.expressionType)) {
|
|
163
181
|
useInstead = 'a calculate';
|
|
164
182
|
kind = 'an analytic';
|
|
183
|
+
code = 'group-by-analytic';
|
|
165
184
|
}
|
|
166
185
|
else if ((0, model_1.expressionIsAggregate)(type.expressionType)) {
|
|
167
186
|
useInstead = 'an aggregate';
|
|
168
187
|
kind = 'an aggregate';
|
|
188
|
+
code = 'group-by-aggregate';
|
|
169
189
|
}
|
|
170
190
|
else {
|
|
171
191
|
throw new Error(`Unexpected expression type ${type.expressionType} not handled here`);
|
|
172
192
|
}
|
|
173
|
-
logTo.
|
|
193
|
+
logTo.logError(code, `Cannot use ${kind} field in a group_by operation, did you mean to use ${useInstead} operation instead?`);
|
|
174
194
|
}
|
|
175
195
|
}
|
|
176
196
|
exports.typecheckGroupBy = typecheckGroupBy;
|
|
@@ -36,7 +36,7 @@ class FilterElement extends malloy_element_1.MalloyElement {
|
|
|
36
36
|
filterCondition(fs) {
|
|
37
37
|
const exprVal = this.expr.getExpression(fs);
|
|
38
38
|
if (exprVal.dataType !== 'boolean') {
|
|
39
|
-
this.expr.
|
|
39
|
+
this.expr.logError('non-boolean-filter', 'Filter expression must have boolean value');
|
|
40
40
|
return {
|
|
41
41
|
node: 'filterCondition',
|
|
42
42
|
code: this.exprSrc,
|
|
@@ -81,17 +81,17 @@ class Filter extends malloy_element_1.ListOf {
|
|
|
81
81
|
const isAnalytic = (0, malloy_types_1.expressionIsAnalytic)(fExpr.expressionType);
|
|
82
82
|
if (this.havingClause) {
|
|
83
83
|
if (isAnalytic) {
|
|
84
|
-
oneElement.
|
|
84
|
+
oneElement.logError('analytic-in-having', 'Analytic expressions are not allowed in `having:`');
|
|
85
85
|
continue;
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
else {
|
|
89
89
|
if (isAnalytic) {
|
|
90
|
-
oneElement.
|
|
90
|
+
oneElement.logError('analytic-in-where', 'Analytic expressions are not allowed in `where:`');
|
|
91
91
|
continue;
|
|
92
92
|
}
|
|
93
93
|
else if (isAggregate) {
|
|
94
|
-
oneElement.
|
|
94
|
+
oneElement.logError('aggregate-in-where', 'Aggregate expressions are not allowed in `where:`; use `having:`');
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
}
|
|
@@ -48,13 +48,13 @@ class OrderBy extends malloy_element_1.MalloyElement {
|
|
|
48
48
|
const output = fs.outputSpace();
|
|
49
49
|
const entry = this.field.getField(output);
|
|
50
50
|
if (entry.error) {
|
|
51
|
-
this.field.
|
|
51
|
+
this.field.logError(entry.error.code, entry.error.message);
|
|
52
52
|
}
|
|
53
53
|
if (!entry.found || !entry.isOutputField) {
|
|
54
|
-
this.
|
|
54
|
+
this.logError('order-by-not-found-in-output', `Unknown field ${this.field.refString} in output space`);
|
|
55
55
|
}
|
|
56
56
|
if ((0, malloy_types_1.expressionIsAnalytic)((_a = entry.found) === null || _a === void 0 ? void 0 : _a.typeDesc().expressionType)) {
|
|
57
|
-
this.
|
|
57
|
+
this.logError('order-by-analytic', `Illegal order by of analytic field ${this.field.refString}`);
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
const orderElement = { field: this.modelField };
|
|
@@ -55,7 +55,7 @@ class QOpDesc extends malloy_element_1.ListOf {
|
|
|
55
55
|
if (el.forceQueryClass) {
|
|
56
56
|
if (guessType) {
|
|
57
57
|
if (guessType !== el.forceQueryClass) {
|
|
58
|
-
el.
|
|
58
|
+
el.logError(`illegal-${guessType}-operation`, `Not legal in ${guessType} query`);
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
else {
|
|
@@ -65,7 +65,7 @@ class QOpDesc extends malloy_element_1.ListOf {
|
|
|
65
65
|
needsExplicitQueryClass || (needsExplicitQueryClass = (_a = el.needsExplicitQueryClass) !== null && _a !== void 0 ? _a : false);
|
|
66
66
|
}
|
|
67
67
|
if (guessType === undefined && needsExplicitQueryClass) {
|
|
68
|
-
this.
|
|
68
|
+
this.logError('ambiguous-view-type', {});
|
|
69
69
|
guessType = query_property_interface_1.QueryClass.Project;
|
|
70
70
|
}
|
|
71
71
|
this.opClass = guessType;
|
|
@@ -47,13 +47,13 @@ class Top extends malloy_element_1.MalloyElement {
|
|
|
47
47
|
const output = fs.outputSpace();
|
|
48
48
|
const entry = this.by.getField(output);
|
|
49
49
|
if (entry.error) {
|
|
50
|
-
this.by.
|
|
50
|
+
this.by.logError(entry.error.code, entry.error.message);
|
|
51
51
|
}
|
|
52
52
|
if (!entry.found || !entry.isOutputField) {
|
|
53
|
-
this.by.
|
|
53
|
+
this.by.logError('top-by-not-found-in-output', `Unknown field ${this.by.refString} in output space`);
|
|
54
54
|
}
|
|
55
55
|
if ((0, malloy_types_1.expressionIsAnalytic)((_a = entry.found) === null || _a === void 0 ? void 0 : _a.typeDesc().expressionType)) {
|
|
56
|
-
this.by.
|
|
56
|
+
this.by.logError('top-by-analytic', `Illegal order by of analytic field ${this.by.refString}`);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
return { by: 'name', name: this.by.refString };
|
|
@@ -61,10 +61,10 @@ class Top extends malloy_element_1.MalloyElement {
|
|
|
61
61
|
else {
|
|
62
62
|
const byExpr = this.by.getExpression(fs);
|
|
63
63
|
if ((0, malloy_types_1.expressionIsAggregate)(byExpr.expressionType)) {
|
|
64
|
-
this.by.
|
|
64
|
+
this.by.logError('top-by-aggregate', 'top by expression must not be an aggregate');
|
|
65
65
|
}
|
|
66
66
|
if (byExpr.evalSpace === 'output') {
|
|
67
|
-
this.by.
|
|
67
|
+
this.by.logError('top-by-not-in-output', 'top by expression must be an output expression');
|
|
68
68
|
}
|
|
69
69
|
return { by: 'expression', e: byExpr.value };
|
|
70
70
|
}
|
|
@@ -39,7 +39,7 @@ function detectAndRemovePartialStages(pipeline, logTo) {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
if (hasPartials) {
|
|
42
|
-
logTo.
|
|
42
|
+
logTo.logError('ambiguous-view-type', {});
|
|
43
43
|
}
|
|
44
44
|
return cleaned;
|
|
45
45
|
}
|
|
@@ -2,7 +2,7 @@ import { Argument, InvokedStructRef, StructDef } from '../../../model/malloy_typ
|
|
|
2
2
|
import { Source } from './source';
|
|
3
3
|
import { ModelEntryReference } from '../types/malloy-element';
|
|
4
4
|
import { Argument as HasArgument } from '../parameters/argument';
|
|
5
|
-
import {
|
|
5
|
+
import { LogMessageOptions, MessageCode, MessageParameterType } from '../../parse-log';
|
|
6
6
|
import { ParameterSpace } from '../field-space/parameter-space';
|
|
7
7
|
import { HasParameter } from '../parameters/has-parameter';
|
|
8
8
|
export declare class NamedSource extends Source {
|
|
@@ -13,7 +13,7 @@ export declare class NamedSource extends Source {
|
|
|
13
13
|
constructor(ref: ModelEntryReference | string, sourceArguments: Record<string, Argument> | undefined, args: HasArgument[] | undefined);
|
|
14
14
|
get refName(): string;
|
|
15
15
|
structRef(parameterSpace: ParameterSpace | undefined): InvokedStructRef;
|
|
16
|
-
|
|
16
|
+
refLogError<T extends MessageCode>(code: T, parameters: MessageParameterType<T>, options?: Omit<LogMessageOptions, 'severity'>): void;
|
|
17
17
|
modelStruct(): StructDef | undefined;
|
|
18
18
|
private evaluateArgumentsForRef;
|
|
19
19
|
private evaluateArguments;
|
|
@@ -61,12 +61,12 @@ class NamedSource extends source_1.Source {
|
|
|
61
61
|
sourceArguments: this.evaluateArgumentsForRef(parameterSpace),
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
|
-
|
|
64
|
+
refLogError(code, parameters, options) {
|
|
65
65
|
if (typeof this.ref === 'string') {
|
|
66
|
-
this.
|
|
66
|
+
this.logError(code, parameters, options);
|
|
67
67
|
}
|
|
68
68
|
else {
|
|
69
|
-
this.ref.
|
|
69
|
+
this.ref.logError(code, parameters, options);
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
modelStruct() {
|
|
@@ -74,24 +74,23 @@ class NamedSource extends source_1.Source {
|
|
|
74
74
|
const modelEnt = this.modelEntry(this.ref);
|
|
75
75
|
const entry = modelEnt === null || modelEnt === void 0 ? void 0 : modelEnt.entry;
|
|
76
76
|
if (!entry) {
|
|
77
|
-
|
|
78
|
-
(this.ref instanceof malloy_element_1.ModelEntryReference ? this.ref : this).log(undefMsg);
|
|
77
|
+
this.refLogError('source-not-found', `Undefined source '${this.refName}'`);
|
|
79
78
|
return;
|
|
80
79
|
}
|
|
81
80
|
if (entry.type === 'query') {
|
|
82
|
-
this.
|
|
81
|
+
this.logError('invalid-source-from-query', `Cannot construct a source from a query '${this.refName}'`);
|
|
83
82
|
return;
|
|
84
83
|
}
|
|
85
84
|
else if (entry.type === 'function') {
|
|
86
|
-
this.
|
|
85
|
+
this.logError('invalid-source-from-function', `Cannot construct a source from a function '${this.refName}'`);
|
|
87
86
|
return;
|
|
88
87
|
}
|
|
89
88
|
else if (entry.type === 'connection') {
|
|
90
|
-
this.
|
|
89
|
+
this.logError('invalid-source-from-connection', `Cannot construct a source from a connection '${this.refName}'`);
|
|
91
90
|
return;
|
|
92
91
|
}
|
|
93
92
|
else if ((0, malloy_types_1.isSQLBlockStruct)(entry) && entry.declaredSQLBlock) {
|
|
94
|
-
this.
|
|
93
|
+
this.logError('invalid-source-from-sql-block', `Must use 'from_sql()' for sql source '${this.refName}'`);
|
|
95
94
|
return;
|
|
96
95
|
}
|
|
97
96
|
else {
|
|
@@ -115,18 +114,18 @@ class NamedSource extends source_1.Source {
|
|
|
115
114
|
? argument.value.fieldReference
|
|
116
115
|
: undefined);
|
|
117
116
|
if (id === undefined) {
|
|
118
|
-
argument.value.
|
|
117
|
+
argument.value.logError('unnamed-source-argument', 'Parameterized source arguments must be named with `parameter_name is`');
|
|
119
118
|
continue;
|
|
120
119
|
}
|
|
121
120
|
const name = id.outputName;
|
|
122
121
|
if (passedNames.has(name)) {
|
|
123
|
-
argument.
|
|
122
|
+
argument.logError('duplicate-source-argument', `Cannot pass argument for \`${name}\` more than once`);
|
|
124
123
|
continue;
|
|
125
124
|
}
|
|
126
125
|
passedNames.add(name);
|
|
127
126
|
const parameter = (parametersIn !== null && parametersIn !== void 0 ? parametersIn : {})[name];
|
|
128
127
|
if (!parameter) {
|
|
129
|
-
id.
|
|
128
|
+
id.logError('source-parameter-not-found', `\`${this.refName}\` has no declared parameter named \`${id.refString}\``);
|
|
130
129
|
}
|
|
131
130
|
else {
|
|
132
131
|
const paramSpace = parameterSpace !== null && parameterSpace !== void 0 ? parameterSpace : new parameter_space_1.ParameterSpace(parametersOut !== null && parametersOut !== void 0 ? parametersOut : []);
|
|
@@ -147,7 +146,7 @@ class NamedSource extends source_1.Source {
|
|
|
147
146
|
outArguments[paramName] = { ...parametersIn[paramName] };
|
|
148
147
|
}
|
|
149
148
|
else {
|
|
150
|
-
this.
|
|
149
|
+
this.refLogError('missing-source-argument', `Argument not provided for required parameter \`${paramName}\``);
|
|
151
150
|
}
|
|
152
151
|
}
|
|
153
152
|
}
|
|
@@ -64,15 +64,17 @@ class RefinedSource extends source_1.Source {
|
|
|
64
64
|
const errTo = el;
|
|
65
65
|
if (el instanceof primary_key_1.PrimaryKey) {
|
|
66
66
|
if (primaryKey) {
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
const code = 'multiple-primary-keys';
|
|
68
|
+
primaryKey.logError(code, 'Primary key already defined');
|
|
69
|
+
el.logError(code, 'Primary key redefined');
|
|
69
70
|
}
|
|
70
71
|
primaryKey = el;
|
|
71
72
|
}
|
|
72
73
|
else if (el instanceof field_list_edit_1.FieldListEdit) {
|
|
73
74
|
if (fieldListEdit) {
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
const code = 'multiple-field-list-edits';
|
|
76
|
+
fieldListEdit.logError(code, 'Too many accept/except statements');
|
|
77
|
+
el.logError(code, 'Too many accept/except statements');
|
|
76
78
|
}
|
|
77
79
|
fieldListEdit = el;
|
|
78
80
|
}
|
|
@@ -89,7 +91,7 @@ class RefinedSource extends source_1.Source {
|
|
|
89
91
|
newTimezone = el.tz;
|
|
90
92
|
}
|
|
91
93
|
else {
|
|
92
|
-
errTo.
|
|
94
|
+
errTo.logError('unexpected-source-property', `Unexpected source property: '${errTo.elementType}'`);
|
|
93
95
|
}
|
|
94
96
|
}
|
|
95
97
|
const paramSpace = pList ? new parameter_space_1.ParameterSpace(pList) : undefined;
|
|
@@ -111,7 +113,7 @@ class RefinedSource extends source_1.Source {
|
|
|
111
113
|
if (primaryKey) {
|
|
112
114
|
const keyDef = primaryKey.field.getField(fs);
|
|
113
115
|
if (keyDef.error) {
|
|
114
|
-
primaryKey.
|
|
116
|
+
primaryKey.logError(keyDef.error.code, keyDef.error.message);
|
|
115
117
|
}
|
|
116
118
|
}
|
|
117
119
|
const retStruct = fs.structDef();
|
|
@@ -121,7 +123,7 @@ class RefinedSource extends source_1.Source {
|
|
|
121
123
|
for (const el of filter.list) {
|
|
122
124
|
const fc = el.filterCondition(fs);
|
|
123
125
|
if ((0, malloy_types_1.expressionIsCalculation)(fc.expressionType)) {
|
|
124
|
-
el.
|
|
126
|
+
el.logError('aggregate-in-source-filter', "Can't use aggregate computations in top level filters");
|
|
125
127
|
}
|
|
126
128
|
else {
|
|
127
129
|
filterList.push(fc);
|
|
@@ -55,7 +55,7 @@ class SQLSource extends source_1.Source {
|
|
|
55
55
|
(_a = this.namespace()) === null || _a === void 0 ? void 0 : _a.setEntry(name, { entry: { type: 'connection', name }, exported: true }, true);
|
|
56
56
|
}
|
|
57
57
|
else if (connection.entry.type !== 'connection') {
|
|
58
|
-
this.connectionName.
|
|
58
|
+
this.connectionName.logError('invalid-connection-for-sql-source', `${this.connectionName.refString} is not a connection`);
|
|
59
59
|
this.connectionNameInvalid = true;
|
|
60
60
|
return false;
|
|
61
61
|
}
|
|
@@ -72,7 +72,7 @@ class SQLSource extends source_1.Source {
|
|
|
72
72
|
const sql = this.sqlBlock();
|
|
73
73
|
const sqlDefEntry = (_a = this.translator()) === null || _a === void 0 ? void 0 : _a.root.sqlQueryZone;
|
|
74
74
|
if (!sqlDefEntry) {
|
|
75
|
-
this.
|
|
75
|
+
this.logError('failed-to-fetch-sql-source-schema', "Cant't look up schema for sql block");
|
|
76
76
|
return;
|
|
77
77
|
}
|
|
78
78
|
sqlDefEntry.reference(sql.name, this.location);
|
|
@@ -94,7 +94,7 @@ class SQLSource extends source_1.Source {
|
|
|
94
94
|
}
|
|
95
95
|
const sqlDefEntry = (_a = this.translator()) === null || _a === void 0 ? void 0 : _a.root.sqlQueryZone;
|
|
96
96
|
if (!sqlDefEntry) {
|
|
97
|
-
this.
|
|
97
|
+
this.logError('failed-to-fetch-sql-source-schema', "Cant't look up schema for sql block");
|
|
98
98
|
return error_factory_1.ErrorFactory.structDef;
|
|
99
99
|
}
|
|
100
100
|
const sql = this.sqlBlock();
|
|
@@ -102,7 +102,7 @@ class SQLSource extends source_1.Source {
|
|
|
102
102
|
const lookup = sqlDefEntry.getEntry(sql.name);
|
|
103
103
|
if (lookup.status === 'error') {
|
|
104
104
|
const msgLines = lookup.message.split(/\r?\n/);
|
|
105
|
-
this.select.
|
|
105
|
+
this.select.logError('invalid-sql-source', 'Invalid SQL, ' + msgLines.join('\n '));
|
|
106
106
|
return error_factory_1.ErrorFactory.structDef;
|
|
107
107
|
}
|
|
108
108
|
else if (lookup.status === 'present') {
|
|
@@ -120,7 +120,7 @@ class SQLSource extends source_1.Source {
|
|
|
120
120
|
return locStruct;
|
|
121
121
|
}
|
|
122
122
|
else {
|
|
123
|
-
this.
|
|
123
|
+
this.logError('non-top-level-sql-source', '`connection_name.sql(...)` can currently only be used in top level source/query definitions');
|
|
124
124
|
return error_factory_1.ErrorFactory.structDef;
|
|
125
125
|
}
|
|
126
126
|
}
|
|
@@ -59,7 +59,7 @@ class TableSource extends source_1.Source {
|
|
|
59
59
|
msg = tableDefEntry.message;
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
-
this.
|
|
62
|
+
this.logError('failed-to-fetch-table-schema', msg);
|
|
63
63
|
return error_factory_1.ErrorFactory.structDef;
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -80,7 +80,7 @@ class TableMethodSource extends TableSource {
|
|
|
80
80
|
(_a = this.namespace()) === null || _a === void 0 ? void 0 : _a.setEntry(name, { entry: { type: 'connection', name }, exported: true }, true);
|
|
81
81
|
}
|
|
82
82
|
else if (connection.entry.type !== 'connection') {
|
|
83
|
-
this.connectionName.
|
|
83
|
+
this.connectionName.logError('invalid-connection-for-table-source', `${this.connectionName.refString} is not a connection`);
|
|
84
84
|
return undefined;
|
|
85
85
|
}
|
|
86
86
|
return {
|
|
@@ -42,7 +42,7 @@ class Join extends malloy_element_1.MalloyElement {
|
|
|
42
42
|
getStructDefFromExpr(parameterSpace) {
|
|
43
43
|
const source = this.sourceExpr.getSource();
|
|
44
44
|
if (!source) {
|
|
45
|
-
this.sourceExpr.sqLog('Cannot
|
|
45
|
+
this.sourceExpr.sqLog('invalid-join-source', 'Cannot create a source to join from');
|
|
46
46
|
return error_factory_1.ErrorFactory.structDef;
|
|
47
47
|
}
|
|
48
48
|
return source.structDef(parameterSpace);
|
|
@@ -105,15 +105,15 @@ class KeyJoin extends Join {
|
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
107
107
|
else {
|
|
108
|
-
this.
|
|
108
|
+
this.logError('join-on-primary-key-type-mismatch', `join_one: with type mismatch with primary key: ${exprX.dataType}/${pkey.type}`);
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
else {
|
|
112
|
-
this.
|
|
112
|
+
this.logError('join-primary-key-not-found', `join_one: Primary key '${pkey}' not found in source`);
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
else {
|
|
116
|
-
this.
|
|
116
|
+
this.logError('join-with-without-primary-key', 'join_one: Cannot use with unless source has a primary key');
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
}
|
|
@@ -140,7 +140,7 @@ class ExpressionJoin extends Join {
|
|
|
140
140
|
}
|
|
141
141
|
const exprX = this.expr.getExpression(outer);
|
|
142
142
|
if (exprX.dataType !== 'boolean') {
|
|
143
|
-
this.
|
|
143
|
+
this.logError('non-boolean-join-on', 'join conditions must be boolean expressions');
|
|
144
144
|
return;
|
|
145
145
|
}
|
|
146
146
|
const joinRel = inStruct.structRelationship;
|
|
@@ -152,7 +152,7 @@ class ExpressionJoin extends Join {
|
|
|
152
152
|
var _a;
|
|
153
153
|
const source = this.sourceExpr.getSource();
|
|
154
154
|
if (!source) {
|
|
155
|
-
this.sourceExpr.sqLog('Cannot create a source to join from');
|
|
155
|
+
this.sourceExpr.sqLog('invalid-join-source', 'Cannot create a source to join from');
|
|
156
156
|
return error_factory_1.ErrorFactory.structDef;
|
|
157
157
|
}
|
|
158
158
|
const sourceDef = source.structDef(parameterSpace);
|
|
@@ -36,7 +36,7 @@ class RenameField extends malloy_element_1.MalloyElement {
|
|
|
36
36
|
}
|
|
37
37
|
makeEntry(fs) {
|
|
38
38
|
if (this.oldName.refString === this.newName) {
|
|
39
|
-
this.
|
|
39
|
+
this.logError('invalid-rename-with-same-name', "Can't rename field to itself");
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
42
|
const oldValue = this.oldName.getField(fs);
|
|
@@ -45,11 +45,11 @@ class RenameField extends malloy_element_1.MalloyElement {
|
|
|
45
45
|
fs.renameEntry(this.oldName.refString, this.newName, new rename_space_field_1.RenameSpaceField(oldValue.found, this.newName, this.location));
|
|
46
46
|
}
|
|
47
47
|
else {
|
|
48
|
-
this.
|
|
48
|
+
this.logError('failed-rename', `'${this.oldName}' cannot be renamed`);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
else {
|
|
52
|
-
this.
|
|
52
|
+
this.logError('rename-field-not-found', `Can't rename '${this.oldName}', no such field`);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { QueryElement } from '../types/query-element';
|
|
2
2
|
import { MalloyElement } from '../types/malloy-element';
|
|
3
3
|
import { Source } from '../source-elements/source';
|
|
4
|
+
import { LogMessageOptions, MessageCode, MessageParameterType } from '../../parse-log';
|
|
4
5
|
/**
|
|
5
6
|
* An AST element which can be treated as either a source or a query
|
|
6
7
|
* depending on context. For instance, an `SQReference` represents
|
|
@@ -12,6 +13,6 @@ export declare abstract class SourceQueryElement extends MalloyElement {
|
|
|
12
13
|
getSource(): Source | undefined;
|
|
13
14
|
getQuery(): QueryElement | undefined;
|
|
14
15
|
isSource(): boolean;
|
|
15
|
-
sqLog(
|
|
16
|
+
sqLog<T extends MessageCode>(code: T, parameters: MessageParameterType<T>, options?: LogMessageOptions): T;
|
|
16
17
|
isErrorFree(): boolean;
|
|
17
18
|
}
|
|
@@ -44,11 +44,12 @@ class SourceQueryElement extends malloy_element_1.MalloyElement {
|
|
|
44
44
|
isSource() {
|
|
45
45
|
return false;
|
|
46
46
|
}
|
|
47
|
-
sqLog(
|
|
47
|
+
sqLog(code, parameters, options) {
|
|
48
48
|
if (this.isErrorFree()) {
|
|
49
|
-
this.
|
|
49
|
+
this.logError(code, parameters, options);
|
|
50
50
|
}
|
|
51
51
|
this.errored = true;
|
|
52
|
+
return code;
|
|
52
53
|
}
|
|
53
54
|
isErrorFree() {
|
|
54
55
|
if (this.errored) {
|
|
@@ -48,7 +48,7 @@ class SQArrow extends source_query_element_1.SourceQueryElement {
|
|
|
48
48
|
? this.applyTo.getSource()
|
|
49
49
|
: this.applyTo.getQuery();
|
|
50
50
|
if (lhs === undefined) {
|
|
51
|
-
this.sqLog('Could not get LHS of arrow operation');
|
|
51
|
+
this.sqLog('failed-to-compute-arrow-source', 'Could not get LHS of arrow operation');
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
54
|
const arr = new query_arrow_1.QueryArrow(lhs, this.operation);
|
|
@@ -58,7 +58,7 @@ class SQArrow extends source_query_element_1.SourceQueryElement {
|
|
|
58
58
|
getSource() {
|
|
59
59
|
const query = this.getQuery();
|
|
60
60
|
if (!query) {
|
|
61
|
-
this.sqLog("Couldn't comprehend query well enough to make a source");
|
|
61
|
+
this.sqLog('failed-to-compute-source-from-query', "Couldn't comprehend query well enough to make a source");
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
64
|
const asSource = new query_source_1.QuerySource(query);
|
|
@@ -49,7 +49,7 @@ class SQExtend extends source_query_element_1.SourceQueryElement {
|
|
|
49
49
|
this.has({ asSource: this.asSource });
|
|
50
50
|
return this.asSource;
|
|
51
51
|
}
|
|
52
|
-
this.sqLog('Could not compute source to extend');
|
|
52
|
+
this.sqLog('failed-to-compute-source-to-extend', 'Could not compute source to extend');
|
|
53
53
|
}
|
|
54
54
|
isSource() {
|
|
55
55
|
return true;
|