@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.
Files changed (40) hide show
  1. package/dist/DuckDbSlice.d.ts +102 -23
  2. package/dist/DuckDbSlice.d.ts.map +1 -1
  3. package/dist/DuckDbSlice.js +201 -63
  4. package/dist/DuckDbSlice.js.map +1 -1
  5. package/dist/connectors/BaseDuckDbConnector.d.ts +22 -5
  6. package/dist/connectors/BaseDuckDbConnector.d.ts.map +1 -1
  7. package/dist/connectors/BaseDuckDbConnector.js +66 -15
  8. package/dist/connectors/BaseDuckDbConnector.js.map +1 -1
  9. package/dist/connectors/DuckDbConnector.d.ts +237 -4
  10. package/dist/connectors/DuckDbConnector.d.ts.map +1 -1
  11. package/dist/connectors/DuckDbConnector.js.map +1 -1
  12. package/dist/connectors/WasmDuckDbConnector.d.ts +2 -1
  13. package/dist/connectors/WasmDuckDbConnector.d.ts.map +1 -1
  14. package/dist/connectors/WasmDuckDbConnector.js +90 -17
  15. package/dist/connectors/WasmDuckDbConnector.js.map +1 -1
  16. package/dist/duckdb-utils.d.ts +67 -0
  17. package/dist/duckdb-utils.d.ts.map +1 -1
  18. package/dist/duckdb-utils.js +195 -0
  19. package/dist/duckdb-utils.js.map +1 -1
  20. package/dist/exportToCsv.js +1 -1
  21. package/dist/exportToCsv.js.map +1 -1
  22. package/dist/index.d.ts +3 -2
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +3 -2
  25. package/dist/index.js.map +1 -1
  26. package/dist/schemaTree.d.ts +8 -0
  27. package/dist/schemaTree.d.ts.map +1 -0
  28. package/dist/schemaTree.js +76 -0
  29. package/dist/schemaTree.js.map +1 -0
  30. package/dist/typeCategories.d.ts +16 -0
  31. package/dist/typeCategories.d.ts.map +1 -0
  32. package/dist/typeCategories.js +72 -0
  33. package/dist/typeCategories.js.map +1 -0
  34. package/dist/types.d.ts +35 -0
  35. package/dist/types.d.ts.map +1 -1
  36. package/dist/types.js.map +1 -1
  37. package/dist/useSql.d.ts.map +1 -1
  38. package/dist/useSql.js +11 -7
  39. package/dist/useSql.js.map +1 -1
  40. 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
- export declare class BaseDuckDbConnector implements DuckDbConnector {
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
- execute(query: string): Promise<void>;
19
- query<T extends TypeMap = any>(query: string): Promise<arrow.Table<T>>;
20
- queryJson<T = Record<string, any>>(query: string): Promise<Iterable<T>>;
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,eAAe,EAAC,MAAM,mBAAmB,CAAC;AAGlD,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAC;AAErC,qBAAa,mBAAoB,YAAW,eAAe;IACzD,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;gBAExC,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;IAM5C,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrC,KAAK,CAAC,CAAC,SAAS,OAAO,GAAG,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAKtE,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACrC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAKjB,QAAQ,CACZ,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,eAAe;IAalB,SAAS,CACb,IAAI,EAAE,KAAK,CAAC,KAAK,GAAG,UAAU,EAC9B,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAC;IAMpB,WAAW,CACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC/B,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,mBAAmB;CAK7B"}
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.initialize();
31
+ if (!this.initialized && this.initializing) {
32
+ await this.initializing;
32
33
  }
33
34
  }
34
- async execute(query) {
35
- await this.query(query);
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
- async query(query) {
38
- // To be implemented by subclasses
39
- throw new Error('Not implemented', { cause: query });
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
- async queryJson(query) {
42
- const arrowTable = await this.query(query);
43
- return createTypedRowAccessor({ arrowTable });
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
- await this.query(loadSpatial(tableName, fileName, opts));
97
+ const queryHandle = this.query(loadSpatial(tableName, fileName, opts));
98
+ await queryHandle.result;
52
99
  }
53
100
  else {
54
- await this.query(load(opts?.method ?? 'auto', tableName, fileName, opts));
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
- // To be implemented by subclasses
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
- await this.query(loadObjects(tableName, file, opts));
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":"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","sourcesContent":["import {\n isSpatialLoadFileOptions,\n LoadFileOptions,\n StandardLoadOptions,\n} from '@sqlrooms/project-config';\nimport * as arrow from 'apache-arrow';\nimport {DuckDbConnector} from './DuckDbConnector';\nimport {load, loadObjects, loadSpatial} from './load/load';\nimport {createTypedRowAccessor} from '../typedRowAccessor';\nimport {TypeMap} from 'apache-arrow';\n\nexport class BaseDuckDbConnector implements DuckDbConnector {\n protected dbPath: string;\n protected initializationQuery: string;\n protected initialized = false;\n protected initializing: Promise<void> | null = null;\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) {\n await this.initialize();\n }\n }\n\n async execute(query: string): Promise<void> {\n await this.query(query);\n }\n\n async query<T extends TypeMap = any>(query: string): Promise<arrow.Table<T>> {\n // To be implemented by subclasses\n throw new Error('Not implemented', {cause: query});\n }\n\n async queryJson<T = Record<string, any>>(\n query: string,\n ): Promise<Iterable<T>> {\n const arrowTable = await this.query(query);\n return createTypedRowAccessor({arrowTable});\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 await this.query(loadSpatial(tableName, fileName, opts));\n } else {\n await this.query(load(opts?.method ?? 'auto', tableName, fileName, opts));\n }\n }\n\n async loadArrow(\n file: arrow.Table | Uint8Array,\n tableName: string,\n opts?: {schema?: string},\n ) {\n // To be implemented by subclasses\n throw new Error('Not implemented', {cause: {file, tableName, opts}});\n }\n\n async loadObjects(\n file: Record<string, unknown>[],\n tableName: string,\n opts?: StandardLoadOptions,\n ) {\n await this.ensureInitialized();\n await this.query(loadObjects(tableName, file, opts));\n }\n}\n"]}
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): Promise<void>;
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): Promise<arrow.Table<T>>;
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
- * @param query
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): Promise<Iterable<T>>;
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;;;OAGG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpC;;;OAGG;IACH,KAAK,CAAC,CAAC,SAAS,OAAO,GAAG,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvE;;;OAGG;IACH,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAExE;;;;;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
+ {"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
- query<T extends arrow.TypeMap = any>(query: string): Promise<arrow.Table<T>>;
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;IAsE7C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAyBxB,KAAK,CAAC,CAAC,SAAS,KAAK,CAAC,OAAO,GAAG,GAAG,EACvC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAQpB,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;AAED,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"}
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"}