@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.
Files changed (84) hide show
  1. package/dist/api/foundation/compile.d.ts +7 -6
  2. package/dist/api/foundation/compile.js +22 -6
  3. package/dist/api/foundation/config.d.ts +2 -3
  4. package/dist/api/foundation/config.js +23 -11
  5. package/dist/api/foundation/core.js +1 -1
  6. package/dist/api/foundation/runtime.d.ts +85 -5
  7. package/dist/api/foundation/runtime.js +204 -14
  8. package/dist/api/foundation/types.d.ts +2 -0
  9. package/dist/api/util.js +4 -0
  10. package/dist/connection/base_connection.js +6 -0
  11. package/dist/connection/validate_table_path.d.ts +10 -0
  12. package/dist/connection/validate_table_path.js +56 -0
  13. package/dist/dialect/databricks/databricks.d.ts +4 -4
  14. package/dist/dialect/databricks/databricks.js +17 -22
  15. package/dist/dialect/dialect.d.ts +100 -4
  16. package/dist/dialect/dialect.js +145 -1
  17. package/dist/dialect/duckdb/duckdb.d.ts +2 -3
  18. package/dist/dialect/duckdb/duckdb.js +12 -14
  19. package/dist/dialect/duckdb/table-path-parser.d.ts +2 -0
  20. package/dist/dialect/duckdb/table-path-parser.js +57 -0
  21. package/dist/dialect/index.d.ts +2 -0
  22. package/dist/dialect/index.js +4 -1
  23. package/dist/dialect/mysql/mysql.d.ts +4 -4
  24. package/dist/dialect/mysql/mysql.js +25 -20
  25. package/dist/dialect/pg_impl.d.ts +3 -1
  26. package/dist/dialect/pg_impl.js +6 -3
  27. package/dist/dialect/postgres/postgres.d.ts +1 -3
  28. package/dist/dialect/postgres/postgres.js +8 -16
  29. package/dist/dialect/snowflake/snowflake.d.ts +4 -4
  30. package/dist/dialect/snowflake/snowflake.js +11 -27
  31. package/dist/dialect/standardsql/standardsql.d.ts +6 -4
  32. package/dist/dialect/standardsql/standardsql.js +36 -15
  33. package/dist/dialect/table-path.d.ts +54 -0
  34. package/dist/dialect/table-path.js +144 -0
  35. package/dist/dialect/trino/trino.d.ts +0 -3
  36. package/dist/dialect/trino/trino.js +7 -20
  37. package/dist/index.d.ts +2 -2
  38. package/dist/index.js +4 -2
  39. package/dist/lang/ast/expressions/expr-func.js +30 -11
  40. package/dist/lang/ast/expressions/expr-given.js +1 -0
  41. package/dist/lang/ast/field-space/reference-field.js +1 -1
  42. package/dist/lang/ast/source-elements/sql-source.js +4 -0
  43. package/dist/lang/ast/source-elements/table-source.d.ts +1 -7
  44. package/dist/lang/ast/source-elements/table-source.js +24 -19
  45. package/dist/lang/ast/statements/define-given.d.ts +1 -0
  46. package/dist/lang/ast/statements/define-given.js +7 -0
  47. package/dist/lang/ast/statements/import-statement.js +4 -0
  48. package/dist/lang/ast/types/annotation-elements.d.ts +1 -0
  49. package/dist/lang/ast/types/annotation-elements.js +10 -3
  50. package/dist/lang/ast/types/malloy-element.d.ts +1 -0
  51. package/dist/lang/ast/types/malloy-element.js +4 -0
  52. package/dist/lang/malloy-to-ast.d.ts +2 -1
  53. package/dist/lang/malloy-to-ast.js +11 -1
  54. package/dist/lang/parse-log.d.ts +2 -0
  55. package/dist/lang/parse-log.js +4 -0
  56. package/dist/lang/parse-malloy.d.ts +4 -1
  57. package/dist/lang/parse-malloy.js +63 -11
  58. package/dist/lang/parse-tree-walkers/find-external-references.d.ts +2 -15
  59. package/dist/lang/parse-tree-walkers/find-external-references.js +6 -23
  60. package/dist/lang/test/test-translator.d.ts +19 -5
  61. package/dist/lang/test/test-translator.js +15 -12
  62. package/dist/lang/translate-response.d.ts +1 -1
  63. package/dist/lang/zone.d.ts +2 -0
  64. package/dist/lang/zone.js +10 -0
  65. package/dist/model/constant_expression_compiler.js +14 -5
  66. package/dist/model/expression_compiler.js +19 -17
  67. package/dist/model/field_instance.js +7 -3
  68. package/dist/model/filter_compilers.js +1 -1
  69. package/dist/model/given_binding.js +26 -21
  70. package/dist/model/index.d.ts +1 -0
  71. package/dist/model/index.js +3 -1
  72. package/dist/model/malloy_compile_error.d.ts +13 -0
  73. package/dist/model/malloy_compile_error.js +23 -0
  74. package/dist/model/malloy_types.d.ts +2 -0
  75. package/dist/model/query_model_impl.js +9 -8
  76. package/dist/model/query_node.d.ts +5 -5
  77. package/dist/model/query_node.js +21 -16
  78. package/dist/model/query_query.js +60 -44
  79. package/dist/model/sql_compiled.d.ts +2 -4
  80. package/dist/model/sql_compiled.js +20 -18
  81. package/dist/test/test-models.js +2 -2
  82. package/dist/version.d.ts +1 -1
  83. package/dist/version.js +1 -1
  84. 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 Error(`Redefinition of field ${field.fieldDef.name} as struct`);
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 Error(`Ambiguous output field name '${field.fieldDef.name}'.`);
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 Error(`${ungroupSet === null || ungroupSet === void 0 ? void 0 : ungroupSet.type}(): unknown field name "${fieldName}" or name not in scope.`);
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.sqlMaybeQuoteIdentifier('select')[0];
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 Error(`givens.${name}: explicit undefined is not a valid value. ` +
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 Error(`givens: unknown given '${name}'${hint}. Model surfaces [${surfaceNames.join(', ')}]`);
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
- throw new TypeError(`givens.${path}: expected string, got ${describeJs(value)}`);
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
- throw new TypeError(`givens.${path}: number must be finite, got ${value}`);
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
- throw new TypeError(`givens.${path}: number-as-string must be numeric, got '${value}'`);
111
+ bad(`number-as-string must be numeric, got '${value}'`);
107
112
  }
