@malloydata/malloy 0.0.391 → 0.0.393

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 (127) hide show
  1. package/dist/api/asynchronous.js +0 -3
  2. package/dist/api/foundation/compile.d.ts +1 -1
  3. package/dist/api/foundation/config.d.ts +80 -8
  4. package/dist/api/foundation/config.js +151 -69
  5. package/dist/api/foundation/config_compile.js +27 -35
  6. package/dist/api/foundation/config_discover.js +5 -9
  7. package/dist/api/foundation/config_overlays.d.ts +6 -0
  8. package/dist/api/foundation/config_overlays.js +12 -0
  9. package/dist/api/foundation/config_resolve.d.ts +4 -1
  10. package/dist/api/foundation/config_resolve.js +64 -4
  11. package/dist/api/foundation/core.d.ts +75 -2
  12. package/dist/api/foundation/core.js +104 -6
  13. package/dist/api/foundation/index.d.ts +2 -0
  14. package/dist/api/foundation/readers.js +1 -1
  15. package/dist/api/foundation/runtime.d.ts +68 -2
  16. package/dist/api/foundation/runtime.js +212 -10
  17. package/dist/api/foundation/types.d.ts +2 -1
  18. package/dist/index.d.ts +3 -1
  19. package/dist/lang/ast/ast-utils.js +0 -1
  20. package/dist/lang/ast/expressions/expr-aggregate-function.d.ts +1 -1
  21. package/dist/lang/ast/expressions/expr-aggregate-function.js +9 -8
  22. package/dist/lang/ast/expressions/expr-coalesce.d.ts +1 -1
  23. package/dist/lang/ast/expressions/expr-coalesce.js +2 -3
  24. package/dist/lang/ast/expressions/expr-count-distinct.js +1 -1
  25. package/dist/lang/ast/expressions/expr-count.js +6 -4
  26. package/dist/lang/ast/expressions/expr-filter-expr.js +0 -1
  27. package/dist/lang/ast/expressions/expr-func.js +9 -4
  28. package/dist/lang/ast/expressions/expr-given.d.ts +18 -0
  29. package/dist/lang/ast/expressions/expr-given.js +69 -0
  30. package/dist/lang/ast/expressions/expr-granular-time.d.ts +1 -1
  31. package/dist/lang/ast/expressions/expr-id-reference.js +3 -2
  32. package/dist/lang/ast/expressions/expr-now.js +0 -1
  33. package/dist/lang/ast/expressions/expr-props.d.ts +132 -132
  34. package/dist/lang/ast/expressions/expr-props.js +2 -2
  35. package/dist/lang/ast/expressions/expr-ungroup.d.ts +1 -1
  36. package/dist/lang/ast/expressions/expr-ungroup.js +4 -4
  37. package/dist/lang/ast/expressions/for-range.d.ts +1 -1
  38. package/dist/lang/ast/expressions/function-ordering.d.ts +1 -1
  39. package/dist/lang/ast/expressions/function-ordering.js +2 -2
  40. package/dist/lang/ast/expressions/time-literal.d.ts +3 -3
  41. package/dist/lang/ast/field-space/include-utils.js +2 -2
  42. package/dist/lang/ast/field-space/index-field-space.js +18 -23
  43. package/dist/lang/ast/field-space/passthrough-space.d.ts +1 -1
  44. package/dist/lang/ast/field-space/query-spaces.d.ts +6 -2
  45. package/dist/lang/ast/field-space/query-spaces.js +29 -19
  46. package/dist/lang/ast/field-space/reference-field.js +1 -1
  47. package/dist/lang/ast/field-space/rename-space-field.d.ts +1 -1
  48. package/dist/lang/ast/field-space/rename-space-field.js +2 -2
  49. package/dist/lang/ast/field-space/struct-space-field-base.js +2 -3
  50. package/dist/lang/ast/index.d.ts +2 -0
  51. package/dist/lang/ast/index.js +2 -0
  52. package/dist/lang/ast/query-builders/index-builder.d.ts +1 -1
  53. package/dist/lang/ast/query-builders/index-builder.js +4 -3
  54. package/dist/lang/ast/query-builders/reduce-builder.d.ts +2 -2
  55. package/dist/lang/ast/query-builders/reduce-builder.js +4 -5
  56. package/dist/lang/ast/query-elements/query-arrow.js +3 -2
  57. package/dist/lang/ast/query-elements/query-base.d.ts +1 -1
  58. package/dist/lang/ast/query-elements/query-base.js +1 -1
  59. package/dist/lang/ast/query-elements/query-refine.js +3 -1
  60. package/dist/lang/ast/query-items/field-declaration.js +2 -2
  61. package/dist/lang/ast/query-properties/drill.js +6 -6
  62. package/dist/lang/ast/query-properties/filters.js +2 -2
  63. package/dist/lang/ast/query-properties/nest.js +3 -3
  64. package/dist/lang/ast/source-elements/composite-source.js +5 -3
  65. package/dist/lang/ast/source-elements/named-source.js +4 -0
  66. package/dist/lang/ast/source-elements/sql-source.js +2 -2
  67. package/dist/lang/ast/source-elements/table-source.js +3 -1
  68. package/dist/lang/ast/source-properties/join.js +4 -4
  69. package/dist/lang/ast/source-query-elements/sq-reference.js +2 -1
  70. package/dist/lang/ast/statements/define-given.d.ts +23 -0
  71. package/dist/lang/ast/statements/define-given.js +163 -0
  72. package/dist/lang/ast/statements/import-statement.js +72 -9
  73. package/dist/lang/ast/typedesc-utils.d.ts +3 -1
  74. package/dist/lang/ast/typedesc-utils.js +4 -47
  75. package/dist/lang/ast/types/expr-value.js +2 -3
  76. package/dist/lang/ast/types/expression-def.d.ts +2 -2
  77. package/dist/lang/ast/types/expression-def.js +2 -2
  78. package/dist/lang/ast/types/malloy-element.d.ts +5 -15
  79. package/dist/lang/ast/types/malloy-element.js +113 -1
  80. package/dist/lang/ast/types/space-field.js +7 -9
  81. package/dist/lang/ast/view-elements/reference-view.js +6 -5
  82. package/dist/lang/ast/view-elements/refine-utils.js +1 -1
  83. package/dist/lang/composite-source-utils.d.ts +30 -15
  84. package/dist/lang/composite-source-utils.js +234 -64
  85. package/dist/lang/lib/Malloy/MalloyLexer.d.ts +171 -169
  86. package/dist/lang/lib/Malloy/MalloyLexer.js +1194 -1178
  87. package/dist/lang/lib/Malloy/MalloyParser.d.ts +408 -334
  88. package/dist/lang/lib/Malloy/MalloyParser.js +3062 -2561
  89. package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +68 -0
  90. package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +43 -0
  91. package/dist/lang/malloy-to-ast.d.ts +13 -1
  92. package/dist/lang/malloy-to-ast.js +90 -11
  93. package/dist/lang/parse-log.d.ts +8 -0
  94. package/dist/lang/prettify/filter-type.d.ts +3 -0
  95. package/dist/lang/prettify/filter-type.js +38 -0
  96. package/dist/lang/prettify/formatter.js +6 -0
  97. package/dist/lang/prettify/inline-renderer.js +20 -0
  98. package/dist/lang/prettify/rules.d.ts +1 -1
  99. package/dist/lang/prettify/rules.js +1 -0
  100. package/dist/lang/prettify/sections.js +2 -0
  101. package/dist/lang/prettify/tokens.js +2 -0
  102. package/dist/lang/test/expr-to-str.js +2 -0
  103. package/dist/lang/test/parse-expects.d.ts +1 -0
  104. package/dist/lang/test/parse-expects.js +27 -10
  105. package/dist/model/constant_expression_compiler.js +1 -0
  106. package/dist/model/expression_compiler.d.ts +2 -1
  107. package/dist/model/expression_compiler.js +41 -1
  108. package/dist/model/given_binding.d.ts +2 -0
  109. package/dist/model/given_binding.js +204 -0
  110. package/dist/model/index.d.ts +1 -1
  111. package/dist/model/index.js +2 -1
  112. package/dist/model/malloy_types.d.ts +163 -36
  113. package/dist/model/malloy_types.js +97 -0
  114. package/dist/model/query_model_contract.d.ts +2 -1
  115. package/dist/model/query_model_impl.d.ts +2 -1
  116. package/dist/model/query_model_impl.js +7 -0
  117. package/dist/model/query_node.d.ts +2 -1
  118. package/dist/model/source_def_utils.d.ts +2 -1
  119. package/dist/model/source_def_utils.js +4 -0
  120. package/dist/model/utils.d.ts +14 -1
  121. package/dist/model/utils.js +41 -0
  122. package/dist/to_stable.js +1 -1
  123. package/dist/util/closest_match.d.ts +9 -0
  124. package/dist/util/closest_match.js +47 -0
  125. package/dist/version.d.ts +1 -1
  126. package/dist/version.js +1 -1
  127. package/package.json +4 -4
