@malloydata/malloy 0.0.434 → 0.0.436

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 (103) hide show
  1. package/dist/api/foundation/build_targets.d.ts +5 -6
  2. package/dist/api/foundation/build_targets.js +74 -6
  3. package/dist/api/foundation/compile.d.ts +0 -1
  4. package/dist/api/foundation/compile.js +0 -3
  5. package/dist/api/foundation/core.d.ts +16 -4
  6. package/dist/api/foundation/core.js +23 -23
  7. package/dist/api/foundation/index.d.ts +1 -1
  8. package/dist/api/foundation/runtime.d.ts +21 -3
  9. package/dist/api/foundation/runtime.js +45 -54
  10. package/dist/api/foundation/types.d.ts +43 -4
  11. package/dist/connection/dbmeta.d.ts +29 -0
  12. package/dist/connection/dbmeta.js +46 -0
  13. package/dist/connection/index.d.ts +1 -0
  14. package/dist/connection/index.js +1 -0
  15. package/dist/dialect/databricks/databricks.d.ts +11 -12
  16. package/dist/dialect/databricks/databricks.js +24 -36
  17. package/dist/dialect/dialect.d.ts +70 -171
  18. package/dist/dialect/dialect.js +123 -92
  19. package/dist/dialect/dialect_map.js +2 -0
  20. package/dist/dialect/duckdb/duckdb.d.ts +2 -2
  21. package/dist/dialect/duckdb/duckdb.js +1 -1
  22. package/dist/dialect/index.d.ts +3 -2
  23. package/dist/dialect/index.js +4 -2
  24. package/dist/dialect/mysql/mysql.d.ts +11 -12
  25. package/dist/dialect/mysql/mysql.js +20 -32
  26. package/dist/dialect/pg_impl.d.ts +9 -10
  27. package/dist/dialect/pg_impl.js +27 -73
  28. package/dist/dialect/postgres/postgres.d.ts +4 -4
  29. package/dist/dialect/postgres/postgres.js +4 -12
  30. package/dist/dialect/snowflake/snowflake.d.ts +11 -13
  31. package/dist/dialect/snowflake/snowflake.js +30 -82
  32. package/dist/dialect/sqlserver/dialect_functions.d.ts +2 -0
  33. package/dist/dialect/sqlserver/dialect_functions.js +42 -0
  34. package/dist/dialect/sqlserver/function_overrides.d.ts +2 -0
  35. package/dist/dialect/sqlserver/function_overrides.js +55 -0
  36. package/dist/dialect/sqlserver/index.d.ts +1 -0
  37. package/dist/dialect/sqlserver/index.js +22 -0
  38. package/dist/dialect/sqlserver/sqlserver.d.ts +101 -0
  39. package/dist/dialect/sqlserver/sqlserver.js +537 -0
  40. package/dist/dialect/sqlserver/windows_zones.d.ts +1 -0
  41. package/dist/dialect/sqlserver/windows_zones.js +613 -0
  42. package/dist/dialect/standardsql/standardsql.d.ts +11 -16
  43. package/dist/dialect/standardsql/standardsql.js +22 -73
  44. package/dist/dialect/trino/trino.d.ts +16 -18
  45. package/dist/dialect/trino/trino.js +127 -181
  46. package/dist/index.d.ts +2 -2
  47. package/dist/index.js +6 -4
  48. package/dist/lang/ast/expressions/boolean-value.d.ts +24 -0
  49. package/dist/lang/ast/expressions/boolean-value.js +41 -0
  50. package/dist/lang/ast/expressions/case.js +7 -0
  51. package/dist/lang/ast/expressions/expr-alternation-tree.js +11 -0
  52. package/dist/lang/ast/expressions/expr-cast.js +5 -0
  53. package/dist/lang/ast/expressions/expr-coalesce.js +4 -0
  54. package/dist/lang/ast/expressions/expr-func.js +13 -2
  55. package/dist/lang/ast/expressions/expr-minus.js +5 -2
  56. package/dist/lang/ast/expressions/expr-null.js +4 -0
  57. package/dist/lang/ast/expressions/pick-when.js +7 -0
  58. package/dist/lang/ast/field-space/index-field-space.js +13 -1
  59. package/dist/lang/ast/field-space/query-spaces.js +11 -0
  60. package/dist/lang/ast/query-builders/reduce-builder.js +1 -1
  61. package/dist/lang/ast/query-items/field-declaration.d.ts +5 -0
  62. package/dist/lang/ast/query-items/field-declaration.js +22 -16
  63. package/dist/lang/ast/query-items/field-references.d.ts +6 -0
  64. package/dist/lang/ast/query-items/field-references.js +23 -0
  65. package/dist/lang/ast/query-properties/filters.js +3 -1
  66. package/dist/lang/ast/source-elements/named-source.js +0 -2
  67. package/dist/lang/ast/source-elements/sql-source.js +0 -3
  68. package/dist/lang/ast/source-elements/table-source.js +1 -2
  69. package/dist/lang/ast/statements/import-statement.js +17 -0
  70. package/dist/lang/ast/types/expression-def.js +17 -2
  71. package/dist/lang/ast/types/malloy-element.d.ts +24 -8
  72. package/dist/lang/ast/types/malloy-element.js +63 -44
  73. package/dist/lang/ast/view-elements/reference-view.js +4 -0
  74. package/dist/lang/ast/view-elements/refine-utils.js +1 -0
  75. package/dist/lang/composite-source-utils.js +10 -17
  76. package/dist/lang/parse-log.d.ts +12 -0
  77. package/dist/lang/parse-log.js +2 -0
  78. package/dist/lang/parse-malloy.d.ts +17 -2
  79. package/dist/lang/parse-malloy.js +48 -14
  80. package/dist/lang/parse-tree-walkers/find-external-references.d.ts +3 -3
  81. package/dist/lang/parse-tree-walkers/find-external-references.js +17 -16
  82. package/dist/lang/test/test-translator.d.ts +11 -1
  83. package/dist/lang/test/test-translator.js +51 -3
  84. package/dist/model/expression_compiler.js +9 -8
  85. package/dist/model/filter_compilers.js +13 -12
  86. package/dist/model/given_binding.d.ts +8 -0
  87. package/dist/model/given_binding.js +13 -0
  88. package/dist/model/index.d.ts +1 -1
  89. package/dist/model/index.js +2 -1
  90. package/dist/model/query_query.d.ts +3 -1
  91. package/dist/model/query_query.js +157 -139
  92. package/dist/model/source_def_utils.d.ts +7 -1
  93. package/dist/model/source_def_utils.js +20 -0
  94. package/dist/model/sql_compiled.d.ts +19 -20
  95. package/dist/model/sql_compiled.js +29 -17
  96. package/dist/test/index.js +16 -8
  97. package/dist/test/matchers.d.ts +1 -1
  98. package/dist/test/matchers.js +1 -1
  99. package/dist/test/test-models.js +6 -13
  100. package/dist/version.d.ts +1 -1
  101. package/dist/version.js +1 -1
  102. package/femto-config.motly +13 -1
  103. package/package.json +7 -5
