@malloydata/db-duckdb 0.0.386 → 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.
@@ -38,6 +38,12 @@ export declare class DuckDBConnection extends DuckDBCommon {
38
38
  protected connection: DuckDBNodeConnection | null;
39
39
  protected setupError: Error | undefined;
40
40
  protected isSetup: Promise<void> | undefined;
41
+ /**
42
+ * Set by `close()`. Once true, `setup()` throws and no operation will
43
+ * reattach. This is the "poison pill" that distinguishes terminal close
44
+ * from reversible idle.
45
+ */
46
+ protected closed: boolean;
41
47
  static activeDBs: Record<string, ActiveDB>;
42
48
  constructor(options: DuckDBConnectionOptions, queryOptions?: QueryOptionsReader);
43
49
  constructor(name: string, databasePath?: string, workingDirectory?: string, queryOptions?: QueryOptionsReader);
@@ -56,6 +62,14 @@ export declare class DuckDBConnection extends DuckDBCommon {
56
62
  }>;
57
63
  runSQLStream(sql: string, { rowLimit, abortSignal }?: RunSQLOptions): AsyncIterableIterator<QueryRecord>;
58
64
  close(): Promise<void>;
65
+ idle(): Promise<void>;
66
+ /**
67
+ * Remove this connection from the shared `activeDBs` entry. When the
68
+ * last connection sharing the entry is removed, close the underlying
69
+ * `DuckDBInstance` and drop the entry — releasing DuckDB's per-process
70
+ * file lock.
71
+ */
72
+ private detachInstance;
59
73
  /**
60
74
  * Forcefully close all cached DuckDB instances. Useful for test cleanup
61
75
  * to release file locks between test runs.
@@ -36,6 +36,12 @@ class DuckDBConnection extends duckdb_common_1.DuckDBCommon {
36
36
  var _a;
37
37
  super();
38
38
  this.connection = null;
39
+ /**
40
+ * Set by `close()`. Once true, `setup()` throws and no operation will
41
+ * reattach. This is the "poison pill" that distinguishes terminal close
42
+ * from reversible idle.
43
+ */
44
+ this.closed = false;
39
45
  const options = typeof arg === 'string'
40
46
  ? buildLegacyOptions(arg, arg2, workingDirectory)
41
47
  : arg;
@@ -84,6 +90,9 @@ class DuckDBConnection extends duckdb_common_1.DuckDBCommon {
84
90
  }
85
91
  }
86
92
  async setup() {
93
+ if (this.closed) {
94
+ throw new Error(`DuckDB connection "${this.name}" is closed`);
95
+ }
87
96
  if (this.setupError) {
88
97
  throw this.setupError;
89
98
  }
@@ -91,6 +100,16 @@ class DuckDBConnection extends duckdb_common_1.DuckDBCommon {
91
100
  if (this.setupError) {
92
101
  throw this.setupError;
93
102
  }
103
+ // Lazy reattach after idle(): if our connection was released, re-run
104
+ // init() now. setupSQL gets replayed below because isSetup was cleared
105
+ // alongside the connection.
106
+ if (this.connection === null) {
107
+ this.connecting = this.init();
108
+ await this.connecting;
109
+ if (this.setupError) {
110
+ throw this.setupError;
111
+ }
112
+ }
94
113
  if (!this.isSetup) {
95
114
  this.isSetup = this.setupOnce();
96
115
  }
@@ -257,6 +276,31 @@ class DuckDBConnection extends duckdb_common_1.DuckDBCommon {
257
276
  }
258
277
  }
259
278
  async close() {
279
+ this.detachInstance();
280
+ this.connection = null;
281
+ this.isSetup = undefined;
282
+ this.setupError = undefined;
283
+ this.closed = true;
284
+ }
285
+ async idle() {
286
+ // No-op for in-memory: closing the instance silently destroys state.
287
+ if (this.normalized.databasePath === ':memory:')
288
+ return;
289
+ this.detachInstance();
290
+ this.connection = null;
291
+ this.isSetup = undefined;
292
+ this.setupError = undefined;
293
+ // Reattach is deferred — `setup()` detects the null connection on next
294
+ // use and runs a fresh init() then. Doing it eagerly here would
295
+ // re-acquire the lock immediately and defeat the point of idling.
296
+ }
297
+ /**
298
+ * Remove this connection from the shared `activeDBs` entry. When the
299
+ * last connection sharing the entry is removed, close the underlying
300
+ * `DuckDBInstance` and drop the entry — releasing DuckDB's per-process
301
+ * file lock.
302
+ */
303
+ detachInstance() {
260
304
  const activeDB = DuckDBConnection.activeDBs[this.shareKey];
261
305
  if (activeDB) {
262
306
  activeDB.connections = activeDB.connections.filter(connection => connection !== this.connection);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/db-duckdb",
3
- "version": "0.0.386",
3
+ "version": "0.0.388",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -60,7 +60,7 @@
60
60
  "dependencies": {
61
61
  "@duckdb/duckdb-wasm": "1.33.1-dev13.0",
62
62
  "@duckdb/node-api": "1.4.4-r.1",
63
- "@malloydata/malloy": "0.0.386",
63
+ "@malloydata/malloy": "0.0.388",
64
64
  "@motherduck/wasm-client": "^0.6.6",
65
65
  "apache-arrow": "^17.0.0",
66
66
  "web-worker": "^1.3.0"