@@ -0,0 +1,163 @@
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.DefineGivens = exports.GivenDeclaration = void 0;
8
+ const malloy_types_1 = require("../../../model/malloy_types");
9
+ const source_def_utils_1 = require("../../../model/source_def_utils");
10
+ const utils_1 = require("../../../model/utils");
11
+ const expression_def_1 = require("../types/expression-def");
12
+ const malloy_element_1 = require("../types/malloy-element");
13
+ const noteable_1 = require("../types/noteable");
14
+ // `filter<T>` defaults can't be type-checked via TD.eq — the filter
15
+ // expression value shape doesn't match an atomic typeDef. Catch only
16
+ // the gross kind mismatch here; inner-content validation (filter
17
+ // syntax + T compatibility) belongs to the filter machinery at use
18
+ // site.
19
+ function filterTypeMismatch(declared, constVal) {
20
+ return ((declared.type === 'filter expression') !==
21
+ (constVal.type === 'filter expression'));
22
+ }
23
+ class GivenDeclaration extends malloy_element_1.MalloyElement {
24
+ constructor(name, typeDef, defaultExpr) {
25
+ super();
26
+ this.name = name;
27
+ this.typeDef = typeDef;
28
+ this.elementType = 'given';
29
+ this.isNoteableObj = true;
30
+ this.extendNote = noteable_1.extendNoteMethod;
31
+ if (defaultExpr) {
32
+ this.default = defaultExpr;
33
+ this.has({ default: defaultExpr });
34
+ }
35
+ }
36
+ varInfo() {
37
+ return ` ${this.name} :: ${(0, utils_1.typeDefToString)(this.typeDef)}`;
38
+ }
39
+ execute(doc) {
40
+ var _a, _b, _c, _d, _e;
41
+ if (this.typeDef.type === 'error')
42
+ return;
43
+ if (doc.modelEntry(this.name)) {
44
+ this.logError('given-definition-name-conflict', `Cannot redefine '${this.name}'`);
45
+ return;
46
+ }
47
+ // Default expression. ConstantExpression evaluates through a
48
+ // ConstantFieldSpace that errors on every name lookup, so any
49
+ // non-constant subexpression (field refs, aggregates, etc.) gets
50
+ // logged here. `$NAME` references bypass that field space (see
51
+ // GivenReference.getExpression) so given-to-given refs in defaults
52
+ // are allowed.
53
+ let defaultExpr;
54
+ let givenUsage;
55
+ if (this.default) {
56
+ const constVal = this.default.constantValue();
57
+ if (constVal.type !== 'error') {
58
+ // `X :: timestamp is @2024-01-01` works because date literals
59
+ // carry a morphic.timestamp. Date/timestamp are the only
60
+ // MorphicType targets — other declared types fall through to
61
+ // the TD.eq check below.
62
+ const morphed = this.typeDef.type === 'date' || this.typeDef.type === 'timestamp'
63
+ ? (0, expression_def_1.getMorphicValue)(constVal, this.typeDef.type)
64
+ : undefined;
65
+ // `filter<T>` defaults are filter-expression literals — their
66
+ // shape doesn't match an atomic typeDef, so type-check there is
67
+ // owned by the filter machinery, not us. `null` is implicitly
68
+ // accepted for any declared type.
69
+ if (constVal.type !== 'null' &&
70
+ morphed === undefined &&
71
+ (filterTypeMismatch(this.typeDef, constVal) ||
72
+ !malloy_types_1.TD.eq(this.typeDef, constVal))) {
73
+ const actual = malloy_types_1.TD.isAtomic(constVal)
74
+ ? (0, utils_1.typeDefToString)(constVal)
75
+ : constVal.type;
76
+ this.default.logError('parameter-default-does-not-match-declared-type', `Default value of type \`${actual}\` does not match declared type \`${(0, utils_1.typeDefToString)(this.typeDef)}\``);
77
+ }
78
+ else if (this.typeDef.type === 'filter expression' &&
79
+ constVal.type === 'filter expression') {
80
+ // We know T at the declaration site, so validate the filter
81
+ // literal here even though the filter machinery will check it
82
+ // again at use site. Catches bad filter syntax early.
83
+ (0, expression_def_1.checkFilterExpression)(this.default, this.typeDef.filterType, constVal.value);
84
+ }
85
+ defaultExpr = (_a = morphed === null || morphed === void 0 ? void 0 : morphed.value) !== null && _a !== void 0 ? _a : constVal.value;
86
+ // Build the transitive closure of givens reachable through this
87
+ // default's expression. We only include direct refs PLUS each
88
+ // referenced given's already-precomputed transitive (which is
89
+ // present because Malloy requires `$X` to resolve to a given
90
+ // declared earlier or imported). The satisfiability check then
91
+ // becomes a flat iteration — no recursion at check time.
92
+ //
93
+ // For `A :: number is $B + 1` where `B :: number is $C`:
94
+ // - B's givenUsage was computed when B was declared = [C]
95
+ // - A's givenUsage = [B] ∪ B.givenUsage = [B, C]
96
+ const directRefs = (0, malloy_types_1.givenUsageFrom)(constVal.refSummary);
97
+ if (directRefs.length > 0) {
98
+ const seen = new Set();
99
+ const closure = [];
100
+ for (const g of directRefs) {
101
+ if (seen.has(g.id))
102
+ continue;
103
+ seen.add(g.id);
104
+ closure.push(g);
105
+ const refDecl = doc.documentGivens.get(g.id);
106
+ for (const t of (_b = refDecl === null || refDecl === void 0 ? void 0 : refDecl.givenUsage) !== null && _b !== void 0 ? _b : []) {
107
+ if (seen.has(t.id))
108
+ continue;
109
+ seen.add(t.id);
110
+ closure.push(t);
111
+ }
112
+ }
113
+ givenUsage = closure;
114
+ }
115
+ }
116
+ }
117
+ const id = (0, source_def_utils_1.mkGivenID)(this.name, (_c = this.location) === null || _c === void 0 ? void 0 : _c.url);
118
+ const defaultText = defaultExpr !== undefined ? (_d = this.default) === null || _d === void 0 ? void 0 : _d.code : undefined;
119
+ const givenIR = {
120
+ name: this.name,
121
+ type: this.typeDef,
122
+ default: defaultExpr,
123
+ defaultText,
124
+ givenUsage,
125
+ location: this.location,
126
+ annotation: this.note,
127
+ };
128
+ doc.documentGivens.set(id, givenIR);
129
+ const entry = { type: 'given', name: this.name, id };
130
+ doc.setEntry(this.name, { entry, exported: true });
131
+ // Declaration-site reference. `location` covers the whole
132
+ // declaration; `definition.location` points at the same place.
133
+ // Self-referential by design — parallel to how fieldReference
134
+ // behaves on field declarations.
135
+ this.addReference({
136
+ type: 'givenReference',
137
+ text: this.name,
138
+ location: (_e = this.location) !== null && _e !== void 0 ? _e : {
139
+ url: '',
140
+ range: {
141
+ start: { line: 0, character: 0 },
142
+ end: { line: 0, character: 0 },
143
+ },
144
+ },
145
+ definition: {
146
+ type: (0, utils_1.typeDefToString)(this.typeDef),
147
+ annotation: this.note,
148
+ location: this.location,
149
+ defaultText,
150
+ },
151
+ });
152
+ }
153
+ }
154
+ exports.GivenDeclaration = GivenDeclaration;
155
+ class DefineGivens extends malloy_element_1.DocStatementList {
156
+ constructor(givens) {
157
+ super(givens);
158
+ this.elementType = 'defineGivens';
159
+ this.givens = givens;
160
+ }
161
+ }
162
+ exports.DefineGivens = DefineGivens;
163
+ //# sourceMappingURL=define-given.js.map
@@ -27,6 +27,7 @@ const malloy_element_1 = require("../types/malloy-element");
27
27
  const malloy_types_1 = require("../../../model/malloy_types");
