@sqlrooms/duckdb 0.15.0 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/DuckDbSlice.d.ts +102 -23
- package/dist/DuckDbSlice.d.ts.map +1 -1
- package/dist/DuckDbSlice.js +201 -63
- package/dist/DuckDbSlice.js.map +1 -1
- package/dist/connectors/BaseDuckDbConnector.d.ts +22 -5
- package/dist/connectors/BaseDuckDbConnector.d.ts.map +1 -1
- package/dist/connectors/BaseDuckDbConnector.js +66 -15
- package/dist/connectors/BaseDuckDbConnector.js.map +1 -1
- package/dist/connectors/DuckDbConnector.d.ts +237 -4
- package/dist/connectors/DuckDbConnector.d.ts.map +1 -1
- package/dist/connectors/DuckDbConnector.js.map +1 -1
- package/dist/connectors/WasmDuckDbConnector.d.ts +2 -1
- package/dist/connectors/WasmDuckDbConnector.d.ts.map +1 -1
- package/dist/connectors/WasmDuckDbConnector.js +90 -17
- package/dist/connectors/WasmDuckDbConnector.js.map +1 -1
- package/dist/duckdb-utils.d.ts +67 -0
- package/dist/duckdb-utils.d.ts.map +1 -1
- package/dist/duckdb-utils.js +195 -0
- package/dist/duckdb-utils.js.map +1 -1
- package/dist/exportToCsv.js +1 -1
- package/dist/exportToCsv.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/schemaTree.d.ts +8 -0
- package/dist/schemaTree.d.ts.map +1 -0
- package/dist/schemaTree.js +76 -0
- package/dist/schemaTree.js.map +1 -0
- package/dist/typeCategories.d.ts +16 -0
- package/dist/typeCategories.d.ts.map +1 -0
- package/dist/typeCategories.js +72 -0
- package/dist/typeCategories.js.map +1 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/useSql.d.ts.map +1 -1
- package/dist/useSql.js +11 -7
- package/dist/useSql.js.map +1 -1
- package/package.json +13 -12
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { LoadFileOptions, StandardLoadOptions } from '@sqlrooms/project-config';
|
|
2
2
|
import * as arrow from 'apache-arrow';
|
|
3
|
-
import { DuckDbConnector } from './DuckDbConnector';
|
|
4
3
|
import { TypeMap } from 'apache-arrow';
|
|
5
|
-
|
|
4
|
+
import { DuckDbConnector, QueryHandle, QueryOptions } from './DuckDbConnector';
|
|
5
|
+
export declare abstract class BaseDuckDbConnector implements DuckDbConnector {
|
|
6
6
|
protected dbPath: string;
|
|
7
7
|
protected initializationQuery: string;
|
|
8
8
|
protected initialized: boolean;
|
|
9
9
|
protected initializing: Promise<void> | null;
|
|
10
|
+
protected activeQueries: Map<string, AbortController>;
|
|
10
11
|
constructor({ initializationQuery, dbPath, }?: {
|
|
11
12
|
dbPath?: string;
|
|
12
13
|
initializationQuery?: string;
|
|
@@ -15,13 +16,29 @@ export declare class BaseDuckDbConnector implements DuckDbConnector {
|
|
|
15
16
|
protected initializeInternal(): Promise<void>;
|
|
16
17
|
destroy(): Promise<void>;
|
|
17
18
|
protected ensureInitialized(): Promise<void>;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Cancel a query by its internal ID
|
|
21
|
+
* @param queryId Internal query ID to cancel
|
|
22
|
+
*/
|
|
23
|
+
protected cancelQueryInternal(queryId: string): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Abstract method for executing a query with abort signal support.
|
|
26
|
+
* Subclasses must implement this to handle the actual query execution.
|
|
27
|
+
*/
|
|
28
|
+
protected abstract executeQueryInternal<T extends TypeMap = any>(query: string, signal: AbortSignal, queryId?: string): Promise<arrow.Table<T>>;
|
|
29
|
+
/**
|
|
30
|
+
* Creates a QueryHandle with common signal handling logic.
|
|
31
|
+
* This method handles the AbortController setup, signal chaining, and cleanup.
|
|
32
|
+
*/
|
|
33
|
+
protected createQueryHandleInternal<T>(queryPromiseFactory: (signal: AbortSignal, queryId: string) => Promise<T>, options?: QueryOptions): QueryHandle<T>;
|
|
34
|
+
execute(sql: string, options?: QueryOptions): QueryHandle;
|
|
35
|
+
query<T extends TypeMap = any>(query: string, options?: QueryOptions): QueryHandle<arrow.Table<T>>;
|
|
36
|
+
queryJson<T = Record<string, any>>(query: string, options?: QueryOptions): QueryHandle<Iterable<T>>;
|
|
21
37
|
loadFile(file: string | File, tableName: string, opts?: LoadFileOptions): Promise<void>;
|
|
22
38
|
loadArrow(file: arrow.Table | Uint8Array, tableName: string, opts?: {
|
|
23
39
|
schema?: string;
|
|
24
40
|
}): Promise<void>;
|
|
25
41
|
loadObjects(file: Record<string, unknown>[], tableName: string, opts?: StandardLoadOptions): Promise<void>;
|
|
42
|
+
protected generateQueryId(): string;
|
|
26
43
|
}
|
|
27
44
|
//# sourceMappingURL=BaseDuckDbConnector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseDuckDbConnector.d.ts","sourceRoot":"","sources":["../../src/connectors/BaseDuckDbConnector.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EACf,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"BaseDuckDbConnector.d.ts","sourceRoot":"","sources":["../../src/connectors/BaseDuckDbConnector.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EACf,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAC;AACrC,OAAO,EAAC,eAAe,EAAE,WAAW,EAAE,YAAY,EAAC,MAAM,mBAAmB,CAAC;AAI7E,8BAAsB,mBAAoB,YAAW,eAAe;IAClE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACtC,SAAS,CAAC,WAAW,UAAS;IAC9B,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAQ;IACpD,SAAS,CAAC,aAAa,+BAAsC;gBAEjD,EACV,mBAAwB,EACxB,MAAmB,GACpB,GAAE;QACD,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,mBAAmB,CAAC,EAAE,MAAM,CAAC;KACzB;IAKA,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;cAWjB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAI7C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;cAId,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAMlD;;;OAGG;cACa,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASnE;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,SAAS,OAAO,GAAG,GAAG,EAC7D,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,WAAW,EACnB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE1B;;;OAGG;IACH,SAAS,CAAC,yBAAyB,CAAC,CAAC,EACnC,mBAAmB,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EACzE,OAAO,CAAC,EAAE,YAAY,GACrB,WAAW,CAAC,CAAC,CAAC;IAkCjB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,WAAW;IAOzD,KAAK,CAAC,CAAC,SAAS,OAAO,GAAG,GAAG,EAC3B,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,YAAY,GACrB,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAO9B,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC/B,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,YAAY,GACrB,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAOrB,QAAQ,CACZ,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,eAAe;IAiBlB,SAAS,CACb,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;IAIV,WAAW,CACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC/B,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,mBAAmB;IAO5B,SAAS,CAAC,eAAe,IAAI,MAAM;CAGpC"}
|
|
@@ -6,6 +6,7 @@ export class BaseDuckDbConnector {
|
|
|
6
6
|
initializationQuery;
|
|
7
7
|
initialized = false;
|
|
8
8
|
initializing = null;
|
|
9
|
+
activeQueries = new Map();
|
|
9
10
|
constructor({ initializationQuery = '', dbPath = ':memory:', } = {}) {
|
|
10
11
|
this.dbPath = dbPath;
|
|
11
12
|
this.initializationQuery = initializationQuery;
|
|
@@ -27,20 +28,65 @@ export class BaseDuckDbConnector {
|
|
|
27
28
|
// To be implemented by subclasses
|
|
28
29
|
}
|
|
29
30
|
async ensureInitialized() {
|
|
30
|
-
if (!this.initialized) {
|
|
31
|
-
await this.
|
|
31
|
+
if (!this.initialized && this.initializing) {
|
|
32
|
+
await this.initializing;
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Cancel a query by its internal ID
|
|
37
|
+
* @param queryId Internal query ID to cancel
|
|
38
|
+
*/
|
|
39
|
+
async cancelQueryInternal(queryId) {
|
|
40
|
+
const abortController = this.activeQueries.get(queryId);
|
|
41
|
+
if (abortController) {
|
|
42
|
+
abortController.abort();
|
|
43
|
+
this.activeQueries.delete(queryId);
|
|
44
|
+
}
|
|
45
|
+
// Subclasses can override this for additional cleanup
|
|
36
46
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Creates a QueryHandle with common signal handling logic.
|
|
49
|
+
* This method handles the AbortController setup, signal chaining, and cleanup.
|
|
50
|
+
*/
|
|
51
|
+
createQueryHandleInternal(queryPromiseFactory, options) {
|
|
52
|
+
const abortController = new AbortController();
|
|
53
|
+
const queryId = this.generateQueryId();
|
|
54
|
+
// If user provided a signal, listen for its abort event
|
|
55
|
+
if (options?.signal) {
|
|
56
|
+
const userSignal = options.signal;
|
|
57
|
+
if (userSignal.aborted) {
|
|
58
|
+
abortController.abort();
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
userSignal.addEventListener('abort', () => {
|
|
62
|
+
abortController.abort();
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
this.activeQueries.set(queryId, abortController);
|
|
67
|
+
// Execute the query with abort signal support
|
|
68
|
+
const resultPromise = queryPromiseFactory(abortController.signal, queryId).finally(() => {
|
|
69
|
+
this.activeQueries.delete(queryId);
|
|
70
|
+
});
|
|
71
|
+
return {
|
|
72
|
+
result: resultPromise,
|
|
73
|
+
signal: abortController.signal,
|
|
74
|
+
cancel: async () => {
|
|
75
|
+
await this.cancelQueryInternal(queryId);
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
execute(sql, options) {
|
|
80
|
+
return this.createQueryHandleInternal((signal, queryId) => this.executeQueryInternal(sql, signal, queryId), options);
|
|
40
81
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
82
|
+
query(query, options) {
|
|
83
|
+
return this.createQueryHandleInternal((signal, queryId) => this.executeQueryInternal(query, signal, queryId), options);
|
|
84
|
+
}
|
|
85
|
+
queryJson(query, options) {
|
|
86
|
+
return this.createQueryHandleInternal(async (signal, queryId) => {
|
|
87
|
+
const table = await this.executeQueryInternal(query, signal, queryId);
|
|
88
|
+
return createTypedRowAccessor({ arrowTable: table });
|
|
89
|
+
}, options);
|
|
44
90
|
}
|
|
45
91
|
async loadFile(file, tableName, opts) {
|
|
46
92
|
if (file instanceof File) {
|
|
@@ -48,19 +94,24 @@ export class BaseDuckDbConnector {
|
|
|
48
94
|
}
|
|
49
95
|
const fileName = file;
|
|
50
96
|
if (opts && isSpatialLoadFileOptions(opts)) {
|
|
51
|
-
|
|
97
|
+
const queryHandle = this.query(loadSpatial(tableName, fileName, opts));
|
|
98
|
+
await queryHandle.result;
|
|
52
99
|
}
|
|
53
100
|
else {
|
|
54
|
-
|
|
101
|
+
const queryHandle = this.query(load(opts?.method ?? 'auto', tableName, fileName, opts));
|
|
102
|
+
await queryHandle.result;
|
|
55
103
|
}
|
|
56
104
|
}
|
|
57
105
|
async loadArrow(file, tableName, opts) {
|
|
58
|
-
|
|
59
|
-
throw new Error('Not implemented', { cause: { file, tableName, opts } });
|
|
106
|
+
throw new Error('Not implemented');
|
|
60
107
|
}
|
|
61
108
|
async loadObjects(file, tableName, opts) {
|
|
62
109
|
await this.ensureInitialized();
|
|
63
|
-
|
|
110
|
+
const queryHandle = this.query(loadObjects(tableName, file, opts));
|
|
111
|
+
await queryHandle.result;
|
|
112
|
+
}
|
|
113
|
+
generateQueryId() {
|
|
114
|
+
return `q_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
64
115
|
}
|
|
65
116
|
}
|
|
66
117
|
//# sourceMappingURL=BaseDuckDbConnector.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseDuckDbConnector.js","sourceRoot":"","sources":["../../src/connectors/BaseDuckDbConnector.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,GAGzB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"BaseDuckDbConnector.js","sourceRoot":"","sources":["../../src/connectors/BaseDuckDbConnector.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n isSpatialLoadFileOptions,\n LoadFileOptions,\n StandardLoadOptions,\n} from '@sqlrooms/project-config';\nimport * as arrow from 'apache-arrow';\nimport {TypeMap} from 'apache-arrow';\nimport {DuckDbConnector, QueryHandle, QueryOptions} from './DuckDbConnector';\nimport {load, loadObjects, loadSpatial} from './load/load';\nimport {createTypedRowAccessor} from '../typedRowAccessor';\n\nexport abstract class BaseDuckDbConnector implements DuckDbConnector {\n protected dbPath: string;\n protected initializationQuery: string;\n protected initialized = false;\n protected initializing: Promise<void> | null = null;\n protected activeQueries = new Map<string, AbortController>();\n\n constructor({\n initializationQuery = '',\n dbPath = ':memory:',\n }: {\n dbPath?: string;\n initializationQuery?: string;\n } = {}) {\n this.dbPath = dbPath;\n this.initializationQuery = initializationQuery;\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n if (this.initializing) {\n return this.initializing;\n }\n this.initializing = this.initializeInternal();\n return this.initializing;\n }\n\n protected async initializeInternal(): Promise<void> {\n // To be implemented by subclasses\n }\n\n async destroy(): Promise<void> {\n // To be implemented by subclasses\n }\n\n protected async ensureInitialized(): Promise<void> {\n if (!this.initialized && this.initializing) {\n await this.initializing;\n }\n }\n\n /**\n * Cancel a query by its internal ID\n * @param queryId Internal query ID to cancel\n */\n protected async cancelQueryInternal(queryId: string): Promise<void> {\n const abortController = this.activeQueries.get(queryId);\n if (abortController) {\n abortController.abort();\n this.activeQueries.delete(queryId);\n }\n // Subclasses can override this for additional cleanup\n }\n\n /**\n * Abstract method for executing a query with abort signal support.\n * Subclasses must implement this to handle the actual query execution.\n */\n protected abstract executeQueryInternal<T extends TypeMap = any>(\n query: string,\n signal: AbortSignal,\n queryId?: string,\n ): Promise<arrow.Table<T>>;\n\n /**\n * Creates a QueryHandle with common signal handling logic.\n * This method handles the AbortController setup, signal chaining, and cleanup.\n */\n protected createQueryHandleInternal<T>(\n queryPromiseFactory: (signal: AbortSignal, queryId: string) => Promise<T>,\n options?: QueryOptions,\n ): QueryHandle<T> {\n const abortController = new AbortController();\n const queryId = this.generateQueryId();\n\n // If user provided a signal, listen for its abort event\n if (options?.signal) {\n const userSignal = options.signal;\n if (userSignal.aborted) {\n abortController.abort();\n } else {\n userSignal.addEventListener('abort', () => {\n abortController.abort();\n });\n }\n }\n\n this.activeQueries.set(queryId, abortController);\n\n // Execute the query with abort signal support\n const resultPromise = queryPromiseFactory(abortController.signal, queryId).finally(\n () => {\n this.activeQueries.delete(queryId);\n },\n );\n\n return {\n result: resultPromise,\n signal: abortController.signal,\n cancel: async () => {\n await this.cancelQueryInternal(queryId);\n },\n };\n }\n\n execute(sql: string, options?: QueryOptions): QueryHandle {\n return this.createQueryHandleInternal(\n (signal, queryId) => this.executeQueryInternal(sql, signal, queryId),\n options,\n );\n }\n\n query<T extends TypeMap = any>(\n query: string,\n options?: QueryOptions,\n ): QueryHandle<arrow.Table<T>> {\n return this.createQueryHandleInternal(\n (signal, queryId) => this.executeQueryInternal<T>(query, signal, queryId),\n options,\n );\n }\n\n queryJson<T = Record<string, any>>(\n query: string,\n options?: QueryOptions,\n ): QueryHandle<Iterable<T>> {\n return this.createQueryHandleInternal(async (signal, queryId) => {\n const table = await this.executeQueryInternal(query, signal, queryId);\n return createTypedRowAccessor({arrowTable: table});\n }, options);\n }\n\n async loadFile(\n file: string | File,\n tableName: string,\n opts?: LoadFileOptions,\n ) {\n if (file instanceof File) {\n throw new Error('Not implemented', {cause: {file, tableName, opts}});\n }\n const fileName = file;\n if (opts && isSpatialLoadFileOptions(opts)) {\n const queryHandle = this.query(loadSpatial(tableName, fileName, opts));\n await queryHandle.result;\n } else {\n const queryHandle = this.query(\n load(opts?.method ?? 'auto', tableName, fileName, opts),\n );\n await queryHandle.result;\n }\n }\n\n async loadArrow(\n file: arrow.Table | Uint8Array,\n tableName: string,\n opts?: {schema?: string}\n ): Promise<void> {\n throw new Error('Not implemented');\n }\n\n async loadObjects(\n file: Record<string, unknown>[],\n tableName: string,\n opts?: StandardLoadOptions,\n ) {\n await this.ensureInitialized();\n const queryHandle = this.query(loadObjects(tableName, file, opts));\n await queryHandle.result;\n }\n\n protected generateQueryId(): string {\n return `q_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n}\n"]}
|
|
@@ -1,6 +1,154 @@
|
|
|
1
1
|
import { LoadFileOptions, StandardLoadOptions } from '@sqlrooms/project-config';
|
|
2
2
|
import * as arrow from 'apache-arrow';
|
|
3
3
|
import { TypeMap } from 'apache-arrow';
|
|
4
|
+
/**
|
|
5
|
+
* Options for query execution
|
|
6
|
+
*/
|
|
7
|
+
export interface QueryOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Optional external abort signal for coordinated cancellation.
|
|
10
|
+
* When provided, the query will be cancelled if this signal is aborted.
|
|
11
|
+
* This enables powerful composition patterns like cancelling multiple
|
|
12
|
+
* queries together or integrating with other cancellable operations.
|
|
13
|
+
*/
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Handle for managing query execution and cancellation
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // Simple usage
|
|
22
|
+
* const handle = connector.query('SELECT * FROM table');
|
|
23
|
+
* await handle.result;
|
|
24
|
+
*
|
|
25
|
+
* // With cancellation
|
|
26
|
+
* const handle = connector.query('SELECT * FROM large_table');
|
|
27
|
+
* setTimeout(() => handle.cancel(), 5000);
|
|
28
|
+
*
|
|
29
|
+
* // Composable cancellation
|
|
30
|
+
* const controller = new AbortController();
|
|
31
|
+
* const handle1 = connector.query('SELECT * FROM table1', { signal: controller.signal });
|
|
32
|
+
* const handle2 = connector.query('SELECT * FROM table2', { signal: controller.signal });
|
|
33
|
+
* controller.abort(); // Cancels both queries
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export interface QueryHandle<T = any> {
|
|
37
|
+
/** Promise that resolves with query results */
|
|
38
|
+
result: Promise<T>;
|
|
39
|
+
/**
|
|
40
|
+
* Method to cancel the query with optional cleanup.
|
|
41
|
+
* This provides a clean abstraction over the underlying cancellation mechanism.
|
|
42
|
+
*/
|
|
43
|
+
cancel: () => Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Read-only access to the abort signal for composability.
|
|
46
|
+
*
|
|
47
|
+
* Key benefits:
|
|
48
|
+
* - **Event-driven**: Listen for abort events to update UI or perform cleanup
|
|
49
|
+
* - **Integration**: Use with other Web APIs like fetch() that accept AbortSignal
|
|
50
|
+
* - **Status checking**: Check if query is already cancelled with signal.aborted
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* // Listen for cancellation events
|
|
55
|
+
* handle.signal.addEventListener('abort', () => {
|
|
56
|
+
* console.log('Query cancelled');
|
|
57
|
+
* updateUI('Operation cancelled');
|
|
58
|
+
* });
|
|
59
|
+
*
|
|
60
|
+
* // Check cancellation status
|
|
61
|
+
* if (handle.signal.aborted) {
|
|
62
|
+
* console.log('Query was already cancelled');
|
|
63
|
+
* }
|
|
64
|
+
*
|
|
65
|
+
* // Use with other APIs
|
|
66
|
+
* const response = await fetch('/api/data', { signal: handle.signal });
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
signal: AbortSignal;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* DuckDB connector interface with advanced query cancellation support
|
|
73
|
+
*
|
|
74
|
+
* This interface provides a hybrid approach that combines the simplicity of method-based
|
|
75
|
+
* cancellation with the composability of Web Standards (AbortController/AbortSignal).
|
|
76
|
+
*
|
|
77
|
+
* ## Key Benefits of This Design
|
|
78
|
+
*
|
|
79
|
+
* ### 🔗 Composability
|
|
80
|
+
* Cancel multiple queries with a single controller:
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const controller = new AbortController();
|
|
83
|
+
* const query1 = connector.query('SELECT * FROM table1', { signal: controller.signal });
|
|
84
|
+
* const query2 = connector.query('SELECT * FROM table2', { signal: controller.signal });
|
|
85
|
+
* controller.abort(); // Cancels both queries
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* ### 🌐 Integration with Web APIs
|
|
89
|
+
* Use the same signal for queries and HTTP requests:
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const controller = new AbortController();
|
|
92
|
+
* const queryHandle = connector.query('SELECT * FROM table', { signal: controller.signal });
|
|
93
|
+
* const response = await fetch('/api/data', { signal: controller.signal });
|
|
94
|
+
* // controller.abort() cancels both the query and the HTTP request
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* ### 🎛️ Flexibility
|
|
98
|
+
* Simple usage when you don't need external control, advanced when you do:
|
|
99
|
+
* ```typescript
|
|
100
|
+
* // Simple - internal cancellation management
|
|
101
|
+
* const handle = connector.query('SELECT * FROM table');
|
|
102
|
+
* handle.cancel();
|
|
103
|
+
*
|
|
104
|
+
* // Advanced - external cancellation control
|
|
105
|
+
* const controller = new AbortController();
|
|
106
|
+
* const handle = connector.query('SELECT * FROM table', { signal: controller.signal });
|
|
107
|
+
* controller.abort();
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
* ### 📡 Event-Driven
|
|
111
|
+
* React to cancellation events for better UX:
|
|
112
|
+
* ```typescript
|
|
113
|
+
* handle.signal.addEventListener('abort', () => {
|
|
114
|
+
* showNotification('Query cancelled');
|
|
115
|
+
* hideLoadingSpinner();
|
|
116
|
+
* });
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* ### ⏱️ Timeout Support
|
|
120
|
+
* Built-in timeout capability with manual override:
|
|
121
|
+
* ```typescript
|
|
122
|
+
* const timeoutController = new AbortController();
|
|
123
|
+
* setTimeout(() => timeoutController.abort(), 30000); // 30s timeout
|
|
124
|
+
*
|
|
125
|
+
* const handle = connector.query('SELECT * FROM large_table', {
|
|
126
|
+
* signal: timeoutController.signal
|
|
127
|
+
* });
|
|
128
|
+
*
|
|
129
|
+
* // User can still cancel manually
|
|
130
|
+
* cancelButton.onclick = () => timeoutController.abort();
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* ### 🏗️ Signal Composition
|
|
134
|
+
* Combine multiple cancellation sources:
|
|
135
|
+
* ```typescript
|
|
136
|
+
* function combineSignals(...signals: AbortSignal[]): AbortSignal {
|
|
137
|
+
* const controller = new AbortController();
|
|
138
|
+
* signals.forEach(signal => {
|
|
139
|
+
* if (signal.aborted) controller.abort();
|
|
140
|
+
* else signal.addEventListener('abort', () => controller.abort());
|
|
141
|
+
* });
|
|
142
|
+
* return controller.signal;
|
|
143
|
+
* }
|
|
144
|
+
*
|
|
145
|
+
* const userSignal = userController.signal;
|
|
146
|
+
* const timeoutSignal = createTimeoutSignal(30000);
|
|
147
|
+
* const combinedSignal = combineSignals(userSignal, timeoutSignal);
|
|
148
|
+
*
|
|
149
|
+
* const handle = connector.query('SELECT * FROM table', { signal: combinedSignal });
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
4
152
|
export interface DuckDbConnector {
|
|
5
153
|
/**
|
|
6
154
|
* Initialize the connector
|
|
@@ -12,19 +160,104 @@ export interface DuckDbConnector {
|
|
|
12
160
|
destroy(): Promise<void>;
|
|
13
161
|
/**
|
|
14
162
|
* Execute a SQL query without returning a result
|
|
163
|
+
*
|
|
15
164
|
* @param sql SQL query to execute
|
|
165
|
+
* @param options Optional query options including abort signal for coordinated cancellation
|
|
166
|
+
* @returns QueryHandle containing:
|
|
167
|
+
* - result: Promise that resolves when execution completes
|
|
168
|
+
* - cancel: Method to cancel the query with cleanup
|
|
169
|
+
* - signal: AbortSignal for composability with other cancellable operations
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* // Simple execution
|
|
174
|
+
* const handle = connector.execute('CREATE TABLE test AS SELECT * FROM source');
|
|
175
|
+
* await handle.result;
|
|
176
|
+
*
|
|
177
|
+
* // With external cancellation control
|
|
178
|
+
* const controller = new AbortController();
|
|
179
|
+
* const handle = connector.execute('DROP TABLE large_table', {
|
|
180
|
+
* signal: controller.signal
|
|
181
|
+
* });
|
|
182
|
+
*
|
|
183
|
+
* // Cancel if it takes too long
|
|
184
|
+
* setTimeout(() => controller.abort(), 5000);
|
|
185
|
+
* ```
|
|
16
186
|
*/
|
|
17
|
-
execute(sql: string):
|
|
187
|
+
execute(sql: string, options?: QueryOptions): QueryHandle;
|
|
18
188
|
/**
|
|
19
189
|
* Execute a SQL query and return the result as an Arrow table
|
|
190
|
+
*
|
|
20
191
|
* @param query SQL query to execute
|
|
192
|
+
* @param options Optional query options including abort signal for coordinated cancellation
|
|
193
|
+
* @returns QueryHandle containing:
|
|
194
|
+
* - result: Promise that resolves with Arrow table
|
|
195
|
+
* - cancel: Method to cancel the query with cleanup
|
|
196
|
+
* - signal: AbortSignal for composability with other cancellable operations
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```typescript
|
|
200
|
+
* // Basic query
|
|
201
|
+
* const handle = connector.query('SELECT * FROM users WHERE active = true');
|
|
202
|
+
* const table = await handle.result;
|
|
203
|
+
* console.log(`Found ${table.numRows} active users`);
|
|
204
|
+
*
|
|
205
|
+
* // Query with timeout
|
|
206
|
+
* const controller = new AbortController();
|
|
207
|
+
* setTimeout(() => controller.abort(), 30000); // 30s timeout
|
|
208
|
+
*
|
|
209
|
+
* const handle = connector.query('SELECT * FROM very_large_table', {
|
|
210
|
+
* signal: controller.signal
|
|
211
|
+
* });
|
|
212
|
+
*
|
|
213
|
+
* try {
|
|
214
|
+
* const result = await handle.result;
|
|
215
|
+
* console.log('Query completed within timeout');
|
|
216
|
+
* } catch (error) {
|
|
217
|
+
* if (error.name === 'AbortError') {
|
|
218
|
+
* console.log('Query timed out');
|
|
219
|
+
* }
|
|
220
|
+
* }
|
|
221
|
+
* ```
|
|
21
222
|
*/
|
|
22
|
-
query<T extends TypeMap = any>(query: string):
|
|
223
|
+
query<T extends TypeMap = any>(query: string, options?: QueryOptions): QueryHandle<arrow.Table<T>>;
|
|
23
224
|
/**
|
|
24
225
|
* Execute a SQL query and return the result as a JSON object
|
|
25
|
-
*
|
|
226
|
+
*
|
|
227
|
+
* @param query SQL query to execute
|
|
228
|
+
* @param options Optional query options including abort signal for coordinated cancellation
|
|
229
|
+
* @returns QueryHandle containing:
|
|
230
|
+
* - result: Promise that resolves with iterable of JSON objects
|
|
231
|
+
* - cancel: Method to cancel the query with cleanup
|
|
232
|
+
* - signal: AbortSignal for composability with other cancellable operations
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```typescript
|
|
236
|
+
* // Simple JSON query
|
|
237
|
+
* const handle = connector.queryJson('SELECT name, email FROM users LIMIT 10');
|
|
238
|
+
* const users = await handle.result;
|
|
239
|
+
* for (const user of users) {
|
|
240
|
+
* console.log(`${user.name}: ${user.email}`);
|
|
241
|
+
* }
|
|
242
|
+
*
|
|
243
|
+
* // Coordinated cancellation with multiple operations
|
|
244
|
+
* const operationController = new AbortController();
|
|
245
|
+
*
|
|
246
|
+
* const usersHandle = connector.queryJson('SELECT * FROM users', {
|
|
247
|
+
* signal: operationController.signal
|
|
248
|
+
* });
|
|
249
|
+
*
|
|
250
|
+
* const ordersHandle = connector.queryJson('SELECT * FROM orders', {
|
|
251
|
+
* signal: operationController.signal
|
|
252
|
+
* });
|
|
253
|
+
*
|
|
254
|
+
* // Cancel both queries if user navigates away
|
|
255
|
+
* window.addEventListener('beforeunload', () => {
|
|
256
|
+
* operationController.abort();
|
|
257
|
+
* });
|
|
258
|
+
* ```
|
|
26
259
|
*/
|
|
27
|
-
queryJson<T = Record<string, any>>(query: string):
|
|
260
|
+
queryJson<T = Record<string, any>>(query: string, options?: QueryOptions): QueryHandle<Iterable<T>>;
|
|
28
261
|
/**
|
|
29
262
|
* Load a file into DuckDB and create a table
|
|
30
263
|
* @param fileName - Path to the file to load
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DuckDbConnector.d.ts","sourceRoot":"","sources":["../../src/connectors/DuckDbConnector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAE,mBAAmB,EAAC,MAAM,0BAA0B,CAAC;AAC9E,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAC;AAErC,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B;;OAEG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB
|
|
1
|
+
{"version":3,"file":"DuckDbConnector.d.ts","sourceRoot":"","sources":["../../src/connectors/DuckDbConnector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAE,mBAAmB,EAAC,MAAM,0BAA0B,CAAC;AAC9E,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAC;AAErC;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,GAAG;IAClC,+CAA+C;IAC/C,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAEnB;;;OAGG;IACH,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,MAAM,EAAE,WAAW,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgFG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B;;OAEG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,WAAW,CAAC;IAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;IACH,KAAK,CAAC,CAAC,SAAS,OAAO,GAAG,GAAG,EAC3B,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,YAAY,GACrB,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCG;IACH,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC/B,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,YAAY,GACrB,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAE5B;;;;;OAKG;IACH,QAAQ,CACN,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,eAAe,GACrB,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;;;OAIG;IACH,SAAS,CACP,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,UAAU,EAC/B,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAC,GACvB,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;;;;OAKG;IACH,WAAW,CACT,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;CAClB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DuckDbConnector.js","sourceRoot":"","sources":["../../src/connectors/DuckDbConnector.ts"],"names":[],"mappings":"","sourcesContent":["import {LoadFileOptions, StandardLoadOptions} from '@sqlrooms/project-config';\nimport * as arrow from 'apache-arrow';\nimport {TypeMap} from 'apache-arrow';\n\nexport interface DuckDbConnector {\n /**\n * Initialize the connector\n */\n initialize(): Promise<void>;\n\n /**\n * Destroy the connector and clean up resources\n */\n destroy(): Promise<void>;\n\n /**\n * Execute a SQL query without returning a result\n * @param sql SQL query to execute\n */\n execute(sql: string): Promise<void>;\n\n /**\n * Execute a SQL query and return the result as an Arrow table\n * @param query SQL query to execute\n */\n query<T extends TypeMap = any>(query: string): Promise<arrow.Table<T>>;\n\n /**\n * Execute a SQL query and return the result as a JSON object\n * @param query\n */\n queryJson<T = Record<string, any>>(query: string): Promise<Iterable<T>>;\n\n /**\n * Load a file into DuckDB and create a table\n * @param fileName - Path to the file to load\n * @param tableName - Name of the table to create\n * @param opts - Load options\n */\n loadFile(\n fileName: string | File,\n tableName: string,\n opts?: LoadFileOptions,\n ): Promise<void>;\n\n /**\n * Load an arrow table or an arrow IPC stream into DuckDB\n * @param table - Arrow table or arrow IPC stream to load\n * @param tableName - Name of the table to create\n */\n loadArrow(\n table: arrow.Table | Uint8Array,\n tableName: string,\n opts?: {schema?: string},\n ): Promise<void>;\n\n /**\n * Load JavaScript objects into DuckDB\n * @param data - Array of objects to load\n * @param tableName - Name of the table to create\n * @param opts - Load options\n */\n loadObjects(\n data: Record<string, unknown>[],\n tableName: string,\n opts?: StandardLoadOptions,\n ): Promise<void>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"DuckDbConnector.js","sourceRoot":"","sources":["../../src/connectors/DuckDbConnector.ts"],"names":[],"mappings":"","sourcesContent":["import {LoadFileOptions, StandardLoadOptions} from '@sqlrooms/project-config';\nimport * as arrow from 'apache-arrow';\nimport {TypeMap} from 'apache-arrow';\n\n/**\n * Options for query execution\n */\nexport interface QueryOptions {\n /**\n * Optional external abort signal for coordinated cancellation.\n * When provided, the query will be cancelled if this signal is aborted.\n * This enables powerful composition patterns like cancelling multiple\n * queries together or integrating with other cancellable operations.\n */\n signal?: AbortSignal;\n}\n\n/**\n * Handle for managing query execution and cancellation\n *\n * @example\n * ```typescript\n * // Simple usage\n * const handle = connector.query('SELECT * FROM table');\n * await handle.result;\n *\n * // With cancellation\n * const handle = connector.query('SELECT * FROM large_table');\n * setTimeout(() => handle.cancel(), 5000);\n *\n * // Composable cancellation\n * const controller = new AbortController();\n * const handle1 = connector.query('SELECT * FROM table1', { signal: controller.signal });\n * const handle2 = connector.query('SELECT * FROM table2', { signal: controller.signal });\n * controller.abort(); // Cancels both queries\n * ```\n */\nexport interface QueryHandle<T = any> {\n /** Promise that resolves with query results */\n result: Promise<T>;\n\n /**\n * Method to cancel the query with optional cleanup.\n * This provides a clean abstraction over the underlying cancellation mechanism.\n */\n cancel: () => Promise<void>;\n\n /**\n * Read-only access to the abort signal for composability.\n *\n * Key benefits:\n * - **Event-driven**: Listen for abort events to update UI or perform cleanup\n * - **Integration**: Use with other Web APIs like fetch() that accept AbortSignal\n * - **Status checking**: Check if query is already cancelled with signal.aborted\n *\n * @example\n * ```typescript\n * // Listen for cancellation events\n * handle.signal.addEventListener('abort', () => {\n * console.log('Query cancelled');\n * updateUI('Operation cancelled');\n * });\n *\n * // Check cancellation status\n * if (handle.signal.aborted) {\n * console.log('Query was already cancelled');\n * }\n *\n * // Use with other APIs\n * const response = await fetch('/api/data', { signal: handle.signal });\n * ```\n */\n signal: AbortSignal;\n}\n\n/**\n * DuckDB connector interface with advanced query cancellation support\n *\n * This interface provides a hybrid approach that combines the simplicity of method-based\n * cancellation with the composability of Web Standards (AbortController/AbortSignal).\n *\n * ## Key Benefits of This Design\n *\n * ### 🔗 Composability\n * Cancel multiple queries with a single controller:\n * ```typescript\n * const controller = new AbortController();\n * const query1 = connector.query('SELECT * FROM table1', { signal: controller.signal });\n * const query2 = connector.query('SELECT * FROM table2', { signal: controller.signal });\n * controller.abort(); // Cancels both queries\n * ```\n *\n * ### 🌐 Integration with Web APIs\n * Use the same signal for queries and HTTP requests:\n * ```typescript\n * const controller = new AbortController();\n * const queryHandle = connector.query('SELECT * FROM table', { signal: controller.signal });\n * const response = await fetch('/api/data', { signal: controller.signal });\n * // controller.abort() cancels both the query and the HTTP request\n * ```\n *\n * ### 🎛️ Flexibility\n * Simple usage when you don't need external control, advanced when you do:\n * ```typescript\n * // Simple - internal cancellation management\n * const handle = connector.query('SELECT * FROM table');\n * handle.cancel();\n *\n * // Advanced - external cancellation control\n * const controller = new AbortController();\n * const handle = connector.query('SELECT * FROM table', { signal: controller.signal });\n * controller.abort();\n * ```\n *\n * ### 📡 Event-Driven\n * React to cancellation events for better UX:\n * ```typescript\n * handle.signal.addEventListener('abort', () => {\n * showNotification('Query cancelled');\n * hideLoadingSpinner();\n * });\n * ```\n *\n * ### ⏱️ Timeout Support\n * Built-in timeout capability with manual override:\n * ```typescript\n * const timeoutController = new AbortController();\n * setTimeout(() => timeoutController.abort(), 30000); // 30s timeout\n *\n * const handle = connector.query('SELECT * FROM large_table', {\n * signal: timeoutController.signal\n * });\n *\n * // User can still cancel manually\n * cancelButton.onclick = () => timeoutController.abort();\n * ```\n *\n * ### 🏗️ Signal Composition\n * Combine multiple cancellation sources:\n * ```typescript\n * function combineSignals(...signals: AbortSignal[]): AbortSignal {\n * const controller = new AbortController();\n * signals.forEach(signal => {\n * if (signal.aborted) controller.abort();\n * else signal.addEventListener('abort', () => controller.abort());\n * });\n * return controller.signal;\n * }\n *\n * const userSignal = userController.signal;\n * const timeoutSignal = createTimeoutSignal(30000);\n * const combinedSignal = combineSignals(userSignal, timeoutSignal);\n *\n * const handle = connector.query('SELECT * FROM table', { signal: combinedSignal });\n * ```\n */\nexport interface DuckDbConnector {\n /**\n * Initialize the connector\n */\n initialize(): Promise<void>;\n\n /**\n * Destroy the connector and clean up resources\n */\n destroy(): Promise<void>;\n\n /**\n * Execute a SQL query without returning a result\n *\n * @param sql SQL query to execute\n * @param options Optional query options including abort signal for coordinated cancellation\n * @returns QueryHandle containing:\n * - result: Promise that resolves when execution completes\n * - cancel: Method to cancel the query with cleanup\n * - signal: AbortSignal for composability with other cancellable operations\n *\n * @example\n * ```typescript\n * // Simple execution\n * const handle = connector.execute('CREATE TABLE test AS SELECT * FROM source');\n * await handle.result;\n *\n * // With external cancellation control\n * const controller = new AbortController();\n * const handle = connector.execute('DROP TABLE large_table', {\n * signal: controller.signal\n * });\n *\n * // Cancel if it takes too long\n * setTimeout(() => controller.abort(), 5000);\n * ```\n */\n execute(sql: string, options?: QueryOptions): QueryHandle;\n\n /**\n * Execute a SQL query and return the result as an Arrow table\n *\n * @param query SQL query to execute\n * @param options Optional query options including abort signal for coordinated cancellation\n * @returns QueryHandle containing:\n * - result: Promise that resolves with Arrow table\n * - cancel: Method to cancel the query with cleanup\n * - signal: AbortSignal for composability with other cancellable operations\n *\n * @example\n * ```typescript\n * // Basic query\n * const handle = connector.query('SELECT * FROM users WHERE active = true');\n * const table = await handle.result;\n * console.log(`Found ${table.numRows} active users`);\n *\n * // Query with timeout\n * const controller = new AbortController();\n * setTimeout(() => controller.abort(), 30000); // 30s timeout\n *\n * const handle = connector.query('SELECT * FROM very_large_table', {\n * signal: controller.signal\n * });\n *\n * try {\n * const result = await handle.result;\n * console.log('Query completed within timeout');\n * } catch (error) {\n * if (error.name === 'AbortError') {\n * console.log('Query timed out');\n * }\n * }\n * ```\n */\n query<T extends TypeMap = any>(\n query: string,\n options?: QueryOptions,\n ): QueryHandle<arrow.Table<T>>;\n\n /**\n * Execute a SQL query and return the result as a JSON object\n *\n * @param query SQL query to execute\n * @param options Optional query options including abort signal for coordinated cancellation\n * @returns QueryHandle containing:\n * - result: Promise that resolves with iterable of JSON objects\n * - cancel: Method to cancel the query with cleanup\n * - signal: AbortSignal for composability with other cancellable operations\n *\n * @example\n * ```typescript\n * // Simple JSON query\n * const handle = connector.queryJson('SELECT name, email FROM users LIMIT 10');\n * const users = await handle.result;\n * for (const user of users) {\n * console.log(`${user.name}: ${user.email}`);\n * }\n *\n * // Coordinated cancellation with multiple operations\n * const operationController = new AbortController();\n *\n * const usersHandle = connector.queryJson('SELECT * FROM users', {\n * signal: operationController.signal\n * });\n *\n * const ordersHandle = connector.queryJson('SELECT * FROM orders', {\n * signal: operationController.signal\n * });\n *\n * // Cancel both queries if user navigates away\n * window.addEventListener('beforeunload', () => {\n * operationController.abort();\n * });\n * ```\n */\n queryJson<T = Record<string, any>>(\n query: string,\n options?: QueryOptions,\n ): QueryHandle<Iterable<T>>;\n\n /**\n * Load a file into DuckDB and create a table\n * @param fileName - Path to the file to load\n * @param tableName - Name of the table to create\n * @param opts - Load options\n */\n loadFile(\n fileName: string | File,\n tableName: string,\n opts?: LoadFileOptions,\n ): Promise<void>;\n\n /**\n * Load an arrow table or an arrow IPC stream into DuckDB\n * @param table - Arrow table or arrow IPC stream to load\n * @param tableName - Name of the table to create\n */\n loadArrow(\n table: arrow.Table | Uint8Array,\n tableName: string,\n opts?: {schema?: string},\n ): Promise<void>;\n\n /**\n * Load JavaScript objects into DuckDB\n * @param data - Array of objects to load\n * @param tableName - Name of the table to create\n * @param opts - Load options\n */\n loadObjects(\n data: Record<string, unknown>[],\n tableName: string,\n opts?: StandardLoadOptions,\n ): Promise<void>;\n}\n"]}
|
|
@@ -17,7 +17,8 @@ export declare class WasmDuckDbConnector extends BaseDuckDbConnector {
|
|
|
17
17
|
});
|
|
18
18
|
protected initializeInternal(): Promise<void>;
|
|
19
19
|
destroy(): Promise<void>;
|
|
20
|
-
|
|
20
|
+
protected executeQueryInternal<T extends arrow.TypeMap = any>(query: string, signal: AbortSignal): Promise<arrow.Table<T>>;
|
|
21
|
+
protected cancelQueryInternal(queryId: string): Promise<void>;
|
|
21
22
|
loadFile(file: string | File, tableName: string, opts?: LoadFileOptions): Promise<void>;
|
|
22
23
|
loadArrow(file: arrow.Table | Uint8Array, tableName: string, opts?: {
|
|
23
24
|
schema?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WasmDuckDbConnector.d.ts","sourceRoot":"","sources":["../../src/connectors/WasmDuckDbConnector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAqB,iBAAiB,EAAC,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAC,eAAe,EAAE,mBAAmB,EAAC,MAAM,0BAA0B,CAAC;AAE9E,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAC;AAG1D,qBAAa,mBAAoB,SAAQ,mBAAmB;IAC1D,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,EAAE,CAAmC;IAC7C,OAAO,CAAC,IAAI,CAA6C;IACzD,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,WAAW,CAAC,CAAoB;gBAE5B,EACV,OAAe,EACf,mBAAwB,EACxB,MAAmB,EACnB,WAAW,GACZ,GAAE;QACD,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,iBAAiB,CAAC;QAChC,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;KACd;cAMU,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"WasmDuckDbConnector.d.ts","sourceRoot":"","sources":["../../src/connectors/WasmDuckDbConnector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAqB,iBAAiB,EAAC,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAC,eAAe,EAAE,mBAAmB,EAAC,MAAM,0BAA0B,CAAC;AAE9E,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAC;AAG1D,qBAAa,mBAAoB,SAAQ,mBAAmB;IAC1D,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,EAAE,CAAmC;IAC7C,OAAO,CAAC,IAAI,CAA6C;IACzD,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,WAAW,CAAC,CAAoB;gBAE5B,EACV,OAAe,EACf,mBAAwB,EACxB,MAAmB,EACnB,WAAW,GACZ,GAAE;QACD,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,iBAAiB,CAAC;QAChC,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;KACd;cAMU,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IA0D7C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;cAyBd,oBAAoB,CAAC,CAAC,SAAS,KAAK,CAAC,OAAO,GAAG,GAAG,EAChE,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;cAqEV,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAe7D,QAAQ,CACZ,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,eAAe;IAOlB,SAAS,CACb,IAAI,EAAE,KAAK,CAAC,KAAK,GAAG,UAAU,EAC9B,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAC;IAcpB,WAAW,CACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC/B,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,mBAAmB;YASd,sBAAsB;IAoCpC,KAAK,IAAI,MAAM,CAAC,WAAW;IAO3B,aAAa,IAAI,MAAM,CAAC,qBAAqB;CAM9C;AAoBD,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;gBAChC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS;IAOlE,kBAAkB;IAOlB,iBAAiB;CAIlB"}
|