@malloydata/malloy 0.0.387 → 0.0.388
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.
- package/dist/api/foundation/config.d.ts +29 -14
- package/dist/api/foundation/config.js +37 -15
- package/dist/api/foundation/config_lookup.js +15 -1
- package/dist/api/foundation/runtime.d.ts +21 -10
- package/dist/api/foundation/runtime.js +44 -13
- package/dist/connection/base_connection.d.ts +1 -0
- package/dist/connection/base_connection.js +1 -0
- package/dist/connection/registry.d.ts +5 -2
- package/dist/connection/registry.js +7 -0
- package/dist/connection/types.d.ts +14 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -133,27 +133,42 @@ export declare class MalloyConfig {
|
|
|
133
133
|
*/
|
|
134
134
|
wrapConnections(wrapper: (base: LookupConnection<Connection>) => LookupConnection<Connection>): void;
|
|
135
135
|
/**
|
|
136
|
-
* Notify every connection this config has handed out that
|
|
137
|
-
*
|
|
136
|
+
* Notify every connection this config has handed out that the host is
|
|
137
|
+
* done with it, applying the requested disposition to its backend
|
|
138
|
+
* resources. Two policies:
|
|
138
139
|
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
140
|
+
* - `'close'` (default) — destructive. Calls `Connection.close()` on each
|
|
141
|
+
* cached entry and drops the cache. Subsequent operations on those
|
|
142
|
+
* connection objects may fail. Use this at real shutdown: process
|
|
143
|
+
* exit, extension deactivate, config-file change.
|
|
144
|
+
*
|
|
145
|
+
* - `'idle'` — reversible. Calls `Connection.idle()` on each cached entry
|
|
146
|
+
* without dropping the cache. The same Connection objects are reused
|
|
147
|
+
* on next lookup; schema cache and other in-process state survive.
|
|
148
|
+
* The next operation transparently reattaches any backend resources
|
|
149
|
+
* that were released. Use this between operations in long-lived hosts
|
|
150
|
+
* (VSCode, MCP servers, anything that builds Runtimes per request) to
|
|
151
|
+
* release file locks / pooled sockets while the host is otherwise
|
|
152
|
+
* idle.
|
|
153
|
+
*
|
|
154
|
+
* Most callers should use `Runtime.shutdown(...)` instead — the expected
|
|
155
|
+
* contract is one MalloyConfig per Runtime, and the runtime is the
|
|
156
|
+
* natural handle for lifecycle. This method exists because Runtime
|
|
142
157
|
* forwards to it, and for the rare case of a MalloyConfig constructed
|
|
143
158
|
* without an accompanying Runtime.
|
|
144
159
|
*
|
|
145
160
|
* MalloyConfig does not own any connection resources itself — pools,
|
|
146
161
|
* sockets, file handles, and in-process databases all live inside the
|
|
147
162
|
* individual Connection objects. What the managed lookup owns is a cache
|
|
148
|
-
* of `name → Connection` populated lazily as callers request
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
*
|
|
163
|
+
* of `name → Connection` populated lazily as callers request
|
|
164
|
+
* connections. Connections that were never looked up were never
|
|
165
|
+
* constructed and have nothing to release; they are skipped. Wrapping
|
|
166
|
+
* lookups installed via `wrapConnections()` do not interfere — the
|
|
167
|
+
* managed lookup under the wrap is the one holding the cache.
|
|
168
|
+
*/
|
|
169
|
+
shutdown(connections?: 'close' | 'idle'): Promise<void>;
|
|
170
|
+
/**
|
|
171
|
+
* @deprecated Use `shutdown('close')` instead.
|
|
157
172
|
*/
|
|
158
173
|
releaseConnections(): Promise<void>;
|
|
159
174
|
/**
|
|
@@ -216,30 +216,52 @@ class MalloyConfig {
|
|
|
216
216
|
this._connections = wrapper(this._connections);
|
|
217
217
|
}
|
|
218
218
|
/**
|
|
219
|
-
* Notify every connection this config has handed out that
|
|
220
|
-
*
|
|
219
|
+
* Notify every connection this config has handed out that the host is
|
|
220
|
+
* done with it, applying the requested disposition to its backend
|
|
221
|
+
* resources. Two policies:
|
|
221
222
|
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
223
|
+
* - `'close'` (default) — destructive. Calls `Connection.close()` on each
|
|
224
|
+
* cached entry and drops the cache. Subsequent operations on those
|
|
225
|
+
* connection objects may fail. Use this at real shutdown: process
|
|
226
|
+
* exit, extension deactivate, config-file change.
|
|
227
|
+
*
|
|
228
|
+
* - `'idle'` — reversible. Calls `Connection.idle()` on each cached entry
|
|
229
|
+
* without dropping the cache. The same Connection objects are reused
|
|
230
|
+
* on next lookup; schema cache and other in-process state survive.
|
|
231
|
+
* The next operation transparently reattaches any backend resources
|
|
232
|
+
* that were released. Use this between operations in long-lived hosts
|
|
233
|
+
* (VSCode, MCP servers, anything that builds Runtimes per request) to
|
|
234
|
+
* release file locks / pooled sockets while the host is otherwise
|
|
235
|
+
* idle.
|
|
236
|
+
*
|
|
237
|
+
* Most callers should use `Runtime.shutdown(...)` instead — the expected
|
|
238
|
+
* contract is one MalloyConfig per Runtime, and the runtime is the
|
|
239
|
+
* natural handle for lifecycle. This method exists because Runtime
|
|
225
240
|
* forwards to it, and for the rare case of a MalloyConfig constructed
|
|
226
241
|
* without an accompanying Runtime.
|
|
227
242
|
*
|
|
228
243
|
* MalloyConfig does not own any connection resources itself — pools,
|
|
229
244
|
* sockets, file handles, and in-process databases all live inside the
|
|
230
245
|
* individual Connection objects. What the managed lookup owns is a cache
|
|
231
|
-
* of `name → Connection` populated lazily as callers request
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
246
|
+
* of `name → Connection` populated lazily as callers request
|
|
247
|
+
* connections. Connections that were never looked up were never
|
|
248
|
+
* constructed and have nothing to release; they are skipped. Wrapping
|
|
249
|
+
* lookups installed via `wrapConnections()` do not interfere — the
|
|
250
|
+
* managed lookup under the wrap is the one holding the cache.
|
|
251
|
+
*/
|
|
252
|
+
async shutdown(connections = 'close') {
|
|
253
|
+
if (connections === 'idle') {
|
|
254
|
+
await this._managedLookup.idle();
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
await this._managedLookup.close();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* @deprecated Use `shutdown('close')` instead.
|
|
240
262
|
*/
|
|
241
263
|
async releaseConnections() {
|
|
242
|
-
await this.
|
|
264
|
+
await this.shutdown('close');
|
|
243
265
|
}
|
|
244
266
|
/**
|
|
245
267
|
* Query a value from the overlays used to resolve this config.
|
|
@@ -83,6 +83,13 @@ function buildManagedLookup(compiledConnections, overlays, log) {
|
|
|
83
83
|
await conn.close();
|
|
84
84
|
}
|
|
85
85
|
},
|
|
86
|
+
async idle() {
|
|
87
|
+
// Cache is preserved — same Connection objects are reused so that
|
|
88
|
+
// schema cache and other in-process state survive the idle.
|
|
89
|
+
for (const conn of cache.values()) {
|
|
90
|
+
await conn.idle();
|
|
91
|
+
}
|
|
92
|
+
},
|
|
86
93
|
};
|
|
87
94
|
}
|
|
88
95
|
/**
|
|
@@ -91,7 +98,14 @@ function buildManagedLookup(compiledConnections, overlays, log) {
|
|
|
91
98
|
* gets handed to the factory.
|
|
92
99
|
*/
|
|
93
100
|
async function resolveCompiledEntry(entry, overlays, log) {
|
|
94
|
-
const resolved =
|
|
101
|
+
const resolved = await resolveNode(entry, overlays, log);
|
|
102
|
+
// resolveNode returns `unknown`. The compileConnections pipeline
|
|
103
|
+
// guarantees every connection entry is an object dict with `is` set to
|
|
104
|
+
// a literal string, so this should always pass — but a structured
|
|
105
|
+
// throw beats a downstream NPE if a compiler bug ever sneaks through.
|
|
106
|
+
if (!(0, registry_1.isConnectionConfigEntry)(resolved)) {
|
|
107
|
+
throw new Error('Connection entry did not resolve to a valid {is: string, ...} dict');
|
|
108
|
+
}
|
|
95
109
|
await applyPropertyDefaults(resolved, overlays);
|
|
96
110
|
return resolved;
|
|
97
111
|
}
|
|
@@ -126,16 +126,27 @@ export declare class Runtime {
|
|
|
126
126
|
get virtualMap(): VirtualMap | undefined;
|
|
127
127
|
set virtualMap(map: VirtualMap | undefined);
|
|
128
128
|
/**
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
129
|
+
* Tell this runtime's connections what to do with their backend
|
|
130
|
+
* resources now that the host is done with this Runtime. Two policies:
|
|
131
|
+
*
|
|
132
|
+
* - `'close'` (default) — destructive shutdown. Connections release
|
|
133
|
+
* resources and become unusable. Use at real shutdown: process exit,
|
|
134
|
+
* extension deactivate, config-file change.
|
|
135
|
+
*
|
|
136
|
+
* - `'idle'` — reversible release. Connections release expensive
|
|
137
|
+
* resources (DuckDB file locks, socket pools) but stay logically
|
|
138
|
+
* valid. The same Connection objects are reused on next lookup;
|
|
139
|
+
* schema cache and other in-process state survive. Use between
|
|
140
|
+
* operations in long-lived hosts (a VSCode extension, an MCP server,
|
|
141
|
+
* any host that builds Runtimes per request) so that other writers
|
|
142
|
+
* can claim resources during idle gaps.
|
|
143
|
+
*
|
|
144
|
+
* A no-op for runtimes constructed without a MalloyConfig — in that
|
|
145
|
+
* case the caller owns the connections they passed in.
|
|
146
|
+
*/
|
|
147
|
+
shutdown(connections?: 'close' | 'idle'): Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* @deprecated Use `shutdown('close')` instead.
|
|
139
150
|
*/
|
|
140
151
|
releaseConnections(): Promise<void>;
|
|
141
152
|
/**
|
|
@@ -160,7 +160,11 @@ class Runtime {
|
|
|
160
160
|
return undefined;
|
|
161
161
|
}
|
|
162
162
|
try {
|
|
163
|
-
|
|
163
|
+
const parsed = JSON.parse(text);
|
|
164
|
+
if (!isBuildManifestShape(parsed)) {
|
|
165
|
+
throw new Error('manifest is not an object with an "entries" map');
|
|
166
|
+
}
|
|
167
|
+
return parsed;
|
|
164
168
|
}
|
|
165
169
|
catch (e) {
|
|
166
170
|
// File was present but couldn't be parsed. Return an empty
|
|
@@ -193,20 +197,33 @@ class Runtime {
|
|
|
193
197
|
this._virtualMap = map;
|
|
194
198
|
}
|
|
195
199
|
/**
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
200
|
+
* Tell this runtime's connections what to do with their backend
|
|
201
|
+
* resources now that the host is done with this Runtime. Two policies:
|
|
202
|
+
*
|
|
203
|
+
* - `'close'` (default) — destructive shutdown. Connections release
|
|
204
|
+
* resources and become unusable. Use at real shutdown: process exit,
|
|
205
|
+
* extension deactivate, config-file change.
|
|
206
|
+
*
|
|
207
|
+
* - `'idle'` — reversible release. Connections release expensive
|
|
208
|
+
* resources (DuckDB file locks, socket pools) but stay logically
|
|
209
|
+
* valid. The same Connection objects are reused on next lookup;
|
|
210
|
+
* schema cache and other in-process state survive. Use between
|
|
211
|
+
* operations in long-lived hosts (a VSCode extension, an MCP server,
|
|
212
|
+
* any host that builds Runtimes per request) so that other writers
|
|
213
|
+
* can claim resources during idle gaps.
|
|
201
214
|
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
* call this when a runtime goes out of scope; one-shot CLIs can skip it
|
|
205
|
-
* and let process exit clean up.
|
|
215
|
+
* A no-op for runtimes constructed without a MalloyConfig — in that
|
|
216
|
+
* case the caller owns the connections they passed in.
|
|
206
217
|
*/
|
|
207
|
-
async
|
|
218
|
+
async shutdown(connections = 'close') {
|
|
208
219
|
var _a;
|
|
209
|
-
await ((_a = this._config) === null || _a === void 0 ? void 0 : _a.
|
|
220
|
+
await ((_a = this._config) === null || _a === void 0 ? void 0 : _a.shutdown(connections));
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* @deprecated Use `shutdown('close')` instead.
|
|
224
|
+
*/
|
|
225
|
+
async releaseConnections() {
|
|
226
|
+
await this.shutdown('close');
|
|
210
227
|
}
|
|
211
228
|
/**
|
|
212
229
|
* Load a Malloy model by URL or contents.
|
|
@@ -532,7 +549,7 @@ class ModelMaterializer extends FluentState {
|
|
|
532
549
|
const result = await this.loadQuery(searchMapMalloy, options).run({
|
|
533
550
|
rowLimit: 1000,
|
|
534
551
|
});
|
|
535
|
-
const rawResult = result.
|
|
552
|
+
const rawResult = result.data.toObject();
|
|
536
553
|
return rawResult.map(row => ({
|
|
537
554
|
...row,
|
|
538
555
|
cardinality: (0, row_data_utils_1.rowDataToNumber)(row.cardinality),
|
|
@@ -870,4 +887,18 @@ class ExploreMaterializer extends FluentState {
|
|
|
870
887
|
}
|
|
871
888
|
}
|
|
872
889
|
exports.ExploreMaterializer = ExploreMaterializer;
|
|
890
|
+
/**
|
|
891
|
+
* Structural check for the `BuildManifest` shape: a non-null object with an
|
|
892
|
+
* object `entries` field. Doesn't validate every entry — `BuildManifestEntry`
|
|
893
|
+
* is just `{tableName: string}`, so a stricter walk could come later if we
|
|
894
|
+
* find malformed entries causing trouble. The current goal is to fail
|
|
895
|
+
* cleanly on a manifest file that parsed to a string/array/null instead of
|
|
896
|
+
* leaving a downstream `entries[buildId]` lookup to crash on `undefined`.
|
|
897
|
+
*/
|
|
898
|
+
function isBuildManifestShape(value) {
|
|
899
|
+
if (typeof value !== 'object' || value === null)
|
|
900
|
+
return false;
|
|
901
|
+
const entries = value.entries;
|
|
902
|
+
return typeof entries === 'object' && entries !== null;
|
|
903
|
+
}
|
|
873
904
|
//# sourceMappingURL=runtime.js.map
|
|
@@ -40,6 +40,7 @@ export declare abstract class BaseConnection implements Connection {
|
|
|
40
40
|
canPersist(): this is PersistSQLResults;
|
|
41
41
|
canStream(): this is StreamingConnection;
|
|
42
42
|
close(): Promise<void>;
|
|
43
|
+
idle(): Promise<void>;
|
|
43
44
|
estimateQueryCost(_sqlCommand: string): Promise<QueryRunStats>;
|
|
44
45
|
fetchMetadata(): Promise<{}>;
|
|
45
46
|
fetchTableMetadata(_tablePath: string): Promise<{}>;
|
|
@@ -122,11 +122,14 @@ export declare function readConnectionsConfig(jsonText: string): ConnectionsConf
|
|
|
122
122
|
export declare function writeConnectionsConfig(config: ConnectionsConfig): string;
|
|
123
123
|
/**
|
|
124
124
|
* A LookupConnection with lifecycle management: close() shuts down all
|
|
125
|
-
* cached connections,
|
|
126
|
-
*
|
|
125
|
+
* cached connections, idle() releases their backend resources but keeps
|
|
126
|
+
* the cache so the same connection objects are reused on next lookup, and
|
|
127
|
+
* an optional onConnectionCreated callback fires once per connection after
|
|
128
|
+
* factory creation (before caching).
|
|
127
129
|
*/
|
|
128
130
|
export interface ManagedConnectionLookup extends LookupConnection<Connection> {
|
|
129
131
|
close(): Promise<void>;
|
|
132
|
+
idle(): Promise<void>;
|
|
130
133
|
}
|
|
131
134
|
/**
|
|
132
135
|
* Create a ManagedConnectionLookup from a ConnectionsConfig using registered
|
|
@@ -159,6 +159,13 @@ function createConnectionsFromConfig(config, onConnectionCreated) {
|
|
|
159
159
|
await conn.close();
|
|
160
160
|
}
|
|
161
161
|
},
|
|
162
|
+
async idle() {
|
|
163
|
+
// Cache is preserved — the same Connection objects are reused so that
|
|
164
|
+
// schema cache and other in-process state survive the idle.
|
|
165
|
+
for (const conn of cache.values()) {
|
|
166
|
+
await conn.idle();
|
|
167
|
+
}
|
|
168
|
+
},
|
|
162
169
|
};
|
|
163
170
|
}
|
|
164
171
|
//# sourceMappingURL=registry.js.map
|
|
@@ -77,6 +77,20 @@ export interface Connection extends InfoConnection {
|
|
|
77
77
|
canPersist(): this is PersistSQLResults;
|
|
78
78
|
canStream(): this is StreamingConnection;
|
|
79
79
|
close(): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Release expensive backend resources (file locks, sockets, sub-processes,
|
|
82
|
+
* pooled connections) but remain logically valid. The next operation
|
|
83
|
+
* transparently reattaches whatever was released; schema cache and other
|
|
84
|
+
* in-process state survive.
|
|
85
|
+
*
|
|
86
|
+
* The default is a no-op for backends that hold no release-able resources
|
|
87
|
+
* between operations. Backends that hold OS-level resources (DuckDB file
|
|
88
|
+
* locks, persistent socket pools) should override.
|
|
89
|
+
*
|
|
90
|
+
* Hosts that share a connection across concurrent operations should not
|
|
91
|
+
* call `idle()` while an operation is in flight.
|
|
92
|
+
*/
|
|
93
|
+
idle(): Promise<void>;
|
|
80
94
|
estimateQueryCost(sqlCommand: string): Promise<QueryRunStats>;
|
|
81
95
|
fetchMetadata: () => Promise<ConnectionMetadata>;
|
|
82
96
|
fetchTableMetadata: (tablePath: string) => Promise<TableMetadata>;
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const MALLOY_VERSION = "0.0.
|
|
1
|
+
export declare const MALLOY_VERSION = "0.0.388";
|
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.
|
|
5
|
+
exports.MALLOY_VERSION = '0.0.388';
|
|
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.
|
|
3
|
+
"version": "0.0.388",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js",
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"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"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@malloydata/malloy-filter": "0.0.
|
|
55
|
-
"@malloydata/malloy-interfaces": "0.0.
|
|
56
|
-
"@malloydata/malloy-tag": "0.0.
|
|
54
|
+
"@malloydata/malloy-filter": "0.0.388",
|
|
55
|
+
"@malloydata/malloy-interfaces": "0.0.388",
|
|
56
|
+
"@malloydata/malloy-tag": "0.0.388",
|
|
57
57
|
"@noble/hashes": "^1.8.0",
|
|
58
58
|
"antlr4ts": "^0.5.0-alpha.4",
|
|
59
59
|
"assert": "^2.0.0",
|