28
28
  const source_def_utils_1 = require("../../../model/source_def_utils");
29
29
  const persist_utils_1 = require("../../../model/persist_utils");
30
+ const utils_1 = require("../../../model/utils");
30
31
  /** Walk BuildNode tree and collect all sourceIDs */
31
32
  function collectSourceIDs(nodes, into) {
32
33
  for (const node of nodes) {
@@ -87,6 +88,7 @@ class ImportStatement extends malloy_element_1.ListOf {
87
88
  return undefined;
88
89
  }
89
90
  execute(doc) {
91
+ var _a;
90
92
  const trans = this.translator();
91
93
  if (!trans) {
92
94
  this.logError('no-translator-for-import', 'Cannot import without translation context');
@@ -98,7 +100,10 @@ class ImportStatement extends malloy_element_1.ListOf {
98
100
  const importedModel = trans.importModelDef(this.fullURL);
99
101
  if (importedModel) {
100
102
  const importAll = this.empty();
101
- const explicitImport = {};
103
+ // `Map` rather than plain object — keys are user-provided names and
104
+ // a plain object would expose Object.prototype keys (`toString`,
105
+ // etc.).
106
+ const explicitImport = new Map();
102
107
  for (const importOne of this.list) {
103
108
  const dstName = importOne.text;
104
109
  const srcName = importOne.from ? importOne.from.text : dstName;
@@ -109,20 +114,64 @@ class ImportStatement extends malloy_element_1.ListOf {
109
114
  importOne.logError('name-conflict-on-selective-import', `Cannot redefine '${dstName}'`);
110
115
  }
111
116
  else {
112
- if (explicitImport[srcName] === undefined) {
113
- explicitImport[srcName] = [];
117
+ const existing = explicitImport.get(srcName);
118
+ if (existing) {
119
+ existing.push(dstName);
120
+ }
121
+ else {
122
+ explicitImport.set(srcName, [dstName]);
114
123
  }
115
- explicitImport[srcName].push(dstName);
116
124
  }
117
125
  }
118
126
  const neededSourceIDs = new Set();
119
127
  for (const srcName of importedModel.exports) {
120
- const pickedNames = explicitImport[srcName];
121
- const dstNames = pickedNames || (importAll ? [srcName] : []);
128
+ const pickedNames = explicitImport.get(srcName);
129
+ const dstNames = pickedNames !== null && pickedNames !== void 0 ? pickedNames : (importAll ? [srcName] : []);
122
130
  for (const dstName of dstNames) {
123
- const importMe = {
124
- ...(0, malloy_types_1.safeRecordGet)(importedModel.contents, srcName),
125
- };
131
+ const sourceEntry = (0, malloy_types_1.safeRecordGet)(importedModel.contents, srcName);
132
+ // Non-selective collision: an entry would shadow something
133
+ // already in the importer's namespace (a local declaration or
134
+ // an entry brought in by a previous import). Selective
135
+ // collisions are caught by the per-item check at the top of
136
+ // the loop; here we re-check because the auto-surface path
137
+ // bypasses that loop. Applies to every entry kind.
138
+ if (!pickedNames && doc.getEntry(dstName)) {
139
+ this.logError('name-conflict-on-indiscriminate-import', `Cannot redefine '${dstName}'`);
140
+ continue;
141
+ }
142
+ if ((sourceEntry === null || sourceEntry === void 0 ? void 0 : sourceEntry.type) === 'given') {
143
+ const givenEntry = {
144
+ type: 'given',
145
+ name: dstName,
146
+ id: sourceEntry.id,
147
+ };
148
+ doc.setEntry(dstName, { entry: givenEntry, exported: false });
149
+ // Selective import-site reference. `location` covers
150
+ // the `NAME` token in the selective list;
151
+ // `definition.location` points at the canonical
152
+ // `given:` declaration in the imported file. Only
153
+ // emitted on the selective form — non-selective
154
+ // auto-surface has no per-name source position.
155
+ if (pickedNames) {
156
+ const givenIR = (_a = importedModel.givens) === null || _a === void 0 ? void 0 : _a[sourceEntry.id];
157
+ const importOne = this.list.find(item => item.text === dstName);
158
+ if (importOne && givenIR) {
159
+ this.addReference({
160
+ type: 'givenReference',
161
+ text: dstName,
162
+ location: importOne.location,
163
+ definition: {
164
+ type: (0, utils_1.typeDefToString)(givenIR.type),
165
+ annotation: givenIR.annotation,
166
+ location: givenIR.location,
167
+ defaultText: givenIR.defaultText,
168
+ },
169
+ });
170
+ }
171
+ }
172
+ continue;
173
+ }
174
+ const importMe = { ...sourceEntry };
126
175
  importMe.as = dstName;
127
176
  doc.setEntry(dstName, { entry: importMe, exported: false });
128
177
  // Collect dependencies for persistable sources
@@ -132,6 +181,20 @@ class ImportStatement extends malloy_element_1.ListOf {
132
181
  }
133
182
  }
134
183
  }
184
+ // Always copy the imported model's given declarations into the
185
+ // local givens map, regardless of whether each given is surfaced
186
+ // into the namespace. This guarantees that any givenRef in
187
+ // imported IR (sources/queries that reference `$X`) resolves to
188
+ // a declaration at SQL-emission time. The import-time
189
+ // satisfiability check that catches unsatisfiable refs lands
190
+ // with the refSummary work.
191
+ if (importedModel.givens) {
192
+ for (const [id, given] of Object.entries(importedModel.givens)) {
193
+ if (!doc.documentGivens.has(id)) {
194
+ doc.documentGivens.set(id, given);
195
+ }
196
+ }
197
+ }
135
198
  // Register hidden dependencies from child's registry
136
199
  for (const sourceID of neededSourceIDs) {
137
200
  if (!(sourceID in doc.documentSrcRegistry)) {
@@ -43,7 +43,9 @@ export declare function typeEq(left: TypeDesc, right: TypeDesc, nullOk?: boolean
43
43
  export declare function inspect(...types: (TypeDesc | undefined)[]): string;
44
44
  /**
45
45
  * Used when using a TypeDesc or TypeDesc-like interface to
46
- * create a field, don't copy the non type fields.
46
+ * create a field, don't copy the non type fields. Thin wrapper over
47
+ * `TD.atomicDef`; exists in `lang/` so callers can pass a `TypeDesc`
48
+ * (translator-side) without leaking that type into the model layer.
47
49
  */
48
50
  export declare function atomicDef(td: AtomicTypeDef | TypeDesc): AtomicTypeDef;
49
51
  export declare function parameterTypeDesc(p: Parameter, evalSpace: EvalSpace): TypeDesc;
@@ -40,7 +40,6 @@ dataType, expressionType = 'scalar', evalSpace = 'constant') {
40
40
  type: dataType,
41
41
  expressionType,
42
42
  evalSpace,
43
- fieldUsage: [],
44
43
  };
45
44
  }
46
45
  exports.nullT = mkTypeDesc('null');
@@ -120,53 +119,12 @@ function inspect(...types) {
120
119
  }
121
120
  /**
122
121
  * Used when using a TypeDesc or TypeDesc-like interface to
123
- * create a field, don't copy the non type fields.
122
+ * create a field, don't copy the non type fields. Thin wrapper over
123
+ * `TD.atomicDef`; exists in `lang/` so callers can pass a `TypeDesc`
124
+ * (translator-side) without leaking that type into the model layer.
124
125
  */
125
126
  function atomicDef(td) {
126
- if (model_1.TD.isAtomic(td)) {
127
- switch (td.type) {
128
- case 'array': {
129
- return (0, model_1.isRepeatedRecord)(td)
130
- ? {
131
- type: 'array',
132
- elementTypeDef: td.elementTypeDef,
133
- fields: td.fields,
134
- }
135
- : {
136
- type: 'array',
137
- elementTypeDef: td.elementTypeDef,
138
- };
139
- }
140
- case 'record': {
141
- return { type: 'record', fields: td.fields };
142
- }
143
- case 'number': {
144
- return td.numberType
145
- ? { type: 'number', numberType: td.numberType }
146
- : { type: 'number' };
147
- }
148
- case 'sql native': {
149
- return td.rawType
150
- ? { type: 'sql native', rawType: td.rawType }
151
- : { type: 'sql native' };
152
- }
153
- case 'timestamp': {
154
- return {
155
- type: 'timestamp',
156
- ...(td.timeframe === undefined ? {} : { timeframe: td.timeframe }),
157
- };
158
- }
159
- case 'timestamptz': {
160
- return {
161
- type: 'timestamptz',
162
- ...(td.timeframe === undefined ? {} : { timeframe: td.timeframe }),
163
- };
164
- }
165
- default:
166
- return { type: td.type };
167
- }
168
- }
169
- return { type: 'error' };
127
+ return model_1.TD.atomicDef(td);
170
128
  }
171
129
  function parameterTypeDesc(p, evalSpace) {
172
130
  const t = p.type;
@@ -177,7 +135,6 @@ function parameterTypeDesc(p, evalSpace) {
177
135
  ...theType,
178
136
  expressionType: 'scalar',
179
137
  evalSpace,
180
- fieldUsage: [],
181
138
  };
182
139
  }
183
140
  //# sourceMappingURL=typedesc-utils.js.map
@@ -37,7 +37,7 @@ function computedExprValue({ value, dataType, from, }) {
37
37
  value,
38
38
  expressionType: (0, model_1.maxOfExpressionTypes)(from.map(e => e.expressionType)),
39
39
  evalSpace: (0, model_1.mergeEvalSpaces)(...from.map(e => e.evalSpace)),
40
- fieldUsage: (0, composite_source_utils_1.mergeFieldUsage)(...from.map(e => e.fieldUsage)),
40
+ refSummary: (0, composite_source_utils_1.mergeRefSummaries)(...from.map(e => e.refSummary)),
41
41
  ungroupings: mergeUngroupings(...from.map(e => e.ungroupings)),
42
42
  requiresGroupBy: mergeGroupedBys(...from.map(e => e.requiresGroupBy)),
43
43
  };
@@ -49,7 +49,7 @@ function computedTimeResult({ value, dataType, from, timeframe, }) {
49
49
  expressionType: xv.expressionType,
50
50
  evalSpace: xv.evalSpace,
51
51
  value: xv.value,
52
- fieldUsage: (0, composite_source_utils_1.mergeFieldUsage)(...from.map(e => e.fieldUsage)),
52
+ refSummary: (0, composite_source_utils_1.mergeRefSummaries)(...from.map(e => e.refSummary)),
53
53
  ungroupings: mergeUngroupings(...from.map(e => e.ungroupings)),
54
54
  requiresGroupBy: mergeGroupedBys(...from.map(e => e.requiresGroupBy)),
55
55
  };
@@ -76,7 +76,6 @@ function literalTimeResult({ value, dataType, timeframe, }) {
76
76
  expressionType: xv.expressionType,
77
77
  evalSpace: xv.evalSpace,
78
78
  value: xv.value,
79
- fieldUsage: [],
80
79
  };
81
80
  if (timeframe) {
82
81
  y.timeframe = timeframe;
@@ -27,7 +27,7 @@ export declare abstract class ExpressionDef extends MalloyElement {
27
27
  * @param space Namespace for looking up field references
28
28
  */
29
29
  abstract getExpression(fs: FieldSpace): ExprValue;
30
- legalChildTypes: import("../../../model/malloy_types").TypeDesc[];
30
+ legalChildTypes: import("../../..").TypeDesc[];
31
31
  /**
32
32
  * Some operators want to give the right hand value a chance to
33
33
  * rewrite itself. This requests a translation for a rewrite,
@@ -66,7 +66,7 @@ export declare class ExprDuration extends ExpressionDef {
66
66
  readonly n: ExpressionDef;
67
67
  readonly timeframe: TimestampUnit;
68
68
  elementType: string;
69
- legalChildTypes: import("../../../model/malloy_types").TypeDesc[];
69
+ legalChildTypes: import("../../..").TypeDesc[];
70
70
  constructor(n: ExpressionDef, timeframe: TimestampUnit);
71
71
  apply(fs: FieldSpace, op: BinaryMalloyOperator, left: ExpressionDef): ExprValue;
72
72
  getExpression(fs: FieldSpace): ExprValue;
@@ -296,8 +296,8 @@ function equality(fs, left, op, right) {
296
296
  while (actualFilter.node === '()') {
297
297
  actualFilter = actualFilter.e;
298
298
  }
299
- if (actualFilter.node !== 'parameter') {
300
- // Parameters are checked when parameter value is parsed
299
+ if (actualFilter.node !== 'parameter' && actualFilter.node !== 'given') {
300
+ // Parameter and given values are checked when supplied
301
301
  checkFilterExpression(right, lhs.type, actualFilter);
302
302
  }
303
303
  const filterMatch = {
@@ -1,4 +1,4 @@
1
- import type { Annotation, DocumentLocation, DocumentReference, ModelDef, ModelAnnotation, NamedModelObject, Query, SourceID, SourceRegistryValue, StructDef } from '../../../model/malloy_types';
1
+ import type { Annotation, DocumentLocation, DocumentReference, Given, ModelDef, ModelAnnotation, NamedModelObject, Query, SourceID, SourceRegistryValue, StructDef } from '../../../model/malloy_types';
2
2
  import { Tag } from '@malloydata/malloy-tag';
3
3
  import type { LogMessageOptions, MessageLogger, MessageParameterType, MessageCode } from '../../parse-log';
4
4
  import type { MalloyTranslation } from '../../parse-malloy';
@@ -55,7 +55,7 @@ export declare abstract class MalloyElement {
55
55
  toString(): string;
56
56
  private stringify;
57
57
  walk(): Generator<MalloyElement>;
58
- private varInfo;
58
+ protected varInfo(): string;
59
59
  protected internalError(msg: string): Error;
60
60
  needs(doc: Document): ModelDataRequest | undefined;
61
61
  inExperiment(experimentId: string, silent?: boolean): boolean;
@@ -104,24 +104,12 @@ export declare class DocStatementList extends ListOf<DocStatement | DocStatement
104
104
  noteCursor: number;
105
105
  executeList(doc: Document): ModelDataRequest;
106
106
  }
107
- /**
108
- * The Document class is a little weird because we might need to bounce back
109
- * to the requestor, which might be on the other side of a wire, to get
110
- * back some schema information. The intended translation of a Document
111
- * is to call initModelDef(), and then to call modelDataRequest() until it
112
- * returns undefined. At any time you can call modelDef to get the model
113
- * as it exists so far, but the translation is not complete until
114
- * modelDataRequest() returns undefined;
115
- *
116
- * TODO probably modelRequest should be the method and you call it
117
- * until it returns a model with no additional data needed ...
118
- * that can be tomorrow
119
- */
120
107
  export declare class Document extends MalloyElement implements NameSpace {
121
108
  elementType: string;
122
109
  globalNameSpace: NameSpace;
123
110
  documentModel: Map<string, ModelEntry>;
124
111
  documentSrcRegistry: Record<SourceID, SourceRegistryValue>;
112
+ documentGivens: Map<string, Given>;
125
113
  queryList: Query[];
126
114
  statements: DocStatementList;
127
115
  didInitModel: boolean;
@@ -133,6 +121,8 @@ export declare class Document extends MalloyElement implements NameSpace {
133
121
  compile(): DocumentCompileResult;
134
122
  private modelAnnotationTodoList;
135
123
  rememberToAddModelAnnotations(sd: StructDef): void;
124
+ private checkGivenAliasCollisions;
125
+ private checkQueryGivenSatisfiability;
136
126
  hasAnnotation(): boolean;
137
127
  currentModelAnnotation(): ModelAnnotation | undefined;
138
128
  modelDef(): ModelDef;
@@ -432,6 +432,20 @@ function annotationID(a) {
432
432
  * until it returns a model with no additional data needed ...
433
433
  * that can be tomorrow
434
434
  */
435
+ function unsatisfiedGivenMessage(label, decl, id) {
436
+ var _a, _b;
437
+ // We always have the GivenID; we may or may not have the declaration
438
+ // (we should — every given referenced should have been copied into
439
+ // documentGivens at import time — but defend against it being absent).
440
+ const surface = (_a = decl === null || decl === void 0 ? void 0 : decl.name) !== null && _a !== void 0 ? _a : id;
441
+ const where = ((_b = decl === null || decl === void 0 ? void 0 : decl.location) === null || _b === void 0 ? void 0 : _b.url)
442
+ ? ` (declared in ${decl.location.url})`
443
+ : '';
444
+ return (`${label} references given \`${surface}\`${where}, ` +
445
+ 'which is not surfaced in this model and has no default. ' +
446
+ `Either import it (e.g. \`import { ${surface} } from "..."\`) ` +
447
+ 'or supply a default at the declaration site.');
448
+ }
435
449
  class Document extends MalloyElement {
436
450
  constructor(statements) {
437
451
  super();
@@ -439,6 +453,7 @@ class Document extends MalloyElement {
439
453
  this.globalNameSpace = new global_name_space_1.GlobalNameSpace();
440
454
  this.documentModel = new Map();
441
455
  this.documentSrcRegistry = {};
456
+ this.documentGivens = new Map();
442
457
  this.queryList = [];
443
458
  this.didInitModel = false;
444
459
  this.modelWasModified = false;
@@ -455,6 +470,7 @@ class Document extends MalloyElement {
455
470
  }
456
471
  this.documentModel = new Map();
457
472
  this.documentSrcRegistry = {};
473
+ this.documentGivens = new Map();
458
474
  this.queryList = [];
459
475
  if (extendingModelDef) {
460
476
  if (extendingModelDef.annotation) {
@@ -465,11 +481,17 @@ class Document extends MalloyElement {
465
481
  if ((0, malloy_types_1.isSourceDef)(entry) ||
466
482
  entry.type === 'query' ||
467
483
  entry.type === 'function' ||
468
- entry.type === 'userType') {
484
+ entry.type === 'userType' ||
485
+ entry.type === 'given') {
469
486
  const exported = extendingModelDef.exports.includes(nm);
470
487
  this.setEntry(nm, { entry, exported });
471
488
  }
472
489
  }
490
+ if (extendingModelDef.givens) {
491
+ for (const [id, given] of Object.entries(extendingModelDef.givens)) {
492
+ this.documentGivens.set(id, given);
493
+ }
494
+ }
473
495
  }
474
496
  this.didInitModel = true;
475
497
  }
@@ -477,6 +499,8 @@ class Document extends MalloyElement {
477
499
  const needs = this.statements.executeList(this);
478
500
  const modelDef = this.modelDef();
479
501
  if (needs === undefined) {
502
+ this.checkGivenAliasCollisions();
503
+ this.checkQueryGivenSatisfiability();
480
504
  for (const q of this.queryList) {
481
505
  if (q.modelAnnotation === undefined && modelDef.annotation) {
482
506
  q.modelAnnotation = modelDef.annotation;
@@ -501,6 +525,82 @@ class Document extends MalloyElement {
501
525
  rememberToAddModelAnnotations(sd) {
502
526
  this.modelAnnotationTodoList.push(sd);
503
527
  }
528
+ checkGivenAliasCollisions() {
529
+ var _a, _b;
530
+ const byId = new Map();
531
+ for (const [name, m] of this.documentModel) {
532
+ if (m.entry.type !== 'given')
533
+ continue;
534
+ const list = byId.get(m.entry.id);
535
+ if (list) {
536
+ list.push(name);
537
+ }
538
+ else {
539
+ byId.set(m.entry.id, [name]);
540
+ }
541
+ }
542
+ for (const [id, names] of byId) {
543
+ if (names.length < 2)
544
+ continue;
545
+ const decl = this.documentGivens.get(id);
546
+ const sourceName = (_a = decl === null || decl === void 0 ? void 0 : decl.name) !== null && _a !== void 0 ? _a : names[0];
547
+ const where = ((_b = decl === null || decl === void 0 ? void 0 : decl.location) === null || _b === void 0 ? void 0 : _b.url)
548
+ ? ` (declared in ${decl.location.url})`
549
+ : '';
550
+ const sorted = [...names].sort();
551
+ this.logError('given-alias-collision', `Given \`${sourceName}\`${where} is surfaced under multiple names ` +
552
+ `[${sorted.join(', ')}] in this model. ` +
553
+ 'Surfacing the same given under two names is ambiguous at supply ' +
554
+ 'time. To expose it under a second name, declare a local given ' +
555
+ `with a default-chain reference: \`given: NEW_NAME :: T is $${sourceName}\`.`);
556
+ }
557
+ }
558
+ checkQueryGivenSatisfiability() {
559
+ // Always runs at end-of-compile, not gated on imports — a notebook cell
560
+ // that calls `extendModel` with a prior modelDef inherits that model's
561
+ // queries and givens, and a query inherited from cell N can become
562
+ // unsatisfiable in cell N+1 if the satisfying given is removed (or
563
+ // never re-supplied). Cheap when there's nothing to check.
564
+ const namespaceGivens = new Set();
565
+ for (const m of this.documentModel.values()) {
566
+ if (m.entry.type === 'given')
567
+ namespaceGivens.add(m.entry.id);
568
+ }
569
+ const checkOne = (q, label) => {
570
+ var _a;
571
+ const usage = q.givenUsage;
572
+ if (!usage || usage.length === 0)
573
+ return;
574
+ // Build the full set of ids the query transitively needs: each id
575
+ // in Q.givenUsage, plus each id's precomputed default-chain closure
576
+ // (Given.givenUsage). Since the closure is already transitive, no
577
+ // recursion at check time.
578
+ const allIds = new Set();
579
+ for (const g of usage) {
580
+ allIds.add(g.id);
581
+ const decl = this.documentGivens.get(g.id);
582
+ for (const t of (_a = decl === null || decl === void 0 ? void 0 : decl.givenUsage) !== null && _a !== void 0 ? _a : [])
583
+ allIds.add(t.id);
584
+ }
585
+ for (const id of allIds) {
586
+ if (namespaceGivens.has(id))
587
+ continue;
588
+ const decl = this.documentGivens.get(id);
589
+ if ((decl === null || decl === void 0 ? void 0 : decl.default) !== undefined)
590
+ continue;
591
+ this.logError('unsatisfied-given-in-query', unsatisfiedGivenMessage(label, decl, id), { at: q.location });
592
+ }
593
+ };
594
+ // Named queries in the namespace (locally defined OR imported).
595
+ for (const [name, m] of this.documentModel) {
596
+ if (m.entry.type === 'query')
597
+ checkOne(m.entry, `Query '${name}'`);
598
+ }
599
+ // `run:` statements.
600
+ for (const q of this.queryList) {
601
+ checkOne(q, 'run: statement');
602
+ }
603
+ }
504
604
  hasAnnotation() {
505
605
  return ((this.annotation.notes && this.annotation.notes.length > 0) ||
506
606
  this.annotation.inherits !== undefined);
@@ -536,9 +636,21 @@ class Document extends MalloyElement {
536
636
  def.contents[name] = newEntry;
537
637
  }
538
638
  }
639
+ else if (entryDef.type === 'given') {
640
+ if (modelEntry.exported) {
641
+ def.exports.push(name);
642
+ }
643
+ def.contents[name] = { ...entryDef };
644
+ }
539
645
  }
540
646
  // Copy the accumulated sourceRegistry
541
647
  def.sourceRegistry = { ...this.documentSrcRegistry };
648
+ if (this.documentGivens.size > 0) {
649
+ def.givens = {};
650
+ for (const [id, given] of this.documentGivens) {
651
+ def.givens[id] = given;
652
+ }
653
+ }
542
654
  return def;
543
655
  }
544
656
  getEntry(str) {