@malloydata/malloy 0.0.394 → 0.0.396
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/api/foundation/compile.d.ts +7 -6
- package/dist/api/foundation/compile.js +22 -6
- package/dist/api/foundation/config.d.ts +2 -3
- package/dist/api/foundation/config.js +23 -11
- package/dist/api/foundation/core.js +1 -1
- package/dist/api/foundation/runtime.d.ts +85 -5
- package/dist/api/foundation/runtime.js +204 -14
- package/dist/api/foundation/types.d.ts +2 -0
- package/dist/api/util.js +4 -0
- package/dist/connection/base_connection.js +6 -0
- package/dist/connection/validate_table_path.d.ts +10 -0
- package/dist/connection/validate_table_path.js +56 -0
- package/dist/dialect/databricks/databricks.d.ts +4 -4
- package/dist/dialect/databricks/databricks.js +17 -22
- package/dist/dialect/dialect.d.ts +100 -4
- package/dist/dialect/dialect.js +145 -1
- package/dist/dialect/duckdb/duckdb.d.ts +2 -3
- package/dist/dialect/duckdb/duckdb.js +12 -14
- package/dist/dialect/duckdb/table-path-parser.d.ts +2 -0
- package/dist/dialect/duckdb/table-path-parser.js +57 -0
- package/dist/dialect/index.d.ts +2 -0
- package/dist/dialect/index.js +4 -1
- package/dist/dialect/mysql/mysql.d.ts +4 -4
- package/dist/dialect/mysql/mysql.js +25 -20
- package/dist/dialect/pg_impl.d.ts +3 -1
- package/dist/dialect/pg_impl.js +6 -3
- package/dist/dialect/postgres/postgres.d.ts +1 -3
- package/dist/dialect/postgres/postgres.js +8 -16
- package/dist/dialect/snowflake/snowflake.d.ts +4 -4
- package/dist/dialect/snowflake/snowflake.js +11 -27
- package/dist/dialect/standardsql/standardsql.d.ts +6 -4
- package/dist/dialect/standardsql/standardsql.js +36 -15
- package/dist/dialect/table-path.d.ts +54 -0
- package/dist/dialect/table-path.js +144 -0
- package/dist/dialect/trino/trino.d.ts +0 -3
- package/dist/dialect/trino/trino.js +7 -20
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -2
- 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.d.ts +1 -7
- package/dist/lang/ast/source-elements/table-source.js +24 -19
- 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/malloy-to-ast.d.ts +2 -1
- package/dist/lang/malloy-to-ast.js +11 -1
- package/dist/lang/parse-log.d.ts +2 -0
- package/dist/lang/parse-log.js +4 -0
- package/dist/lang/parse-malloy.d.ts +4 -1
- package/dist/lang/parse-malloy.js +63 -11
- package/dist/lang/parse-tree-walkers/find-external-references.d.ts +2 -15
- package/dist/lang/parse-tree-walkers/find-external-references.js +6 -23
- package/dist/lang/test/test-translator.d.ts +19 -5
- package/dist/lang/test/test-translator.js +15 -12
- package/dist/lang/translate-response.d.ts +1 -1
- 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/filter_compilers.js +1 -1
- 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 +2 -0
- package/dist/model/query_model_impl.js +9 -8
- package/dist/model/query_node.d.ts +5 -5
- package/dist/model/query_node.js +21 -16
- package/dist/model/query_query.js +60 -44
- package/dist/model/sql_compiled.d.ts +2 -4
- package/dist/model/sql_compiled.js +20 -18
- package/dist/test/test-models.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -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;
|
|
@@ -129,7 +129,7 @@ exports.FilterCompilers = {
|
|
|
129
129
|
// For some databases checking NULL combined with a boolean check
|
|
130
130
|
// is faster than a COALESCE, for now, just detect if the expression
|
|
131
131
|
// is just a column reference, and if so, don't use COALECSE.
|
|
132
|
-
const quoteChar = d.
|
|
132
|
+
const quoteChar = d.sqlQuoteIdentifier('select')[0];
|
|
133
133
|
const isColumn = x.match(`^[()${quoteChar}\\w.]+$`);
|
|
134
134
|
if (isColumn) {
|
|
135
135
|
if (bc.operator === 'true') {
|
|
@@ -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';
|
|
@@ -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 = {});
|
|
@@ -107,12 +108,12 @@ class QueryModelImpl {
|
|
|
107
108
|
const fieldNames = [];
|
|
108
109
|
for (const f of ret.outputStruct.fields) {
|
|
109
110
|
if ((0, malloy_types_1.isAtomic)(f)) {
|
|
110
|
-
const quoted = q.parent.dialect.
|
|
111
|
+
const quoted = q.parent.dialect.sqlQuoteIdentifier(f.name);
|
|
111
112
|
fieldNames.push(quoted);
|
|
112
113
|
}
|
|
113
114
|
}
|
|
114
115
|
// const fieldNames = getAtomicFields(ret.outputStruct).map(fieldDef =>
|
|
115
|
-
// q.parent.dialect.
|
|
116
|
+
// q.parent.dialect.sqlQuoteIdentifier(fieldDef.name)
|
|
116
117
|
// );
|
|
117
118
|
ret.lastStageName = stageWriter.addStage(q.parent.dialect.sqlFinalStage(ret.lastStageName, fieldNames));
|
|
118
119
|
}
|
|
@@ -217,11 +218,11 @@ class QueryModelImpl {
|
|
|
217
218
|
},
|
|
218
219
|
],
|
|
219
220
|
};
|
|
220
|
-
const fieldNameColumn = d.
|
|
221
|
-
const fieldPathColumn = d.
|
|
222
|
-
const fieldValueColumn = d.
|
|
223
|
-
const fieldTypeColumn = d.
|
|
224
|
-
const weightColumn = d.
|
|
221
|
+
const fieldNameColumn = d.sqlQuoteIdentifier('fieldName');
|
|
222
|
+
const fieldPathColumn = d.sqlQuoteIdentifier('fieldPath');
|
|
223
|
+
const fieldValueColumn = d.sqlQuoteIdentifier('fieldValue');
|
|
224
|
+
const fieldTypeColumn = d.sqlQuoteIdentifier('fieldType');
|
|
225
|
+
const weightColumn = d.sqlQuoteIdentifier('weight');
|
|
225
226
|
// if we've compiled the SQL before use it otherwise
|
|
226
227
|
let sqlPDT = this.exploreSearchSQLMap.get(explore);
|
|
227
228
|
if (sqlPDT === undefined) {
|
|
@@ -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");
|
|
@@ -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') {
|