@@ -2,7 +2,7 @@ import type { BuildIdOptions } from '../../model';
2
2
  import type { LogMessage } from '../../lang';
3
3
  import type { PersistNode } from '../../model/persist_utils';
4
4
  import type { Model, PersistSource } from './core';
5
- import type { ConnectionBuild } from './types';
5
+ import type { BuildTargets } from './types';
6
6
  /**
7
7
  * A walk node with its source already resolved.
8
8
  *
@@ -47,9 +47,8 @@ export declare function resolvePersistWalk(model: Model, tagParseLog: LogMessage
47
47
  *
48
48
  * @param walk A resolved walk from {@link resolvePersistWalk}, in order
49
49
  * @param connectionDigests One digest per connection named by a persist source
50
- * @param buildIdOpts What the BuildID's SQL is compiled under. The compiler
51
- * recomputes the same key at serve time through `buildIdOptions()`; supply a
52
- * different `virtualMap` here and the table is built under a key nothing
53
- * looks up.
50
+ * @param buildIdOpts What every BuildID's SQL is generated under.
51
+ * `BuildTarget.buildSQL` generates its SQL under the same options, and
52
+ * `persistedTableFor` recomputes the key under a query's.
54
53
  */
55
- export declare function mkBuildTargets(walk: ResolvedNode[], connectionDigests: Record<string, string>, buildIdOpts: BuildIdOptions): ConnectionBuild[];
54
+ export declare function mkBuildTargets(walk: ResolvedNode[], connectionDigests: Record<string, string>, buildIdOpts: BuildIdOptions): Pick<BuildTargets, 'connections' | 'unbuildable'>;
@@ -6,6 +6,8 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.resolvePersistWalk = resolvePersistWalk;
8
8
  exports.mkBuildTargets = mkBuildTargets;
