@sqlrooms/duckdb 0.16.3 → 0.17.0

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,202 +1,167 @@
1
1
  import * as duckdb from '@duckdb/duckdb-wasm';
2
2
  import { DuckDBDataProtocol } from '@duckdb/duckdb-wasm';
3
+ import { isSpatialLoadFileOptions, } from '@sqlrooms/room-config';
3
4
  import { splitFilePath } from '@sqlrooms/utils';
4
5
  import * as arrow from 'apache-arrow';
5
- import { BaseDuckDbConnector } from './BaseDuckDbConnector';
6
- import { loadObjects } from './load/load';
7
- export class WasmDuckDbConnector extends BaseDuckDbConnector {
8
- logging;
9
- db = null;
10
- conn = null;
11
- worker = null;
12
- queryConfig;
13
- constructor({ logging = false, initializationQuery = '', dbPath = ':memory:', queryConfig, } = {}) {
14
- super({ dbPath, initializationQuery });
15
- this.queryConfig = queryConfig;
16
- this.logging = logging;
17
- }
18
- async initializeInternal() {
19
- if (!globalThis.Worker) {
20
- throw new Error('No Worker support in this environment');
21
- }
22
- try {
23
- const allBundles = duckdb.getJsDelivrBundles();
24
- const bestBundle = await duckdb.selectBundle(allBundles);
25
- if (!bestBundle.mainWorker) {
26
- throw new Error('No best bundle found for DuckDB worker');
6
+ import { createBaseDuckDbConnector, } from './BaseDuckDbConnector';
7
+ import { loadObjects as loadObjectsSql, load, loadSpatial } from './load/load';
8
+ export function createWasmDuckDbConnector(options = {}) {
9
+ const { logging = false, initializationQuery = '', dbPath = ':memory:', queryConfig, } = options;
10
+ let db = null;
11
+ let conn = null;
12
+ let worker = null;
13
+ const impl = {
14
+ async initializeInternal() {
15
+ if (!globalThis.Worker) {
16
+ throw new Error('No Worker support in this environment');
27
17
  }
28
- const workerUrl = URL.createObjectURL(new Blob([`importScripts("${bestBundle.mainWorker}");`], {
29
- type: 'text/javascript',
30
- }));
31
- const worker = new window.Worker(workerUrl);
32
- const logger = this.logging
33
- ? new duckdb.ConsoleLogger()
34
- : {
35
- // Silently log
36
- log: () => {
37
- /* do nothing */
38
- },
39
- };
40
- const db = new (class extends duckdb.AsyncDuckDB {
41
- onError(event) {
42
- super.onError(event);
43
- console.error('DuckDB worker error:', event);
18
+ try {
19
+ const allBundles = duckdb.getJsDelivrBundles();
20
+ const bestBundle = await duckdb.selectBundle(allBundles);
21
+ if (!bestBundle.mainWorker) {
22
+ throw new Error('No best bundle found for DuckDB worker');
23
+ }
24
+ const workerUrl = URL.createObjectURL(new Blob([`importScripts("${bestBundle.mainWorker}");`], {
25
+ type: 'text/javascript',
26
+ }));
27
+ worker = new window.Worker(workerUrl);
28
+ const logger = logging ? new duckdb.ConsoleLogger() : { log: () => { } };
29
+ db = new (class extends duckdb.AsyncDuckDB {
30
+ onError(event) {
31
+ super.onError(event);
32
+ console.error('DuckDB worker error:', event);
33
+ }
34
+ })(logger, worker);
35
+ await db.instantiate(bestBundle.mainModule, bestBundle.pthreadWorker);
36
+ URL.revokeObjectURL(workerUrl);
37
+ await db.open({
38
+ path: dbPath,
39
+ query: queryConfig,
40
+ });
41
+ conn = augmentConnectionQueryError(await db.connect());
42
+ if (initializationQuery) {
43
+ await conn.query(initializationQuery);
44
44
  }
45
- })(logger, worker);
46
- await db.instantiate(bestBundle.mainModule, bestBundle.pthreadWorker);
47
- URL.revokeObjectURL(workerUrl);
48
- await db.open({
49
- path: this.dbPath,
50
- query: this.queryConfig,
51
- });
52
- const conn = augmentConnectionQueryError(await db.connect());
53
- if (this.initializationQuery) {
54
- await conn.query(this.initializationQuery);
55
45
  }
56
- this.db = db;
57
- this.conn = conn;
58
- this.worker = worker;
59
- this.initialized = true;
60
- }
61
- catch (err) {
62
- this.initialized = false;
63
- this.initializing = null;
64
- throw err;
65
- }
66
- }
67
- async destroy() {
68
- try {
69
- if (this.conn) {
70
- await this.conn.close();
71
- this.conn = null;
46
+ catch (err) {
47
+ db = null;
48
+ conn = null;
49
+ worker = null;
50
+ throw err;
72
51
  }
73
- if (this.db) {
74
- await this.db.terminate();
75
- this.db = null;
52
+ },
53
+ async destroyInternal() {
54
+ if (conn) {
55
+ await conn.close();
56
+ conn = null;
76
57
  }
77
- if (this.worker) {
78
- this.worker.terminate();
79
- this.worker = null;
58
+ if (db) {
59
+ await db.terminate();
60
+ db = null;
80
61
  }
81
- this.initialized = false;
82
- this.initializing = null;
83
- }
84
- catch (err) {
85
- console.error('Error during DuckDB shutdown:', err);
86
- throw err;
87
- }
88
- }
89
- async executeQueryInternal(query, signal) {
90
- // Make sure the WASM runtime is ready.
91
- await this.ensureInitialized();
92
- if (!this.db) {
93
- throw new Error('DuckDB not initialized');
94
- }
95
- // Short‑circuit if the caller already aborted.
96
- if (signal.aborted) {
97
- throw new Error('Query aborted before execution');
98
- }
99
- // 👉 Open a *fresh* connection dedicated to this request.
100
- const conn = augmentConnectionQueryError(await this.db.connect());
101
- // 1️⃣ Kick‑off the statement using the *cancellable* streaming API
102
- const streamPromise = conn.send(query, /* allowStreamResult */ true);
103
- // Handle to the Arrow reader so we can cancel it later.
104
- let reader = null;
105
- // 2️⃣ Helper to materialise all batches into one Arrow Table.
106
- const buildTable = async () => {
107
- reader = await streamPromise;
108
- const batches = [];
109
- let rowCount = 0;
110
- for await (const batch of reader) {
111
- // DuckDB‑wasm may emit an empty placeholder batch when connections
112
- // race. Ignore any batch whose `numRows` is zero.
113
- if (batch.numRows === 0)
114
- continue;
115
- batches.push(batch);
116
- rowCount += batch.numRows;
62
+ if (worker) {
63
+ worker.terminate();
64
+ worker = null;
117
65
  }
118
- if (rowCount === 0) {
119
- return arrow.tableFromArrays({});
66
+ },
67
+ async executeQueryInternal(query, signal) {
68
+ if (!db) {
69
+ throw new Error('DuckDB not initialized');
120
70
  }
121
- return new arrow.Table(batches);
122
- };
123
- // 3️⃣ Wire the AbortSignal → DuckDB interrupt.
124
- let abortHandler;
125
- const abortPromise = new Promise((_, reject) => {
126
- abortHandler = () => {
127
- // Interrupt DuckDB *and* stop the Arrow stream
128
- conn.cancelSent().catch(() => {
129
- /* ignore if nothing to cancel */
130
- });
131
- reader?.cancel?.();
132
- reject(new Error('Query cancelled'));
133
- };
134
- signal.addEventListener('abort', abortHandler);
135
- });
136
- try {
137
- // Whichever finishes first (query or cancel) wins.
138
- return await Promise.race([buildTable(), abortPromise]);
139
- }
140
- finally {
141
- if (abortHandler) {
142
- signal.removeEventListener('abort', abortHandler);
71
+ if (signal.aborted) {
72
+ throw new Error('Query aborted before execution');
143
73
  }
144
- // Always close the per‑query connection.
145
- await conn.close();
146
- }
147
- }
148
- async cancelQueryInternal(queryId) {
149
- // First, invoke the base‑class logic (removes AbortController listeners, etc.)
150
- await super.cancelQueryInternal(queryId);
151
- // Then, interrupt the running statement on the DuckDB side.
152
- if (this.conn) {
74
+ const localConn = augmentConnectionQueryError(await db.connect());
75
+ const streamPromise = localConn.send(query, true);
76
+ let reader = null;
77
+ const buildTable = async () => {
78
+ reader = await streamPromise;
79
+ const batches = [];
80
+ let rowCount = 0;
81
+ for await (const batch of reader) {
82
+ if (batch.numRows === 0)
83
+ continue;
84
+ batches.push(batch);
85
+ rowCount += batch.numRows;
86
+ }
87
+ if (rowCount === 0) {
88
+ return arrow.tableFromArrays({});
89
+ }
90
+ return new arrow.Table(batches);
91
+ };
92
+ let abortHandler;
93
+ const abortPromise = new Promise((_, reject) => {
94
+ abortHandler = () => {
95
+ localConn.cancelSent().catch(() => { });
96
+ reader?.cancel?.();
97
+ reject(new Error('Query cancelled'));
98
+ };
99
+ signal.addEventListener('abort', abortHandler);
100
+ });
153
101
  try {
154
- await this.conn.cancelSent();
102
+ return await Promise.race([buildTable(), abortPromise]);
155
103
  }
156
- catch (err) {
157
- // If no statement is active or interrupt fails, just log and move on.
158
- console.warn('DuckDB cancelSent failed:', err);
104
+ finally {
105
+ if (abortHandler) {
106
+ signal.removeEventListener('abort', abortHandler);
107
+ }
108
+ await localConn.close();
159
109
  }
160
- }
161
- }
162
- async loadFile(file, tableName, opts) {
163
- await this.withTempRegisteredFile(file, async (fileName) => {
164
- await super.loadFile(fileName, tableName, opts);
165
- });
166
- }
167
- async loadArrow(file, tableName, opts) {
168
- await this.ensureInitialized();
169
- if (!this.conn) {
170
- throw new Error('DuckDB connection not initialized');
171
- }
172
- const options = { name: tableName, schema: opts?.schema };
173
- if (file instanceof arrow.Table) {
174
- await this.conn.insertArrowTable(file, options);
175
- }
176
- else {
177
- await this.conn.insertArrowFromIPCStream(file, options);
178
- }
179
- }
180
- async loadObjects(file, tableName, opts) {
181
- await this.ensureInitialized();
182
- if (!this.conn) {
183
- throw new Error('DuckDB connection not initialized');
184
- }
185
- await this.conn.query(loadObjects(tableName, file, opts));
186
- }
187
- async withTempRegisteredFile(file, action) {
188
- await this.ensureInitialized();
189
- if (!this.conn || !this.db) {
110
+ },
111
+ async cancelQueryInternal() {
112
+ if (conn) {
113
+ try {
114
+ await conn.cancelSent();
115
+ }
116
+ catch (err) {
117
+ console.warn('DuckDB cancelSent failed:', err);
118
+ }
119
+ }
120
+ },
121
+ async loadFileInternal(file, tableName, opts) {
122
+ if (!conn) {
123
+ throw new Error('DuckDB connection not initialized');
124
+ }
125
+ await withTempRegisteredFile(file, async (fileName) => {
126
+ if (opts && isSpatialLoadFileOptions(opts)) {
127
+ await conn.query(loadSpatial(tableName, fileName, opts));
128
+ }
129
+ else {
130
+ await conn.query(load(opts?.method ?? 'auto', tableName, fileName, opts));
131
+ }
132
+ });
133
+ },
134
+ async loadArrowInternal(file, tableName, opts) {
135
+ if (!conn) {
136
+ throw new Error('DuckDB connection not initialized');
137
+ }
138
+ const options = { name: tableName, schema: opts?.schema };
139
+ if (file instanceof arrow.Table) {
140
+ await conn.insertArrowTable(file, options);
141
+ }
142
+ else {
143
+ await conn.insertArrowFromIPCStream(file, options);
144
+ }
145
+ },
146
+ async loadObjectsInternal(file, tableName, opts) {
147
+ if (!conn) {
148
+ throw new Error('DuckDB connection not initialized');
149
+ }
150
+ await conn.query(loadObjectsSql(tableName, file, opts));
151
+ },
152
+ };
153
+ const base = createBaseDuckDbConnector({ dbPath, initializationQuery }, impl);
154
+ async function withTempRegisteredFile(file, action) {
155
+ if (!conn || !db) {
190
156
  throw new Error('DuckDB connection not initialized');
191
157
  }
192
158
  let fileName;
193
159
  let tempFileName = undefined;
194
160
  if (file instanceof File) {
195
- // Extension might help DuckDB determine the file type
196
161
  const { ext } = splitFilePath(file.name);
197
162
  tempFileName = `${Math.random().toString(36).substring(2, 15)}${ext ? `.${ext}` : ''}`;
198
163
  fileName = tempFileName;
199
- await this.db.registerFileHandle(fileName, file, DuckDBDataProtocol.BROWSER_FILEREADER, true);
164
+ await db.registerFileHandle(fileName, file, DuckDBDataProtocol.BROWSER_FILEREADER, true);
200
165
  }
201
166
  else {
202
167
  fileName = file;
@@ -204,34 +169,31 @@ export class WasmDuckDbConnector extends BaseDuckDbConnector {
204
169
  try {
205
170
  await action(fileName);
206
171
  }
207
- catch (err) {
208
- console.error(`Error during file loading "${fileName}":`, err);
209
- throw err;
210
- }
211
172
  finally {
212
173
  if (tempFileName) {
213
- await this.db.dropFile(tempFileName);
174
+ await db.dropFile(tempFileName);
214
175
  }
215
176
  }
216
177
  }
217
- getDb() {
218
- if (!this.db) {
219
- throw new Error('DuckDB not initialized');
220
- }
221
- return this.db;
222
- }
223
- getConnection() {
224
- if (!this.conn) {
225
- throw new Error('DuckDB connection not initialized');
226
- }
227
- return this.conn;
228
- }
178
+ return {
179
+ ...base,
180
+ getDb() {
181
+ if (!db) {
182
+ throw new Error('DuckDB not initialized');
183
+ }
184
+ return db;
185
+ },
186
+ getConnection() {
187
+ if (!conn) {
188
+ throw new Error('DuckDB connection not initialized');
189
+ }
190
+ return conn;
191
+ },
192
+ get type() {
193
+ return 'wasm';
194
+ },
195
+ };
229
196
  }
230
- /**
231
- * Augment the connection query method to include the full query and stack trace in the error.
232
- * @param conn - The connection to augment.
233
- * @returns The augmented connection.
234
- */
235
197
  function augmentConnectionQueryError(conn) {
236
198
  const originalQuery = conn.query;
237
199
  conn.query = (async (q) => {
@@ -262,8 +224,7 @@ export class DuckQueryError extends Error {
262
224
  `\n\nFull query:\n\n${query}\n\nQuery call stack:\n\n${stack}\n\n`);
263
225
  }
264
226
  getMessageForUser() {
265
- const { message } = this;
266
- return message;
227
+ return this.message;
267
228
  }
268
229
  }
269
230
  //# sourceMappingURL=WasmDuckDbConnector.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WasmDuckDbConnector.js","sourceRoot":"","sources":["../../src/connectors/WasmDuckDbConnector.ts"],"names":[],"mappings":"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","sourcesContent":["import * as duckdb from '@duckdb/duckdb-wasm';\nimport {DuckDBDataProtocol, DuckDBQueryConfig} from '@duckdb/duckdb-wasm';\nimport {LoadFileOptions, StandardLoadOptions} from '@sqlrooms/project-config';\nimport {splitFilePath} from '@sqlrooms/utils';\nimport * as arrow from 'apache-arrow';\nimport {BaseDuckDbConnector} from './BaseDuckDbConnector';\nimport {loadObjects} from './load/load';\n\nexport class WasmDuckDbConnector extends BaseDuckDbConnector {\n private logging: boolean;\n private db: duckdb.AsyncDuckDB | null = null;\n private conn: duckdb.AsyncDuckDBConnection | null = null;\n private worker: Worker | null = null;\n private queryConfig?: DuckDBQueryConfig;\n\n constructor({\n logging = false,\n initializationQuery = '',\n dbPath = ':memory:',\n queryConfig,\n }: {\n dbPath?: string;\n queryConfig?: DuckDBQueryConfig;\n initializationQuery?: string;\n logging?: boolean;\n } = {}) {\n super({dbPath, initializationQuery});\n this.queryConfig = queryConfig;\n this.logging = logging;\n }\n\n protected async initializeInternal(): Promise<void> {\n if (!globalThis.Worker) {\n throw new Error('No Worker support in this environment');\n }\n\n try {\n const allBundles = duckdb.getJsDelivrBundles();\n const bestBundle = await duckdb.selectBundle(allBundles);\n if (!bestBundle.mainWorker) {\n throw new Error('No best bundle found for DuckDB worker');\n }\n const workerUrl = URL.createObjectURL(\n new Blob([`importScripts(\"${bestBundle.mainWorker}\");`], {\n type: 'text/javascript',\n }),\n );\n\n const worker = new window.Worker(workerUrl);\n const logger = this.logging\n ? new duckdb.ConsoleLogger()\n : {\n // Silently log\n log: () => {\n /* do nothing */\n },\n };\n\n const db = new (class extends duckdb.AsyncDuckDB {\n onError(event: ErrorEvent) {\n super.onError(event);\n console.error('DuckDB worker error:', event);\n }\n })(logger, worker);\n\n await db.instantiate(bestBundle.mainModule, bestBundle.pthreadWorker);\n URL.revokeObjectURL(workerUrl);\n\n await db.open({\n path: this.dbPath,\n query: this.queryConfig,\n });\n\n const conn = augmentConnectionQueryError(await db.connect());\n if (this.initializationQuery) {\n await conn.query(this.initializationQuery);\n }\n\n this.db = db;\n this.conn = conn;\n this.worker = worker;\n this.initialized = true;\n } catch (err) {\n this.initialized = false;\n this.initializing = null;\n throw err;\n }\n }\n\n async destroy(): Promise<void> {\n try {\n if (this.conn) {\n await this.conn.close();\n this.conn = null;\n }\n\n if (this.db) {\n await this.db.terminate();\n this.db = null;\n }\n\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n }\n\n this.initialized = false;\n this.initializing = null;\n } catch (err) {\n console.error('Error during DuckDB shutdown:', err);\n throw err;\n }\n }\n\n protected async executeQueryInternal<T extends arrow.TypeMap = any>(\n query: string,\n signal: AbortSignal,\n ): Promise<arrow.Table<T>> {\n // Make sure the WASM runtime is ready.\n await this.ensureInitialized();\n if (!this.db) {\n throw new Error('DuckDB not initialized');\n }\n\n // Short‑circuit if the caller already aborted.\n if (signal.aborted) {\n throw new Error('Query aborted before execution');\n }\n\n // 👉 Open a *fresh* connection dedicated to this request.\n const conn = augmentConnectionQueryError(await this.db.connect());\n\n // 1️⃣ Kick‑off the statement using the *cancellable* streaming API\n const streamPromise = conn.send<T>(query, /* allowStreamResult */ true);\n\n // Handle to the Arrow reader so we can cancel it later.\n let reader: arrow.RecordBatchReader<T> | null = null;\n\n // 2️⃣ Helper to materialise all batches into one Arrow Table.\n const buildTable = async () => {\n reader = await streamPromise;\n\n const batches: arrow.RecordBatch<T>[] = [];\n let rowCount = 0;\n\n for await (const batch of reader) {\n // DuckDB‑wasm may emit an empty placeholder batch when connections\n // race. Ignore any batch whose `numRows` is zero.\n if (batch.numRows === 0) continue;\n\n batches.push(batch);\n rowCount += batch.numRows;\n }\n\n if (rowCount === 0) {\n return arrow.tableFromArrays({}) as unknown as arrow.Table<T>;\n }\n return new arrow.Table(batches);\n };\n\n // 3️⃣ Wire the AbortSignal → DuckDB interrupt.\n let abortHandler: (() => void) | undefined;\n const abortPromise = new Promise<never>((_, reject) => {\n abortHandler = () => {\n // Interrupt DuckDB *and* stop the Arrow stream\n conn.cancelSent().catch(() => {\n /* ignore if nothing to cancel */\n });\n reader?.cancel?.();\n reject(new Error('Query cancelled'));\n };\n signal.addEventListener('abort', abortHandler);\n });\n\n try {\n // Whichever finishes first (query or cancel) wins.\n return await Promise.race([buildTable(), abortPromise]);\n } finally {\n if (abortHandler) {\n signal.removeEventListener('abort', abortHandler);\n }\n // Always close the per‑query connection.\n await conn.close();\n }\n }\n\n protected async cancelQueryInternal(queryId: string): Promise<void> {\n // First, invoke the base‑class logic (removes AbortController listeners, etc.)\n await super.cancelQueryInternal(queryId);\n\n // Then, interrupt the running statement on the DuckDB side.\n if (this.conn) {\n try {\n await this.conn.cancelSent();\n } catch (err) {\n // If no statement is active or interrupt fails, just log and move on.\n console.warn('DuckDB cancelSent failed:', err);\n }\n }\n }\n\n async loadFile(\n file: string | File,\n tableName: string,\n opts?: LoadFileOptions,\n ) {\n await this.withTempRegisteredFile(file, async (fileName) => {\n await super.loadFile(fileName, tableName, opts);\n });\n }\n\n async loadArrow(\n file: arrow.Table | Uint8Array,\n tableName: string,\n opts?: {schema?: string},\n ) {\n await this.ensureInitialized();\n if (!this.conn) {\n throw new Error('DuckDB connection not initialized');\n }\n const options = {name: tableName, schema: opts?.schema};\n if (file instanceof arrow.Table) {\n await this.conn.insertArrowTable(file, options);\n } else {\n await this.conn.insertArrowFromIPCStream(file, options);\n }\n }\n\n async loadObjects(\n file: Record<string, unknown>[],\n tableName: string,\n opts?: StandardLoadOptions,\n ) {\n await this.ensureInitialized();\n if (!this.conn) {\n throw new Error('DuckDB connection not initialized');\n }\n await this.conn.query(loadObjects(tableName, file, opts));\n }\n\n private async withTempRegisteredFile(\n file: string | File,\n action: (fileName: string) => Promise<void>,\n ) {\n await this.ensureInitialized();\n if (!this.conn || !this.db) {\n throw new Error('DuckDB connection not initialized');\n }\n let fileName: string;\n let tempFileName: string | undefined = undefined;\n if (file instanceof File) {\n // Extension might help DuckDB determine the file type\n const {ext} = splitFilePath(file.name);\n tempFileName = `${Math.random().toString(36).substring(2, 15)}${ext ? `.${ext}` : ''}`;\n fileName = tempFileName;\n await this.db.registerFileHandle(\n fileName,\n file,\n DuckDBDataProtocol.BROWSER_FILEREADER,\n true,\n );\n } else {\n fileName = file;\n }\n try {\n await action(fileName);\n } catch (err) {\n console.error(`Error during file loading \"${fileName}\":`, err);\n throw err;\n } finally {\n if (tempFileName) {\n await this.db.dropFile(tempFileName);\n }\n }\n }\n\n getDb(): duckdb.AsyncDuckDB {\n if (!this.db) {\n throw new Error('DuckDB not initialized');\n }\n return this.db;\n }\n\n getConnection(): duckdb.AsyncDuckDBConnection {\n if (!this.conn) {\n throw new Error('DuckDB connection not initialized');\n }\n return this.conn;\n }\n}\n\n/**\n * Augment the connection query method to include the full query and stack trace in the error.\n * @param conn - The connection to augment.\n * @returns The augmented connection.\n */\nfunction augmentConnectionQueryError(conn: duckdb.AsyncDuckDBConnection) {\n const originalQuery = conn.query;\n conn.query = (async (q: string) => {\n const stack = new Error().stack;\n try {\n return await originalQuery.call(conn, q);\n } catch (err) {\n throw new DuckQueryError(err, q, stack);\n }\n }) as typeof conn.query;\n return conn;\n}\n\nexport class DuckQueryError extends Error {\n readonly cause: unknown;\n readonly query: string | undefined;\n readonly queryCallStack: string | undefined;\n constructor(err: unknown, query: string, stack: string | undefined) {\n super(err instanceof Error ? err.message : `${err}`);\n this.cause = err;\n this.query = query;\n this.queryCallStack = stack;\n Object.setPrototypeOf(this, DuckQueryError.prototype);\n }\n getDetailedMessage() {\n const {message, query, queryCallStack: stack} = this;\n return (\n `DB query failed: ${message}` +\n `\\n\\nFull query:\\n\\n${query}\\n\\nQuery call stack:\\n\\n${stack}\\n\\n`\n );\n }\n getMessageForUser() {\n const {message} = this;\n return message;\n }\n}\n"]}
1
+ {"version":3,"file":"WasmDuckDbConnector.js","sourceRoot":"","sources":["../../src/connectors/WasmDuckDbConnector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAC,kBAAkB,EAAoB,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAGL,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EACL,yBAAyB,GAE1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAC,WAAW,IAAI,cAAc,EAAE,IAAI,EAAE,WAAW,EAAC,MAAM,aAAa,CAAC;AAgB7E,MAAM,UAAU,yBAAyB,CACvC,UAAsC,EAAE;IAExC,MAAM,EACJ,OAAO,GAAG,KAAK,EACf,mBAAmB,GAAG,EAAE,EACxB,MAAM,GAAG,UAAU,EACnB,WAAW,GACZ,GAAG,OAAO,CAAC;IAEZ,IAAI,EAAE,GAA8B,IAAI,CAAC;IACzC,IAAI,IAAI,GAAwC,IAAI,CAAC;IACrD,IAAI,MAAM,GAAkB,IAAI,CAAC;IAEjC,MAAM,IAAI,GAA4B;QACpC,KAAK,CAAC,kBAAkB;YACtB,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;YAC3D,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,UAAU,GAAG,MAAM,CAAC,kBAAkB,EAAE,CAAC;gBAC/C,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;gBACzD,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;oBAC3B,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;gBAC5D,CAAC;gBACD,MAAM,SAAS,GAAG,GAAG,CAAC,eAAe,CACnC,IAAI,IAAI,CAAC,CAAC,kBAAkB,UAAU,CAAC,UAAU,KAAK,CAAC,EAAE;oBACvD,IAAI,EAAE,iBAAiB;iBACxB,CAAC,CACH,CAAC;gBAEF,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBACtC,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAC,GAAG,EAAE,GAAG,EAAE,GAAE,CAAC,EAAC,CAAC;gBAEtE,EAAE,GAAG,IAAI,CAAC,KAAM,SAAQ,MAAM,CAAC,WAAW;oBACxC,OAAO,CAAC,KAAiB;wBACvB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;wBACrB,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;oBAC/C,CAAC;iBACF,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAEnB,MAAM,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC;gBACtE,GAAG,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;gBAE/B,MAAM,EAAE,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,MAAM;oBACZ,KAAK,EAAE,WAAW;iBACnB,CAAC,CAAC;gBAEH,IAAI,GAAG,2BAA2B,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;gBACvD,IAAI,mBAAmB,EAAE,CAAC;oBACxB,MAAM,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBACxC,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,EAAE,GAAG,IAAI,CAAC;gBACV,IAAI,GAAG,IAAI,CAAC;gBACZ,MAAM,GAAG,IAAI,CAAC;gBACd,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC;QAED,KAAK,CAAC,eAAe;YACnB,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;gBACnB,IAAI,GAAG,IAAI,CAAC;YACd,CAAC;YACD,IAAI,EAAE,EAAE,CAAC;gBACP,MAAM,EAAE,CAAC,SAAS,EAAE,CAAC;gBACrB,EAAE,GAAG,IAAI,CAAC;YACZ,CAAC;YACD,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,SAAS,EAAE,CAAC;gBACnB,MAAM,GAAG,IAAI,CAAC;YAChB,CAAC;QACH,CAAC;QAED,KAAK,CAAC,oBAAoB,CACxB,KAAa,EACb,MAAmB;YAEnB,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;YAC5C,CAAC;YAED,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;YACpD,CAAC;YAED,MAAM,SAAS,GAAG,2BAA2B,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YAClE,MAAM,aAAa,GAAG,SAAS,CAAC,IAAI,CAAI,KAAK,EAAE,IAAI,CAAC,CAAC;YACrD,IAAI,MAAM,GAAsC,IAAI,CAAC;YAErD,MAAM,UAAU,GAAG,KAAK,IAAI,EAAE;gBAC5B,MAAM,GAAG,MAAM,aAAa,CAAC;gBAC7B,MAAM,OAAO,GAA2B,EAAE,CAAC;gBAC3C,IAAI,QAAQ,GAAG,CAAC,CAAC;gBACjB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;oBACjC,IAAI,KAAK,CAAC,OAAO,KAAK,CAAC;wBAAE,SAAS;oBAClC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBACpB,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC;gBAC5B,CAAC;gBACD,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;oBACnB,OAAO,KAAK,CAAC,eAAe,CAAC,EAAE,CAA8B,CAAC;gBAChE,CAAC;gBACD,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAClC,CAAC,CAAC;YAEF,IAAI,YAAsC,CAAC;YAC3C,MAAM,YAAY,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;gBACpD,YAAY,GAAG,GAAG,EAAE;oBAClB,SAAS,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;oBACvC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;oBACnB,MAAM,CAAC,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC;gBACvC,CAAC,CAAC;gBACF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;YACjD,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC;gBACH,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC;YAC1D,CAAC;oBAAS,CAAC;gBACT,IAAI,YAAY,EAAE,CAAC;oBACjB,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;gBACpD,CAAC;gBACD,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,KAAK,CAAC,mBAAmB;YACvB,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;gBAC1B,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,OAAO,CAAC,IAAI,CAAC,2BAA2B,EAAE,GAAG,CAAC,CAAC;gBACjD,CAAC;YACH,CAAC;QACH,CAAC;QAED,KAAK,CAAC,gBAAgB,CACpB,IAAmB,EACnB,SAAiB,EACjB,IAAsB;YAEtB,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACvD,CAAC;YACD,MAAM,sBAAsB,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;gBACpD,IAAI,IAAI,IAAI,wBAAwB,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC3C,MAAM,IAAK,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC5D,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAK,CAAC,KAAK,CACf,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,CACxD,CAAC;gBACJ,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;QAED,KAAK,CAAC,iBAAiB,CACrB,IAA8B,EAC9B,SAAiB,EACjB,IAAwB;YAExB,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACvD,CAAC;YACD,MAAM,OAAO,GAAG,EAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAC,CAAC;YACxD,IAAI,IAAI,YAAY,KAAK,CAAC,KAAK,EAAE,CAAC;gBAChC,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC7C,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,CAAC,wBAAwB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACrD,CAAC;QACH,CAAC;QAED,KAAK,CAAC,mBAAmB,CACvB,IAA+B,EAC/B,SAAiB,EACjB,IAA0B;YAE1B,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACvD,CAAC;YACD,MAAM,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAC1D,CAAC;KACF,CAAC;IAEF,MAAM,IAAI,GAAG,yBAAyB,CAAC,EAAC,MAAM,EAAE,mBAAmB,EAAC,EAAE,IAAI,CAAC,CAAC;IAE5E,KAAK,UAAU,sBAAsB,CACnC,IAAmB,EACnB,MAA2C;QAE3C,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,QAAgB,CAAC;QACrB,IAAI,YAAY,GAAuB,SAAS,CAAC;QACjD,IAAI,IAAI,YAAY,IAAI,EAAE,CAAC;YACzB,MAAM,EAAC,GAAG,EAAC,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvC,YAAY,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACvF,QAAQ,GAAG,YAAY,CAAC;YACxB,MAAM,EAAE,CAAC,kBAAkB,CACzB,QAAQ,EACR,IAAI,EACJ,kBAAkB,CAAC,kBAAkB,EACrC,IAAI,CACL,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;gBAAS,CAAC;YACT,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,EAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,GAAG,IAAI;QACP,KAAK;YACH,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;YAC5C,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,aAAa;YACX,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACvD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,IAAI;YACN,OAAO,MAAe,CAAC;QACzB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,2BAA2B,CAAC,IAAkC;IACrE,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC;IACjC,IAAI,CAAC,KAAK,GAAG,CAAC,KAAK,EAAE,CAAS,EAAE,EAAE;QAChC,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC,KAAK,CAAC;QAChC,IAAI,CAAC;YACH,OAAO,MAAM,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,cAAc,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC,CAAsB,CAAC;IACxB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,OAAO,cAAe,SAAQ,KAAK;IAC9B,KAAK,CAAU;IACf,KAAK,CAAqB;IAC1B,cAAc,CAAqB;IAC5C,YAAY,GAAY,EAAE,KAAa,EAAE,KAAyB;QAChE,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC;QACrD,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;QAC5B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;IACxD,CAAC;IACD,kBAAkB;QAChB,MAAM,EAAC,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAC,GAAG,IAAI,CAAC;QACrD,OAAO,CACL,oBAAoB,OAAO,EAAE;YAC7B,sBAAsB,KAAK,4BAA4B,KAAK,MAAM,CACnE,CAAC;IACJ,CAAC;IACD,iBAAiB;QACf,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CACF","sourcesContent":["import * as duckdb from '@duckdb/duckdb-wasm';\nimport {DuckDBDataProtocol, DuckDBQueryConfig} from '@duckdb/duckdb-wasm';\nimport {\n LoadFileOptions,\n StandardLoadOptions,\n isSpatialLoadFileOptions,\n} from '@sqlrooms/room-config';\nimport {splitFilePath} from '@sqlrooms/utils';\nimport * as arrow from 'apache-arrow';\nimport {\n createBaseDuckDbConnector,\n BaseDuckDbConnectorImpl,\n} from './BaseDuckDbConnector';\nimport {loadObjects as loadObjectsSql, load, loadSpatial} from './load/load';\nimport {DuckDbConnector} from './DuckDbConnector';\n\nexport interface WasmDuckDbConnectorOptions {\n dbPath?: string;\n queryConfig?: DuckDBQueryConfig;\n initializationQuery?: string;\n logging?: boolean;\n}\n\nexport interface WasmDuckDbConnector extends DuckDbConnector {\n getDb(): duckdb.AsyncDuckDB;\n getConnection(): duckdb.AsyncDuckDBConnection;\n readonly type: 'wasm';\n}\n\nexport function createWasmDuckDbConnector(\n options: WasmDuckDbConnectorOptions = {},\n): WasmDuckDbConnector {\n const {\n logging = false,\n initializationQuery = '',\n dbPath = ':memory:',\n queryConfig,\n } = options;\n\n let db: duckdb.AsyncDuckDB | null = null;\n let conn: duckdb.AsyncDuckDBConnection | null = null;\n let worker: Worker | null = null;\n\n const impl: BaseDuckDbConnectorImpl = {\n async initializeInternal() {\n if (!globalThis.Worker) {\n throw new Error('No Worker support in this environment');\n }\n try {\n const allBundles = duckdb.getJsDelivrBundles();\n const bestBundle = await duckdb.selectBundle(allBundles);\n if (!bestBundle.mainWorker) {\n throw new Error('No best bundle found for DuckDB worker');\n }\n const workerUrl = URL.createObjectURL(\n new Blob([`importScripts(\"${bestBundle.mainWorker}\");`], {\n type: 'text/javascript',\n }),\n );\n\n worker = new window.Worker(workerUrl);\n const logger = logging ? new duckdb.ConsoleLogger() : {log: () => {}};\n\n db = new (class extends duckdb.AsyncDuckDB {\n onError(event: ErrorEvent) {\n super.onError(event);\n console.error('DuckDB worker error:', event);\n }\n })(logger, worker);\n\n await db.instantiate(bestBundle.mainModule, bestBundle.pthreadWorker);\n URL.revokeObjectURL(workerUrl);\n\n await db.open({\n path: dbPath,\n query: queryConfig,\n });\n\n conn = augmentConnectionQueryError(await db.connect());\n if (initializationQuery) {\n await conn.query(initializationQuery);\n }\n } catch (err) {\n db = null;\n conn = null;\n worker = null;\n throw err;\n }\n },\n\n async destroyInternal() {\n if (conn) {\n await conn.close();\n conn = null;\n }\n if (db) {\n await db.terminate();\n db = null;\n }\n if (worker) {\n worker.terminate();\n worker = null;\n }\n },\n\n async executeQueryInternal<T extends arrow.TypeMap = any>(\n query: string,\n signal: AbortSignal,\n ): Promise<arrow.Table<T>> {\n if (!db) {\n throw new Error('DuckDB not initialized');\n }\n\n if (signal.aborted) {\n throw new Error('Query aborted before execution');\n }\n\n const localConn = augmentConnectionQueryError(await db.connect());\n const streamPromise = localConn.send<T>(query, true);\n let reader: arrow.RecordBatchReader<T> | null = null;\n\n const buildTable = async () => {\n reader = await streamPromise;\n const batches: arrow.RecordBatch<T>[] = [];\n let rowCount = 0;\n for await (const batch of reader) {\n if (batch.numRows === 0) continue;\n batches.push(batch);\n rowCount += batch.numRows;\n }\n if (rowCount === 0) {\n return arrow.tableFromArrays({}) as unknown as arrow.Table<T>;\n }\n return new arrow.Table(batches);\n };\n\n let abortHandler: (() => void) | undefined;\n const abortPromise = new Promise<never>((_, reject) => {\n abortHandler = () => {\n localConn.cancelSent().catch(() => {});\n reader?.cancel?.();\n reject(new Error('Query cancelled'));\n };\n signal.addEventListener('abort', abortHandler);\n });\n\n try {\n return await Promise.race([buildTable(), abortPromise]);\n } finally {\n if (abortHandler) {\n signal.removeEventListener('abort', abortHandler);\n }\n await localConn.close();\n }\n },\n\n async cancelQueryInternal() {\n if (conn) {\n try {\n await conn.cancelSent();\n } catch (err) {\n console.warn('DuckDB cancelSent failed:', err);\n }\n }\n },\n\n async loadFileInternal(\n file: string | File,\n tableName: string,\n opts?: LoadFileOptions,\n ) {\n if (!conn) {\n throw new Error('DuckDB connection not initialized');\n }\n await withTempRegisteredFile(file, async (fileName) => {\n if (opts && isSpatialLoadFileOptions(opts)) {\n await conn!.query(loadSpatial(tableName, fileName, opts));\n } else {\n await conn!.query(\n load(opts?.method ?? 'auto', tableName, fileName, opts),\n );\n }\n });\n },\n\n async loadArrowInternal(\n file: arrow.Table | Uint8Array,\n tableName: string,\n opts?: {schema?: string},\n ) {\n if (!conn) {\n throw new Error('DuckDB connection not initialized');\n }\n const options = {name: tableName, schema: opts?.schema};\n if (file instanceof arrow.Table) {\n await conn.insertArrowTable(file, options);\n } else {\n await conn.insertArrowFromIPCStream(file, options);\n }\n },\n\n async loadObjectsInternal(\n file: Record<string, unknown>[],\n tableName: string,\n opts?: StandardLoadOptions,\n ) {\n if (!conn) {\n throw new Error('DuckDB connection not initialized');\n }\n await conn.query(loadObjectsSql(tableName, file, opts));\n },\n };\n\n const base = createBaseDuckDbConnector({dbPath, initializationQuery}, impl);\n\n async function withTempRegisteredFile(\n file: string | File,\n action: (fileName: string) => Promise<void>,\n ) {\n if (!conn || !db) {\n throw new Error('DuckDB connection not initialized');\n }\n let fileName: string;\n let tempFileName: string | undefined = undefined;\n if (file instanceof File) {\n const {ext} = splitFilePath(file.name);\n tempFileName = `${Math.random().toString(36).substring(2, 15)}${ext ? `.${ext}` : ''}`;\n fileName = tempFileName;\n await db.registerFileHandle(\n fileName,\n file,\n DuckDBDataProtocol.BROWSER_FILEREADER,\n true,\n );\n } else {\n fileName = file;\n }\n try {\n await action(fileName);\n } finally {\n if (tempFileName) {\n await db!.dropFile(tempFileName);\n }\n }\n }\n\n return {\n ...base,\n getDb() {\n if (!db) {\n throw new Error('DuckDB not initialized');\n }\n return db;\n },\n getConnection() {\n if (!conn) {\n throw new Error('DuckDB connection not initialized');\n }\n return conn;\n },\n get type() {\n return 'wasm' as const;\n },\n };\n}\n\nfunction augmentConnectionQueryError(conn: duckdb.AsyncDuckDBConnection) {\n const originalQuery = conn.query;\n conn.query = (async (q: string) => {\n const stack = new Error().stack;\n try {\n return await originalQuery.call(conn, q);\n } catch (err) {\n throw new DuckQueryError(err, q, stack);\n }\n }) as typeof conn.query;\n return conn;\n}\n\nexport class DuckQueryError extends Error {\n readonly cause: unknown;\n readonly query: string | undefined;\n readonly queryCallStack: string | undefined;\n constructor(err: unknown, query: string, stack: string | undefined) {\n super(err instanceof Error ? err.message : `${err}`);\n this.cause = err;\n this.query = query;\n this.queryCallStack = stack;\n Object.setPrototypeOf(this, DuckQueryError.prototype);\n }\n getDetailedMessage() {\n const {message, query, queryCallStack: stack} = this;\n return (\n `DB query failed: ${message}` +\n `\\n\\nFull query:\\n\\n${query}\\n\\nQuery call stack:\\n\\n${stack}\\n\\n`\n );\n }\n getMessageForUser() {\n return this.message;\n }\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import { DuckDbConnector } from './DuckDbConnector';
2
+ import { createWasmDuckDbConnector, WasmDuckDbConnectorOptions, WasmDuckDbConnector } from './WasmDuckDbConnector';
3
+ export type DuckDbConnectorType = 'wasm';
4
+ export type DuckDbConnectorOptions = {
5
+ type: DuckDbConnectorType;
6
+ } & WasmDuckDbConnectorOptions;
7
+ export declare function createDuckDbConnector(options: DuckDbConnectorOptions): DuckDbConnector;
8
+ export { createWasmDuckDbConnector };
9
+ export type { WasmDuckDbConnector };
10
+ export declare function isWasmDuckDbConnector(connector: DuckDbConnector): connector is WasmDuckDbConnector;
11
+ //# sourceMappingURL=createDuckDbConnector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createDuckDbConnector.d.ts","sourceRoot":"","sources":["../../src/connectors/createDuckDbConnector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,mBAAmB,CAAC;AAClD,OAAO,EACL,yBAAyB,EACzB,0BAA0B,EAC1B,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEzC,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,mBAAmB,CAAC;CAC3B,GAAG,0BAA0B,CAAC;AAE/B,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,GAC9B,eAAe,CAQjB;AAED,OAAO,EAAC,yBAAyB,EAAC,CAAC;AACnC,YAAY,EAAC,mBAAmB,EAAC,CAAC;AAElC,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,eAAe,GACzB,SAAS,IAAI,mBAAmB,CAElC"}
@@ -0,0 +1,15 @@
1
+ import { createWasmDuckDbConnector, } from './WasmDuckDbConnector';
2
+ export function createDuckDbConnector(options) {
3
+ const { type, ...rest } = options;
4
+ switch (type) {
5
+ case 'wasm':
6
+ return createWasmDuckDbConnector(rest);
7
+ default:
8
+ throw new Error(`Unsupported DuckDB connector type: ${type}`);
9
+ }
10
+ }
11
+ export { createWasmDuckDbConnector };
12
+ export function isWasmDuckDbConnector(connector) {
13
+ return connector.type === 'wasm';
14
+ }
15
+ //# sourceMappingURL=createDuckDbConnector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createDuckDbConnector.js","sourceRoot":"","sources":["../../src/connectors/createDuckDbConnector.ts"],"names":[],"mappings":"AACA,OAAO,EACL,yBAAyB,GAG1B,MAAM,uBAAuB,CAAC;AAQ/B,MAAM,UAAU,qBAAqB,CACnC,OAA+B;IAE/B,MAAM,EAAC,IAAI,EAAE,GAAG,IAAI,EAAC,GAAG,OAAO,CAAC;IAChC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,MAAM;YACT,OAAO,yBAAyB,CAAC,IAAI,CAAC,CAAC;QACzC;YACE,MAAM,IAAI,KAAK,CAAC,sCAAsC,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED,OAAO,EAAC,yBAAyB,EAAC,CAAC;AAGnC,MAAM,UAAU,qBAAqB,CACnC,SAA0B;IAE1B,OAAQ,SAAiB,CAAC,IAAI,KAAK,MAAM,CAAC;AAC5C,CAAC","sourcesContent":["import {DuckDbConnector} from './DuckDbConnector';\nimport {\n createWasmDuckDbConnector,\n WasmDuckDbConnectorOptions,\n WasmDuckDbConnector,\n} from './WasmDuckDbConnector';\n\nexport type DuckDbConnectorType = 'wasm';\n\nexport type DuckDbConnectorOptions = {\n type: DuckDbConnectorType;\n} & WasmDuckDbConnectorOptions;\n\nexport function createDuckDbConnector(\n options: DuckDbConnectorOptions,\n): DuckDbConnector {\n const {type, ...rest} = options;\n switch (type) {\n case 'wasm':\n return createWasmDuckDbConnector(rest);\n default:\n throw new Error(`Unsupported DuckDB connector type: ${type}`);\n }\n}\n\nexport {createWasmDuckDbConnector};\nexport type {WasmDuckDbConnector};\n\nexport function isWasmDuckDbConnector(\n connector: DuckDbConnector,\n): connector is WasmDuckDbConnector {\n return (connector as any).type === 'wasm';\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { LoadFile, SpatialLoadOptions, StandardLoadOptions } from '@sqlrooms/project-config';
1
+ import { LoadFile, SpatialLoadOptions, StandardLoadOptions } from '@sqlrooms/room-config';
2
2
  /**
3
3
  * Generic function to load data from a file into a DuckDB table
4
4
  * @param method - The DuckDB read method to use (e.g., 'read_csv', 'read_json')
@@ -1 +1 @@
1
- {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../../src/connectors/load/load.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,QAAQ,EACR,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AAIlC;;;;;;;;GAQG;AACH,wBAAgB,IAAI,CAClB,MAAM,EAAE,QAAQ,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,mBAAwB,EACjC,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACrC,MAAM,CA2BR;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CACrB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,MAAM,CAKR;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CACtB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,MAAM,CAKR;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,MAAM,CAER;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CAsBR;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC/B,OAAO,GAAE,mBAAwB,GAChC,MAAM,CAQR"}
1
+ {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../../src/connectors/load/load.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,QAAQ,EACR,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAI/B;;;;;;;;GAQG;AACH,wBAAgB,IAAI,CAClB,MAAM,EAAE,QAAQ,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,mBAAwB,EACjC,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACrC,MAAM,CA2BR;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CACrB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,MAAM,CAKR;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CACtB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,MAAM,CAKR;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,MAAM,CAER;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CAsBR;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC/B,OAAO,GAAE,mBAAwB,GAChC,MAAM,CAQR"}
@@ -1 +1 @@
1
- {"version":3,"file":"load.js","sourceRoot":"","sources":["../../../src/connectors/load/load.ts"],"names":[],"mappings":"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","sourcesContent":["// Adapted from https://github.com/uwdata/mosaic/blob/main/packages/sql/src/load/\n// BSD 3-Clause License Copyright (c) 2023, UW Interactive Data Lab\n\nimport {\n LoadFile,\n SpatialLoadOptions,\n StandardLoadOptions,\n} from '@sqlrooms/project-config';\nimport {createSchema, createTable} from './create';\nimport {sqlFrom} from './sql-from';\n\n/**\n * Generic function to load data from a file into a DuckDB table\n * @param method - The DuckDB read method to use (e.g., 'read_csv', 'read_json')\n * @param tableName - Name of the table to create\n * @param fileName - Path to the input file\n * @param options - Load options including select, where, view, temp, replace and file-specific options\n * @param defaults - Default options to merge with provided options\n * @returns SQL query string to create the table\n */\nexport function load(\n method: LoadFile,\n tableName: string,\n fileName: string,\n options: StandardLoadOptions = {},\n defaults: Record<string, unknown> = {},\n): string {\n const {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n method: _method, // Remove from options\n schema,\n select = ['*'],\n where,\n view,\n temp,\n replace,\n ...file\n } = options;\n const params = parameters({...defaults, ...file});\n const read =\n method === 'auto'\n ? `'${fileName}'${params ? ', ' + params : ''}`\n : `${method}('${fileName}'${params ? ', ' + params : ''})`;\n const filter = where ? ` WHERE ${where}` : '';\n const query = `SELECT ${select.join(', ')} FROM ${read}${filter}`;\n return (\n (schema ? `${createSchema(schema)}; ` : '') +\n createTable(schema ? `${schema}.${tableName}` : tableName, query, {\n view,\n temp,\n replace,\n })\n );\n}\n\n/**\n * Load data from a CSV file into a DuckDB table\n * @param tableName - Name of the table to create\n * @param fileName - Path to the CSV file\n * @param options - Load options\n * @returns SQL query string to create the table\n */\nexport function loadCSV(\n tableName: string,\n fileName: string,\n options?: StandardLoadOptions,\n): string {\n return load('read_csv', tableName, fileName, options, {\n auto_detect: true,\n sample_size: -1,\n });\n}\n\n/**\n * Load data from a JSON file into a DuckDB table\n * @param tableName - Name of the table to create\n * @param fileName - Path to the JSON file\n * @param options - Load options\n * @returns SQL query string to create the table\n */\nexport function loadJSON(\n tableName: string,\n fileName: string,\n options?: StandardLoadOptions,\n): string {\n return load('read_json', tableName, fileName, options, {\n auto_detect: true,\n format: 'auto',\n });\n}\n\n/**\n * Load data from a Parquet file into a DuckDB table\n * @param tableName - Name of the table to create\n * @param fileName - Path to the Parquet file\n * @param options - Load options\n * @returns SQL query string to create the table\n */\nexport function loadParquet(\n tableName: string,\n fileName: string,\n options?: StandardLoadOptions,\n): string {\n return load('read_parquet', tableName, fileName, options);\n}\n\n/**\n * Load geometry data within a spatial file format.\n * This method requires that the DuckDB spatial extension is loaded.\n * Supports GeoJSON, TopoJSON, and other common spatial formats.\n * For TopoJSON, set the layer option to indicate the feature to extract.\n * @param tableName - Name of the table to create\n * @param fileName - Path to the spatial data file\n * @param options - Load options including spatial-specific options\n * @returns SQL query string to create the table\n */\nexport function loadSpatial(\n tableName: string,\n fileName: string,\n options: SpatialLoadOptions = {},\n): string {\n // nested options map to the open_options argument of st_read\n const {schema, options: opt, ...rest} = options;\n if (opt) {\n // TODO: check correct syntax for open_options\n const open = Array.isArray(opt)\n ? opt.join(', ')\n : typeof opt === 'string'\n ? opt\n : Object.entries(opt)\n .map(([key, value]) => `${key}=${value}`)\n .join(', ');\n Object.assign(rest, {open_options: open.toUpperCase()});\n }\n // TODO: handle box_2d for spatial_filter_box option\n // TODO: handle wkb_blob for spatial_filter option\n return load(\n 'st_read',\n schema ? `${schema}.${tableName}` : tableName,\n fileName,\n rest,\n );\n}\n\n/**\n * Load JavaScript objects directly into a DuckDB table\n * @param tableName - Name of the table to create\n * @param data - Array of objects to load\n * @param options - Load options\n * @returns SQL query string to create the table\n */\nexport function loadObjects(\n tableName: string,\n data: Record<string, unknown>[],\n options: StandardLoadOptions = {},\n): string {\n const {schema, select = ['*'], ...opt} = options;\n const values = sqlFrom(data);\n const query =\n select.length === 1 && select[0] === '*'\n ? values\n : `SELECT ${select} FROM ${values}`;\n return createTable(schema ? `${schema}.${tableName}` : tableName, query, opt);\n}\n\n/**\n * Convert options object to DuckDB parameter string\n * @param options - Object containing parameter key-value pairs\n * @returns Formatted parameter string\n */\nfunction parameters(options: Record<string, unknown>): string {\n return Object.entries(options)\n .map(([key, value]) => `${key}=${toDuckDBValue(value)}`)\n .join(', ');\n}\n\n/**\n * Convert JavaScript value to DuckDB literal string representation\n * @param value - Value to convert\n * @returns DuckDB literal string\n */\nfunction toDuckDBValue(value: unknown): string {\n switch (typeof value) {\n case 'boolean':\n return String(value);\n case 'string':\n return `'${value}'`;\n case 'undefined':\n case 'object':\n if (value == null) {\n return 'NULL';\n } else if (Array.isArray(value)) {\n return '[' + value.map((v) => toDuckDBValue(v)).join(', ') + ']';\n } else {\n return (\n '{' +\n Object.entries(value)\n .map(([k, v]) => `'${k}': ${toDuckDBValue(v)}`)\n .join(', ') +\n '}'\n );\n }\n default:\n return String(value);\n }\n}\n"]}
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../../../src/connectors/load/load.ts"],"names":[],"mappings":"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","sourcesContent":["// Adapted from https://github.com/uwdata/mosaic/blob/main/packages/sql/src/load/\n// BSD 3-Clause License Copyright (c) 2023, UW Interactive Data Lab\n\nimport {\n LoadFile,\n SpatialLoadOptions,\n StandardLoadOptions,\n} from '@sqlrooms/room-config';\nimport {createSchema, createTable} from './create';\nimport {sqlFrom} from './sql-from';\n\n/**\n * Generic function to load data from a file into a DuckDB table\n * @param method - The DuckDB read method to use (e.g., 'read_csv', 'read_json')\n * @param tableName - Name of the table to create\n * @param fileName - Path to the input file\n * @param options - Load options including select, where, view, temp, replace and file-specific options\n * @param defaults - Default options to merge with provided options\n * @returns SQL query string to create the table\n */\nexport function load(\n method: LoadFile,\n tableName: string,\n fileName: string,\n options: StandardLoadOptions = {},\n defaults: Record<string, unknown> = {},\n): string {\n const {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n method: _method, // Remove from options\n schema,\n select = ['*'],\n where,\n view,\n temp,\n replace,\n ...file\n } = options;\n const params = parameters({...defaults, ...file});\n const read =\n method === 'auto'\n ? `'${fileName}'${params ? ', ' + params : ''}`\n : `${method}('${fileName}'${params ? ', ' + params : ''})`;\n const filter = where ? ` WHERE ${where}` : '';\n const query = `SELECT ${select.join(', ')} FROM ${read}${filter}`;\n return (\n (schema ? `${createSchema(schema)}; ` : '') +\n createTable(schema ? `${schema}.${tableName}` : tableName, query, {\n view,\n temp,\n replace,\n })\n );\n}\n\n/**\n * Load data from a CSV file into a DuckDB table\n * @param tableName - Name of the table to create\n * @param fileName - Path to the CSV file\n * @param options - Load options\n * @returns SQL query string to create the table\n */\nexport function loadCSV(\n tableName: string,\n fileName: string,\n options?: StandardLoadOptions,\n): string {\n return load('read_csv', tableName, fileName, options, {\n auto_detect: true,\n sample_size: -1,\n });\n}\n\n/**\n * Load data from a JSON file into a DuckDB table\n * @param tableName - Name of the table to create\n * @param fileName - Path to the JSON file\n * @param options - Load options\n * @returns SQL query string to create the table\n */\nexport function loadJSON(\n tableName: string,\n fileName: string,\n options?: StandardLoadOptions,\n): string {\n return load('read_json', tableName, fileName, options, {\n auto_detect: true,\n format: 'auto',\n });\n}\n\n/**\n * Load data from a Parquet file into a DuckDB table\n * @param tableName - Name of the table to create\n * @param fileName - Path to the Parquet file\n * @param options - Load options\n * @returns SQL query string to create the table\n */\nexport function loadParquet(\n tableName: string,\n fileName: string,\n options?: StandardLoadOptions,\n): string {\n return load('read_parquet', tableName, fileName, options);\n}\n\n/**\n * Load geometry data within a spatial file format.\n * This method requires that the DuckDB spatial extension is loaded.\n * Supports GeoJSON, TopoJSON, and other common spatial formats.\n * For TopoJSON, set the layer option to indicate the feature to extract.\n * @param tableName - Name of the table to create\n * @param fileName - Path to the spatial data file\n * @param options - Load options including spatial-specific options\n * @returns SQL query string to create the table\n */\nexport function loadSpatial(\n tableName: string,\n fileName: string,\n options: SpatialLoadOptions = {},\n): string {\n // nested options map to the open_options argument of st_read\n const {schema, options: opt, ...rest} = options;\n if (opt) {\n // TODO: check correct syntax for open_options\n const open = Array.isArray(opt)\n ? opt.join(', ')\n : typeof opt === 'string'\n ? opt\n : Object.entries(opt)\n .map(([key, value]) => `${key}=${value}`)\n .join(', ');\n Object.assign(rest, {open_options: open.toUpperCase()});\n }\n // TODO: handle box_2d for spatial_filter_box option\n // TODO: handle wkb_blob for spatial_filter option\n return load(\n 'st_read',\n schema ? `${schema}.${tableName}` : tableName,\n fileName,\n rest,\n );\n}\n\n/**\n * Load JavaScript objects directly into a DuckDB table\n * @param tableName - Name of the table to create\n * @param data - Array of objects to load\n * @param options - Load options\n * @returns SQL query string to create the table\n */\nexport function loadObjects(\n tableName: string,\n data: Record<string, unknown>[],\n options: StandardLoadOptions = {},\n): string {\n const {schema, select = ['*'], ...opt} = options;\n const values = sqlFrom(data);\n const query =\n select.length === 1 && select[0] === '*'\n ? values\n : `SELECT ${select} FROM ${values}`;\n return createTable(schema ? `${schema}.${tableName}` : tableName, query, opt);\n}\n\n/**\n * Convert options object to DuckDB parameter string\n * @param options - Object containing parameter key-value pairs\n * @returns Formatted parameter string\n */\nfunction parameters(options: Record<string, unknown>): string {\n return Object.entries(options)\n .map(([key, value]) => `${key}=${toDuckDBValue(value)}`)\n .join(', ');\n}\n\n/**\n * Convert JavaScript value to DuckDB literal string representation\n * @param value - Value to convert\n * @returns DuckDB literal string\n */\nfunction toDuckDBValue(value: unknown): string {\n switch (typeof value) {\n case 'boolean':\n return String(value);\n case 'string':\n return `'${value}'`;\n case 'undefined':\n case 'object':\n if (value == null) {\n return 'NULL';\n } else if (Array.isArray(value)) {\n return '[' + value.map((v) => toDuckDBValue(v)).join(', ') + ']';\n } else {\n return (\n '{' +\n Object.entries(value)\n .map(([k, v]) => `'${k}': ${toDuckDBValue(v)}`)\n .join(', ') +\n '}'\n );\n }\n default:\n return String(value);\n }\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -11,9 +11,9 @@ export * from './useSql';
11
11
  export { createDuckDbSlice, createDefaultDuckDbConfig, DuckDbSliceConfig, type DuckDbSliceState, useStoreWithDuckDb, } from './DuckDbSlice';
12
12
  export * from './connectors/DuckDbConnector';
13
13
  export * from './connectors/BaseDuckDbConnector';
14
- export * from './connectors/WasmDuckDbConnector';
14
+ export { createDuckDbConnector, createWasmDuckDbConnector, isWasmDuckDbConnector, type WasmDuckDbConnector, } from './connectors/createDuckDbConnector';
15
15
  export * from './connectors/load/load';
16
16
  export * from './duckdb-utils';
17
- export { LoadFileOptions, SpatialLoadFileOptions, isSpatialLoadFileOptions, } from '@sqlrooms/project-config';
17
+ export { LoadFileOptions, SpatialLoadFileOptions, isSpatialLoadFileOptions, } from '@sqlrooms/room-config';
18
18
  export { type TypedRowAccessor, createTypedRowAccessor, } from './typedRowAccessor';
19
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAC,gBAAgB,EAAC,MAAM,eAAe,CAAC;AAC/C,OAAO,EACL,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,OAAO,EACL,iBAAiB,EACjB,yBAAyB,EACzB,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,gBAAgB,EACrB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAC,gBAAgB,EAAC,MAAM,eAAe,CAAC;AAC/C,OAAO,EACL,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,OAAO,EACL,iBAAiB,EACjB,yBAAyB,EACzB,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AACjD,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,KAAK,mBAAmB,GACzB,MAAM,oCAAoC,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,gBAAgB,EACrB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC"}