@malloydata/malloy 0.0.344 → 0.0.346

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.
@@ -1,6 +1,6 @@
1
1
  import type { LogMessage } from '../../lang';
2
2
  import type { Connection, InfoConnection, LookupConnection, FetchSchemaOptions } from '../../connection/types';
3
- import type { ConnectionTypeDef, ConnectionPropertyDefinition, ConnectionsConfig } from '../../connection/registry';
3
+ import type { ConnectionTypeDef, ConnectionPropertyDefinition } from '../../connection/registry';
4
4
  import type { URLReader, EventStream } from '../../runtime_types';
5
5
  import type { SQLSourceDef, QueryRunStats } from '../../model';
6
6
  import type { RunSQLOptions } from '../../run_sql_options';
@@ -73,18 +73,6 @@ export declare class Malloy {
73
73
  * Get the names of all registered connection types.
74
74
  */
75
75
  static getRegisteredConnectionTypes(): string[];
76
- /**
77
- * Parse a JSON config string into an editable ConnectionsConfig.
78
- */
79
- static readConnectionsConfig(jsonText: string): ConnectionsConfig;
80
- /**
81
- * Serialize a ConnectionsConfig to a JSON string.
82
- */
83
- static writeConnectionsConfig(config: ConnectionsConfig): string;
84
- /**
85
- * Create a LookupConnection from a ConnectionsConfig using registered factories.
86
- */
87
- static createConnectionsFromConfig(config: ConnectionsConfig): LookupConnection<Connection>;
88
76
  private static _parse;
89
77
  /**
90
78
  * Parse a Malloy document by URL.
@@ -69,24 +69,6 @@ class Malloy {
69
69
  static getRegisteredConnectionTypes() {
70
70
  return (0, registry_1.getRegisteredConnectionTypes)();
71
71
  }
72
- /**
73
- * Parse a JSON config string into an editable ConnectionsConfig.
74
- */
75
- static readConnectionsConfig(jsonText) {
76
- return (0, registry_1.readConnectionsConfig)(jsonText);
77
- }
78
- /**
79
- * Serialize a ConnectionsConfig to a JSON string.
80
- */
81
- static writeConnectionsConfig(config) {
82
- return (0, registry_1.writeConnectionsConfig)(config);
83
- }
84
- /**
85
- * Create a LookupConnection from a ConnectionsConfig using registered factories.
86
- */
87
- static createConnectionsFromConfig(config) {
88
- return (0, registry_1.createConnectionsFromConfig)(config);
89
- }
90
72
  static _parse(source, url, eventStream, options, invalidationKey) {
91
73
  if (url === undefined) {
92
74
  url = new URL(MALLOY_INTERNAL_URL);
@@ -0,0 +1,116 @@
1
+ import type { URLReader } from '../../runtime_types';
2
+ import type { Connection, LookupConnection } from '../../connection/types';
3
+ import type { ConnectionConfigEntry } from '../../connection/registry';
4
+ import type { BuildID, BuildManifest, BuildManifestEntry } from '../../model/malloy_types';
5
+ /**
6
+ * The parsed contents of a malloy-config.json file.
7
+ */
8
+ export interface MalloyProjectConfig {
9
+ connections?: Record<string, ConnectionConfigEntry>;
10
+ manifestPath?: string;
11
+ }
12
+ /**
13
+ * In-memory manifest store. Reads, updates, and serializes manifest data.
14
+ *
15
+ * Always valid — starts empty, call load() to populate from a file.
16
+ * The internal BuildManifest object is stable: load() and update() mutate
17
+ * the same object, so any reference obtained via `buildManifest` stays current.
18
+ */
19
+ export declare class Manifest {
20
+ private readonly _urlReader?;
21
+ private readonly _data;
22
+ private readonly _touched;
23
+ constructor(urlReader?: URLReader);
24
+ /**
25
+ * Load manifest data from a manifest root directory.
26
+ * Reads `<manifestRoot>/malloy-manifest.json` via the URLReader.
27
+ * Replaces any existing data. If the file doesn't exist or no URLReader
28
+ * is available, clears to empty.
29
+ */
30
+ load(manifestRoot: URL): Promise<void>;
31
+ /**
32
+ * Load manifest data from a JSON string.
33
+ * Replaces any existing data.
34
+ */
35
+ loadText(jsonText: string): void;
36
+ /**
37
+ * The live BuildManifest. This is a stable reference — load() and update()
38
+ * mutate the same object, so passing this to a Runtime means the Runtime
39
+ * always sees current data.
40
+ */
41
+ get buildManifest(): BuildManifest;
42
+ /**
43
+ * Add or replace a manifest entry. Also marks it as touched.
44
+ */
45
+ update(buildId: BuildID, entry: BuildManifestEntry): void;
46
+ /**
47
+ * Mark an existing entry as active without changing it.
48
+ * Use this for entries that already exist and don't need rebuilding.
49
+ */
50
+ touch(buildId: BuildID): void;
51
+ /**
52
+ * Returns only entries that were update()d or touch()ed.
53
+ * This is the manifest a builder should write — it reflects
54
+ * exactly what the current build references.
55
+ */
56
+ get activeEntries(): BuildManifest;
57
+ }
58
+ /**
59
+ * Loads and holds a Malloy project configuration (connections + manifest).
60
+ *
61
+ * Two construction modes:
62
+ *
63
+ * // From a URL — reads config + manifest via URLReader
64
+ * const config = new MalloyConfig(urlReader, configURL);
65
+ * await config.load();
66
+ *
67
+ * // From text you already have
68
+ * const config = new MalloyConfig(configText);
69
+ *
70
+ * // Either way, construct Runtime the same way
71
+ * const runtime = new Runtime({
72
+ * urlReader,
73
+ * connections: config.connections,
74
+ * buildManifest: config.manifest.buildManifest,
75
+ * });
76
+ */
77
+ export declare class MalloyConfig {
78
+ private readonly _urlReader?;
79
+ private readonly _configURL?;
80
+ private _data;
81
+ private _connectionMap;
82
+ private readonly _manifest;
83
+ constructor(configText: string);
84
+ constructor(urlReader: URLReader, configURL: string);
85
+ /**
86
+ * Load everything: parse config file, then load the default manifest.
87
+ * No-op if created from text.
88
+ */
89
+ load(): Promise<void>;
90
+ /**
91
+ * Load only the config file. Does not load the manifest.
92
+ * No-op if created from text.
93
+ */
94
+ loadConfig(): Promise<void>;
95
+ /**
96
+ * The parsed config data. Undefined if created from URL and not yet loaded.
97
+ */
98
+ get data(): MalloyProjectConfig | undefined;
99
+ /**
100
+ * The active connection entries. Set this to override which connections
101
+ * are used before constructing a Runtime.
102
+ */
103
+ get connectionMap(): Record<string, ConnectionConfigEntry> | undefined;
104
+ set connectionMap(map: Record<string, ConnectionConfigEntry>);
105
+ /**
106
+ * A LookupConnection built from the current connectionMap via the
107
+ * connection type registry. Each access creates a fresh snapshot —
108
+ * changing connectionMap after this does not affect previously-returned
109
+ * LookupConnections.
110
+ */
111
+ get connections(): LookupConnection<Connection>;
112
+ /**
113
+ * The Manifest object. Always exists, may be empty if not yet loaded.
114
+ */
115
+ get manifest(): Manifest;
116
+ }
@@ -0,0 +1,211 @@
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.MalloyConfig = exports.Manifest = void 0;
8
+ const registry_1 = require("../../connection/registry");
9
+ const DEFAULT_MANIFEST_PATH = 'MANIFESTS';
10
+ const MANIFEST_FILENAME = 'malloy-manifest.json';
11
+ /**
12
+ * In-memory manifest store. Reads, updates, and serializes manifest data.
13
+ *
14
+ * Always valid — starts empty, call load() to populate from a file.
15
+ * The internal BuildManifest object is stable: load() and update() mutate
16
+ * the same object, so any reference obtained via `buildManifest` stays current.
17
+ */
18
+ class Manifest {
19
+ constructor(urlReader) {
20
+ this._data = {};
21
+ this._touched = new Set();
22
+ this._urlReader = urlReader;
23
+ }
24
+ /**
25
+ * Load manifest data from a manifest root directory.
26
+ * Reads `<manifestRoot>/malloy-manifest.json` via the URLReader.
27
+ * Replaces any existing data. If the file doesn't exist or no URLReader
28
+ * is available, clears to empty.
29
+ */
30
+ async load(manifestRoot) {
31
+ // Clear existing entries and touched set
32
+ for (const key of Object.keys(this._data)) {
33
+ delete this._data[key];
34
+ }
35
+ this._touched.clear();
36
+ if (!this._urlReader)
37
+ return;
38
+ const dir = manifestRoot.toString().endsWith('/')
39
+ ? manifestRoot.toString()
40
+ : manifestRoot.toString() + '/';
41
+ const manifestURL = new URL(MANIFEST_FILENAME, dir);
42
+ let contents;
43
+ try {
44
+ const result = await this._urlReader.readURL(manifestURL);
45
+ contents = typeof result === 'string' ? result : result.contents;
46
+ }
47
+ catch {
48
+ // No manifest file — stay empty
49
+ return;
50
+ }
51
+ const loaded = JSON.parse(contents);
52
+ Object.assign(this._data, loaded);
53
+ }
54
+ /**
55
+ * Load manifest data from a JSON string.
56
+ * Replaces any existing data.
57
+ */
58
+ loadText(jsonText) {
59
+ for (const key of Object.keys(this._data)) {
60
+ delete this._data[key];
61
+ }
62
+ this._touched.clear();
63
+ const loaded = JSON.parse(jsonText);
64
+ Object.assign(this._data, loaded);
65
+ }
66
+ /**
67
+ * The live BuildManifest. This is a stable reference — load() and update()
68
+ * mutate the same object, so passing this to a Runtime means the Runtime
69
+ * always sees current data.
70
+ */
71
+ get buildManifest() {
72
+ return this._data;
73
+ }
74
+ /**
75
+ * Add or replace a manifest entry. Also marks it as touched.
76
+ */
77
+ update(buildId, entry) {
78
+ this._data[buildId] = entry;
79
+ this._touched.add(buildId);
80
+ }
81
+ /**
82
+ * Mark an existing entry as active without changing it.
83
+ * Use this for entries that already exist and don't need rebuilding.
84
+ */
85
+ touch(buildId) {
86
+ this._touched.add(buildId);
87
+ }
88
+ /**
89
+ * Returns only entries that were update()d or touch()ed.
90
+ * This is the manifest a builder should write — it reflects
91
+ * exactly what the current build references.
92
+ */
93
+ get activeEntries() {
94
+ const result = {};
95
+ for (const id of this._touched) {
96
+ if (this._data[id]) {
97
+ result[id] = this._data[id];
98
+ }
99
+ }
100
+ return result;
101
+ }
102
+ }
103
+ exports.Manifest = Manifest;
104
+ /**
105
+ * Loads and holds a Malloy project configuration (connections + manifest).
106
+ *
107
+ * Two construction modes:
108
+ *
109
+ * // From a URL — reads config + manifest via URLReader
110
+ * const config = new MalloyConfig(urlReader, configURL);
111
+ * await config.load();
112
+ *
113
+ * // From text you already have
114
+ * const config = new MalloyConfig(configText);
115
+ *
116
+ * // Either way, construct Runtime the same way
117
+ * const runtime = new Runtime({
118
+ * urlReader,
119
+ * connections: config.connections,
120
+ * buildManifest: config.manifest.buildManifest,
121
+ * });
122
+ */
123
+ class MalloyConfig {
124
+ constructor(urlReaderOrText, configURL) {
125
+ if (typeof urlReaderOrText === 'string') {
126
+ this._data = parseConfigText(urlReaderOrText);
127
+ this._connectionMap = this._data.connections
128
+ ? { ...this._data.connections }
129
+ : undefined;
130
+ this._manifest = new Manifest();
131
+ }
132
+ else {
133
+ this._urlReader = urlReaderOrText;
134
+ this._configURL = configURL;
135
+ this._manifest = new Manifest(urlReaderOrText);
136
+ }
137
+ }
138
+ /**
139
+ * Load everything: parse config file, then load the default manifest.
140
+ * No-op if created from text.
141
+ */
142
+ async load() {
143
+ var _a, _b;
144
+ await this.loadConfig();
145
+ if (this._configURL) {
146
+ const manifestPath = (_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a.manifestPath) !== null && _b !== void 0 ? _b : DEFAULT_MANIFEST_PATH;
147
+ const manifestRoot = new URL(manifestPath, this._configURL);
148
+ await this._manifest.load(manifestRoot);
149
+ }
150
+ }
151
+ /**
152
+ * Load only the config file. Does not load the manifest.
153
+ * No-op if created from text.
154
+ */
155
+ async loadConfig() {
156
+ if (!this._urlReader || !this._configURL)
157
+ return;
158
+ const result = await this._urlReader.readURL(new URL(this._configURL));
159
+ const contents = typeof result === 'string' ? result : result.contents;
160
+ this._data = parseConfigText(contents);
161
+ this._connectionMap = this._data.connections
162
+ ? { ...this._data.connections }
163
+ : undefined;
164
+ }
165
+ /**
166
+ * The parsed config data. Undefined if created from URL and not yet loaded.
167
+ */
168
+ get data() {
169
+ return this._data;
170
+ }
171
+ /**
172
+ * The active connection entries. Set this to override which connections
173
+ * are used before constructing a Runtime.
174
+ */
175
+ get connectionMap() {
176
+ return this._connectionMap;
177
+ }
178
+ set connectionMap(map) {
179
+ this._connectionMap = map;
180
+ }
181
+ /**
182
+ * A LookupConnection built from the current connectionMap via the
183
+ * connection type registry. Each access creates a fresh snapshot —
184
+ * changing connectionMap after this does not affect previously-returned
185
+ * LookupConnections.
186
+ */
187
+ get connections() {
188
+ if (!this._connectionMap) {
189
+ throw new Error('Config not loaded. Call load() or loadConfig() first.');
190
+ }
191
+ return (0, registry_1.createConnectionsFromConfig)({ connections: this._connectionMap });
192
+ }
193
+ /**
194
+ * The Manifest object. Always exists, may be empty if not yet loaded.
195
+ */
196
+ get manifest() {
197
+ return this._manifest;
198
+ }
199
+ }
200
+ exports.MalloyConfig = MalloyConfig;
201
+ /**
202
+ * Parse a config JSON string into a MalloyProjectConfig.
203
+ * Invalid connection entries (missing `is`) are silently dropped.
204
+ */
205
+ function parseConfigText(jsonText) {
206
+ var _a;
207
+ const parsed = JSON.parse(jsonText);
208
+ const connections = Object.fromEntries(Object.entries((_a = parsed.connections) !== null && _a !== void 0 ? _a : {}).filter(([, v]) => (0, registry_1.isConnectionConfigEntry)(v)));
209
+ return { ...parsed, connections };
210
+ }
211
+ //# sourceMappingURL=config.js.map
@@ -7,4 +7,5 @@ export { SourceRelationship, AtomicFieldType, DateTimeframe, TimestampTimeframe,
7
7
  export { type ResultJSON, type DataColumn, type DataArrayOrRecord, Result, DataArray, DataRecord, } from './result';
8
8
  export { type WriteStream, DataWriter, JSONWriter, CSVWriter } from './writers';
9
9
  export { Runtime, ConnectionRuntime, SingleConnectionRuntime, ModelMaterializer, QueryMaterializer, PreparedResultMaterializer, ExploreMaterializer, } from './runtime';
10
+ export { Manifest, MalloyConfig } from './config';
10
11
  export { Malloy, MalloyError, type MalloyCompileOptions, type MalloyRunOptions, } from './compile';
@@ -4,8 +4,8 @@
4
4
  * SPDX-License-Identifier: MIT
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.Malloy = exports.ExploreMaterializer = exports.PreparedResultMaterializer = exports.QueryMaterializer = exports.ModelMaterializer = exports.SingleConnectionRuntime = exports.ConnectionRuntime = exports.Runtime = exports.CSVWriter = exports.JSONWriter = exports.DataWriter = exports.DataRecord = exports.DataArray = exports.Result = exports.PreparedResult = exports.PreparedQuery = exports.PersistSource = exports.Model = exports.QueryField = exports.Query = exports.StringField = exports.UnsupportedField = exports.JSONField = exports.BooleanField = exports.NumberField = exports.TimestampField = exports.DateField = exports.AtomicField = exports.ExploreField = exports.Explore = exports.JoinRelationship = exports.TimestampTimeframe = exports.DateTimeframe = exports.AtomicFieldType = exports.SourceRelationship = exports.DocumentCompletion = exports.DocumentSymbol = exports.DocumentPosition = exports.DocumentRange = exports.DocumentTablePath = exports.Parse = exports.InMemoryModelCache = exports.CacheManager = exports.getInvalidationKey = exports.readURL = exports.isInternalURL = exports.hashForInvalidationKey = exports.FixedConnectionMap = exports.InMemoryURLReader = exports.EmptyURLReader = void 0;
8
- exports.MalloyError = void 0;
7
+ exports.Manifest = exports.ExploreMaterializer = exports.PreparedResultMaterializer = exports.QueryMaterializer = exports.ModelMaterializer = exports.SingleConnectionRuntime = exports.ConnectionRuntime = exports.Runtime = exports.CSVWriter = exports.JSONWriter = exports.DataWriter = exports.DataRecord = exports.DataArray = exports.Result = exports.PreparedResult = exports.PreparedQuery = exports.PersistSource = exports.Model = exports.QueryField = exports.Query = exports.StringField = exports.UnsupportedField = exports.JSONField = exports.BooleanField = exports.NumberField = exports.TimestampField = exports.DateField = exports.AtomicField = exports.ExploreField = exports.Explore = exports.JoinRelationship = exports.TimestampTimeframe = exports.DateTimeframe = exports.AtomicFieldType = exports.SourceRelationship = exports.DocumentCompletion = exports.DocumentSymbol = exports.DocumentPosition = exports.DocumentRange = exports.DocumentTablePath = exports.Parse = exports.InMemoryModelCache = exports.CacheManager = exports.getInvalidationKey = exports.readURL = exports.isInternalURL = exports.hashForInvalidationKey = exports.FixedConnectionMap = exports.InMemoryURLReader = exports.EmptyURLReader = void 0;
8
+ exports.MalloyError = exports.Malloy = exports.MalloyConfig = void 0;
9
9
  // URL readers and connection helpers
10
10
  var readers_1 = require("./readers");
11
11
  Object.defineProperty(exports, "EmptyURLReader", { enumerable: true, get: function () { return readers_1.EmptyURLReader; } });
@@ -70,6 +70,10 @@ Object.defineProperty(exports, "ModelMaterializer", { enumerable: true, get: fun
70
70
  Object.defineProperty(exports, "QueryMaterializer", { enumerable: true, get: function () { return runtime_1.QueryMaterializer; } });
71
71
  Object.defineProperty(exports, "PreparedResultMaterializer", { enumerable: true, get: function () { return runtime_1.PreparedResultMaterializer; } });
72
72
  Object.defineProperty(exports, "ExploreMaterializer", { enumerable: true, get: function () { return runtime_1.ExploreMaterializer; } });
73
+ // Config and Manifest
74
+ var config_1 = require("./config");
75
+ Object.defineProperty(exports, "Manifest", { enumerable: true, get: function () { return config_1.Manifest; } });
76
+ Object.defineProperty(exports, "MalloyConfig", { enumerable: true, get: function () { return config_1.MalloyConfig; } });
73
77
  // Compile (Malloy static class)
74
78
  var compile_1 = require("./compile");
75
79
  Object.defineProperty(exports, "Malloy", { enumerable: true, get: function () { return compile_1.Malloy; } });
@@ -1,6 +1,6 @@
1
1
  import type { Connection, LookupConnection } from '../../connection/types';
2
2
  import type { URLReader, EventStream } from '../../runtime_types';
3
- import type { ModelDef, Query as InternalQuery, SearchIndexResult, SearchValueMapResult, QueryRunStats } from '../../model';
3
+ import type { ModelDef, Query as InternalQuery, SearchIndexResult, SearchValueMapResult, QueryRunStats, BuildManifest } from '../../model';
4
4
  import type { Dialect } from '../../dialect';
5
5
  import type { RunSQLOptions } from '../../run_sql_options';
6
6
  import type { CacheManager } from './cache';
@@ -39,10 +39,12 @@ export declare class Runtime {
39
39
  private _connections;
40
40
  private _eventStream;
41
41
  private _cacheManager;
42
- constructor({ urlReader, connections, connection, eventStream, cacheManager, }: {
42
+ private _buildManifest;
43
+ constructor({ urlReader, connections, connection, eventStream, cacheManager, buildManifest, }: {
43
44
  urlReader?: URLReader;
44
45
  eventStream?: EventStream;
45
46
  cacheManager?: CacheManager;
47
+ buildManifest?: BuildManifest;
46
48
  } & Connectionable);
47
49
  /**
48
50
  * @return The `CacheManager` for this runtime instance.
@@ -60,6 +62,14 @@ export declare class Runtime {
60
62
  * @return The `EventStream` for this runtime instance.
61
63
  */
62
64
  get eventStream(): EventStream | undefined;
65
+ /**
66
+ * The build manifest for persist source substitution.
67
+ * When set, compiled queries automatically resolve persist sources
68
+ * against this manifest. Can be overridden per-query via
69
+ * CompileQueryOptions.buildManifest.
70
+ */
71
+ get buildManifest(): BuildManifest | undefined;
72
+ set buildManifest(manifest: BuildManifest | undefined);
63
73
  /**
64
74
  * Load a Malloy model by URL or contents.
65
75
  *
@@ -132,17 +142,19 @@ export declare class Runtime {
132
142
  }
133
143
  export declare class ConnectionRuntime extends Runtime {
134
144
  readonly rawConnections: Connection[];
135
- constructor({ urlReader, connections, }: {
145
+ constructor({ urlReader, connections, buildManifest, }: {
136
146
  urlReader?: URLReader;
137
147
  connections: Connection[];
148
+ buildManifest?: BuildManifest;
138
149
  });
139
150
  }
140
151
  export declare class SingleConnectionRuntime<T extends Connection = Connection> extends Runtime {
141
152
  readonly connection: T;
142
- constructor({ urlReader, connection, eventStream, cacheManager, }: {
153
+ constructor({ urlReader, connection, eventStream, cacheManager, buildManifest, }: {
143
154
  urlReader?: URLReader;
144
155
  eventStream?: EventStream;
145
156
  cacheManager?: CacheManager;
157
+ buildManifest?: BuildManifest;
146
158
  connection: T;
147
159
  });
148
160
  get supportsNesting(): boolean;
@@ -46,7 +46,7 @@ class FluentState {
46
46
  * An environment for compiling and running Malloy queries.
47
47
  */
48
48
  class Runtime {
49
- constructor({ urlReader, connections, connection, eventStream, cacheManager, }) {
49
+ constructor({ urlReader, connections, connection, eventStream, cacheManager, buildManifest, }) {
50
50
  this.isTestRuntime = false;
51
51
  if (connections === undefined) {
52
52
  if (connection === undefined) {
@@ -63,6 +63,7 @@ class Runtime {
63
63
  this._connections = connections;
64
64
  this._eventStream = eventStream;
65
65
  this._cacheManager = cacheManager;
66
+ this._buildManifest = buildManifest;
66
67
  }
67
68
  /**
68
69
  * @return The `CacheManager` for this runtime instance.
@@ -88,6 +89,18 @@ class Runtime {
88
89
  get eventStream() {
89
90
  return this._eventStream;
90
91
  }
92
+ /**
93
+ * The build manifest for persist source substitution.
94
+ * When set, compiled queries automatically resolve persist sources
95
+ * against this manifest. Can be overridden per-query via
96
+ * CompileQueryOptions.buildManifest.
97
+ */
98
+ get buildManifest() {
99
+ return this._buildManifest;
100
+ }
101
+ set buildManifest(manifest) {
102
+ this._buildManifest = manifest;
103
+ }
91
104
  /**
92
105
  * Load a Malloy model by URL or contents.
93
106
  *
@@ -210,21 +223,23 @@ exports.Runtime = Runtime;
210
223
  // ConnectionRuntime and SingleConnectionRuntime
211
224
  // =============================================================================
212
225
  class ConnectionRuntime extends Runtime {
213
- constructor({ urlReader, connections, }) {
226
+ constructor({ urlReader, connections, buildManifest, }) {
214
227
  super({
215
228
  connections: readers_1.FixedConnectionMap.fromArray(connections),
216
229
  urlReader,
230
+ buildManifest,
217
231
  });
218
232
  this.rawConnections = connections;
219
233
  }
220
234
  }
221
235
  exports.ConnectionRuntime = ConnectionRuntime;
222
236
  class SingleConnectionRuntime extends Runtime {
223
- constructor({ urlReader, connection, eventStream, cacheManager, }) {
237
+ constructor({ urlReader, connection, eventStream, cacheManager, buildManifest, }) {
224
238
  super({
225
239
  urlReader,
226
240
  eventStream,
227
241
  cacheManager,
242
+ buildManifest,
228
243
  connection,
229
244
  });
230
245
  this.connection = connection;
@@ -554,17 +569,21 @@ class QueryMaterializer extends FluentState {
554
569
  */
555
570
  loadPreparedResult(options) {
556
571
  return this.makePreparedResultMaterializer(async () => {
572
+ var _a;
557
573
  const preparedQuery = await this.materialize();
558
574
  const mergedOptions = {
559
575
  eventStream: this.eventStream,
560
576
  ...this.compileQueryOptions,
561
577
  ...options,
562
578
  };
563
- // If buildManifest is provided, compute connectionDigests for manifest lookups
579
+ // Use manifest from options if provided, otherwise fall back to Runtime's manifest.
580
+ // Pass an empty {} in options to explicitly suppress manifest substitution.
581
+ const buildManifest = (_a = mergedOptions.buildManifest) !== null && _a !== void 0 ? _a : this.runtime.buildManifest;
582
+ // If we have a manifest, compute connectionDigests for manifest lookups
564
583
  // TODO: This is inefficient - we call getBuildPlan just to find connection names.
565
584
  // Consider adding a listConnections() method to LookupConnection, or caching this.
566
585
  let connectionDigests;
567
- if (mergedOptions.buildManifest) {
586
+ if (buildManifest) {
568
587
  // Require experimental.persistence compiler flag to use buildManifest
569
588
  const modelTag = preparedQuery.model.tagParse({ prefix: /^##! / }).tag;
570
589
  if (!modelTag.has('experimental', 'persistence')) {
@@ -581,7 +600,7 @@ class QueryMaterializer extends FluentState {
581
600
  // Build PrepareResultOptions from CompileQueryOptions + connectionDigests
582
601
  const prepareResultOptions = {
583
602
  defaultRowLimit: mergedOptions.defaultRowLimit,
584
- buildManifest: mergedOptions.buildManifest,
603
+ buildManifest,
585
604
  connectionDigests,
586
605
  strictPersist: mergedOptions.strictPersist,
587
606
  };
@@ -54,6 +54,10 @@ export interface ConnectionConfigEntry {
54
54
  is: string;
55
55
  [key: string]: ConfigValue;
56
56
  }
57
+ /**
58
+ * Type guard for ConnectionConfigEntry.
59
+ */
60
+ export declare function isConnectionConfigEntry(value: unknown): value is ConnectionConfigEntry;
57
61
  /**
58
62
  * The editable intermediate representation of a connections config file.
59
63
  */
@@ -87,7 +91,7 @@ export declare function getConnectionTypeDisplayName(typeName: string): string |
87
91
  export declare function getRegisteredConnectionTypes(): string[];
88
92
  /**
89
93
  * Parse a JSON config string into a ConnectionsConfig.
90
- * Validates that each connection entry has an `is` field.
94
+ * Entries without a valid `is` field are silently dropped.
91
95
  */
92
96
  export declare function readConnectionsConfig(jsonText: string): ConnectionsConfig;
93
97
  /**
@@ -6,6 +6,7 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.isValueRef = isValueRef;
8
8
  exports.resolveValue = resolveValue;
9
+ exports.isConnectionConfigEntry = isConnectionConfigEntry;
9
10
  exports.registerConnectionType = registerConnectionType;
10
11
  exports.getConnectionProperties = getConnectionProperties;
11
12
  exports.getConnectionTypeDisplayName = getConnectionTypeDisplayName;
@@ -26,6 +27,14 @@ function isValueRef(value) {
26
27
  function resolveValue(vr) {
27
28
  return process.env[vr.env];
28
29
  }
30
+ /**
31
+ * Type guard for ConnectionConfigEntry.
32
+ */
33
+ function isConnectionConfigEntry(value) {
34
+ return (typeof value === 'object' &&
35
+ value !== null &&
36
+ typeof value.is === 'string');
37
+ }
29
38
  // Module-level registry
30
39
  const registry = new Map();
31
40
  /**
@@ -65,22 +74,13 @@ function getRegisteredConnectionTypes() {
65
74
  }
66
75
  /**
67
76
  * Parse a JSON config string into a ConnectionsConfig.
68
- * Validates that each connection entry has an `is` field.
77
+ * Entries without a valid `is` field are silently dropped.
69
78
  */
70
79
  function readConnectionsConfig(jsonText) {
80
+ var _a;
71
81
  const parsed = JSON.parse(jsonText);
72
- const connections = parsed.connections;
73
- if (connections === undefined || typeof connections !== 'object') {
74
- throw new Error('Invalid connections config: missing "connections" object');
75
- }
76
- for (const [name, entry] of Object.entries(connections)) {
77
- if (typeof entry !== 'object' ||
78
- entry === null ||
79
- !entry.is) {
80
- throw new Error(`Connection "${name}" is missing required "is" property`);
81
- }
82
- }
83
- return parsed;
82
+ const connections = Object.fromEntries(Object.entries((_a = parsed.connections) !== null && _a !== void 0 ? _a : {}).filter(([, v]) => isConnectionConfigEntry(v)));
83
+ return { ...parsed, connections };
84
84
  }
85
85
  /**
86
86
  * Serialize a ConnectionsConfig to a JSON string with 2-space indent.
package/dist/index.d.ts CHANGED
@@ -1,15 +1,15 @@
1
1
  export { DuckDBDialect, StandardSQLDialect, TrinoDialect, PostgresDialect, SnowflakeDialect, MySQLDialect, registerDialect, arg, qtz, overload, minScalar, anyExprType, minAggregate, maxScalar, sql, makeParam, param, variadicParam, literal, spread, Dialect, TinyParser, } from './dialect';
2
2
  export type { DialectFieldList, DialectFunctionOverloadDef, QueryInfo, MalloyStandardFunctionImplementations, DefinitionBlueprint, DefinitionBlueprintMap, OverloadedDefinitionBlueprint, TinyToken, } 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, BuildManifest, BuildManifestEntry, } 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, } 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
- 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, } from './api/foundation';
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, } 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 { QueryOptionsReader, RunSQLOptions } from './run_sql_options';
10
10
  export type { EventStream, ModelString, ModelURL, QueryString, QueryURL, URLReader, InvalidationKey, } from './runtime_types';
11
11
  export type { Connection, ConnectionConfig, ConnectionParameterValue, FetchSchemaOptions, InfoConnection, LookupConnection, PersistSQLResults, PooledConnection, TestableConnection, StreamingConnection, } from './connection/types';
12
- export { registerConnectionType, getConnectionProperties, getConnectionTypeDisplayName, getRegisteredConnectionTypes, readConnectionsConfig, writeConnectionsConfig, createConnectionsFromConfig, isValueRef, resolveValue, } from './connection/registry';
12
+ export { registerConnectionType, getConnectionProperties, getConnectionTypeDisplayName, getRegisteredConnectionTypes, isValueRef, resolveValue, } from './connection/registry';
13
13
  export type { ConnectionTypeFactory, ConnectionPropertyType, ConnectionPropertyDefinition, ConnectionTypeDef, ConnectionConfigEntry, ConnectionsConfig, ConfigValue, ValueRef, } from './connection/registry';
14
14
  export { toAsyncGenerator } from './connection_utils';
15
15
  export { modelDefToModelInfo, sourceDefToSourceInfo } from './to_stable';
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.Runtime = exports.Malloy = exports.Model = exports.MalloyTranslator = exports.malloyToQuery = exports.constantExprToSQL = exports.isDateUnit = exports.isTimestampUnit = exports.composeSQLExpr = exports.indent = exports.expressionIsUngroupedAggregate = exports.expressionIsScalar = exports.expressionIsCalculation = exports.expressionIsAnalytic = exports.expressionIsAggregate = exports.mkFieldDef = exports.mkArrayDef = exports.isBasicArray = exports.isRepeatedRecord = exports.isSamplingRows = exports.isSamplingPercent = exports.isSamplingEnable = exports.isJoinedSource = exports.isJoined = exports.isCompoundArrayData = exports.isBasicAtomic = exports.isAtomic = exports.isSourceDef = exports.TinyParser = exports.Dialect = exports.spread = exports.literal = exports.variadicParam = exports.param = exports.makeParam = exports.sql = exports.maxScalar = exports.minAggregate = exports.anyExprType = exports.minScalar = exports.overload = exports.qtz = exports.arg = exports.registerDialect = exports.MySQLDialect = exports.SnowflakeDialect = exports.PostgresDialect = exports.TrinoDialect = exports.StandardSQLDialect = exports.DuckDBDialect = void 0;
37
- exports.makeDigest = exports.PersistSource = exports.annotationToTaglines = exports.annotationToTag = exports.sqlKey = exports.API = exports.sourceDefToSourceInfo = exports.modelDefToModelInfo = exports.toAsyncGenerator = exports.resolveValue = exports.isValueRef = exports.createConnectionsFromConfig = exports.writeConnectionsConfig = exports.readConnectionsConfig = exports.getRegisteredConnectionTypes = exports.getConnectionTypeDisplayName = exports.getConnectionProperties = exports.registerConnectionType = exports.CacheManager = exports.InMemoryModelCache = exports.Explore = exports.DataWriter = exports.Parse = exports.JSONWriter = exports.CSVWriter = exports.QueryMaterializer = exports.Result = exports.PreparedResult = exports.TimestampTimeframe = exports.DateTimeframe = exports.SourceRelationship = exports.JoinRelationship = exports.MalloyError = exports.FixedConnectionMap = exports.InMemoryURLReader = exports.EmptyURLReader = exports.SingleConnectionRuntime = exports.ConnectionRuntime = exports.AtomicFieldType = void 0;
37
+ exports.makeDigest = exports.PersistSource = exports.annotationToTaglines = exports.annotationToTag = exports.sqlKey = exports.API = exports.sourceDefToSourceInfo = exports.modelDefToModelInfo = exports.toAsyncGenerator = exports.resolveValue = exports.isValueRef = exports.getRegisteredConnectionTypes = exports.getConnectionTypeDisplayName = exports.getConnectionProperties = exports.registerConnectionType = exports.MalloyConfig = exports.Manifest = exports.CacheManager = exports.InMemoryModelCache = exports.Explore = exports.DataWriter = exports.Parse = exports.JSONWriter = exports.CSVWriter = exports.QueryMaterializer = exports.Result = exports.PreparedResult = exports.TimestampTimeframe = exports.DateTimeframe = exports.SourceRelationship = exports.JoinRelationship = exports.MalloyError = exports.FixedConnectionMap = exports.InMemoryURLReader = exports.EmptyURLReader = exports.SingleConnectionRuntime = exports.ConnectionRuntime = exports.AtomicFieldType = void 0;
38
38
  /*
39
39
  * Copyright 2023 Google LLC
40
40
  *
@@ -135,14 +135,13 @@ Object.defineProperty(exports, "DataWriter", { enumerable: true, get: function (
135
135
  Object.defineProperty(exports, "Explore", { enumerable: true, get: function () { return foundation_1.Explore; } });
136
136
  Object.defineProperty(exports, "InMemoryModelCache", { enumerable: true, get: function () { return foundation_1.InMemoryModelCache; } });
137
137
  Object.defineProperty(exports, "CacheManager", { enumerable: true, get: function () { return foundation_1.CacheManager; } });
138
+ Object.defineProperty(exports, "Manifest", { enumerable: true, get: function () { return foundation_1.Manifest; } });
139
+ Object.defineProperty(exports, "MalloyConfig", { enumerable: true, get: function () { return foundation_1.MalloyConfig; } });
138
140
  var registry_1 = require("./connection/registry");
139
141
  Object.defineProperty(exports, "registerConnectionType", { enumerable: true, get: function () { return registry_1.registerConnectionType; } });
140
142
  Object.defineProperty(exports, "getConnectionProperties", { enumerable: true, get: function () { return registry_1.getConnectionProperties; } });
141
143
  Object.defineProperty(exports, "getConnectionTypeDisplayName", { enumerable: true, get: function () { return registry_1.getConnectionTypeDisplayName; } });
142
144
  Object.defineProperty(exports, "getRegisteredConnectionTypes", { enumerable: true, get: function () { return registry_1.getRegisteredConnectionTypes; } });
143
- Object.defineProperty(exports, "readConnectionsConfig", { enumerable: true, get: function () { return registry_1.readConnectionsConfig; } });
144
- Object.defineProperty(exports, "writeConnectionsConfig", { enumerable: true, get: function () { return registry_1.writeConnectionsConfig; } });
145
- Object.defineProperty(exports, "createConnectionsFromConfig", { enumerable: true, get: function () { return registry_1.createConnectionsFromConfig; } });
146
145
  Object.defineProperty(exports, "isValueRef", { enumerable: true, get: function () { return registry_1.isValueRef; } });
147
146
  Object.defineProperty(exports, "resolveValue", { enumerable: true, get: function () { return registry_1.resolveValue; } });
148
147
  var connection_utils_1 = require("./connection_utils");
@@ -1120,20 +1120,13 @@ export declare function mergeUniqueKeyRequirement(existing: UniqueKeyRequirement
1120
1120
  * Entry in a BuildManifest for a persisted table.
1121
1121
  */
1122
1122
  export interface BuildManifestEntry {
1123
- /** Hash of (connectionDigest, sql) - also the key in buildEntries */
1124
- buildId: BuildID;
1125
1123
  tableName: string;
1126
- buildStartedAt: string;
1127
- buildFinishedAt: string;
1128
1124
  }
1129
1125
  /**
1130
- * Manifest of persisted query results (the build cache).
1131
- * Used by compileQuery to substitute persist queries with table references.
1126
+ * Manifest of persisted build results (the build cache).
1127
+ * Maps BuildID → BuildManifestEntry. Used by compileQuery to substitute
1128
+ * persist sources with table references. Content-addressable: same SQL +
1129
+ * same connection digest = same BuildID regardless of which model produced it.
1132
1130
  */
1133
- export interface BuildManifest {
1134
- modelUrl: string;
1135
- buildStartedAt: string;
1136
- buildFinishedAt: string;
1137
- buildEntries: Record<BuildID, BuildManifestEntry>;
1138
- }
1131
+ export type BuildManifest = Record<BuildID, BuildManifestEntry>;
1139
1132
  export {};
@@ -542,7 +542,7 @@ class QueryQuery extends query_node_1.QueryField {
542
542
  // Compile with empty opts to get manifest-ignorant SQL for BuildID
543
543
  const fullRet = this.compileQueryToStages(qs.structDef.query, {}, undefined, false);
544
544
  const buildId = (0, source_def_utils_1.mkBuildID)(connDigest, fullRet.sql);
545
- const entry = buildManifest.buildEntries[buildId];
545
+ const entry = buildManifest[buildId];
546
546
  if (entry) {
547
547
  // Found in manifest - use persisted table
548
548
  return this.parent.dialect.quoteTablePath(entry.tableName);
@@ -59,7 +59,7 @@ function expandPersistableSource(source, opts, quoteTablePath, compileQuery) {
59
59
  // Get the SQL for this source to compute BuildID (no opts = full SQL)
60
60
  const sql = getSourceSQL(source, quoteTablePath, compileQuery);
61
61
  const buildId = (0, source_def_utils_1.mkBuildID)(connDigest, sql);
62
- const entry = buildManifest.buildEntries[buildId];
62
+ const entry = buildManifest[buildId];
63
63
  if (entry) {
64
64
  // Found in manifest - substitute with subquery from persisted table
65
65
  return `(SELECT * FROM ${quoteTablePath(entry.tableName)})`;
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const MALLOY_VERSION = "0.0.344";
1
+ export declare const MALLOY_VERSION = "0.0.346";
package/dist/version.js CHANGED
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MALLOY_VERSION = void 0;
4
4
  // generated with 'generate-version-file' script; do not edit manually
5
- exports.MALLOY_VERSION = '0.0.344';
5
+ exports.MALLOY_VERSION = '0.0.346';
6
6
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.344",
3
+ "version": "0.0.346",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./dist/index.js",
@@ -45,9 +45,9 @@
45
45
  "generate-version-file": "VERSION=$(npm pkg get version --workspaces=false | tr -d \\\")\necho \"// generated with 'generate-version-file' script; do not edit manually\\nexport const MALLOY_VERSION = '$VERSION';\" > src/version.ts"
46
46
  },
47
47
  "dependencies": {
48
- "@malloydata/malloy-filter": "0.0.344",
49
- "@malloydata/malloy-interfaces": "0.0.344",
50
- "@malloydata/malloy-tag": "0.0.344",
48
+ "@malloydata/malloy-filter": "0.0.346",
49
+ "@malloydata/malloy-interfaces": "0.0.346",
50
+ "@malloydata/malloy-tag": "0.0.346",
51
51
  "@noble/hashes": "^1.8.0",
52
52
  "antlr4ts": "^0.5.0-alpha.4",
53
53
  "assert": "^2.0.0",