9
+ const model_1 = require("../../model");
10
+ const given_binding_1 = require("../../model/given_binding");
9
11
  /**
10
12
  * Read a key this function's own construction guarantees is present.
11
13
  *
@@ -38,6 +40,54 @@ function resolvePersistWalk(model, tagParseLog) {
38
40
  }
39
41
  return resolved;
40
42
  }
43
+ /**
44
+ * Describes a given that `source` reads and this build has no value for.
45
+ * Names it by the name this model surfaces it under, since that is the name a
46
+ * builder supplies a value by: under `import { T is TENANT }` it is `T`.
47
+ */
48
+ function unvaluedGivenProblem(source, use) {
49
+ var _a, _b, _c, _d, _e;
50
+ const modelDef = source._model._modelDef;
51
+ const surfaced = Object.entries(modelDef.contents).find(([, entry]) => entry.type === 'given' && entry.id === use.id);
52
+ const name = (_d = (_a = surfaced === null || surfaced === void 0 ? void 0 : surfaced[0]) !== null && _a !== void 0 ? _a : (_c = (_b = modelDef.givens) === null || _b === void 0 ? void 0 : _b[use.id]) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : use.id;
53
+ return {
54
+ severity: 'error',
55
+ code: 'runtime-persist-given-no-value',
56
+ at: (_e = use.at) !== null && _e !== void 0 ? _e : source.location,
57
+ message: `Persisted source '${source.sourceID}' reads given '${name}', which ` +
58
+ `has no value in this build and no default. Supply '${name}' to the ` +
59
+ 'build, or give it a default at its declaration.',
60
+ };
61
+ }
62
+ /**
63
+ * Generates the SQL that keys `source`'s table, or returns why no key can be
64
+ * computed. A `MalloyCompileError` is a problem with the source; any other
65
+ * error is the compiler's own and propagates.
66
+ */
67
+ function buildIdSQL(source, opts) {
68
+ var _a;
69
+ const reads = (0, model_1.givenUsageOfRelation)(source._sourceDef);
70
+ const givens = source._model._modelDef.givens;
71
+ const unvalued = reads.find(use => (0, given_binding_1.lookupGivenValue)(opts.resolvedGivens, givens, use.id) === undefined);
72
+ if (unvalued !== undefined) {
73
+ return { problem: unvaluedGivenProblem(source, unvalued) };
74
+ }
75
+ try {
76
+ return { sql: source._compileSQL(opts), readsGivens: reads.length > 0 };
77
+ }
78
+ catch (e) {
79
+ if (!(e instanceof model_1.MalloyCompileError))
80
+ throw e;
81
+ return {
82
+ problem: {
83
+ message: e.message,
84
+ severity: 'error',
85
+ code: e.code,
86
+ at: (_a = e.at) !== null && _a !== void 0 ? _a : source.location,
87
+ },
88
+ };
89
+ }
90
+ }
41
91
  /** A BuildID is a hex digest, so it cannot contain the separator. */
42
92
  function targetKey(connectionName, buildId) {
43
93
  return `${connectionName}:${buildId}`;
@@ -75,14 +125,14 @@ function addUnique(into, seen, keys) {
75
125
  *
76
126
  * @param walk A resolved walk from {@link resolvePersistWalk}, in order
77
127
  * @param connectionDigests One digest per connection named by a persist source
78
- * @param buildIdOpts What the BuildID's SQL is compiled under. The compiler
79
- * recomputes the same key at serve time through `buildIdOptions()`; supply a
80
- * different `virtualMap` here and the table is built under a key nothing
81
- * looks up.
128
+ * @param buildIdOpts What every BuildID's SQL is generated under.
129
+ * `BuildTarget.buildSQL` generates its SQL under the same options, and
130
+ * `persistedTableFor` recomputes the key under a query's.
82
131
  */
83
132
  function mkBuildTargets(walk, connectionDigests, buildIdOpts) {
84
133
  var _a;
85
134
  const targets = new Map();
135
+ const unbuildable = [];
86
136
  // What each source hands to whoever referenced it: its own target if it is
87
137
  // one, otherwise whatever it was a route to.
88
138
  const contributes = new Map();
@@ -105,7 +155,15 @@ function mkBuildTargets(walk, connectionDigests, buildIdOpts) {
105
155
  `BuildID of '${node.sourceID}'. Supply a digest for every connection ` +
106
156
  'named by a persist source.');
107
157
  }
108
- const sql = source.getSQL(buildIdOpts);
158
+ const keyed = buildIdSQL(source, buildIdOpts);
159
+ if ('problem' in keyed) {
160
+ // No key, so no table: pass its dependencies up as a route does.
161
+ // Whatever reads it inlines its SQL and ends up here too.
162
+ unbuildable.push({ source, problem: keyed.problem });
163
+ contributes.set(node.sourceID, childKeys);
164
+ continue;
165
+ }
166
+ const { sql, readsGivens } = keyed;
109
167
  const buildId = source.makeBuildId(digest, sql);
110
168
  const key = targetKey(connectionName, buildId);
111
169
  let target = targets.get(key);
@@ -114,6 +172,7 @@ function mkBuildTargets(walk, connectionDigests, buildIdOpts) {
114
172
  buildId,
115
173
  connectionName,
116
174
  sql,
175
+ readsGivens,
117
176
  sources: [],
118
177
  dependsOn: new Set(),
119
178
  };
@@ -164,10 +223,19 @@ function mkBuildTargets(walk, connectionDigests, buildIdOpts) {
164
223
  // point both ways round a diamond.
165
224
  const built = new Map();
166
225
  for (const [key, partial] of targets) {
226
+ // Every source on a target compiles to the same SQL, so any of them can
227
+ // produce the build SQL; the manifest is the only thing the builder adds.
228
+ const [source] = partial.sources;
167
229
  built.set(key, {
168
230
  buildId: partial.buildId,
169
231
  connectionName: partial.connectionName,
170
232
  sql: partial.sql,
233
+ buildSQL: (manifest) => source._compileSQL({
234
+ ...buildIdOpts,
235
+ buildManifest: manifest,
236
+ connectionDigests,
237
+ }),
238
+ readsGivens: partial.readsGivens,
171
239
  sources: partial.sources,
172
240
  dependsOn: [],
173
241
  });
@@ -220,6 +288,6 @@ function mkBuildTargets(walk, connectionDigests, buildIdOpts) {
220
288
  for (const [connectionName, connectionTargets] of byConnection) {
221
289
  connections.push({ connectionName, targets: connectionTargets });
222
290
  }
223
- return connections;
291
+ return { connections, unbuildable };
224
292
  }
225
293
  //# sourceMappingURL=build_targets.js.map
@@ -35,7 +35,6 @@ export interface MalloyCompileOptions {
35
35
  noThrowOnError?: boolean;
36
36
  eventStream?: EventStream;
37
37
  importBaseURL?: URL;
38
- testEnvironment?: boolean;
39
38
  virtualMap?: VirtualMap;
40
39
  }
41
40
  export interface MalloyRunOptions {
@@ -88,9 +88,6 @@ class Malloy {
88
88
  const translator = new lang_1.MalloyTranslator(url.toString(), importBaseURL.toString(), {
89
89
  urls: { [url.toString()]: source },
90
90
  }, eventStream, (_a = options === null || options === void 0 ? void 0 : options.restrictedMode) !== null && _a !== void 0 ? _a : false);
91
- if (options === null || options === void 0 ? void 0 : options.testEnvironment) {
92
- translator.allDialectsEnabled = true;
93
- }
94
91
  return new document_1.Parse(translator, invalidationKey);
95
92
  }
96
93
  static parse({ url, urlReader, source, eventStream, options, }) {
@@ -1,5 +1,5 @@
1
1
  import type { LogMessage } from '../../lang';
2
- import type { BuildID, CompiledQuery, ConstantExpr, DocumentLocation, BooleanFieldDef, JSONFieldDef, NumberFieldDef, StringFieldDef, FilterCondition, Given as InternalGiven, GivenID, GivenTypeDef, Query as InternalQuery, Pipeline, ModelDef, DocumentPosition as ModelDocumentPosition, NamedQueryDef, StructDef, TurtleDef, NativeUnsupportedFieldDef, ImportLocation, AnnotationsDef, ModelAnnotationEntry, ModelID, NamedModelObject, AtomicFieldDef, DateFieldDef, ATimestampFieldDef, SourceDef, Argument, SourceComponentInfo, DocumentReference, PersistableSourceDef } from '../../model';
2
+ import type { BuildID, CompiledQuery, ConstantExpr, DocumentLocation, BooleanFieldDef, JSONFieldDef, NumberFieldDef, StringFieldDef, FilterCondition, Given as InternalGiven, GivenID, GivenTypeDef, Query as InternalQuery, Pipeline, ModelDef, DocumentPosition as ModelDocumentPosition, NamedQueryDef, StructDef, TurtleDef, NativeUnsupportedFieldDef, ImportLocation, AnnotationsDef, ModelAnnotationEntry, ModelID, NamedModelObject, AtomicFieldDef, DateFieldDef, ATimestampFieldDef, SourceDef, Argument, SourceComponentInfo, DocumentReference, PersistableSourceDef, PrepareResultOptions } from '../../model';
3
3
  import { QueryModel } from '../../model';
4
4
  import type { Dialect } from '../../dialect';
5
5
  import type { BuildGraph, CompileQueryOptions } from './types';
@@ -603,6 +603,8 @@ export declare class PersistSource implements Taggable {
603
603
  * @param connectionDigest - Digest from connection.getDigest()
604
604
  * @param sql - The SQL for this source (from getSQL())
605
605
  * @return The BuildID for manifest lookup
606
+ * @deprecated `BuildTarget.buildId` is already computed, under the build's
607
+ * own givens and `virtualMap`. Used only with `Model.getBuildPlan`.
606
608
  */
607
609
  makeBuildId(connectionDigest: string, sql: string): BuildID;
608
610
  /**
@@ -613,12 +615,22 @@ export declare class PersistSource implements Taggable {
613
615
  *
614
616
  * @param options - Compile options. `buildManifest` and `connectionDigests`
615
617
  * substitute already-built dependencies, giving the SQL to execute.
616
- * Anything that changes the SQL without them — `virtualMap` — must match
617
- * what the compiler will use, or the table is built under a key nothing
618
- * looks up.
619
618
  * @return The SQL string for this source.
619
+ * @deprecated Read `BuildTarget.sql` and call `BuildTarget.buildSQL()`. This
620
+ * generates SQL under whatever `options` say, so it can disagree with the key
621
+ * the build computed; the target's methods cannot. Used only with
622
+ * `Model.getBuildPlan`.
620
623
  */
621
624
  getSQL(options?: CompileQueryOptions): string;
625
+ /**
626
+ * This source's SQL under `opts`: the bare `SELECT`, not finalized, because
627
+ * `persistedTableFor` hashes the same unfinalized SELECT to look the table
628
+ * up, and a dialect with a final stage (Postgres) would hash differently.
629
+ *
630
+ * @internal `opts` is whatever the caller passes; `BuildTarget.sql` and
631
+ * `buildSQL()` pass the build's own.
632
+ */
633
+ _compileSQL(opts: PrepareResultOptions): string;
622
634
  /**
623
635
  * Get the underlying persistable source definition.
624
636
  */
@@ -1347,6 +1347,8 @@ class PersistSource {
1347
1347
  * @param connectionDigest - Digest from connection.getDigest()
1348
1348
  * @param sql - The SQL for this source (from getSQL())
1349
1349
  * @return The BuildID for manifest lookup
1350
+ * @deprecated `BuildTarget.buildId` is already computed, under the build's
1351
+ * own givens and `virtualMap`. Used only with `Model.getBuildPlan`.
1350
1352
  */
1351
1353
  makeBuildId(connectionDigest, sql) {
1352
1354
  return (0, source_def_utils_1.mkBuildID)(connectionDigest, sql);
@@ -1359,26 +1361,33 @@ class PersistSource {
1359
1361
  *
1360
1362
  * @param options - Compile options. `buildManifest` and `connectionDigests`
1361
1363
  * substitute already-built dependencies, giving the SQL to execute.
1362
- * Anything that changes the SQL without them — `virtualMap` — must match
1363
- * what the compiler will use, or the table is built under a key nothing
1364
- * looks up.
1365
1364
  * @return The SQL string for this source.
1365
+ * @deprecated Read `BuildTarget.sql` and call `BuildTarget.buildSQL()`. This
1366
+ * generates SQL under whatever `options` say, so it can disagree with the key
1367
+ * the build computed; the target's methods cannot. Used only with
1368
+ * `Model.getBuildPlan`.
1366
1369
  */
1367
1370
  getSQL(options) {
1371
+ return this._compileSQL({
1372
+ ...options,
1373
+ resolvedGivens: (0, given_binding_1.bindGivens)(options === null || options === void 0 ? void 0 : options.givens, this.model._modelDef),
1374
+ });
1375
+ }
1376
+ /**
1377
+ * This source's SQL under `opts`: the bare `SELECT`, not finalized, because
1378
+ * `persistedTableFor` hashes the same unfinalized SELECT to look the table
1379
+ * up, and a dialect with a final stage (Postgres) would hash differently.
1380
+ *
1381
+ * @internal `opts` is whatever the caller passes; `BuildTarget.sql` and
1382
+ * `buildSQL()` pass the build's own.
1383
+ */
1384
+ _compileSQL(opts) {
1368
1385
  const sd = this.persistableDef;
1369
1386
  const queryModel = this.model.queryModel;
1370
- // Compile with finalize=false so this SQL is the bare source SELECT.
1371
- // The build-time key (makeBuildId over this SQL) must equal the serve-time
1372
- // manifest lookup key, which persistedTableFor recomputes from the same
1373
- // unfinalized SELECT; finalizing would diverge the two on dialects with a
1374
- // final stage (Postgres) and mis-materialize the table.
1375
1387
  if (sd.type === 'sql_select') {
1376
- return (0, model_1.getCompiledSQL)(sd, options !== null && options !== void 0 ? options : {}, (query, opts) => queryModel.compileQuery(query, opts, false).sql);
1377
- }
1378
- else {
1379
- const compiled = queryModel.compileQuery(sd.query, options, false);
1380
- return compiled.sql;
1388
+ return (0, model_1.getCompiledSQL)(sd, opts, (query, o) => queryModel.compileQuery(query, o, false).sql);
1381
1389
  }
1390
+ return queryModel.compileQuery(sd.query, opts, false).sql;
1382
1391
  }
1383
1392
  /**
1384
1393
  * Get the underlying persistable source definition.
@@ -1503,18 +1512,9 @@ class PreparedQuery extends PipelineBase {
1503
1512
  */
1504
1513
  getPreparedResult(options) {
1505
1514
  const queryModel = this._model.queryModel;
1506
- // Build the resolved-givens map in two phases:
1507
- // 1. caller-supplied values (resolveSuppliedGivens)
1508
- // 2. inline-given defaults eager-evaluated against the map
1509
- // Result is undefined when no values land — preserves the previous
1510
- // "no givens path" downstream.
1511
- const resolved = (options === null || options === void 0 ? void 0 : options.givens)
1512
- ? (0, given_binding_1.resolveSuppliedGivens)(options.givens, this._modelDef)
1513
- : new Map();
1514
- (0, given_binding_1.evaluateInlineGivens)(resolved, this._modelDef);
1515
1515
  const prepareResultOptions = {
1516
1516
  ...options,
1517
- resolvedGivens: resolved.size > 0 ? resolved : undefined,
1517
+ resolvedGivens: (0, given_binding_1.bindGivens)(options === null || options === void 0 ? void 0 : options.givens, this._modelDef),
1518
1518
  };
1519
1519
  const translatedQuery = queryModel.compileQuery(this._query, prepareResultOptions);
1520
1520
  return new PreparedResult({
@@ -1,4 +1,4 @@
1
- export type { Taggable, Loggable, ParseOptions, CompileOptions, CompileQueryOptions, BuildNode, BuildGraph, BuildTarget, BuildTargets, ConnectionBuild, } from './types';
1
+ export type { Taggable, Loggable, ParseOptions, CompileOptions, CompileQueryOptions, BuildNode, BuildGraph, BuildTarget, BuildTargetOptions, BuildTargets, ConnectionBuild, UnbuildableSource, } from './types';
2
2
  export { EMPTY_BUILD_MANIFEST } from './types';
3
3
  export { EmptyURLReader, InMemoryURLReader, FixedConnectionMap, hashForInvalidationKey, isInternalURL, readURL, getInvalidationKey, } from './readers';
4
4
  export type { ModelCache, CachedModel } from './cache';
@@ -6,7 +6,7 @@ import type { Dialect } from '../../dialect';
6
6
  import type { RunSQLOptions } from '../../run_sql_options';
7
7
  import type { CacheManager } from './cache';
8
8
  import type { MalloyConfig } from './config';
9
- import type { ParseOptions, CompileOptions, CompileQueryOptions, BuildTargets } from './types';
9
+ import type { ParseOptions, CompileOptions, CompileQueryOptions, BuildTargets, BuildTargetOptions } from './types';
10
10
  import type { PreparedResult, Explore } from './core';
11
11
  import { Model, PreparedQuery } from './core';
12
12
  import type { DataRecord, Result } from './result';
@@ -42,7 +42,6 @@ declare class FluentState<T> {
42
42
  * An environment for compiling and running Malloy queries.
43
43
  */
44
44
  export declare class Runtime {
45
- isTestRuntime: boolean;
46
45
  private _urlReader;
47
46
  private _connections;
48
47
  private _eventStream;
@@ -103,6 +102,18 @@ export declare class Runtime {
103
102
  * the cached promise.
104
103
  */
105
104
  getGivens(): Promise<ReadonlyMap<string, GivenValue>>;
105
+ /**
106
+ * The given values one compile runs under: the config file's, then the
107
+ * constructor's, then `perCall`, each winning per key over the one before.
108
+ * Undefined when no layer supplies anything.
109
+ *
110
+ * A per-call value for a finalized given is refused before anything else
111
+ * happens: finalizing means the Runtime decides, and that holds for a build
112
+ * as it does for a query.
113
+ *
114
+ * @internal Accessed from QueryMaterializer and getBuildTargets.
115
+ */
116
+ _givensFor(perCall: Record<string, GivenValue> | undefined): Promise<Record<string, GivenValue> | undefined>;
106
117
  /**
107
118
  * Surface names of givens locked at the runtime layer (the resolved set
108
119
  * the `config.finalizeGivens` directive produced). Per-query supply for
@@ -293,10 +304,17 @@ export declare class Runtime {
293
304
  * in dependency order and each carries its own `dependsOn`. See
294
305
  * {@link BuildTargets}.
295
306
  *
307
+ * The build generates SQL under this Runtime's givens and `virtualMap`, with
308
+ * `options` layered over them, exactly as a query would; a persisted table
309
+ * is therefore found by the queries that run under the same values. A
310
+ * source whose SQL needs a value this build does not have is reported in
311
+ * `unbuildable`, not thrown.
312
+ *
296
313
  * @param model A compiled model with `##! experimental.persistence`
314
+ * @param options Given values and a `virtualMap` for this build
297
315
  * @return The targets to build, with any annotation parse messages
298
316
  */
299
- getBuildTargets(model: Model): Promise<BuildTargets>;
317
+ getBuildTargets(model: Model, options?: BuildTargetOptions): Promise<BuildTargets>;
300
318
  }
301
319
  export declare class ConnectionRuntime extends Runtime {
302
320
  readonly rawConnections: Connection[];
@@ -6,6 +6,7 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.ExploreMaterializer = exports.PreparedResultMaterializer = exports.QueryMaterializer = exports.ModelMaterializer = exports.SingleConnectionRuntime = exports.ConnectionRuntime = exports.Runtime = void 0;
8
8
  const model_1 = require("../../model");
9
+ const given_binding_1 = require("../../model/given_binding");
9
10
  const dialect_1 = require("../../dialect");
10
11
  const validate_table_path_1 = require("../../connection/validate_table_path");
11
12
  const config_1 = require("./config");
@@ -51,7 +52,6 @@ class FluentState {
51
52
  class Runtime {
52
53
  constructor({ urlReader, connections, connection, config, buildManifest, eventStream, cacheManager, givens, }) {
53
54
  var _a, _b;
54
- this.isTestRuntime = false;
55
55
  if (config !== undefined) {
56
56
  this._config = config;
57
57
  connections = connections !== null && connections !== void 0 ? connections : config.connections;
@@ -142,6 +142,33 @@ class Runtime {
142
142
  merged.set(k, v);
143
143
  return merged;
144
144
  }
145
+ /**
146
+ * The given values one compile runs under: the config file's, then the
147
+ * constructor's, then `perCall`, each winning per key over the one before.
148
+ * Undefined when no layer supplies anything.
149
+ *
150
+ * A per-call value for a finalized given is refused before anything else
151
+ * happens: finalizing means the Runtime decides, and that holds for a build
152
+ * as it does for a query.
153
+ *
154
+ * @internal Accessed from QueryMaterializer and getBuildTargets.
155
+ */
156
+ async _givensFor(perCall) {
157
+ if (this._finalizedGivensSet.size > 0 && perCall) {
158
+ for (const name of Object.keys(perCall)) {
159
+ if (this._finalizedGivensSet.has(name)) {
160
+ throw new model_1.MalloyCompileError(`Cannot supply given '${name}' per call: it is finalized at ` +
161
+ 'the runtime layer via `config.finalizeGivens`.', 'runtime-given-finalized', undefined);
162
+ }
163
+ }
164
+ }
165
+ const fileGivens = await this._resolveGivens();
166
+ const constructorGivens = mapToRecord(this._constructorGivensMap);
167
+ const haveAny = fileGivens || constructorGivens || perCall;
168
+ return haveAny
169
+ ? { ...fileGivens, ...constructorGivens, ...perCall }
170
+ : undefined;
171
+ }
145
172
  /**
146
173
  * Surface names of givens locked at the runtime layer (the resolved set
147
174
  * the `config.finalizeGivens` directive produced). Per-query supply for
@@ -350,14 +377,6 @@ class Runtime {
350
377
  */
351
378
  loadModel(source, options) {
352
379
  const { refreshSchemaCache, noThrowOnError } = options || {};
353
- if (this.isTestRuntime) {
354
- if (options === undefined) {
355
- options = { testEnvironment: true };
356
- }
357
- else {
358
- options = { ...options, testEnvironment: true };
359
- }
360
- }
361
380
  const compilable = source instanceof URL ? { url: source } : { source };
362
381
  return new ModelMaterializer(this, async () => {
363
382
  var _a;
@@ -369,7 +388,6 @@ class Runtime {
369
388
  noThrowOnError,
370
389
  eventStream: this.eventStream,
371
390
  importBaseURL: options === null || options === void 0 ? void 0 : options.importBaseURL,
372
- testEnvironment: options === null || options === void 0 ? void 0 : options.testEnvironment,
373
391
  cacheManager: this.cacheManager,
374
392
  virtualMap: (_a = options === null || options === void 0 ? void 0 : options.virtualMap) !== null && _a !== void 0 ? _a : this.virtualMap,
375
393
  });
@@ -491,10 +509,18 @@ class Runtime {
491
509
  * in dependency order and each carries its own `dependsOn`. See
492
510
  * {@link BuildTargets}.
493
511
  *
512
+ * The build generates SQL under this Runtime's givens and `virtualMap`, with
513
+ * `options` layered over them, exactly as a query would; a persisted table
514
+ * is therefore found by the queries that run under the same values. A
515
+ * source whose SQL needs a value this build does not have is reported in
516
+ * `unbuildable`, not thrown.
517
+ *
494
518
  * @param model A compiled model with `##! experimental.persistence`
519
+ * @param options Given values and a `virtualMap` for this build
495
520
  * @return The targets to build, with any annotation parse messages
496
521
  */
497
- async getBuildTargets(model) {
522
+ async getBuildTargets(model, options) {
523
+ var _a;
498
524
  const tagParseLog = [];
499
525
  const walk = (0, build_targets_1.resolvePersistWalk)(model, tagParseLog);
500
526
  const connectionDigests = (0, model_1.mkSafeRecord)();
@@ -507,12 +533,12 @@ class Runtime {
507
533
  connectionDigests[connectionName] = connection.getDigest();
508
534
  }
509
535
  }
510
- return {
511
- connections: (0, build_targets_1.mkBuildTargets)(walk, connectionDigests, {
512
- virtualMap: this.virtualMap,
513
- }),
514
- tagParseLog,
515
- };
536
+ const givens = await this._givensFor(options === null || options === void 0 ? void 0 : options.givens);
537
+ const { connections, unbuildable } = (0, build_targets_1.mkBuildTargets)(walk, connectionDigests, {
538
+ virtualMap: (_a = options === null || options === void 0 ? void 0 : options.virtualMap) !== null && _a !== void 0 ? _a : this.virtualMap,
539
+ resolvedGivens: (0, given_binding_1.bindGivens)(givens, model._modelDef),
540
+ });
541
+ return { connections, tagParseLog, unbuildable };
516
542
  }
517
543
  }
518
544
  exports.Runtime = Runtime;
@@ -631,7 +657,7 @@ class ModelMaterializer extends FluentState {
631
657
  // `restrictedMode` and `method` are named to hold them back: this entry
632
658
  // point has never honored them, and `loadRestrictedQuery` is how a caller
633
659
  // asks for restricted compilation.
634
- const { importBaseURL, testEnvironment, refreshSchemaCache, noThrowOnError, restrictedMode: _restrictedMode, method: _method, ...callQueryOptions } = options !== null && options !== void 0 ? options : {};
660
+ const { importBaseURL, refreshSchemaCache, noThrowOnError, restrictedMode: _restrictedMode, method: _method, ...callQueryOptions } = options !== null && options !== void 0 ? options : {};
635
661
  const compileQueryOptions = {
636
662
  ...this.compileQueryOptions,
637
663
  ...callQueryOptions,
@@ -647,7 +673,6 @@ class ModelMaterializer extends FluentState {
647
673
  refreshSchemaCache,
648
674
  noThrowOnError,
649
675
  importBaseURL,
650
- testEnvironment: testEnvironment || this.runtime.isTestRuntime,
651
676
  ...compileQueryOptions,
652
677
  virtualMap: (_a = compileQueryOptions.virtualMap) !== null && _a !== void 0 ? _a : this.runtime.virtualMap,
653
678
  });
@@ -701,7 +726,6 @@ class ModelMaterializer extends FluentState {
701
726
  return this.makeQueryMaterializer(async () => {
702
727
  const urlReader = this.runtime.urlReader;
703
728
  const connections = this.runtime.connections;
704
- const testEnvironment = this.runtime.isTestRuntime ? true : undefined;
705
729
  const model = await this.getModel();
706
730
  const queryModel = await compile_1.Malloy.compile({
707
731
  source: text,
@@ -710,7 +734,6 @@ class ModelMaterializer extends FluentState {
710
734
  urlReader,
711
735
  connections,
712
736
  model,
713
- testEnvironment,
714
737
  ...this.compileQueryOptions,
715
738
  });
716
739
  return queryModel.preparedQuery;
@@ -726,14 +749,6 @@ class ModelMaterializer extends FluentState {
726
749
  extendModel(query, options) {
727
750
  var _a, _b;
728
751
  const virtualMap = (_a = options === null || options === void 0 ? void 0 : options.virtualMap) !== null && _a !== void 0 ? _a : (_b = this.compileQueryOptions) === null || _b === void 0 ? void 0 : _b.virtualMap;
729
- if (this.runtime.isTestRuntime) {
730
- if (options === undefined) {
731
- options = { testEnvironment: true };
732
- }
733
- else {
734
- options = { ...options, testEnvironment: true };
735
- }
736
- }
737
752
  return new ModelMaterializer(this.runtime, async () => {
738
753
  const urlReader = this.runtime.urlReader;
739
754
  const connections = this.runtime.connections;
@@ -748,7 +763,6 @@ class ModelMaterializer extends FluentState {
748
763
  refreshSchemaCache: options === null || options === void 0 ? void 0 : options.refreshSchemaCache,
749
764
  noThrowOnError: options === null || options === void 0 ? void 0 : options.noThrowOnError,
750
765
  importBaseURL: options === null || options === void 0 ? void 0 : options.importBaseURL,
751
- testEnvironment: options === null || options === void 0 ? void 0 : options.testEnvironment,
752
766
  ...this.compileQueryOptions,
753
767
  virtualMap: virtualMap !== null && virtualMap !== void 0 ? virtualMap : this.runtime.virtualMap,
754
768
  });
@@ -1067,31 +1081,8 @@ class QueryMaterializer extends FluentState {
1067
1081
  }
1068
1082
  }
1069
1083
  const virtualMap = (_b = mergedOptions.virtualMap) !== null && _b !== void 0 ? _b : this.runtime.virtualMap;
1070
- // Per-query supply for a finalized given is rejected at API entry
1071
- // — the finalized-givens set is the runtime's "this can't be
1072
- // overridden by the caller" guarantee. Fail before any IO so misuse
1073
- // is loud.
1084
+ const mergedGivens = await this.runtime._givensFor(mergedOptions.givens);
1074
1085
  const finalizedSet = this.runtime._finalizedGivens;
1075
- if (finalizedSet.size > 0 && mergedOptions.givens) {
1076
- for (const name of Object.keys(mergedOptions.givens)) {
1077
- if (finalizedSet.has(name)) {
1078
- throw new model_1.MalloyCompileError(`Cannot supply given '${name}' per-query: it is finalized at ` +
1079
- 'the runtime layer via `config.finalizeGivens`.', 'runtime-given-finalized', undefined);
1080
- }
1081
- }
1082
- }
1083
- // Three layers of givens, merged per-key in precedence order:
1084
- // 1. config.givensURL file (lazy + cached)
1085
- // 2. Runtime constructor `givens:` option
1086
- // 3. Per-query supply via `.run({givens: ...})`
1087
- // Higher-numbered layers win on collision. Each layer is optional;
1088
- // the merge collapses to undefined when all three are absent.
1089
- const fileGivens = await this.runtime._resolveGivens();
1090
- const constructorGivens = mapToRecord(this.runtime._constructorGivens);
1091
- const haveAny = fileGivens || constructorGivens || mergedOptions.givens;
1092
- const mergedGivens = haveAny
1093
- ? { ...fileGivens, ...constructorGivens, ...mergedOptions.givens }
1094
- : undefined;
1095
1086
  // Query-scoped validation: of the givens THIS query references,
1096
1087
  // any that are finalized must have a value somewhere (file or
1097
1088
  // constructor). One config covers a project; individual files
@@ -20,7 +20,6 @@ export interface Loggable {
20
20
  }
21
21
  export interface ParseOptions {
22
22
  importBaseURL?: URL;
23
- testEnvironment?: boolean;
24
23
  /** Reject language constructs that reach outside the trusted model. */
25
24
  restrictedMode?: boolean;
26
25
  /**
@@ -108,11 +107,23 @@ export interface BuildTarget {
108
107
  * The SQL the BuildID is computed from: fully inlined, no manifest
109
108
  * substitution, so it is the same string whatever else has been built.
110
109
  *
111
- * It is not the SQL to execute. That one substitutes the tables built so far
112
- * — `source.getSQL({buildManifest, connectionDigests})` — so it can only be
113
- * computed as the build walks, and only by the builder holding the manifest.
110
+ * It is not the SQL to execute; that is {@link buildSQL}.
114
111
  */
115
112
  sql: string;
113
+ /**
114
+ * The SQL to execute, for a `CREATE TABLE`. Dependencies already in
115
+ * `manifest` are read from their tables rather than recomputed, which is
116
+ * why it is a call made as the build proceeds and not a string computed up
117
+ * front. Generated under the same givens and `virtualMap` as `sql`, so the
118
+ * table that is built is the one the key describes.
119
+ */
120
+ buildSQL(manifest: BuildManifest): string;
121
+ /**
122
+ * True when the SQL reads a given, supplied or defaulted. The table is then
123
+ * one of possibly several for this source, one per value, and a builder
124
+ * naming it by `name=` alone would build every variant under one name.
125
+ */
126
+ readsGivens: boolean;
116
127
  /** Targets that must exist before this one can be built */
117
128
  dependsOn: BuildTarget[];
118
129
  /** Every persist source in the model that maps onto this artifact */
@@ -153,6 +164,32 @@ export interface ConnectionBuild {
153
164
  /** Every table to build, dependencies before dependents */
154
165
  targets: BuildTarget[];
155
166
  }
167
+ /**
168
+ * A persist source with no BuildID, because its SQL cannot be written: it
169
+ * reads a given that has no value in this build, a virtual source the build's
170
+ * `virtualMap` has no entry for, or anything else the compiler reports as a
171
+ * problem with the source rather than with itself. A source that reads it
172
+ * inlines its SQL, so is reported here too.
173
+ */
174
+ export interface UnbuildableSource {
175
+ source: PersistSource;
176
+ /** Why no BuildID could be computed, as a query would report it */
177
+ problem: LogMessage;
178
+ }
179
+ /**
180
+ * What a build generates SQL under, over the Runtime's own values.
181
+ *
182
+ * `givens` layers over the Runtime's file and constructor givens the way a
183
+ * query's do, and a finalized given is refused here the same way. Running
184
+ * `getBuildTargets` once per set of values is how a model whose persisted
185
+ * sources read a given gets one table per value.
186
+ */
187
+ export interface BuildTargetOptions {
188
+ /** Given values for this build, by surface name, over the Runtime's */
189
+ givens?: Record<string, GivenValue>;
190
+ /** Which table each virtual source reads; the Runtime's when omitted */
191
+ virtualMap?: VirtualMap;
192
+ }
156
193
  /**
157
194
  * The build schedule for a model.
158
195
  *
@@ -166,4 +203,6 @@ export interface BuildTargets {
166
203
  connections: ConnectionBuild[];
167
204
  /** Errors and warnings from parsing `#@` annotations on persistable sources */
168
205
  tagParseLog: LogMessage[];
206
+ /** Persist sources with no table to build, each with the reason */
207
+ unbuildable: UnbuildableSource[];
169
208
  }
@@ -0,0 +1,29 @@
1
+ import type { AnnotationsDef } from '../model/malloy_types';
2
+ import type { ConnectionPropertyDefinition } from './registry';
3
+ /**
4
+ * The annotation route a connection writes database metadata to:
5
+ * `#(dbmeta) description="..."`.
6
+ */
7
+ export declare const DBMETA_ROUTE = "dbmeta";
8
+ /**
9
+ * The connection property that turns on database metadata. Connections that
10
+ * support it register this definition, so the option has the same name and
11
+ * meaning on every backend. Off unless set.
12
+ */
13
+ export declare const dbmetaProperty: ConnectionPropertyDefinition;
14
+ /**
15
+ * Metadata a connection read from the database for one table or column.
16
+ * Keys are normalized across databases: whatever a database calls it (a
17
+ * description, a COMMENT), it arrives here as `description`.
18
+ */
19
+ export interface DbMeta {
20
+ description?: string | null;
21
+ }
22
+ /**
23
+ * The `#(dbmeta)` annotation for a table or column, as a fragment to spread
24
+ * into its field or table def: `{annotations}`, or `{}` when there is nothing
25
+ * to say.
26
+ */
27
+ export declare function dbmetaAnnotations(meta: DbMeta): {
28
+ annotations?: AnnotationsDef;
29
+ };