@malloydata/malloy 0.0.390 → 0.0.392

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 +29 -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
@@ -46,7 +46,8 @@ class FluentState {
46
46
  * An environment for compiling and running Malloy queries.
47
47
  */
48
48
  class Runtime {
49
- constructor({ urlReader, connections, connection, config, buildManifest, eventStream, cacheManager, }) {
49
+ constructor({ urlReader, connections, connection, config, buildManifest, eventStream, cacheManager, givens, }) {
50
+ var _a, _b;
50
51
  this.isTestRuntime = false;
51
52
  if (config !== undefined) {
52
53
  this._config = config;
@@ -68,6 +69,19 @@ class Runtime {
68
69
  this._buildManifest = buildManifest;
69
70
  this._eventStream = eventStream;
70
71
  this._cacheManager = cacheManager;
72
+ if (givens) {
73
+ for (const [name, value] of Object.entries(givens)) {
74
+ if (value === undefined) {
75
+ throw new Error(`Runtime givens.${name}: explicit undefined is not a valid value. ` +
76
+ 'Omit the key to defer to declaration default or the file layer; ' +
77
+ 'use null for an explicit null value.');
78
+ }
79
+ }
80
+ }
81
+ this._constructorGivensMap = givens
82
+ ? new Map(Object.entries(givens))
83
+ : new Map();
84
+ this._finalizedGivensSet = new Set((_b = (_a = this._config) === null || _a === void 0 ? void 0 : _a.finalizeGivens) !== null && _b !== void 0 ? _b : []);
71
85
  }
72
86
  /**
73
87
  * @return The `CacheManager` for this runtime instance.
@@ -93,6 +107,49 @@ class Runtime {
93
107
  get eventStream() {
94
108
  return this._eventStream;
95
109
  }
110
+ /**
111
+ * Constructor-supplied givens, exposed for the materializer's per-query
112
+ * merge. Underscore-prefixed because it's the constructor layer only —
113
+ * use `getGivens()` for the full file+constructor view a caller usually
114
+ * wants.
115
+ *
116
+ * @internal Accessed from QueryMaterializer.
117
+ */
118
+ get _constructorGivens() {
119
+ return this._constructorGivensMap;
120
+ }
121
+ /**
122
+ * The runtime's effective givens — file (from `config.givensPath`,
123
+ * lazily loaded) merged with the constructor `givens:` option, with
124
+ * the constructor winning per-key. Per-query supply via
125
+ * `.run({ givens: ... })` is *not* included; that's a per-call
126
+ * argument, not runtime state.
127
+ *
128
+ * Async because the file may not yet be loaded; subsequent calls share
129
+ * the cached promise.
130
+ */
131
+ async getGivens() {
132
+ const file = await this._resolveGivens();
133
+ const merged = new Map();
134
+ if (file) {
135
+ for (const [k, v] of Object.entries(file))
136
+ merged.set(k, v);
137
+ }
138
+ for (const [k, v] of this._constructorGivensMap)
139
+ merged.set(k, v);
140
+ return merged;
141
+ }
142
+ /**
143
+ * Surface names of givens locked at the runtime layer (the resolved set
144
+ * the `config.finalizeGivens` directive produced). Per-query supply for
145
+ * these names throws; `Model.givens` and `PreparedQuery.givens` filter
146
+ * them out so introspection-driven UIs don't render editors for them.
147
+ *
148
+ * @internal Accessed from QueryMaterializer and Model construction.
149
+ */
150
+ get _finalizedGivens() {
151
+ return this._finalizedGivensSet;
152
+ }
96
153
  /**
97
154
  * Setter — install an explicit build manifest for persist source
98
155
  * substitution. From this point on, compiled queries resolve persist
@@ -142,14 +199,14 @@ class Runtime {
142
199
  if (this._buildManifest) {
143
200
  return Promise.resolve(this._buildManifest);
144
201
  }
145
- const url = (_a = this._config) === null || _a === void 0 ? void 0 : _a.manifestURL;
146
- if (!url)
202
+ const urlStr = (_a = this._config) === null || _a === void 0 ? void 0 : _a.manifestURL;
203
+ if (!urlStr)
147
204
  return Promise.resolve(undefined);
148
205
  if (!this._resolvedBuildManifestPromise) {
149
206
  this._resolvedBuildManifestPromise = (async () => {
150
207
  let text;
151
208
  try {
152
- const result = await this._urlReader.readURL(url);
209
+ const result = await this._urlReader.readURL(new URL(urlStr));
153
210
  text = typeof result === 'string' ? result : result.contents;
154
211
  }
155
212
  catch {
@@ -173,13 +230,68 @@ class Runtime {
173
230
  const msg = e instanceof Error ? e.message : String(e);
174
231
  return {
175
232
  entries: {},
176
- loadError: `Manifest file at ${url.toString()} could not be parsed: ${msg}`,
233
+ loadError: `Manifest file at ${urlStr} could not be parsed: ${msg}`,
177
234
  };
178
235
  }
179
236
  })();
180
237
  }
181
238
  return this._resolvedBuildManifestPromise;
182
239
  }
240
+ /**
241
+ * Resolve the per-runtime givens map from `config.givensURL` (the file
242
+ * `givensPath` points at). Lazy and cached as a Promise — first compile
243
+ * triggers the read, subsequent compiles share the result.
244
+ *
245
+ * Stricter error policy than `_resolveBuildManifest`: a missing file or
246
+ * malformed JSON throws. Per design, the per-runtime givens layer is a
247
+ * configured contract, not an opportunistic read; a misconfigured path
248
+ * should fail loudly at the first compile, not silently degrade.
249
+ *
250
+ * Returns `undefined` only when no `givensURL` is configured.
251
+ *
252
+ * @internal Accessed from QueryMaterializer.
253
+ */
254
+ _resolveGivens() {
255
+ var _a;
256
+ const urlStr = (_a = this._config) === null || _a === void 0 ? void 0 : _a.givensURL;
257
+ if (!urlStr)
258
+ return Promise.resolve(undefined);
259
+ if (!this._resolvedGivensPromise) {
260
+ this._resolvedGivensPromise = (async () => {
261
+ let text;
262
+ try {
263
+ const result = await this._urlReader.readURL(new URL(urlStr));
264
+ text = typeof result === 'string' ? result : result.contents;
265
+ }
266
+ catch (e) {
267
+ const msg = e instanceof Error ? e.message : String(e);
268
+ throw new Error(`givens: failed to read givens file at ${urlStr}: ${msg}`);
269
+ }
270
+ let parsed;
271
+ try {
272
+ parsed = JSON.parse(text);
273
+ }
274
+ catch (e) {
275
+ const msg = e instanceof Error ? e.message : String(e);
276
+ throw new Error(`givens: failed to parse JSON at ${urlStr}: ${msg}`);
277
+ }
278
+ if (!isGivensObject(parsed)) {
279
+ const got = Array.isArray(parsed)
280
+ ? 'array'
281
+ : parsed === null
282
+ ? 'null'
283
+ : typeof parsed;
284
+ throw new Error(`givens: file at ${urlStr} must be a JSON object of name → value pairs, got ${got}`);
285
+ }
286
+ return parsed;
287
+ })();
288
+ }
289
+ return this._resolvedGivensPromise;
290
+ }
291
+ /** @internal */
292
+ _invalidateGivensCache() {
293
+ this._resolvedGivensPromise = undefined;
294
+ }
183
295
  /**
184
296
  * The virtual map for virtual source resolution.
185
297
  * When set, compiled queries automatically resolve virtual sources
@@ -244,7 +356,7 @@ class Runtime {
244
356
  }
245
357
  const compilable = source instanceof URL ? { url: source } : { source };
246
358
  return new ModelMaterializer(this, async () => {
247
- return compile_1.Malloy.compile({
359
+ const m = await compile_1.Malloy.compile({
248
360
  ...compilable,
249
361
  urlReader: this.urlReader,
250
362
  connections: this.connections,
@@ -255,15 +367,34 @@ class Runtime {
255
367
  testEnvironment: options === null || options === void 0 ? void 0 : options.testEnvironment,
256
368
  cacheManager: this.cacheManager,
257
369
  });
370
+ return this._withRuntimeContext(m);
258
371
  }, options);
259
372
  }
373
+ /**
374
+ * Re-wrap a `Model` produced by `Malloy.compile` with this runtime's
375
+ * `RuntimeContext` so context-sensitive Model methods (currently
376
+ * `Model.givens` filtering finalized names; future runtime-aware
377
+ * concerns) work correctly. No-op when there's nothing in the context.
378
+ *
379
+ * @internal Accessed from `ModelMaterializer.extendModel` and Runtime
380
+ * loadModel paths.
381
+ */
382
+ _withRuntimeContext(m) {
383
+ if (this._finalizedGivensSet.size === 0)
384
+ return m;
385
+ return new core_1.Model(m._modelDef, m.problems, m.fromSources, m.getExistingQueryModel(), {
386
+ finalizedGivens: this._finalizedGivensSet,
387
+ });
388
+ }
260
389
  // TODO Consider formalizing this. Perhaps as a `withModel` method,
261
390
  // as well as a `Model.fromModelDefinition` if we choose to expose
262
391
  // `ModelDef` to the world formally. For now, this should only
263
392
  // be used in tests.
264
393
  _loadModelFromModelDef(modelDef, options) {
265
394
  return new ModelMaterializer(this, async () => {
266
- return new core_1.Model(modelDef, [], []);
395
+ return new core_1.Model(modelDef, [], [], undefined, this._finalizedGivensSet.size > 0
396
+ ? { finalizedGivens: this._finalizedGivensSet }
397
+ : undefined);
267
398
  }, options);
268
399
  }
269
400
  /**
@@ -507,7 +638,7 @@ class ModelMaterializer extends FluentState {
507
638
  testEnvironment: options === null || options === void 0 ? void 0 : options.testEnvironment,
508
639
  ...this.compileQueryOptions,
509
640
  });
510
- return queryModel;
641
+ return this.runtime._withRuntimeContext(queryModel);
511
642
  }, options);
512
643
  }
513
644
  async search(sourceName, searchTerm, limit = 1000, searchField = undefined) {
@@ -691,7 +822,7 @@ class QueryMaterializer extends FluentState {
691
822
  */
692
823
  loadPreparedResult(options) {
693
824
  return this.makePreparedResultMaterializer(async () => {
694
- var _a, _b;
825
+ var _a, _b, _c;
695
826
  const preparedQuery = await this.materialize();
696
827
  const mergedOptions = {
697
828
  eventStream: this.eventStream,
@@ -735,7 +866,58 @@ class QueryMaterializer extends FluentState {
735
866
  }
736
867
  // Use virtualMap from options if provided, otherwise fall back to Runtime's.
737
868
  const virtualMap = (_b = mergedOptions.virtualMap) !== null && _b !== void 0 ? _b : this.runtime.virtualMap;
738
- // Build PrepareResultOptions from CompileQueryOptions + connectionDigests
869
+ // Per-query supply for a finalized given is rejected at API entry
870
+ // — the finalized-givens set is the runtime's "this can't be
871
+ // overridden by the caller" guarantee. Fail before any IO so misuse
872
+ // is loud.
873
+ const finalizedSet = this.runtime._finalizedGivens;
874
+ if (finalizedSet.size > 0 && mergedOptions.givens) {
875
+ for (const name of Object.keys(mergedOptions.givens)) {
876
+ if (finalizedSet.has(name)) {
877
+ throw new Error(`Cannot supply '${name}' per-query: it is finalized at the runtime layer (config.finalizeGivens).`);
878
+ }
879
+ }
880
+ }
881
+ // Three layers of givens, merged per-key in precedence order:
882
+ // 1. config.givensURL file (lazy + cached)
883
+ // 2. Runtime constructor `givens:` option
884
+ // 3. Per-query supply via `.run({givens: ...})`
885
+ // Higher-numbered layers win on collision. Each layer is optional;
886
+ // the merge collapses to undefined when all three are absent.
887
+ const fileGivens = await this.runtime._resolveGivens();
888
+ const constructorGivens = mapToRecord(this.runtime._constructorGivens);
889
+ const haveAny = fileGivens || constructorGivens || mergedOptions.givens;
890
+ const mergedGivens = haveAny
891
+ ? { ...fileGivens, ...constructorGivens, ...mergedOptions.givens }
892
+ : undefined;
893
+ // Query-scoped validation: of the givens THIS query references,
894
+ // any that are finalized must have a value somewhere (file or
895
+ // constructor). One config covers a project; individual files
896
+ // declare overlapping but distinct given sets; an unrelated query
897
+ // shouldn't fail because some other file's given is in the
898
+ // finalize list without a value. The per-query rejection above is
899
+ // the actual security primitive; this check is the sanity net for
900
+ // "you locked it but forgot to supply it."
901
+ const queryGivenUsage = (_c = preparedQuery._query.givenUsage) !== null && _c !== void 0 ? _c : [];
902
+ if (finalizedSet.size > 0 && queryGivenUsage.length > 0) {
903
+ const referencedIds = new Set(queryGivenUsage.map(g => g.id));
904
+ const missing = [];
905
+ for (const [surfaceName, entry] of Object.entries(preparedQuery._modelDef.contents)) {
906
+ if (entry.type !== 'given')
907
+ continue;
908
+ if (!referencedIds.has(entry.id))
909
+ continue;
910
+ if (!finalizedSet.has(surfaceName))
911
+ continue;
912
+ if (mergedGivens && surfaceName in mergedGivens)
913
+ continue;
914
+ missing.push(surfaceName);
915
+ }
916
+ if (missing.length > 0) {
917
+ throw new Error(`Query references finalized given(s) with no resolved value: ${missing.join(', ')}. Each finalized given the query needs must have a value in givensPath or in the Runtime constructor's \`givens\`.`);
918
+ }
919
+ }
920
+ // Build PrepareResultOptions from CompileQueryOptions + connectionDigests.
739
921
  const prepareResultOptions = {
740
922
  defaultRowLimit: mergedOptions.defaultRowLimit,
741
923
  buildManifest,
@@ -745,6 +927,7 @@ class QueryMaterializer extends FluentState {
745
927
  return preparedQuery.getPreparedResult({
746
928
  ...mergedOptions,
747
929
  ...prepareResultOptions,
930
+ givens: mergedGivens,
748
931
  });
749
932
  });
750
933
  }
@@ -901,4 +1084,23 @@ function isBuildManifestShape(value) {
901
1084
  const entries = value.entries;
902
1085
  return typeof entries === 'object' && entries !== null;
903
1086
  }
1087
+ /**
1088
+ * Shallow shape-check for the givens-values file: must be a non-array
1089
+ * non-null object. Per-value type checking happens later when each
1090
+ * declared given is bound via `resolveSuppliedGivens` — at this layer we
1091
+ * only ensure the top-level shape is a name → value map.
1092
+ */
1093
+ function isGivensObject(value) {
1094
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
1095
+ }
1096
+ /**
1097
+ * Convert a non-empty `ReadonlyMap` into a plain object for spread-merging
1098
+ * with other given layers. Returns `undefined` for an empty map so the
1099
+ * merge can short-circuit when all layers are absent.
1100
+ */
1101
+ function mapToRecord(m) {
1102
+ if (m.size === 0)
1103
+ return undefined;
1104
+ return Object.fromEntries(m);
1105
+ }
904
1106
  //# sourceMappingURL=runtime.js.map
@@ -1,5 +1,5 @@
1
1
  import type { EventStream } from '../../runtime_types';
2
- import type { BuildManifest, VirtualMap } from '../../model';
2
+ import type { BuildManifest, GivenValue, VirtualMap } from '../../model';
3
3
  /**
4
4
  * An empty BuildManifest with no entries and strict mode off.
5
5
  * Use this to explicitly suppress manifest substitution in a query:
@@ -35,6 +35,7 @@ export interface CompileQueryOptions {
35
35
  connectionDigests?: Record<string, string>;
36
36
  /** Map from connectionName → virtualName → tablePath for virtual source resolution */
37
37
  virtualMap?: VirtualMap;
38
+ givens?: Record<string, GivenValue>;
38
39
  }
39
40
  /**
40
41
  * A node in the build graph (recursive DAG structure).
package/dist/index.d.ts CHANGED
@@ -1,12 +1,14 @@
1
1
  export { DuckDBDialect, StandardSQLDialect, TrinoDialect, PostgresDialect, SnowflakeDialect, MySQLDialect, DatabricksDialect, registerDialect, arg, qtz, overload, minScalar, anyExprType, minAggregate, maxScalar, sql, makeParam, param, variadicParam, literal, spread, Dialect, } from './dialect';
2
2
  export type { DialectFieldList, DialectFunctionOverloadDef, QueryInfo, MalloyStandardFunctionImplementations, DefinitionBlueprint, DefinitionBlueprintMap, OverloadedDefinitionBlueprint, } from './dialect';
3
- export type { QueryRecord, StructDef, TableSourceDef, SQLSourceDef, SourceDef, JoinFieldDef, NamedSourceDefs, MalloyQueryData, DateUnit, ExtractUnit, TimestampUnit, TemporalFieldType, QueryData, QueryValue, Expr, FilterCondition, Argument, Parameter, FieldDef, PipeSegment, QueryFieldDef, IndexFieldDef, TurtleDef, SearchValueMapResult, SearchIndexResult, ModelDef, Query, QueryResult, QueryResultDef, QueryRunStats, QueryScalar, NamedQueryDef, NamedModelObject, ExpressionType, FunctionDef, FunctionOverloadDef, FunctionParameterDef, ExpressionValueType, TypeDesc, FunctionParamTypeDesc, DocumentLocation, DocumentRange, DocumentPosition, Sampling, Annotation, BasicAtomicTypeDef, BasicAtomicDef, AtomicTypeDef, AtomicFieldDef, ArrayDef, ArrayTypeDef, RecordTypeDef, RepeatedRecordTypeDef, RecordDef, RepeatedRecordDef, RecordLiteralNode, StringLiteralNode, ArrayLiteralNode, SourceComponentInfo, DateLiteralNode, TimestampLiteralNode, TimestamptzLiteralNode, TimeLiteralExpr, TypecastExpr, BuildID, BuildManifest, BuildManifestEntry, VirtualMap, } from './model';
3
+ export type { QueryRecord, StructDef, TableSourceDef, SQLSourceDef, SourceDef, JoinFieldDef, NamedSourceDefs, MalloyQueryData, DateUnit, ExtractUnit, TimestampUnit, TemporalFieldType, QueryData, QueryValue, Expr, FilterCondition, Argument, Parameter, FieldDef, PipeSegment, QueryFieldDef, IndexFieldDef, TurtleDef, SearchValueMapResult, SearchIndexResult, ModelDef, Query, QueryResult, QueryResultDef, QueryRunStats, QueryScalar, NamedQueryDef, NamedModelObject, ExpressionType, FunctionDef, FunctionOverloadDef, FunctionParameterDef, ExpressionValueType, TypeDesc, FunctionParamTypeDesc, DocumentLocation, DocumentRange, DocumentPosition, Sampling, Annotation, BasicAtomicTypeDef, BasicAtomicDef, AtomicTypeDef, AtomicFieldDef, ArrayDef, ArrayTypeDef, RecordTypeDef, RepeatedRecordTypeDef, RecordDef, RepeatedRecordDef, RecordLiteralNode, StringLiteralNode, ArrayLiteralNode, SourceComponentInfo, DateLiteralNode, TimestampLiteralNode, TimestamptzLiteralNode, TimeLiteralExpr, TypecastExpr, BuildID, BuildManifest, BuildManifestEntry, GivenValue, VirtualMap, } from './model';
4
4
  export { isSourceDef, isAtomic, isBasicAtomic, isCompoundArrayData, isJoined, isJoinedSource, isSamplingEnable, isSamplingPercent, isSamplingRows, isRepeatedRecord, isBasicArray, mkArrayDef, mkFieldDef, expressionIsAggregate, expressionIsAnalytic, expressionIsCalculation, expressionIsScalar, expressionIsUngroupedAggregate, indent, composeSQLExpr, isTimestampUnit, isDateUnit, constantExprToSQL, } from './model';
5
5
  export { malloyToQuery, MalloyTranslator, } from './lang';
6
6
  export type { LogMessage, TranslateResponse } from './lang';
7
7
  export { Model, Malloy, Runtime, AtomicFieldType, ConnectionRuntime, SingleConnectionRuntime, EmptyURLReader, InMemoryURLReader, FixedConnectionMap, MalloyError, JoinRelationship, SourceRelationship, DateTimeframe, TimestampTimeframe, PreparedResult, Result, QueryMaterializer, CSVWriter, JSONWriter, Parse, DataWriter, Explore, InMemoryModelCache, CacheManager, Manifest, MalloyConfig, envOverlay, contextOverlay, defaultConfigOverlays, discoverConfig, } from './api/foundation';
8
8
  export type { PreparedQuery, Field, AtomicField, ExploreField, QueryField, SortableField, DataArray, DataRecord, DataColumn, DataArrayOrRecord, Loggable, ModelMaterializer, DocumentTablePath, DocumentSymbol, ResultJSON, PreparedResultJSON, PreparedResultMaterializer, ExploreMaterializer, WriteStream, SerializedExplore, ModelCache, CachedModel, DateField, TimestampField, } from './api/foundation';
9
9
  export type { Overlay, ConfigOverlays } from './api/foundation';
10
+ export type { FilesystemContext, MalloyConfigOptions } from './api/foundation';
11
+ export type { RuntimeContext } from './api/foundation';
10
12
  export type { QueryOptionsReader, RunSQLOptions } from './run_sql_options';
11
13
  export type { EventStream, ModelString, ModelURL, QueryString, QueryURL, URLReader, InvalidationKey, } from './runtime_types';
12
14
  export type { Connection, ConnectionConfig, ConnectionParameterValue, FetchSchemaOptions, InfoConnection, LookupConnection, PersistSQLResults, PooledConnection, TestableConnection, StreamingConnection, } from './connection/types';
@@ -37,7 +37,6 @@ function errorFor(reason) {
37
37
  expressionType: 'scalar',
38
38
  value: { node: 'error', message: reason },
39
39
  evalSpace: 'constant',
40
- fieldUsage: [],
41
40
  };
42
41
  }
43
42
  //# sourceMappingURL=ast-utils.js.map
@@ -10,7 +10,7 @@ export declare abstract class ExprAggregateFunction extends ExpressionDef {
10
10
  source?: FieldReference;
11
11
  expr?: ExpressionDef;
12
12
  explicitSource?: boolean;
13
- legalChildTypes: import("../../../model/malloy_types").TypeDesc[];
13
+ legalChildTypes: import("../../..").TypeDesc[];
14
14
  constructor(func: AggregateFunctionType, expr?: ExpressionDef, explicitSource?: boolean);
15
15
  abstract returns(fromExpr: ExprValue): ExprValue;
16
16
  getExpression(fs: FieldSpace): ExprValue;
@@ -106,7 +106,11 @@ class ExprAggregateFunction extends expression_def_1.ExpressionDef {
106
106
  at: this.source.location,
107
107
  },
108
108
  evalSpace: footType.evalSpace,
109
- fieldUsage: [{ path: this.source.path, at: this.source.location }],
109
+ refSummary: {
110
+ fieldUsage: [
111
+ { path: this.source.path, at: this.source.location },
112
+ ],
113
+ },
110
114
  };
111
115
  structPath = this.source.path.slice(0, -1);
112
116
  // Here we handle a special case where you write `foo.agg()` and `foo` is a
@@ -178,13 +182,10 @@ class ExprAggregateFunction extends expression_def_1.ExpressionDef {
178
182
  }
179
183
  const returnExpr = this.returns(exprVal);
180
184
  if (!this.isSymmetricFunction()) {
181
- if (returnExpr.fieldUsage === undefined) {
182
- returnExpr.fieldUsage = [];
183
- }
184
- returnExpr.fieldUsage.push({
185
- path: structPath || [],
186
- uniqueKeyRequirement: { isCount: false },
187
- });
185
+ (0, malloy_types_1.setFieldUsage)(returnExpr, [
186
+ ...(0, malloy_types_1.fieldUsageFrom)(returnExpr.refSummary),
187
+ { path: structPath || [], uniqueKeyRequirement: { isCount: false } },
188
+ ]);
188
189
  }
189
190
  return {
190
191
  ...returnExpr,
@@ -5,7 +5,7 @@ export declare class ExprCoalesce extends ExpressionDef {
5
5
  readonly expr: ExpressionDef;
6
6
  readonly altExpr: ExpressionDef;
7
7
  elementType: string;
8
- legalChildTypes: import("../../../model").TypeDesc[];
8
+ legalChildTypes: import("../../..").TypeDesc[];
9
9
  constructor(expr: ExpressionDef, altExpr: ExpressionDef);
10
10
  getExpression(fs: FieldSpace): ExprValue;
11
11
  }
@@ -57,9 +57,9 @@ var __importStar = (this && this.__importStar) || (function () {
57
57
  Object.defineProperty(exports, "__esModule", { value: true });
58
58
  exports.ExprCoalesce = void 0;
59
59
  const model_1 = require("../../../model");
60
+ const composite_source_utils_1 = require("../../composite-source-utils");
60
61
  const TDU = __importStar(require("../typedesc-utils"));
61
62
  const expression_def_1 = require("../types/expression-def");
62
- const composite_source_utils_1 = require("../../composite-source-utils");
63
63
  class ExprCoalesce extends expression_def_1.ExpressionDef {
64
64
  constructor(expr, altExpr) {
65
65
  super({ expr, altExpr });
@@ -69,7 +69,6 @@ class ExprCoalesce extends expression_def_1.ExpressionDef {
69
69
  this.legalChildTypes = TDU.anyAtomicT;
70
70
  }
71
71
  getExpression(fs) {
72
- var _a;
73
72
  const maybeNull = this.expr.getExpression(fs);
74
73
  const whenNull = this.altExpr.getExpression(fs);
75
74
  if (maybeNull.type === 'null') {
@@ -101,7 +100,7 @@ class ExprCoalesce extends expression_def_1.ExpressionDef {
101
100
  kids: { left: maybeNull.value, right: whenNull.value },
102
101
  },
103
102
  evalSpace: (0, model_1.mergeEvalSpaces)(maybeNull.evalSpace, whenNull.evalSpace),
104
- fieldUsage: (_a = (0, composite_source_utils_1.mergeFieldUsage)(maybeNull.fieldUsage, whenNull.fieldUsage)) !== null && _a !== void 0 ? _a : [],
103
+ refSummary: (0, composite_source_utils_1.mergeRefSummaries)(maybeNull.refSummary, whenNull.refSummary),
105
104
  };
106
105
  }
107
106
  }
@@ -76,7 +76,7 @@ class ExprCountDistinct extends expr_aggregate_function_1.ExprAggregateFunction
76
76
  evalSpace: ev.evalSpace,
77
77
  expressionType: 'aggregate',
78
78
  value: ev.value,
79
- fieldUsage: ev.fieldUsage,
79
+ refSummary: ev.refSummary,
80
80
  };
81
81
  }
82
82
  }
@@ -44,7 +44,7 @@ class ExprCount extends expr_aggregate_function_1.ExprAggregateFunction {
44
44
  evalSpace: ev.evalSpace,
45
45
  expressionType: 'aggregate',
46
46
  value: ev.value,
47
- fieldUsage: ev.fieldUsage,
47
+ refSummary: ev.refSummary,
48
48
  };
49
49
  }
50
50
  getExpression(_fs) {
@@ -63,9 +63,11 @@ class ExprCount extends expr_aggregate_function_1.ExprAggregateFunction {
63
63
  expressionType: 'aggregate',
64
64
  value: ret,
65
65
  evalSpace: 'output',
66
- fieldUsage: [
67
- { path: ret.structPath || [], uniqueKeyRequirement: { isCount: true } },
68
- ],
66
+ refSummary: {
67
+ fieldUsage: [
68
+ { path: ret.structPath || [], uniqueKeyRequirement: { isCount: true } },
69
+ ],
70
+ },
69
71
  };
70
72
  }
71
73
  }
@@ -20,7 +20,6 @@ class ExprFilterExpression extends expression_def_1.ExpressionDef {
20
20
  value: { node: 'filterLiteral', filterSrc: this.filterText },
21
21
  expressionType: 'scalar',
22
22
  evalSpace: 'constant',
23
- fieldUsage: [],
24
23
  };
25
24
  }
26
25
  }
@@ -154,7 +154,9 @@ class ExprFunc extends expression_def_1.ExpressionDef {
154
154
  at: this.source.location,
155
155
  },
156
156
  evalSpace: footType.evalSpace,
157
- fieldUsage: [{ path: this.source.path, at: this.source.location }],
157
+ refSummary: {
158
+ fieldUsage: [{ path: this.source.path, at: this.source.location }],
159
+ },
158
160
  };
159
161
  structPath = this.source.path.slice(0, -1);
160
162
  }
@@ -357,14 +359,17 @@ class ExprFunc extends expression_def_1.ExpressionDef {
357
359
  : 'output';
358
360
  const aggregateFunctionUsage = [];
359
361
  if (isAsymmetric || isAnalytic) {
360
- const funcUsage = { path: structPath || [], at: this.location };
362
+ const funcUsage = {
363
+ path: structPath || [],
364
+ at: this.location,
365
+ };
361
366
  if (isAsymmetric)
362
367
  funcUsage.uniqueKeyRequirement = { isCount: false };
363
368
  if (isAnalytic)
364
369
  funcUsage.analyticFunctionUse = true;
365
370
  aggregateFunctionUsage.push(funcUsage);
366
371
  }
367
- const fieldUsage = (0, composite_source_utils_1.mergeFieldUsage)(...argExprs.map(ae => ae.fieldUsage), orderByUsage, sqlFunctionFieldUsage, aggregateFunctionUsage);
372
+ const refSummary = (0, composite_source_utils_1.mergeRefSummaries)(...argExprs.map(ae => ae.refSummary), (0, malloy_types_1.mkRefSummary)({ fieldUsage: orderByUsage }), (0, malloy_types_1.mkRefSummary)({ fieldUsage: sqlFunctionFieldUsage }), (0, malloy_types_1.mkRefSummary)({ fieldUsage: aggregateFunctionUsage }));
368
373
  const ungroupings = argExprs.reduce((ug, a) => { var _a; return (_a = a.ungroupings) !== null && _a !== void 0 ? _a : ug; }, []);
369
374
  // TODO consider if I can use `computedExprValue` here...
370
375
  // seems like the rules for the evalSpace is a bit different from normal though
@@ -374,7 +379,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
374
379
  expressionType,
375
380
  value: funcCall,
376
381
  evalSpace,
377
- fieldUsage,
382
+ refSummary,
378
383
  ungroupings,
379
384
  };
380
385
  }
@@ -0,0 +1,18 @@
1
+ import { ExpressionDef } from '../types/expression-def';
2
+ import type { ExprValue } from '../types/expr-value';
3
+ import type { FieldSpace } from '../types/field-space';
4
+ /**
5
+ * Reference to a given inside an expression: `$NAME`.
6
+ *
7
+ * Resolution bypasses `fs.lookup` (which is source-scoped) and goes
8
+ * straight to the document's given namespace — that lets `$NAME` work
9
+ * even inside a `ConstantFieldSpace`, which is how default values
10
+ * (`given: B :: number is $A + 1`) refuse field references but accept
11
+ * other givens.
12
+ */
13
+ export declare class GivenReference extends ExpressionDef {
14
+ readonly name: string;
15
+ elementType: string;
16
+ constructor(name: string);
17
+ getExpression(_fs: FieldSpace): ExprValue;
18
+ }
@@ -0,0 +1,69 @@
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.GivenReference = void 0;
8
+ const utils_1 = require("../../../model/utils");
9
+ const expression_def_1 = require("../types/expression-def");
10
+ const expr_value_1 = require("../types/expr-value");
11
+ /**
12
+ * Reference to a given inside an expression: `$NAME`.
13
+ *
14
+ * Resolution bypasses `fs.lookup` (which is source-scoped) and goes
15
+ * straight to the document's given namespace — that lets `$NAME` work
16
+ * even inside a `ConstantFieldSpace`, which is how default values
17
+ * (`given: B :: number is $A + 1`) refuse field references but accept
18
+ * other givens.
19
+ */
20
+ class GivenReference extends expression_def_1.ExpressionDef {
21
+ constructor(name) {
22
+ super();
23
+ this.name = name;
24
+ this.elementType = 'givenReference';
25
+ }
26
+ getExpression(_fs) {
27
+ var _a;
28
+ const doc = this.document();
29
+ const entry = (_a = doc === null || doc === void 0 ? void 0 : doc.getEntry(this.name)) === null || _a === void 0 ? void 0 : _a.entry;
30
+ if (entry === undefined) {
31
+ return this.loggedErrorExpr('given-not-found', `\`$${this.name}\` references a given named \`${this.name}\`, which is not declared in this model`);
32
+ }
33
+ if (entry.type !== 'given') {
34
+ return this.loggedErrorExpr('given-not-found', `\`$${this.name}\` expects a given named \`${this.name}\`, but \`${this.name}\` is a ${entry.type}`);
35
+ }
36
+ const given = doc === null || doc === void 0 ? void 0 : doc.documentGivens.get(entry.id);
37
+ if (given === undefined) {
38
+ return this.loggedErrorExpr('given-not-found', `Internal error: given \`${this.name}\` is in the namespace but has no declaration. Likely a compiler bug.`);
39
+ }
40
+ // Use-site reference. `location` covers `$NAME` at the use site;
41
+ // `definition.location` points at the canonical `given:`
42
+ // declaration (in the same file or in an imported file).
43
+ this.addReference({
44
+ type: 'givenReference',
45
+ text: this.name,
46
+ location: this.location,
47
+ definition: {
48
+ type: (0, utils_1.typeDefToString)(given.type),
49
+ annotation: given.annotation,
50
+ location: given.location,
51
+ defaultText: given.defaultText,
52
+ },
53
+ });
54
+ const refNode = {
55
+ node: 'given',
56
+ id: entry.id,
57
+ refName: this.name,
58
+ };
59
+ return {
60
+ ...(0, expr_value_1.literalExprValue)({ value: refNode, dataType: given.type }),
61
+ refSummary: {
62
+ fieldUsage: [],
63
+ givenUsage: [{ id: entry.id, at: this.location }],
64
+ },
65
+ };
66
+ }
67
+ }
68
+ exports.GivenReference = GivenReference;
69
+ //# sourceMappingURL=expr-given.js.map
@@ -16,7 +16,7 @@ export declare class ExprGranularTime extends ExpressionDef {
16
16
  readonly units: TimestampUnit;
17
17
  readonly truncate: boolean;
18
18
  elementType: string;
19
- legalChildTypes: import("../../../model/malloy_types").TypeDesc[];
19
+ legalChildTypes: import("../../..").TypeDesc[];
20
20
  constructor(expr: ExpressionDef, units: TimestampUnit, truncate: boolean);
21
21
  granular(): boolean;
22
22
  drillExpression(): Malloy.Expression | undefined;
@@ -57,13 +57,14 @@ class ExprIdReference extends expression_def_1.ExpressionDef {
57
57
  ]
58
58
  : [];
59
59
  const td = def.found.typeDesc();
60
+ const refSummary = (0, malloy_types_1.mkRefSummary)({ fieldUsage: fieldUsage });
60
61
  if (def.isOutputField) {
61
62
  return {
62
63
  ...td,
63
64
  // TODO what about literal??
64
65
  evalSpace: td.evalSpace === 'constant' ? 'constant' : 'output',
65
66
  value: { node: 'outputField', name: this.refString },
66
- fieldUsage,
67
+ refSummary,
67
68
  };
68
69
  }
69
70
  const value = {
@@ -79,7 +80,7 @@ class ExprIdReference extends expression_def_1.ExpressionDef {
79
80
  ...td,
80
81
  value,
81
82
  evalSpace,
82
- fieldUsage,
83
+ refSummary,
83
84
  requiresGroupBy: undefined,
84
85
  };
85
86
  }