@sqlrooms/duckdb-core 0.26.1-rc.11
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/LICENSE.md +9 -0
- package/README.md +387 -0
- package/dist/BaseDuckDbConnector.d.ts +20 -0
- package/dist/BaseDuckDbConnector.d.ts.map +1 -0
- package/dist/BaseDuckDbConnector.js +122 -0
- package/dist/BaseDuckDbConnector.js.map +1 -0
- package/dist/DuckDbConnector.d.ts +312 -0
- package/dist/DuckDbConnector.d.ts.map +1 -0
- package/dist/DuckDbConnector.js +2 -0
- package/dist/DuckDbConnector.js.map +1 -0
- package/dist/arrow-utils.d.ts +8 -0
- package/dist/arrow-utils.d.ts.map +1 -0
- package/dist/arrow-utils.js +28 -0
- package/dist/arrow-utils.js.map +1 -0
- package/dist/duckdb-utils.d.ts +140 -0
- package/dist/duckdb-utils.d.ts.map +1 -0
- package/dist/duckdb-utils.js +290 -0
- package/dist/duckdb-utils.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/load/create.d.ts +33 -0
- package/dist/load/create.d.ts.map +1 -0
- package/dist/load/create.js +33 -0
- package/dist/load/create.js.map +1 -0
- package/dist/load/load.d.ts +57 -0
- package/dist/load/load.d.ts.map +1 -0
- package/dist/load/load.js +153 -0
- package/dist/load/load.js.map +1 -0
- package/dist/load/sql-from.d.ts +18 -0
- package/dist/load/sql-from.d.ts.map +1 -0
- package/dist/load/sql-from.js +69 -0
- package/dist/load/sql-from.js.map +1 -0
- package/dist/schema-tree/schemaTree.d.ts +9 -0
- package/dist/schema-tree/schemaTree.d.ts.map +1 -0
- package/dist/schema-tree/schemaTree.js +75 -0
- package/dist/schema-tree/schemaTree.js.map +1 -0
- package/dist/schema-tree/typeCategories.d.ts +16 -0
- package/dist/schema-tree/typeCategories.d.ts.map +1 -0
- package/dist/schema-tree/typeCategories.js +72 -0
- package/dist/schema-tree/typeCategories.js.map +1 -0
- package/dist/schema-tree/types.d.ts +28 -0
- package/dist/schema-tree/types.d.ts.map +1 -0
- package/dist/schema-tree/types.js +2 -0
- package/dist/schema-tree/types.js.map +1 -0
- package/dist/typedRowAccessor.d.ts +19 -0
- package/dist/typedRowAccessor.d.ts.map +1 -0
- package/dist/typedRowAccessor.js +45 -0
- package/dist/typedRowAccessor.js.map +1 -0
- package/dist/types.d.ts +21 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +42 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright 2025 Ilya Boyandin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
A powerful wrapper around DuckDB-WASM that provides React hooks and utilities for working with DuckDB in browser environments.
|
|
2
|
+
|
|
3
|
+
## Features
|
|
4
|
+
|
|
5
|
+
### React Integration & Type Safety
|
|
6
|
+
|
|
7
|
+
- **React Hooks**: Seamless integration with React applications via `useSql`
|
|
8
|
+
- **Runtime Validation**: Optional Zod schema validation for query results with type transformations
|
|
9
|
+
- **Typed Row Accessors**: Type-safe row access with validation and multiple iteration methods
|
|
10
|
+
|
|
11
|
+
### Data Management
|
|
12
|
+
|
|
13
|
+
- **File Operations**: Import data from various file formats (CSV, JSON, Parquet) with auto-detection
|
|
14
|
+
- **Arrow Integration**: Work directly with Apache Arrow tables for efficient columnar data processing
|
|
15
|
+
- **Schema Management**: Comprehensive database, schema, and table discovery and management
|
|
16
|
+
- **Qualified Table Names**: Full support for `database.schema.table` naming convention
|
|
17
|
+
|
|
18
|
+
### Performance & Operations
|
|
19
|
+
|
|
20
|
+
- **Query Deduplication**: Automatic deduplication of identical running queries to prevent duplicate execution
|
|
21
|
+
- **Query Cancellation**: Cancel running queries with full composability support via `QueryHandle` interface ([learn more](https://sqlrooms.org/query-cancellation))
|
|
22
|
+
- **Data Export**: Export query results to CSV files with pagination for large datasets
|
|
23
|
+
- **Batch Processing**: Handle large datasets efficiently with built-in pagination support
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install @sqlrooms/duckdb
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Basic Usage
|
|
32
|
+
|
|
33
|
+
### Using the SQL Hook
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import {useSql} from '@sqlrooms/duckdb';
|
|
37
|
+
|
|
38
|
+
function UserList() {
|
|
39
|
+
// Basic usage with TypeScript types
|
|
40
|
+
const {data, isLoading, error} = useSql<{id: number; name: string}>({
|
|
41
|
+
query: 'SELECT id, name FROM users',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (isLoading) return <div>Loading...</div>;
|
|
45
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
46
|
+
if (!data) return null;
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<ul>
|
|
50
|
+
{Array.from(data.rows()).map((user) => (
|
|
51
|
+
<li key={user.id}>{user.name}</li>
|
|
52
|
+
))}
|
|
53
|
+
</ul>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
For more information and examples on using the `useSql` hook, see the [useSql API documentation](/api/duckdb/functions/useSql).
|
|
59
|
+
|
|
60
|
+
### Using Zod for Runtime Validation
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
import {useSql} from '@sqlrooms/duckdb';
|
|
64
|
+
import {z} from 'zod';
|
|
65
|
+
|
|
66
|
+
const userSchema = z.object({
|
|
67
|
+
id: z.number(),
|
|
68
|
+
name: z.string(),
|
|
69
|
+
email: z.string().email(),
|
|
70
|
+
created_at: z.string().transform((str) => new Date(str)),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
function ValidatedUserList() {
|
|
74
|
+
const {data, isLoading, error} = useSql(userSchema, {
|
|
75
|
+
query: 'SELECT id, name, email, created_at FROM users',
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (isLoading) return <div>Loading...</div>;
|
|
79
|
+
if (error) {
|
|
80
|
+
if (error instanceof z.ZodError) {
|
|
81
|
+
return <div>Validation Error: {error.errors[0].message}</div>;
|
|
82
|
+
}
|
|
83
|
+
return <div>Error: {error.message}</div>;
|
|
84
|
+
}
|
|
85
|
+
if (!data) return null;
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<ul>
|
|
89
|
+
{data.toArray().map((user) => (
|
|
90
|
+
<li key={user.id}>
|
|
91
|
+
{user.name} ({user.email}) - Joined:{' '}
|
|
92
|
+
{user.created_at.toLocaleDateString()}
|
|
93
|
+
</li>
|
|
94
|
+
))}
|
|
95
|
+
</ul>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Accessing the Underlying Arrow Table and Schema
|
|
101
|
+
|
|
102
|
+
You can access the underlying Arrow table and schema of a `useSql()` query result. This is especially useful if you want to pass the data to a library that expect an Apache Arrow Table as input without additional data transformation:
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
import {useSql} from '@sqlrooms/duckdb';
|
|
106
|
+
|
|
107
|
+
function ArrowTableSchemaExample() {
|
|
108
|
+
const {data, isLoading, error} = useSql({
|
|
109
|
+
query: 'SELECT id, name FROM users',
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
if (isLoading) return <div>Loading...</div>;
|
|
113
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
114
|
+
if (!data || !data.arrowTable) return null;
|
|
115
|
+
|
|
116
|
+
const {arrowTable} = data;
|
|
117
|
+
const fields = arrowTable.schema.fields;
|
|
118
|
+
const numRows = arrowTable.numRows;
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<table>
|
|
122
|
+
<thead>
|
|
123
|
+
<tr>
|
|
124
|
+
{fields.map((field) => (
|
|
125
|
+
<th key={field.name}>{field.name}</th>
|
|
126
|
+
))}
|
|
127
|
+
</tr>
|
|
128
|
+
</thead>
|
|
129
|
+
<tbody>
|
|
130
|
+
{Array.from({length: numRows}).map((_, rowIdx) => (
|
|
131
|
+
<tr key={rowIdx}>
|
|
132
|
+
{fields.map((field, colIdx) => (
|
|
133
|
+
<td key={field.name}>
|
|
134
|
+
{String(arrowTable.getChildAt(colIdx)?.get(rowIdx) ?? '')}
|
|
135
|
+
</td>
|
|
136
|
+
))}
|
|
137
|
+
</tr>
|
|
138
|
+
))}
|
|
139
|
+
</tbody>
|
|
140
|
+
</table>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Working with Tables
|
|
146
|
+
|
|
147
|
+
### Using the Store for Direct Database Operations
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
function DatabaseManager() {
|
|
151
|
+
const createTableFromQuery = useRoomStore(
|
|
152
|
+
(state) => state.db.createTableFromQuery,
|
|
153
|
+
);
|
|
154
|
+
const addTable = useRoomStore((state) => state.db.addTable);
|
|
155
|
+
const dropTable = useRoomStore((state) => state.db.dropTable);
|
|
156
|
+
const tables = useRoomStore((state) => state.db.tables);
|
|
157
|
+
const refreshTableSchemas = useRoomStore(
|
|
158
|
+
(state) => state.db.refreshTableSchemas,
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
// Create a table from a query
|
|
162
|
+
const handleCreateTable = async () => {
|
|
163
|
+
const result = await createTableFromQuery(
|
|
164
|
+
'filtered_users',
|
|
165
|
+
'SELECT * FROM users WHERE active = true',
|
|
166
|
+
);
|
|
167
|
+
console.log(`Created table with ${result.rowCount} rows`);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// Add a table from JavaScript objects
|
|
171
|
+
const handleAddTable = async () => {
|
|
172
|
+
const users = [
|
|
173
|
+
{id: 1, name: 'Alice', email: 'alice@example.com'},
|
|
174
|
+
{id: 2, name: 'Bob', email: 'bob@example.com'},
|
|
175
|
+
];
|
|
176
|
+
await addTable('new_users', users);
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// Drop a table
|
|
180
|
+
const handleDropTable = async () => {
|
|
181
|
+
await dropTable('old_table');
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
<div>
|
|
186
|
+
<button onClick={handleCreateTable}>Create Filtered Users Table</button>
|
|
187
|
+
<button onClick={handleAddTable}>Add New Users Table</button>
|
|
188
|
+
<button onClick={handleDropTable}>Drop Old Table</button>
|
|
189
|
+
<button onClick={refreshTableSchemas}>Refresh Schemas</button>
|
|
190
|
+
|
|
191
|
+
<h3>Available Tables:</h3>
|
|
192
|
+
<ul>
|
|
193
|
+
{tables.map((table) => (
|
|
194
|
+
<li key={table.table.toString()}>
|
|
195
|
+
{table.table.toString()} ({table.columns.length} columns)
|
|
196
|
+
</li>
|
|
197
|
+
))}
|
|
198
|
+
</ul>
|
|
199
|
+
</div>
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Working with Qualified Table Names
|
|
205
|
+
|
|
206
|
+
```tsx
|
|
207
|
+
import {makeQualifiedTableName} from '@sqlrooms/duckdb';
|
|
208
|
+
|
|
209
|
+
// Support for database.schema.table naming
|
|
210
|
+
const qualifiedTable = makeQualifiedTableName({
|
|
211
|
+
database: 'mydb',
|
|
212
|
+
schema: 'public',
|
|
213
|
+
table: 'users',
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Use with table operations
|
|
217
|
+
await createTableFromQuery(qualifiedTable, 'SELECT * FROM source_table');
|
|
218
|
+
await dropTable(qualifiedTable);
|
|
219
|
+
const tableExists = await checkTableExists(qualifiedTable);
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Loading Data from Files
|
|
223
|
+
|
|
224
|
+
### Using Load Functions Directly
|
|
225
|
+
|
|
226
|
+
```tsx
|
|
227
|
+
import {loadCSV, loadJSON, loadParquet, loadObjects} from '@sqlrooms/duckdb';
|
|
228
|
+
|
|
229
|
+
function DataLoader() {
|
|
230
|
+
const getConnector = useRoomStore((state) => state.db.getConnector);
|
|
231
|
+
|
|
232
|
+
const handleLoadCSV = async (file: File) => {
|
|
233
|
+
const connector = await getConnector();
|
|
234
|
+
|
|
235
|
+
// Generate SQL to load CSV file
|
|
236
|
+
const sql = loadCSV('my_table', file.name, {
|
|
237
|
+
auto_detect: true,
|
|
238
|
+
replace: true,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Execute the load operation
|
|
242
|
+
await connector.query(sql).result;
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
const handleLoadObjects = async () => {
|
|
246
|
+
const connector = await getConnector();
|
|
247
|
+
const data = [
|
|
248
|
+
{id: 1, name: 'Alice'},
|
|
249
|
+
{id: 2, name: 'Bob'},
|
|
250
|
+
];
|
|
251
|
+
|
|
252
|
+
// Generate SQL to load objects
|
|
253
|
+
const sql = loadObjects('users', data, {replace: true});
|
|
254
|
+
await connector.query(sql).result;
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
return (
|
|
258
|
+
<div>
|
|
259
|
+
<input
|
|
260
|
+
type="file"
|
|
261
|
+
accept=".csv"
|
|
262
|
+
onChange={(e) => {
|
|
263
|
+
if (e.target.files?.[0]) handleLoadCSV(e.target.files[0]);
|
|
264
|
+
}}
|
|
265
|
+
/>
|
|
266
|
+
<button onClick={handleLoadObjects}>Load Sample Data</button>
|
|
267
|
+
</div>
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Using the Connector Directly
|
|
273
|
+
|
|
274
|
+
```tsx
|
|
275
|
+
function AdvancedDataLoader() {
|
|
276
|
+
const connector = useRoomStore((state) => state.db.connector);
|
|
277
|
+
|
|
278
|
+
const handleFileUpload = async (file: File) => {
|
|
279
|
+
// Load file directly using the connector
|
|
280
|
+
await connector.loadFile(file, 'uploaded_data', {
|
|
281
|
+
method: 'auto', // Auto-detect file type
|
|
282
|
+
replace: true,
|
|
283
|
+
temp: false,
|
|
284
|
+
});
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const handleLoadArrowTable = async (arrowTable: arrow.Table) => {
|
|
288
|
+
// Load Arrow table directly
|
|
289
|
+
await connector.loadArrow(arrowTable, 'arrow_data');
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
return (
|
|
293
|
+
<input
|
|
294
|
+
type="file"
|
|
295
|
+
accept=".csv,.json,.parquet"
|
|
296
|
+
onChange={(e) => {
|
|
297
|
+
if (e.target.files?.[0]) handleFileUpload(e.target.files[0]);
|
|
298
|
+
}}
|
|
299
|
+
/>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Exporting Data to CSV
|
|
305
|
+
|
|
306
|
+
```tsx
|
|
307
|
+
import {useExportToCsv} from '@sqlrooms/duckdb';
|
|
308
|
+
|
|
309
|
+
function ExportButton() {
|
|
310
|
+
const {exportToCsv} = useExportToCsv();
|
|
311
|
+
|
|
312
|
+
const handleExport = async () => {
|
|
313
|
+
await exportToCsv('SELECT * FROM users ORDER BY name', 'users_export.csv');
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
return <button onClick={handleExport}>Export to CSV</button>;
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Low-Level DuckDB Access
|
|
321
|
+
|
|
322
|
+
### Basic direct usage
|
|
323
|
+
|
|
324
|
+
```tsx
|
|
325
|
+
async function executeCustomQuery() {
|
|
326
|
+
// Grab the connector directly (no React hook necessary inside plain TS)
|
|
327
|
+
const connector = useRoomStore((state) => state.db.connector);
|
|
328
|
+
|
|
329
|
+
// QueryHandle is promise-like – await it directly
|
|
330
|
+
const result = await connector.query('SELECT COUNT(*) AS count FROM users');
|
|
331
|
+
|
|
332
|
+
// Inspect Arrow table
|
|
333
|
+
const count = result.getChildAt(0)?.get(0);
|
|
334
|
+
console.log(`Total users: ${count}`);
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Cancellation examples
|
|
339
|
+
|
|
340
|
+
```tsx
|
|
341
|
+
async function cancelExample() {
|
|
342
|
+
const connector = useRoomStore((state) => state.db.connector);
|
|
343
|
+
|
|
344
|
+
// 1. Manual cancel via the handle
|
|
345
|
+
const query = connector.query('SELECT * FROM large_table');
|
|
346
|
+
setTimeout(() => h.cancel(), 2000); // cancel after 2 s
|
|
347
|
+
await query; // throws if cancelled
|
|
348
|
+
|
|
349
|
+
// 2. Composable cancellation – many queries, one controller
|
|
350
|
+
const controller = new AbortController();
|
|
351
|
+
const q1 = connector.query('SELECT 1', {signal: controller.signal});
|
|
352
|
+
const q2 = connector.query('SELECT 2', {signal: controller.signal});
|
|
353
|
+
controller.abort(); // cancels q1 & q2
|
|
354
|
+
await Promise.allSettled([q1, q2]);
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Advanced operations with the Zustand store
|
|
359
|
+
|
|
360
|
+
```tsx
|
|
361
|
+
function AdvancedOperations() {
|
|
362
|
+
const executeSql = useRoomStore((s) => s.db.executeSql);
|
|
363
|
+
const sqlSelectToJson = useRoomStore((s) => s.db.sqlSelectToJson);
|
|
364
|
+
const checkTableExists = useRoomStore((s) => s.db.checkTableExists);
|
|
365
|
+
|
|
366
|
+
const handleAdvancedQuery = async () => {
|
|
367
|
+
// Cached execution with deduplication
|
|
368
|
+
const query = await executeSql('SELECT * FROM users LIMIT 10');
|
|
369
|
+
if (query) {
|
|
370
|
+
const rows = await query; // await handle directly
|
|
371
|
+
console.log('Query result:', rows);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Parse SQL to JSON (analysis tool)
|
|
375
|
+
const parsed = await sqlSelectToJson('SELECT id, name FROM users');
|
|
376
|
+
console.log('Parsed query:', parsed);
|
|
377
|
+
|
|
378
|
+
// Safety check before destructive operations
|
|
379
|
+
const exists = await checkTableExists('users');
|
|
380
|
+
console.log('Table exists:', exists);
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
return <button onClick={handleAdvancedQuery}>Run Advanced Operations</button>;
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
For more information, visit the SQLRooms documentation.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { LoadFileOptions, StandardLoadOptions } from '@sqlrooms/room-config';
|
|
2
|
+
import * as arrow from 'apache-arrow';
|
|
3
|
+
import { DuckDbConnector } from './DuckDbConnector';
|
|
4
|
+
export interface BaseDuckDbConnectorOptions {
|
|
5
|
+
dbPath?: string;
|
|
6
|
+
initializationQuery?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface BaseDuckDbConnectorImpl {
|
|
9
|
+
initializeInternal?(): Promise<void>;
|
|
10
|
+
destroyInternal?(): Promise<void>;
|
|
11
|
+
executeQueryInternal<T extends arrow.TypeMap = any>(query: string, signal: AbortSignal, queryId?: string): Promise<arrow.Table<T>>;
|
|
12
|
+
cancelQueryInternal?(queryId: string): Promise<void>;
|
|
13
|
+
loadArrowInternal?(file: arrow.Table | Uint8Array, tableName: string, opts?: {
|
|
14
|
+
schema?: string;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
loadObjectsInternal?(file: Record<string, unknown>[], tableName: string, opts?: StandardLoadOptions): Promise<void>;
|
|
17
|
+
loadFileInternal?(file: string | File, tableName: string, opts?: LoadFileOptions): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export declare function createBaseDuckDbConnector({ dbPath, initializationQuery, }: BaseDuckDbConnectorOptions | undefined, impl: BaseDuckDbConnectorImpl): DuckDbConnector;
|
|
20
|
+
//# sourceMappingURL=BaseDuckDbConnector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseDuckDbConnector.d.ts","sourceRoot":"","sources":["../src/BaseDuckDbConnector.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EACf,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAC,eAAe,EAA4B,MAAM,mBAAmB,CAAC;AAI7E,MAAM,WAAW,0BAA0B;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,uBAAuB;IACtC,kBAAkB,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,eAAe,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,oBAAoB,CAAC,CAAC,SAAS,KAAK,CAAC,OAAO,GAAG,GAAG,EAChD,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,WAAW,EACnB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,mBAAmB,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,iBAAiB,CAAC,CAChB,IAAI,EAAE,KAAK,CAAC,KAAK,GAAG,UAAU,EAC9B,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAC,GACvB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,mBAAmB,CAAC,CAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC/B,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,mBAAmB,GACzB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,gBAAgB,CAAC,CACf,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,eAAe,GACrB,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAED,wBAAgB,yBAAyB,CACvC,EACE,MAAmB,EACnB,mBAAwB,GACzB,EAAE,0BAA0B,YAAK,EAClC,IAAI,EAAE,uBAAuB,GAC5B,eAAe,CAoKjB"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { isSpatialLoadFileOptions, } from '@sqlrooms/room-config';
|
|
2
|
+
import { load, loadObjects as loadObjectsSql, loadSpatial } from './load/load';
|
|
3
|
+
import { createTypedRowAccessor } from './typedRowAccessor';
|
|
4
|
+
export function createBaseDuckDbConnector({ dbPath = ':memory:', initializationQuery = '', } = {}, impl) {
|
|
5
|
+
const state = {
|
|
6
|
+
dbPath,
|
|
7
|
+
initializationQuery,
|
|
8
|
+
initialized: false,
|
|
9
|
+
initializing: null,
|
|
10
|
+
activeQueries: new Map(),
|
|
11
|
+
};
|
|
12
|
+
const ensureInitialized = async () => {
|
|
13
|
+
if (!state.initialized && state.initializing) {
|
|
14
|
+
await state.initializing;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const initialize = async () => {
|
|
18
|
+
if (state.initialized) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (state.initializing) {
|
|
22
|
+
return state.initializing;
|
|
23
|
+
}
|
|
24
|
+
state.initializing = (async () => {
|
|
25
|
+
await impl.initializeInternal?.();
|
|
26
|
+
if (initializationQuery) {
|
|
27
|
+
await impl.executeQueryInternal(initializationQuery, new AbortController().signal);
|
|
28
|
+
}
|
|
29
|
+
state.initialized = true;
|
|
30
|
+
state.initializing = null;
|
|
31
|
+
})().catch((err) => {
|
|
32
|
+
state.initialized = false;
|
|
33
|
+
state.initializing = null;
|
|
34
|
+
throw err;
|
|
35
|
+
});
|
|
36
|
+
return state.initializing;
|
|
37
|
+
};
|
|
38
|
+
const destroy = async () => {
|
|
39
|
+
await impl.destroyInternal?.();
|
|
40
|
+
state.initialized = false;
|
|
41
|
+
state.initializing = null;
|
|
42
|
+
};
|
|
43
|
+
const generateQueryId = () => `q_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
44
|
+
const cancelQuery = async (queryId) => {
|
|
45
|
+
const abortController = state.activeQueries.get(queryId);
|
|
46
|
+
if (abortController) {
|
|
47
|
+
abortController.abort();
|
|
48
|
+
state.activeQueries.delete(queryId);
|
|
49
|
+
}
|
|
50
|
+
await impl.cancelQueryInternal?.(queryId);
|
|
51
|
+
};
|
|
52
|
+
const createQueryHandle = (queryPromiseFactory, options) => {
|
|
53
|
+
const abortController = new AbortController();
|
|
54
|
+
const queryId = generateQueryId();
|
|
55
|
+
if (options?.signal) {
|
|
56
|
+
const userSignal = options.signal;
|
|
57
|
+
if (userSignal.aborted)
|
|
58
|
+
abortController.abort();
|
|
59
|
+
else
|
|
60
|
+
userSignal.addEventListener('abort', () => abortController.abort());
|
|
61
|
+
}
|
|
62
|
+
state.activeQueries.set(queryId, abortController);
|
|
63
|
+
const resultPromise = queryPromiseFactory(abortController.signal, queryId).finally(() => {
|
|
64
|
+
state.activeQueries.delete(queryId);
|
|
65
|
+
});
|
|
66
|
+
const handle = {
|
|
67
|
+
result: resultPromise,
|
|
68
|
+
signal: abortController.signal,
|
|
69
|
+
cancel: async () => cancelQuery(queryId),
|
|
70
|
+
then: resultPromise.then.bind(resultPromise),
|
|
71
|
+
catch: resultPromise.catch.bind(resultPromise),
|
|
72
|
+
finally: resultPromise.finally?.bind(resultPromise),
|
|
73
|
+
};
|
|
74
|
+
return handle;
|
|
75
|
+
};
|
|
76
|
+
const execute = (sql, options) => createQueryHandle((signal, id) => impl.executeQueryInternal(sql, signal, id), options);
|
|
77
|
+
const query = (queryStr, options) => createQueryHandle((signal, id) => impl.executeQueryInternal(queryStr, signal, id), options);
|
|
78
|
+
const queryJson = (queryStr, options) => createQueryHandle(async (signal, id) => {
|
|
79
|
+
const table = await impl.executeQueryInternal(queryStr, signal, id);
|
|
80
|
+
return createTypedRowAccessor({ arrowTable: table });
|
|
81
|
+
}, options);
|
|
82
|
+
const loadFile = async (file, tableName, opts) => {
|
|
83
|
+
if (impl.loadFileInternal) {
|
|
84
|
+
return impl.loadFileInternal(file, tableName, opts);
|
|
85
|
+
}
|
|
86
|
+
if (file instanceof File) {
|
|
87
|
+
throw new Error('Not implemented', { cause: { file, tableName, opts } });
|
|
88
|
+
}
|
|
89
|
+
const fileName = file;
|
|
90
|
+
await ensureInitialized();
|
|
91
|
+
if (opts && isSpatialLoadFileOptions(opts)) {
|
|
92
|
+
await query(loadSpatial(tableName, fileName, opts));
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
await query(load(opts?.method ?? 'auto', tableName, fileName, opts));
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const loadArrow = async (file, tableName, opts) => {
|
|
99
|
+
if (impl.loadArrowInternal) {
|
|
100
|
+
return impl.loadArrowInternal(file, tableName, opts);
|
|
101
|
+
}
|
|
102
|
+
throw new Error('Not implemented');
|
|
103
|
+
};
|
|
104
|
+
const loadObjects = async (file, tableName, opts) => {
|
|
105
|
+
if (impl.loadObjectsInternal) {
|
|
106
|
+
return impl.loadObjectsInternal(file, tableName, opts);
|
|
107
|
+
}
|
|
108
|
+
await ensureInitialized();
|
|
109
|
+
await query(loadObjectsSql(tableName, file, opts));
|
|
110
|
+
};
|
|
111
|
+
return {
|
|
112
|
+
initialize,
|
|
113
|
+
destroy,
|
|
114
|
+
execute,
|
|
115
|
+
query,
|
|
116
|
+
queryJson,
|
|
117
|
+
loadFile,
|
|
118
|
+
loadArrow,
|
|
119
|
+
loadObjects,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=BaseDuckDbConnector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseDuckDbConnector.js","sourceRoot":"","sources":["../src/BaseDuckDbConnector.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n isSpatialLoadFileOptions,\n LoadFileOptions,\n StandardLoadOptions,\n} from '@sqlrooms/room-config';\nimport * as arrow from 'apache-arrow';\nimport {DuckDbConnector, QueryHandle, QueryOptions} from './DuckDbConnector';\nimport {load, loadObjects as loadObjectsSql, loadSpatial} from './load/load';\nimport {createTypedRowAccessor} from './typedRowAccessor';\n\nexport interface BaseDuckDbConnectorOptions {\n dbPath?: string;\n initializationQuery?: string;\n}\n\nexport interface BaseDuckDbConnectorImpl {\n initializeInternal?(): Promise<void>;\n destroyInternal?(): Promise<void>;\n executeQueryInternal<T extends arrow.TypeMap = any>(\n query: string,\n signal: AbortSignal,\n queryId?: string,\n ): Promise<arrow.Table<T>>;\n cancelQueryInternal?(queryId: string): Promise<void>;\n loadArrowInternal?(\n file: arrow.Table | Uint8Array,\n tableName: string,\n opts?: {schema?: string},\n ): Promise<void>;\n loadObjectsInternal?(\n file: Record<string, unknown>[],\n tableName: string,\n opts?: StandardLoadOptions,\n ): Promise<void>;\n loadFileInternal?(\n file: string | File,\n tableName: string,\n opts?: LoadFileOptions,\n ): Promise<void>;\n}\n\nexport function createBaseDuckDbConnector(\n {\n dbPath = ':memory:',\n initializationQuery = '',\n }: BaseDuckDbConnectorOptions = {},\n impl: BaseDuckDbConnectorImpl,\n): DuckDbConnector {\n const state = {\n dbPath,\n initializationQuery,\n initialized: false,\n initializing: null as Promise<void> | null,\n activeQueries: new Map<string, AbortController>(),\n };\n\n const ensureInitialized = async () => {\n if (!state.initialized && state.initializing) {\n await state.initializing;\n }\n };\n\n const initialize = async () => {\n if (state.initialized) {\n return;\n }\n if (state.initializing) {\n return state.initializing;\n }\n state.initializing = (async () => {\n await impl.initializeInternal?.();\n if (initializationQuery) {\n await impl.executeQueryInternal(\n initializationQuery,\n new AbortController().signal,\n );\n }\n state.initialized = true;\n state.initializing = null;\n })().catch((err) => {\n state.initialized = false;\n state.initializing = null;\n throw err;\n });\n return state.initializing;\n };\n\n const destroy = async () => {\n await impl.destroyInternal?.();\n state.initialized = false;\n state.initializing = null;\n };\n\n const generateQueryId = () =>\n `q_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\n const cancelQuery = async (queryId: string) => {\n const abortController = state.activeQueries.get(queryId);\n if (abortController) {\n abortController.abort();\n state.activeQueries.delete(queryId);\n }\n await impl.cancelQueryInternal?.(queryId);\n };\n\n const createQueryHandle = <T>(\n queryPromiseFactory: (signal: AbortSignal, queryId: string) => Promise<T>,\n options?: QueryOptions,\n ): QueryHandle<T> => {\n const abortController = new AbortController();\n const queryId = generateQueryId();\n if (options?.signal) {\n const userSignal = options.signal;\n if (userSignal.aborted) abortController.abort();\n else userSignal.addEventListener('abort', () => abortController.abort());\n }\n state.activeQueries.set(queryId, abortController);\n const resultPromise = queryPromiseFactory(\n abortController.signal,\n queryId,\n ).finally(() => {\n state.activeQueries.delete(queryId);\n });\n const handle: QueryHandle<T> = {\n result: resultPromise,\n signal: abortController.signal,\n cancel: async () => cancelQuery(queryId),\n then: resultPromise.then.bind(resultPromise),\n catch: resultPromise.catch.bind(resultPromise),\n finally: resultPromise.finally?.bind(resultPromise),\n } as unknown as QueryHandle<T>;\n return handle;\n };\n\n const execute = (sql: string, options?: QueryOptions): QueryHandle =>\n createQueryHandle(\n (signal, id) => impl.executeQueryInternal(sql, signal, id),\n options,\n );\n\n const query = <T extends arrow.TypeMap = any>(\n queryStr: string,\n options?: QueryOptions,\n ): QueryHandle<arrow.Table<T>> =>\n createQueryHandle(\n (signal, id) => impl.executeQueryInternal<T>(queryStr, signal, id),\n options,\n );\n\n const queryJson = <T = Record<string, any>>(\n queryStr: string,\n options?: QueryOptions,\n ): QueryHandle<Iterable<T>> =>\n createQueryHandle(async (signal, id) => {\n const table = await impl.executeQueryInternal(queryStr, signal, id);\n return createTypedRowAccessor({arrowTable: table});\n }, options);\n\n const loadFile = async (\n file: string | File,\n tableName: string,\n opts?: LoadFileOptions,\n ) => {\n if (impl.loadFileInternal) {\n return impl.loadFileInternal(file, tableName, opts);\n }\n if (file instanceof File) {\n throw new Error('Not implemented', {cause: {file, tableName, opts}});\n }\n const fileName = file;\n await ensureInitialized();\n if (opts && isSpatialLoadFileOptions(opts)) {\n await query(loadSpatial(tableName, fileName, opts));\n } else {\n await query(load(opts?.method ?? 'auto', tableName, fileName, opts));\n }\n };\n\n const loadArrow = async (\n file: arrow.Table | Uint8Array,\n tableName: string,\n opts?: {schema?: string},\n ): Promise<void> => {\n if (impl.loadArrowInternal) {\n return impl.loadArrowInternal(file, tableName, opts);\n }\n throw new Error('Not implemented');\n };\n\n const loadObjects = async (\n file: Record<string, unknown>[],\n tableName: string,\n opts?: StandardLoadOptions,\n ) => {\n if (impl.loadObjectsInternal) {\n return impl.loadObjectsInternal(file, tableName, opts);\n }\n await ensureInitialized();\n await query(loadObjectsSql(tableName, file, opts));\n };\n\n return {\n initialize,\n destroy,\n execute,\n query,\n queryJson,\n loadFile,\n loadArrow,\n loadObjects,\n };\n}\n"]}
|