108
113
  lit = value;
109
114
  }
110
115
  else {
111
- throw new TypeError(`givens.${path}: expected number | bigint | string, got ${describeJs(value)}`);
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
- throw new TypeError(`givens.${path}: expected boolean, got ${describeJs(value)}`);
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
- throw new TypeError(`givens.${path}: expected ISO date string 'YYYY-MM-DD', got ${describeJs(value)}`);
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
- throw new TypeError(`givens.${path}: date must match 'YYYY-MM-DD', got '${value}'`);
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
- throw new TypeError(`givens.${path}: expected ISO timestamp string (no offset), got ${describeJs(value)}`);
141
+ bad(`expected ISO timestamp string (no offset), got ${describeJs(value)}`);
137
142
  }
138
143
  if (/Z$|[+-]\d{2}:?\d{2}$/.test(value)) {
139
- throw new TypeError(`givens.${path}: 'timestamp' is naive — use 'timestamptz' for offset/zoned values, got '${value}'`);
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
- throw new TypeError(`givens.${path}: invalid timestamp value '${value}': ${(_a = dt.invalidReason) !== null && _a !== void 0 ? _a : 'unknown'}`);
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
- throw new TypeError(`givens.${path}: expected JS Date or ISO timestamptz string, got ${describeJs(value)}`);
170
+ bad(`expected JS Date or ISO timestamptz string, got ${describeJs(value)}`);
166
171
  }
167
172
  if (!dt.isValid) {
168
- throw new TypeError(`givens.${path}: invalid timestamptz value '${value}': ${(_b = dt.invalidReason) !== null && _b !== void 0 ? _b : 'unknown'}`);
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
- throw new TypeError(`givens.${path}: filter<T> givens require a JS string of Malloy filter source, got ${describeJs(value)}`);
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
- throw new TypeError(`givens.${path}: expected array, got ${describeJs(value)}`);
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
- throw new TypeError(`givens.${path}: expected object, got ${describeJs(value)}`);
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 TypeError(`givens.${path}.${k}: unexpected key (not in record type [${[...declared].join(', ')}])`);
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 TypeError(`givens.${path}.${field.name}: missing required key`);
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 Error(`givens.${path}: type '${type.type}' is not bindable`);
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;
@@ -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';
@@ -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 Error(`Struct ${name} not found in model.`);
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.sqlMaybeQuoteIdentifier(f.name);
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.sqlMaybeQuoteIdentifier(fieldDef.name)
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.sqlMaybeQuoteIdentifier('fieldName');
221
- const fieldPathColumn = d.sqlMaybeQuoteIdentifier('fieldPath');
222
- const fieldValueColumn = d.sqlMaybeQuoteIdentifier('fieldValue');
223
- const fieldTypeColumn = d.sqlMaybeQuoteIdentifier('fieldType');
224
- const weightColumn = d.sqlMaybeQuoteIdentifier('weight');
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
  }
@@ -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 Error('Invalid parameter value');
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 Error(`Redefinition of ${as}`);
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 Error(`Missing primary key for ${fieldDef}`);
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 Error(`${notFound} not found${pathErr}`);
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 Error(`Cannot reference ${name.join('.')} as a scalar'`);
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 Error(`Error: Path to structure not found '${name.join('.')}'`);
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') {