@aiquants/duckdb-helper 1.6.7 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,20 +2,18 @@
2
2
 
3
3
  DuckDB helper utilities with React hooks, worker initialization, and typed query helpers for browser applications.
4
4
 
5
- DuckDB をブラウザアプリケーションで扱うための React フック、Worker 初期化、型付きクエリヘルパーを提供するユーティリティ集。
5
+ ## Features
6
6
 
7
- ## Features / 機能
7
+ - **Worker-backed initialization**: Set up DuckDB-wasm workers with recommended CDN bundles.
8
+ - **React hooks**: Provide `useDuckDB` and `useDuckDBQuery` for component integrations.
9
+ - **Singleton service**: Share a single DuckDB instance across application components.
10
+ - **Typed helpers**: Safely convert query results with type guards.
11
+ - **TypeScript first**: Full typings for queries, tables, and helper functions.
8
12
 
9
- - **Worker-backed initialization**: Set up DuckDB-wasm workers with the recommended CDN bundles / 推奨 CDN バンドルを用いた DuckDB-wasm Worker 初期化
10
- - **React hooks**: Provide `useDuckDB` と `useDuckDBQuery` for component integrations / コンポーネント統合向けの `useDuckDB` と `useDuckDBQuery`
11
- - **Singleton service**: Share a single DuckDB インスタンス全体で共有できるシングルトンサービス
12
- - **Typed helpers**: Safely convert query results with type guards / 型ガード付きでクエリ結果を安全に変換
13
- - **TypeScript first**: Full typings for queries, tables, and helper functions / クエリやテーブル、ヘルパー関数の完全な型定義
14
-
15
- ## Installation / インストール
13
+ ## Installation
16
14
 
17
15
  ```bash
18
- # Using pnpm (recommended) / pnpm を使用(推奨)
16
+ # Using pnpm (recommended)
19
17
  pnpm add @aiquants/duckdb-helper
20
18
 
21
19
  # Using npm
@@ -25,9 +23,9 @@ npm install @aiquants/duckdb-helper
25
23
  yarn add @aiquants/duckdb-helper
26
24
  ```
27
25
 
28
- ## Quick Start / クイックスタート
26
+ ## Quick Start
29
27
 
30
- ### Initialize the service / サービスの初期化
28
+ ### Initialize the Service
31
29
 
32
30
  ```typescript
33
31
  import duckDBService from '@aiquants/duckdb-helper'
@@ -38,7 +36,7 @@ const result = await duckDBService.executeQuery('SELECT 1 AS value')
38
36
  console.log(result)
39
37
  ```
40
38
 
41
- ### Use the React hook / React フックを利用
39
+ ### Use the React Hook
42
40
 
43
41
  ```tsx
44
42
  import { useDuckDB } from '@aiquants/duckdb-helper'
@@ -65,7 +63,7 @@ export const Dashboard = () => {
65
63
  }
66
64
  ```
67
65
 
68
- ### Convert results to arrays / 結果を配列に変換
66
+ ### Convert Results to Arrays
69
67
 
70
68
  ```typescript
71
69
  import { duckdbTableToArray } from '@aiquants/duckdb-helper'
@@ -74,23 +72,19 @@ const table = await duckDBService.executeQuery('SELECT * FROM items')
74
72
  const rows = duckdbTableToArray<{ id: number; name: string }>(table)
75
73
  ```
76
74
 
77
- ## Documentation / ドキュメント
78
-
79
- 詳しい使用方法は `docs/useDuckDB.md` を参照してください。
75
+ ## Documentation
80
76
 
81
77
  For detailed guidance, see `docs/useDuckDB.md`.
82
78
 
83
- ## Requirements / 必要要件
79
+ ## Requirements
84
80
 
85
- - React 16.8+ with Hooks support / React 16.8 以上(Hooks 対応)
86
- - Modern browsers with Web Worker support / Web Worker をサポートする最新ブラウザ
81
+ - React 16.8+ with Hooks support
82
+ - Modern browsers with Web Worker support
87
83
 
88
- ## License / ライセンス
84
+ ## License
89
85
 
90
86
  MIT License
91
87
 
92
- ## Contributing / 貢献
88
+ ## Contributing
93
89
 
94
90
  Contributions are welcome! Please open an issue or submit a pull request.
95
-
96
- 貢献を歓迎します。Issue や Pull Request をぜひお寄せください。
package/dist/index.d.mts CHANGED
@@ -2,71 +2,34 @@ import { DependencyList } from 'react';
2
2
  import * as duckdb from '@duckdb/duckdb-wasm';
3
3
 
4
4
  /**
5
- * DuckDB React Hook
5
+ * DuckDB Web Worker Service
6
6
  *
7
- * React hook for using DuckDB functionality in components.
8
- * コンポーネントで DuckDB 機能を使用するための React フック。
7
+ * Provides reusable DuckDB-wasm functionality across the application.
8
+ * アプリケーション全体で再利用可能な DuckDB-wasm 機能を提供します。
9
9
  */
10
10
 
11
- interface UseDuckDBResult {
12
- status: "not-initialized" | "initializing" | "ready" | "error";
13
- error: string | null;
14
- executeQuery: (sql: string) => Promise<unknown>;
15
- executeQueries: (queries: string[]) => Promise<unknown[]>;
16
- createTableFromData: <T extends Record<string, unknown>>(tableName: string, data: T[], options?: {
17
- dropIfExists?: boolean;
18
- primaryKey?: string;
19
- verbose?: boolean;
20
- }) => Promise<void>;
21
- getTableInfo: (tableName: string) => Promise<unknown>;
22
- listTables: () => Promise<unknown>;
23
- isReady: boolean;
24
- initialize: () => Promise<void>;
25
- }
26
11
  /**
27
- * DuckDB functionality hook.
28
- * DuckDB 機能を提供するフック。
29
- *
30
- * @param autoInitialize - 自動初期化を行うかどうか
31
- * @returns DuckDB の状態と操作関数
12
+ * Options for opening a persistent database (e.g. OPFS-backed).
13
+ * 永続データベース (OPFS など) を開くためのオプション。
32
14
  */
33
- declare const useDuckDB: (autoInitialize?: boolean, options?: {
34
- bundles?: duckdb.DuckDBBundles;
35
- }) => UseDuckDBResult;
36
- /**
37
- * Hook for simple DuckDB query execution.
38
- * シンプルな DuckDB クエリ実行のためのフック。
39
- *
40
- * @remarks
41
- * `data` は DuckDB(Apache Arrow Table)の**生の結果**であり、行配列ではない。
42
- * `.length` や `.map` は持たないため、行配列として扱う場合は必ず
43
- * {@link duckdbTableToArray} で変換すること(`T` には行の型ではなく
44
- * Arrow Table 相当の型を想定)。
45
- *
46
- * @example
47
- * ```tsx
48
- * const { data } = useDuckDBQuery("SELECT * FROM t")
49
- * const rows = duckdbTableToArray<Row>(data)
50
- * ```
51
- *
52
- * @param sql - 実行する SQL クエリ
53
- * @param dependencies - クエリを再実行するための依存配列
54
- * @returns クエリ結果(生の Arrow Table)と状態
55
- */
56
- declare const useDuckDBQuery: <T = unknown>(sql: string, dependencies?: DependencyList) => {
57
- data: T | null;
58
- loading: boolean;
59
- error: string | null;
60
- refetch: () => Promise<void>;
61
- };
62
-
15
+ interface DuckDBDatabaseOptions {
16
+ /** Database path. Use an `opfs://` path for a persistent OPFS-backed database. `opfs://` パスで OPFS 永続 DB を開く。 */
17
+ path: string;
18
+ /** Access mode (defaults to READ_WRITE). アクセスモード (既定 READ_WRITE)。 */
19
+ accessMode?: duckdb.DuckDBAccessMode;
20
+ /** How `opfs://` files are handled during SQL execution (defaults to "auto"). SQL 実行時の `opfs://` ファイル登録の扱い (既定 "auto")。 */
21
+ opfsFileHandling?: "auto" | "manual";
22
+ }
63
23
  /**
64
- * DuckDB Web Worker Service
65
- *
66
- * Provides reusable DuckDB-wasm functionality across the application.
67
- * アプリケーション全体で再利用可能な DuckDB-wasm 機能を提供します。
24
+ * Options accepted by {@link DuckDBService.initialize}.
25
+ * initialize() が受け取るオプション。
68
26
  */
69
-
27
+ interface DuckDBInitializeOptions {
28
+ /** Custom bundles (defaults to jsDelivr bundles). カスタムバンドル (既定は jsDelivr)。 */
29
+ bundles?: duckdb.DuckDBBundles;
30
+ /** Persistent database to open after instantiation. インスタンス化後に開く永続データベース。 */
31
+ database?: DuckDBDatabaseOptions;
32
+ }
70
33
  /**
71
34
  * DuckDB service for browser-based SQL operations.
72
35
  * ブラウザベースの SQL 操作のための DuckDB サービス。
@@ -94,6 +57,11 @@ declare class DuckDBService {
94
57
  * DuckDBService のシングルトンインスタンスを取得します。
95
58
  */
96
59
  static getInstance(): DuckDBService;
60
+ /**
61
+ * Creates a dedicated (non-shared) service instance, e.g. for a persistent OPFS database.
62
+ * 専用 (非共有) のサービスインスタンスを生成します (OPFS 永続 DB を共有シングルトンと分離して持つ用途)。
63
+ */
64
+ static create(): DuckDBService;
97
65
  /**
98
66
  * Add status change listener.
99
67
  * 状態変更リスナーを追加します。
@@ -124,9 +92,7 @@ declare class DuckDBService {
124
92
  * Initialize DuckDB Worker instance.
125
93
  * DuckDB Worker インスタンスを初期化します。
126
94
  */
127
- initialize(options?: {
128
- bundles?: duckdb.DuckDBBundles;
129
- }): Promise<duckdb.AsyncDuckDB>;
95
+ initialize(options?: DuckDBInitializeOptions): Promise<duckdb.AsyncDuckDB>;
130
96
  /**
131
97
  * Internal worker initialization method.
132
98
  * 内部的な Worker 初期化メソッド。
@@ -229,6 +195,63 @@ declare class DuckDBService {
229
195
 
230
196
  declare const _default: DuckDBService;
231
197
 
198
+ /**
199
+ * DuckDB React Hook
200
+ *
201
+ * React hook for using DuckDB functionality in components.
202
+ * コンポーネントで DuckDB 機能を使用するための React フック。
203
+ */
204
+
205
+ interface UseDuckDBResult {
206
+ status: "not-initialized" | "initializing" | "ready" | "error";
207
+ error: string | null;
208
+ executeQuery: (sql: string) => Promise<unknown>;
209
+ executeQueries: (queries: string[]) => Promise<unknown[]>;
210
+ createTableFromData: <T extends Record<string, unknown>>(tableName: string, data: T[], options?: {
211
+ dropIfExists?: boolean;
212
+ primaryKey?: string;
213
+ verbose?: boolean;
214
+ }) => Promise<void>;
215
+ getTableInfo: (tableName: string) => Promise<unknown>;
216
+ listTables: () => Promise<unknown>;
217
+ isReady: boolean;
218
+ initialize: () => Promise<void>;
219
+ }
220
+ /**
221
+ * DuckDB functionality hook.
222
+ * DuckDB 機能を提供するフック。
223
+ *
224
+ * @param autoInitialize - 自動初期化を行うかどうか
225
+ * @returns DuckDB の状態と操作関数
226
+ */
227
+ declare const useDuckDB: (autoInitialize?: boolean, options?: DuckDBInitializeOptions) => UseDuckDBResult;
228
+ /**
229
+ * Hook for simple DuckDB query execution.
230
+ * シンプルな DuckDB クエリ実行のためのフック。
231
+ *
232
+ * @remarks
233
+ * `data` は DuckDB(Apache Arrow Table)の**生の結果**であり、行配列ではない。
234
+ * `.length` や `.map` は持たないため、行配列として扱う場合は必ず
235
+ * {@link duckdbTableToArray} で変換すること(`T` には行の型ではなく
236
+ * Arrow Table 相当の型を想定)。
237
+ *
238
+ * @example
239
+ * ```tsx
240
+ * const { data } = useDuckDBQuery("SELECT * FROM t")
241
+ * const rows = duckdbTableToArray<Row>(data)
242
+ * ```
243
+ *
244
+ * @param sql - 実行する SQL クエリ
245
+ * @param dependencies - クエリを再実行するための依存配列
246
+ * @returns クエリ結果(生の Arrow Table)と状態
247
+ */
248
+ declare const useDuckDBQuery: <T = unknown>(sql: string, dependencies?: DependencyList) => {
249
+ data: T | null;
250
+ loading: boolean;
251
+ error: string | null;
252
+ refetch: () => Promise<void>;
253
+ };
254
+
232
255
  /**
233
256
  * DuckDB Type Definitions
234
257
  *
@@ -289,6 +312,11 @@ declare const getDuckDBColumnCount: (result: unknown) => number;
289
312
  * @returns True if result is a valid DuckDB table
290
313
  */
291
314
  declare const isDuckDBTable: (result: unknown) => result is DuckDBQueryResult;
315
+ /**
316
+ * Returns whether the current environment can host an OPFS-backed persistent database.
317
+ * 現在の環境が OPFS 永続データベースを利用できるか (navigator.storage.getDirectory の有無) を返します。
318
+ */
319
+ declare const isOpfsSupported: () => boolean;
292
320
 
293
321
  /**
294
322
  * @module utils/logger
@@ -388,4 +416,4 @@ declare class Logger implements ILogger {
388
416
  error(message?: unknown, ...optionalParams: unknown[]): void;
389
417
  }
390
418
 
391
- export { type DuckDBQueryResult, type DuckDBRow, DuckDBService, type ILogger, LogLevel, Logger, type UseDuckDBResult, _default as duckDBService, duckdbTableToArray, getDuckDBColumnCount, getDuckDBRowCount, isDuckDBTable, useDuckDB, useDuckDBQuery };
419
+ export { type DuckDBDatabaseOptions, type DuckDBInitializeOptions, type DuckDBQueryResult, type DuckDBRow, DuckDBService, type ILogger, LogLevel, Logger, type UseDuckDBResult, _default as duckDBService, duckdbTableToArray, getDuckDBColumnCount, getDuckDBRowCount, isDuckDBTable, isOpfsSupported, useDuckDB, useDuckDBQuery };
package/dist/index.d.ts CHANGED
@@ -2,71 +2,34 @@ import { DependencyList } from 'react';
2
2
  import * as duckdb from '@duckdb/duckdb-wasm';
3
3
 
4
4
  /**
5
- * DuckDB React Hook
5
+ * DuckDB Web Worker Service
6
6
  *
7
- * React hook for using DuckDB functionality in components.
8
- * コンポーネントで DuckDB 機能を使用するための React フック。
7
+ * Provides reusable DuckDB-wasm functionality across the application.
8
+ * アプリケーション全体で再利用可能な DuckDB-wasm 機能を提供します。
9
9
  */
10
10
 
11
- interface UseDuckDBResult {
12
- status: "not-initialized" | "initializing" | "ready" | "error";
13
- error: string | null;
14
- executeQuery: (sql: string) => Promise<unknown>;
15
- executeQueries: (queries: string[]) => Promise<unknown[]>;
16
- createTableFromData: <T extends Record<string, unknown>>(tableName: string, data: T[], options?: {
17
- dropIfExists?: boolean;
18
- primaryKey?: string;
19
- verbose?: boolean;
20
- }) => Promise<void>;
21
- getTableInfo: (tableName: string) => Promise<unknown>;
22
- listTables: () => Promise<unknown>;
23
- isReady: boolean;
24
- initialize: () => Promise<void>;
25
- }
26
11
  /**
27
- * DuckDB functionality hook.
28
- * DuckDB 機能を提供するフック。
29
- *
30
- * @param autoInitialize - 自動初期化を行うかどうか
31
- * @returns DuckDB の状態と操作関数
12
+ * Options for opening a persistent database (e.g. OPFS-backed).
13
+ * 永続データベース (OPFS など) を開くためのオプション。
32
14
  */
33
- declare const useDuckDB: (autoInitialize?: boolean, options?: {
34
- bundles?: duckdb.DuckDBBundles;
35
- }) => UseDuckDBResult;
36
- /**
37
- * Hook for simple DuckDB query execution.
38
- * シンプルな DuckDB クエリ実行のためのフック。
39
- *
40
- * @remarks
41
- * `data` は DuckDB(Apache Arrow Table)の**生の結果**であり、行配列ではない。
42
- * `.length` や `.map` は持たないため、行配列として扱う場合は必ず
43
- * {@link duckdbTableToArray} で変換すること(`T` には行の型ではなく
44
- * Arrow Table 相当の型を想定)。
45
- *
46
- * @example
47
- * ```tsx
48
- * const { data } = useDuckDBQuery("SELECT * FROM t")
49
- * const rows = duckdbTableToArray<Row>(data)
50
- * ```
51
- *
52
- * @param sql - 実行する SQL クエリ
53
- * @param dependencies - クエリを再実行するための依存配列
54
- * @returns クエリ結果(生の Arrow Table)と状態
55
- */
56
- declare const useDuckDBQuery: <T = unknown>(sql: string, dependencies?: DependencyList) => {
57
- data: T | null;
58
- loading: boolean;
59
- error: string | null;
60
- refetch: () => Promise<void>;
61
- };
62
-
15
+ interface DuckDBDatabaseOptions {
16
+ /** Database path. Use an `opfs://` path for a persistent OPFS-backed database. `opfs://` パスで OPFS 永続 DB を開く。 */
17
+ path: string;
18
+ /** Access mode (defaults to READ_WRITE). アクセスモード (既定 READ_WRITE)。 */
19
+ accessMode?: duckdb.DuckDBAccessMode;
20
+ /** How `opfs://` files are handled during SQL execution (defaults to "auto"). SQL 実行時の `opfs://` ファイル登録の扱い (既定 "auto")。 */
21
+ opfsFileHandling?: "auto" | "manual";
22
+ }
63
23
  /**
64
- * DuckDB Web Worker Service
65
- *
66
- * Provides reusable DuckDB-wasm functionality across the application.
67
- * アプリケーション全体で再利用可能な DuckDB-wasm 機能を提供します。
24
+ * Options accepted by {@link DuckDBService.initialize}.
25
+ * initialize() が受け取るオプション。
68
26
  */
69
-
27
+ interface DuckDBInitializeOptions {
28
+ /** Custom bundles (defaults to jsDelivr bundles). カスタムバンドル (既定は jsDelivr)。 */
29
+ bundles?: duckdb.DuckDBBundles;
30
+ /** Persistent database to open after instantiation. インスタンス化後に開く永続データベース。 */
31
+ database?: DuckDBDatabaseOptions;
32
+ }
70
33
  /**
71
34
  * DuckDB service for browser-based SQL operations.
72
35
  * ブラウザベースの SQL 操作のための DuckDB サービス。
@@ -94,6 +57,11 @@ declare class DuckDBService {
94
57
  * DuckDBService のシングルトンインスタンスを取得します。
95
58
  */
96
59
  static getInstance(): DuckDBService;
60
+ /**
61
+ * Creates a dedicated (non-shared) service instance, e.g. for a persistent OPFS database.
62
+ * 専用 (非共有) のサービスインスタンスを生成します (OPFS 永続 DB を共有シングルトンと分離して持つ用途)。
63
+ */
64
+ static create(): DuckDBService;
97
65
  /**
98
66
  * Add status change listener.
99
67
  * 状態変更リスナーを追加します。
@@ -124,9 +92,7 @@ declare class DuckDBService {
124
92
  * Initialize DuckDB Worker instance.
125
93
  * DuckDB Worker インスタンスを初期化します。
126
94
  */
127
- initialize(options?: {
128
- bundles?: duckdb.DuckDBBundles;
129
- }): Promise<duckdb.AsyncDuckDB>;
95
+ initialize(options?: DuckDBInitializeOptions): Promise<duckdb.AsyncDuckDB>;
130
96
  /**
131
97
  * Internal worker initialization method.
132
98
  * 内部的な Worker 初期化メソッド。
@@ -229,6 +195,63 @@ declare class DuckDBService {
229
195
 
230
196
  declare const _default: DuckDBService;
231
197
 
198
+ /**
199
+ * DuckDB React Hook
200
+ *
201
+ * React hook for using DuckDB functionality in components.
202
+ * コンポーネントで DuckDB 機能を使用するための React フック。
203
+ */
204
+
205
+ interface UseDuckDBResult {
206
+ status: "not-initialized" | "initializing" | "ready" | "error";
207
+ error: string | null;
208
+ executeQuery: (sql: string) => Promise<unknown>;
209
+ executeQueries: (queries: string[]) => Promise<unknown[]>;
210
+ createTableFromData: <T extends Record<string, unknown>>(tableName: string, data: T[], options?: {
211
+ dropIfExists?: boolean;
212
+ primaryKey?: string;
213
+ verbose?: boolean;
214
+ }) => Promise<void>;
215
+ getTableInfo: (tableName: string) => Promise<unknown>;
216
+ listTables: () => Promise<unknown>;
217
+ isReady: boolean;
218
+ initialize: () => Promise<void>;
219
+ }
220
+ /**
221
+ * DuckDB functionality hook.
222
+ * DuckDB 機能を提供するフック。
223
+ *
224
+ * @param autoInitialize - 自動初期化を行うかどうか
225
+ * @returns DuckDB の状態と操作関数
226
+ */
227
+ declare const useDuckDB: (autoInitialize?: boolean, options?: DuckDBInitializeOptions) => UseDuckDBResult;
228
+ /**
229
+ * Hook for simple DuckDB query execution.
230
+ * シンプルな DuckDB クエリ実行のためのフック。
231
+ *
232
+ * @remarks
233
+ * `data` は DuckDB(Apache Arrow Table)の**生の結果**であり、行配列ではない。
234
+ * `.length` や `.map` は持たないため、行配列として扱う場合は必ず
235
+ * {@link duckdbTableToArray} で変換すること(`T` には行の型ではなく
236
+ * Arrow Table 相当の型を想定)。
237
+ *
238
+ * @example
239
+ * ```tsx
240
+ * const { data } = useDuckDBQuery("SELECT * FROM t")
241
+ * const rows = duckdbTableToArray<Row>(data)
242
+ * ```
243
+ *
244
+ * @param sql - 実行する SQL クエリ
245
+ * @param dependencies - クエリを再実行するための依存配列
246
+ * @returns クエリ結果(生の Arrow Table)と状態
247
+ */
248
+ declare const useDuckDBQuery: <T = unknown>(sql: string, dependencies?: DependencyList) => {
249
+ data: T | null;
250
+ loading: boolean;
251
+ error: string | null;
252
+ refetch: () => Promise<void>;
253
+ };
254
+
232
255
  /**
233
256
  * DuckDB Type Definitions
234
257
  *
@@ -289,6 +312,11 @@ declare const getDuckDBColumnCount: (result: unknown) => number;
289
312
  * @returns True if result is a valid DuckDB table
290
313
  */
291
314
  declare const isDuckDBTable: (result: unknown) => result is DuckDBQueryResult;
315
+ /**
316
+ * Returns whether the current environment can host an OPFS-backed persistent database.
317
+ * 現在の環境が OPFS 永続データベースを利用できるか (navigator.storage.getDirectory の有無) を返します。
318
+ */
319
+ declare const isOpfsSupported: () => boolean;
292
320
 
293
321
  /**
294
322
  * @module utils/logger
@@ -388,4 +416,4 @@ declare class Logger implements ILogger {
388
416
  error(message?: unknown, ...optionalParams: unknown[]): void;
389
417
  }
390
418
 
391
- export { type DuckDBQueryResult, type DuckDBRow, DuckDBService, type ILogger, LogLevel, Logger, type UseDuckDBResult, _default as duckDBService, duckdbTableToArray, getDuckDBColumnCount, getDuckDBRowCount, isDuckDBTable, useDuckDB, useDuckDBQuery };
419
+ export { type DuckDBDatabaseOptions, type DuckDBInitializeOptions, type DuckDBQueryResult, type DuckDBRow, DuckDBService, type ILogger, LogLevel, Logger, type UseDuckDBResult, _default as duckDBService, duckdbTableToArray, getDuckDBColumnCount, getDuckDBRowCount, isDuckDBTable, isOpfsSupported, useDuckDB, useDuckDBQuery };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var O=Object.create;var T=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var F=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,K=Object.prototype.hasOwnProperty;var V=(r,e)=>{for(var n in e)T(r,n,{get:e[n],enumerable:!0})},L=(r,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of F(e))!K.call(r,s)&&s!==n&&T(r,s,{get:()=>e[s],enumerable:!(o=q(e,s))||o.enumerable});return r};var _=(r,e,n)=>(n=r!=null?O(j(r)):{},L(e||!r||!r.__esModule?T(n,"default",{value:r,enumerable:!0}):n,r)),G=r=>L(T({},"__esModule",{value:!0}),r);var J={};V(J,{DuckDBService:()=>b,LogLevel:()=>I,Logger:()=>c,duckDBService:()=>W,duckdbTableToArray:()=>z,getDuckDBColumnCount:()=>U,getDuckDBRowCount:()=>C,isDuckDBTable:()=>N,useDuckDB:()=>B,useDuckDBQuery:()=>A});module.exports=G(J);var l=require("react");var w=_(require("@duckdb/duckdb-wasm"));var I=(t=>(t[t.DEBUG=0]="DEBUG",t[t.INFO=1]="INFO",t[t.WARN=2]="WARN",t[t.ERROR=3]="ERROR",t[t.NONE=4]="NONE",t))(I||{}),k=class k{constructor(e=2,n="[duckdb-helper]",o=console){this.level=e,this.prefix=n,this.impl=o}static setLevel(e){k.instance.setLevel(e)}setLevel(e){this.level=e}static setImplementation(e){k.instance.setImplementation(e)}setImplementation(e){this.impl=e}static setPrefix(e){k.instance.setPrefix(e)}setPrefix(e){this.prefix=e}formatMessage(e){return typeof e=="string"?[`${this.prefix} ${e}`]:[this.prefix,e]}static debug(e,...n){k.instance.debug(e,...n)}debug(e,...n){this.level<=0&&this.impl.debug(...this.formatMessage(e),...n)}static info(e,...n){k.instance.info(e,...n)}info(e,...n){this.level<=1&&this.impl.info(...this.formatMessage(e),...n)}static warn(e,...n){k.instance.warn(e,...n)}warn(e,...n){this.level<=2&&this.impl.warn(...this.formatMessage(e),...n)}static error(e,...n){k.instance.error(e,...n)}error(e,...n){this.level<=3&&this.impl.error(...this.formatMessage(e),...n)}};k.instance=new k(2,"[duckdb-helper]");var c=k;var E=12e4,R=6e4,S=1e4,P=1e3,H=100,Y=/^\d{4}-\d{2}-\d{2}([T ]\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:?\d{2})?)?$/,x=()=>{},h=class h{constructor(){this.operationFlags=new Map;this.workerInstance=null;this.connectionInstance=null;this.connectionPromise=null;this.isInitializing=!1;this.initPromise=null;this.hasError=!1;this.pendingWorker=null;this.pendingWorkerUrl=null;this.operationQueue=Promise.resolve();this.listeners=new Set}static getInstance(){return h.instance||(h.instance=new h),h.instance}addStatusListener(e){this.listeners.add(e)}removeStatusListener(e){this.listeners.delete(e)}notifyListeners(){for(let e of this.listeners)try{e()}catch(n){c.error("\u26A0\uFE0F Error in status listener:",n)}}getStatus(){return this.hasError?"error":this.isInitializing?"initializing":this.workerInstance?"ready":"not-initialized"}enqueue(e){let n=this.operationQueue.then(e,e);return this.operationQueue=n.then(x,x),n}assertNotAborted(e){if(e.aborted)throw new Error("DuckDB initialization aborted")}abortPendingWorker(){if(this.pendingWorker){try{this.pendingWorker.terminate()}catch{}this.pendingWorker=null}if(this.pendingWorkerUrl){try{URL.revokeObjectURL(this.pendingWorkerUrl)}catch{}this.pendingWorkerUrl=null}}async initialize(e){if(this.workerInstance)return this.workerInstance;if(this.isInitializing&&this.initPromise)return this.initPromise;this.isInitializing=!0,this.hasError=!1,this.notifyListeners();let n={aborted:!1},o,s=new Promise((t,i)=>{o=setTimeout(()=>{n.aborted=!0,i(new Error(`DuckDB initialization timed out after ${E}ms`))},E)});this.initPromise=Promise.race([this.internalInitializeWorker(n,e),s]);try{let t=await this.initPromise;return clearTimeout(o),this.isInitializing=!1,this.notifyListeners(),t}catch(t){throw clearTimeout(o),n.aborted=!0,this.isInitializing=!1,this.hasError=!0,this.workerInstance=null,this.connectionInstance=null,this.connectionPromise=null,this.initPromise=null,this.abortPendingWorker(),this.notifyListeners(),t}}async internalInitializeWorker(e,n){let o=null,s=null;try{c.info("\u{1F527} Starting DuckDB Worker initialization..."),c.info("\u{1F4E6} Getting DuckDB bundles...");let t=n?.bundles||w.getJsDelivrBundles();c.info("\u{1F50D} Selecting appropriate bundle for browser...");let i=await w.selectBundle(t);this.assertNotAborted(e);let a=f=>f.startsWith("/")&&typeof window<"u"&&window.location?new URL(f,window.location.origin).toString():f,d={mainWorker:i.mainWorker?a(i.mainWorker):"",mainModule:i.mainModule?a(i.mainModule):"",pthreadWorker:i.pthreadWorker?a(i.pthreadWorker):void 0};c.info("\u2705 Bundle selected:",{mainWorker:d.mainWorker,mainModule:d.mainModule,pthreadWorker:d.pthreadWorker}),c.info("\u{1F680} Creating Worker with Blob URL..."),o=URL.createObjectURL(new Blob([`importScripts("${d.mainWorker}");`],{type:"text/javascript"})),c.info("\u{1F477} Creating Worker instance..."),s=new Worker(o),this.assertNotAborted(e),this.pendingWorker=s,this.pendingWorkerUrl=o,c.info("\u{1F91D} Connecting to AsyncDuckDB instance...");let m=new w.AsyncDuckDB(new w.ConsoleLogger,s);await m.instantiate(d.mainModule,d.pthreadWorker),this.assertNotAborted(e),c.info("\u{1F4E6} Installing splink_udfs from community...");let p=await m.connect();try{let f,g=new Promise((D,u)=>{f=setTimeout(()=>{u(new Error(`splink_udfs installation timed out after ${S}ms`))},S)});await Promise.race([(async()=>{await p.query("INSTALL splink_udfs FROM community;"),c.info("\u2705 splink_udfs installed successfully"),await p.query("LOAD splink_udfs;"),c.info("\u2705 splink_udfs loaded successfully")})(),g]),clearTimeout(f)}catch(f){c.warn("\u26A0\uFE0F Failed to install/load splink_udfs:",f)}finally{await p.close()}return this.assertNotAborted(e),this.workerInstance=m,this.pendingWorker=null,this.pendingWorkerUrl=null,URL.revokeObjectURL(o),c.info("\u2705 DuckDB Worker initialized successfully"),m}catch(t){if(s)try{s.terminate()}catch{}if(o)try{URL.revokeObjectURL(o)}catch{}throw this.pendingWorker===s&&(this.pendingWorker=null),this.pendingWorkerUrl===o&&(this.pendingWorkerUrl=null),c.error("\u274C Failed to initialize DuckDB Worker:",t),t instanceof Error&&(c.error("\u274C Error name:",t.name),c.error("\u274C Error message:",t.message),c.error("\u274C Error stack:",t.stack)),t}}async getConnection(){if(this.connectionInstance)return this.connectionInstance;this.connectionPromise||(this.connectionPromise=(async()=>{let n=await(await this.initialize()).connect();return this.connectionInstance=n,n})());try{return await this.connectionPromise}catch(e){throw this.connectionPromise=null,e}}async runQueryWithTimeout(e){let n=!1,o,s=new Promise((i,a)=>{o=setTimeout(()=>{n=!0,a(new Error(`DuckDB query execution timed out after ${R}ms`))},R)}),t=(async()=>(await this.getConnection()).query(e))();try{let i=await Promise.race([t,s]);return clearTimeout(o),i}catch(i){if(clearTimeout(o),n){let a=this.connectionInstance;this.connectionInstance=null,this.connectionPromise=null,a&&a.close().catch(()=>{})}throw c.error("\u274C Failed to execute SQL query:",i),i}}async executeQuery(e){return this.enqueue(()=>this.runQueryWithTimeout(e))}async executeQueries(e){return this.enqueue(async()=>{let n=[];for(let o of e)n.push(await this.runQueryWithTimeout(o));return n})}collectColumnNames(e){let n=new Set,o=[];for(let s of e)if(s)for(let t of Object.keys(s))n.has(t)||(n.add(t),o.push(t));return o}looksLikeTimestamp(e){return Y.test(e)?!Number.isNaN(new Date(e).getTime()):!1}inferColumnTypes(e,n){let o={};for(let s of n){let t=e.map(a=>a?.[s]).filter(a=>a!=null);if(t.length===0){o[s]="VARCHAR";continue}let i={number:0,integer:0,boolean:0,date:0,string:0};for(let a of t)typeof a=="number"?Number.isFinite(a)?(i.number+=1,Number.isInteger(a)&&(i.integer+=1)):i.string+=1:typeof a=="bigint"?(i.number+=1,i.integer+=1):typeof a=="boolean"?i.boolean+=1:a instanceof Date||typeof a=="string"&&this.looksLikeTimestamp(a)?i.date+=1:i.string+=1;i.number===t.length?o[s]=i.integer===t.length?"BIGINT":"DOUBLE":i.boolean===t.length?o[s]="BOOLEAN":i.date===t.length?o[s]="TIMESTAMP":o[s]="VARCHAR"}return o}formatValueForSQL(e){if(e==null)return"NULL";if(typeof e=="string")return`'${e.replace(/'/g,"''")}'`;if(e instanceof Date)return`'${e.toISOString()}'`;if(typeof e=="boolean")return e?"TRUE":"FALSE";if(typeof e=="bigint")return e.toString();if(typeof e=="number")return Number.isFinite(e)?String(e):"NULL";try{let n=JSON.stringify(e);return n===void 0?"NULL":`'${n.replace(/'/g,"''")}'`}catch{return"NULL"}}quoteIdentifier(e){if(typeof e!="string"||e.length===0)throw new Error("Invalid SQL identifier");return`"${e.replace(/"/g,'""')}"`}async createTableFromData(e,n,o={}){if(!n||n.length===0)throw new Error("Data array is empty");let s=`create_table_${e}`,t=o.verbose??!0,i=this.operationFlags.get(s);if(i)return t&&c.info(`\u23F3 Table creation for '${e}' is already in progress, awaiting existing operation...`),i;let a=this.enqueue(()=>this.buildTable(e,n,o,t));this.operationFlags.set(s,a);try{await a}finally{this.operationFlags.delete(s)}}async buildTable(e,n,o,s){try{let t=await this.getConnection(),i=this.quoteIdentifier(e),a=this.collectColumnNames(n);if(a.length===0)throw new Error("Data rows have no columns");let d=Math.min(n.length,H),m=this.inferColumnTypes(n.slice(0,d),a),p=a.map(u=>`${this.quoteIdentifier(u)} ${m[u]}`),f=o.primaryKey?`, PRIMARY KEY (${this.quoteIdentifier(o.primaryKey)})`:"",g=`CREATE TABLE ${i} (${p.join(", ")}${f})`,D=a.map(u=>this.quoteIdentifier(u)).join(", ");s&&c.info(`\u{1F4E5} Building table '${e}' with ${n.length} rows`),await t.query("BEGIN TRANSACTION");try{o.dropIfExists&&(s&&c.info(`\u{1F5D1}\uFE0F Dropping table '${e}' if exists`),await t.query(`DROP TABLE IF EXISTS ${i}`)),s&&c.info("\u{1F528} Creating table with SQL:",g),await t.query(g);for(let u=0;u<n.length;u+=P){let y=n.slice(u,u+P),v=y.map(M=>`(${a.map(Q=>this.formatValueForSQL(M?.[Q])).join(", ")})`),$=`INSERT INTO ${i} (${D}) VALUES ${v.join(", ")}`;await t.query($),s&&c.info(`\u{1F4CA} Inserted batch ${Math.floor(u/P)+1} (${y.length} rows)`)}await t.query("COMMIT")}catch(u){try{await t.query("ROLLBACK")}catch(y){c.warn("\u26A0\uFE0F Rollback failed:",y)}throw u}s&&c.info(`\u{1F389} Table '${e}' created successfully with ${n.length} rows`)}catch(t){throw c.error(`\u274C Failed to create table '${e}':`,t),t}}async getTableInfo(e){return this.enqueue(async()=>(await this.getConnection()).query(`DESCRIBE ${this.quoteIdentifier(e)}`))}async listTables(){return this.enqueue(async()=>(await this.getConnection()).query("SHOW TABLES"))}isReady(){return this.workerInstance!==null}async cleanup(){try{this.connectionInstance&&(await this.connectionInstance.close(),this.connectionInstance=null),this.workerInstance&&(await this.workerInstance.terminate(),this.workerInstance=null),this.abortPendingWorker(),this.isInitializing=!1,this.hasError=!1,this.initPromise=null,this.connectionPromise=null,this.operationQueue=Promise.resolve(),this.operationFlags.clear(),this.notifyListeners(),this.listeners.clear()}catch(e){c.error("\u26A0\uFE0F Error during cleanup:",e)}}static resetInstance(){h.instance&&(h.instance.cleanup(),h.instance=null)}};h.instance=null;var b=h;var W=b.getInstance();var Z=r=>{let e=(0,l.useRef)({deps:r,version:0}),n=e.current.deps;return(n.length!==r.length||r.some((s,t)=>!Object.is(s,n[t])))&&(e.current={deps:r,version:e.current.version+1}),e.current.version},B=(r=!0,e)=>{let[n,o]=(0,l.useState)("not-initialized"),[s,t]=(0,l.useState)(null),[i]=(0,l.useState)(()=>b.getInstance()),a=(0,l.useCallback)(()=>{let u=i.getStatus();c.info("\u{1F504} DuckDB status updated:",u),o(u),u==="error"?t("DuckDB initialization failed"):u==="ready"&&t(null)},[i]);(0,l.useEffect)(()=>(i.addStatusListener(a),a(),()=>{i.removeStatusListener(a)}),[i,a]);let d=(0,l.useCallback)(async()=>{try{await i.initialize(e)}catch(u){let y=u instanceof Error?u.message:"Unknown error occurred";t(y),c.error("\u274C DuckDB initialization failed:",u)}},[i,e]);(0,l.useEffect)(()=>{r&&n==="not-initialized"&&(c.info("\u{1F680} Auto-initializing DuckDB..."),d())},[r,n,d]);let m=(0,l.useCallback)(async u=>{if(n!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return i.executeQuery(u)},[i,n]),p=(0,l.useCallback)(async u=>{if(n!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return i.executeQueries(u)},[i,n]),f=(0,l.useCallback)(async(u,y,v)=>{if(n!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return i.createTableFromData(u,y,v)},[i,n]),g=(0,l.useCallback)(async u=>{if(n!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return i.getTableInfo(u)},[i,n]),D=(0,l.useCallback)(async()=>{if(n!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return i.listTables()},[i,n]);return{status:n,error:s,executeQuery:m,executeQueries:p,createTableFromData:f,getTableInfo:g,listTables:D,isReady:n==="ready",initialize:d}},A=(r,e=[])=>{let{executeQuery:n,isReady:o}=B(),[s,t]=(0,l.useState)(null),[i,a]=(0,l.useState)(!1),[d,m]=(0,l.useState)(null),p=(0,l.useCallback)(async()=>{if(o&&r.trim())try{a(!0),m(null);let g=await n(r);t(g)}catch(g){let D=g instanceof Error?g.message:"Query execution failed";m(D),t(null)}finally{a(!1)}},[n,o,r]),f=Z(e);return(0,l.useEffect)(()=>{p()},[p,f]),{data:s,loading:i,error:d,refetch:p}};var z=r=>!r||typeof r!="object"?[]:"toArray"in r&&typeof r.toArray=="function"?r.toArray():[],C=r=>!r||typeof r!="object"?0:"numRows"in r&&typeof r.numRows=="number"?r.numRows:0,U=r=>!r||typeof r!="object"?0:"numCols"in r&&typeof r.numCols=="number"?r.numCols:0,N=r=>!r||typeof r!="object"?!1:"toArray"in r&&typeof r.toArray=="function"&&"numRows"in r&&typeof r.numRows=="number";0&&(module.exports={DuckDBService,LogLevel,Logger,duckDBService,duckdbTableToArray,getDuckDBColumnCount,getDuckDBRowCount,isDuckDBTable,useDuckDB,useDuckDBQuery});
1
+ "use strict";var q=Object.create;var I=Object.defineProperty;var F=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var K=Object.getPrototypeOf,H=Object.prototype.hasOwnProperty;var V=(r,e)=>{for(var n in e)I(r,n,{get:e[n],enumerable:!0})},E=(r,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of j(e))!H.call(r,s)&&s!==n&&I(r,s,{get:()=>e[s],enumerable:!(o=F(e,s))||o.enumerable});return r};var _=(r,e,n)=>(n=r!=null?q(K(r)):{},E(e||!r||!r.__esModule?I(n,"default",{value:r,enumerable:!0}):n,r)),G=r=>E(I({},"__esModule",{value:!0}),r);var X={};V(X,{DuckDBService:()=>b,LogLevel:()=>T,Logger:()=>c,duckDBService:()=>A,duckdbTableToArray:()=>z,getDuckDBColumnCount:()=>C,getDuckDBRowCount:()=>O,isDuckDBTable:()=>M,isOpfsSupported:()=>N,useDuckDB:()=>P,useDuckDBQuery:()=>W});module.exports=G(X);var l=require("react");var y=_(require("@duckdb/duckdb-wasm"));var T=(t=>(t[t.DEBUG=0]="DEBUG",t[t.INFO=1]="INFO",t[t.WARN=2]="WARN",t[t.ERROR=3]="ERROR",t[t.NONE=4]="NONE",t))(T||{}),k=class k{constructor(e=2,n="[duckdb-helper]",o=console){this.level=e,this.prefix=n,this.impl=o}static setLevel(e){k.instance.setLevel(e)}setLevel(e){this.level=e}static setImplementation(e){k.instance.setImplementation(e)}setImplementation(e){this.impl=e}static setPrefix(e){k.instance.setPrefix(e)}setPrefix(e){this.prefix=e}formatMessage(e){return typeof e=="string"?[`${this.prefix} ${e}`]:[this.prefix,e]}static debug(e,...n){k.instance.debug(e,...n)}debug(e,...n){this.level<=0&&this.impl.debug(...this.formatMessage(e),...n)}static info(e,...n){k.instance.info(e,...n)}info(e,...n){this.level<=1&&this.impl.info(...this.formatMessage(e),...n)}static warn(e,...n){k.instance.warn(e,...n)}warn(e,...n){this.level<=2&&this.impl.warn(...this.formatMessage(e),...n)}static error(e,...n){k.instance.error(e,...n)}error(e,...n){this.level<=3&&this.impl.error(...this.formatMessage(e),...n)}};k.instance=new k(2,"[duckdb-helper]");var c=k;var R=12e4,L=6e4,S=1e4,B=1e3,Y=100,Z=/^\d{4}-\d{2}-\d{2}([T ]\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:?\d{2})?)?$/,x=()=>{},h=class h{constructor(){this.operationFlags=new Map;this.workerInstance=null;this.connectionInstance=null;this.connectionPromise=null;this.isInitializing=!1;this.initPromise=null;this.hasError=!1;this.pendingWorker=null;this.pendingWorkerUrl=null;this.operationQueue=Promise.resolve();this.listeners=new Set}static getInstance(){return h.instance||(h.instance=new h),h.instance}static create(){return new h}addStatusListener(e){this.listeners.add(e)}removeStatusListener(e){this.listeners.delete(e)}notifyListeners(){for(let e of this.listeners)try{e()}catch(n){c.error("\u26A0\uFE0F Error in status listener:",n)}}getStatus(){return this.hasError?"error":this.isInitializing?"initializing":this.workerInstance?"ready":"not-initialized"}enqueue(e){let n=this.operationQueue.then(e,e);return this.operationQueue=n.then(x,x),n}assertNotAborted(e){if(e.aborted)throw new Error("DuckDB initialization aborted")}abortPendingWorker(){if(this.pendingWorker){try{this.pendingWorker.terminate()}catch{}this.pendingWorker=null}if(this.pendingWorkerUrl){try{URL.revokeObjectURL(this.pendingWorkerUrl)}catch{}this.pendingWorkerUrl=null}}async initialize(e){if(this.workerInstance)return this.workerInstance;if(this.isInitializing&&this.initPromise)return this.initPromise;this.isInitializing=!0,this.hasError=!1,this.notifyListeners();let n={aborted:!1},o,s=new Promise((t,i)=>{o=setTimeout(()=>{n.aborted=!0,i(new Error(`DuckDB initialization timed out after ${R}ms`))},R)});this.initPromise=Promise.race([this.internalInitializeWorker(n,e),s]);try{let t=await this.initPromise;return clearTimeout(o),this.isInitializing=!1,this.notifyListeners(),t}catch(t){throw clearTimeout(o),n.aborted=!0,this.isInitializing=!1,this.hasError=!0,this.workerInstance=null,this.connectionInstance=null,this.connectionPromise=null,this.initPromise=null,this.abortPendingWorker(),this.notifyListeners(),t}}async internalInitializeWorker(e,n){let o=null,s=null;try{c.info("\u{1F527} Starting DuckDB Worker initialization..."),c.info("\u{1F4E6} Getting DuckDB bundles...");let t=n?.bundles||y.getJsDelivrBundles();c.info("\u{1F50D} Selecting appropriate bundle for browser...");let i=await y.selectBundle(t);this.assertNotAborted(e);let a=f=>f.startsWith("/")&&typeof window<"u"&&window.location?new URL(f,window.location.origin).toString():f,d={mainWorker:i.mainWorker?a(i.mainWorker):"",mainModule:i.mainModule?a(i.mainModule):"",pthreadWorker:i.pthreadWorker?a(i.pthreadWorker):void 0};c.info("\u2705 Bundle selected:",{mainWorker:d.mainWorker,mainModule:d.mainModule,pthreadWorker:d.pthreadWorker}),c.info("\u{1F680} Creating Worker with Blob URL..."),o=URL.createObjectURL(new Blob([`importScripts("${d.mainWorker}");`],{type:"text/javascript"})),c.info("\u{1F477} Creating Worker instance..."),s=new Worker(o),this.assertNotAborted(e),this.pendingWorker=s,this.pendingWorkerUrl=o,c.info("\u{1F91D} Connecting to AsyncDuckDB instance...");let p=new y.AsyncDuckDB(new y.ConsoleLogger,s);await p.instantiate(d.mainModule,d.pthreadWorker),this.assertNotAborted(e),n?.database&&(c.info("\u{1F5C4}\uFE0F Opening persistent database:",n.database.path),await p.open({path:n.database.path,accessMode:n.database.accessMode??y.DuckDBAccessMode.READ_WRITE,opfs:{fileHandling:n.database.opfsFileHandling??"auto"}}),this.assertNotAborted(e)),c.info("\u{1F4E6} Installing splink_udfs from community...");let m=await p.connect();try{let f,g=new Promise((D,u)=>{f=setTimeout(()=>{u(new Error(`splink_udfs installation timed out after ${S}ms`))},S)});await Promise.race([(async()=>{await m.query("INSTALL splink_udfs FROM community;"),c.info("\u2705 splink_udfs installed successfully"),await m.query("LOAD splink_udfs;"),c.info("\u2705 splink_udfs loaded successfully")})(),g]),clearTimeout(f)}catch(f){c.warn("\u26A0\uFE0F Failed to install/load splink_udfs:",f)}finally{await m.close()}return this.assertNotAborted(e),this.workerInstance=p,this.pendingWorker=null,this.pendingWorkerUrl=null,URL.revokeObjectURL(o),c.info("\u2705 DuckDB Worker initialized successfully"),p}catch(t){if(s)try{s.terminate()}catch{}if(o)try{URL.revokeObjectURL(o)}catch{}throw this.pendingWorker===s&&(this.pendingWorker=null),this.pendingWorkerUrl===o&&(this.pendingWorkerUrl=null),c.error("\u274C Failed to initialize DuckDB Worker:",t),t instanceof Error&&(c.error("\u274C Error name:",t.name),c.error("\u274C Error message:",t.message),c.error("\u274C Error stack:",t.stack)),t}}async getConnection(){if(this.connectionInstance)return this.connectionInstance;this.connectionPromise||(this.connectionPromise=(async()=>{let n=await(await this.initialize()).connect();return this.connectionInstance=n,n})());try{return await this.connectionPromise}catch(e){throw this.connectionPromise=null,e}}async runQueryWithTimeout(e){let n=!1,o,s=new Promise((i,a)=>{o=setTimeout(()=>{n=!0,a(new Error(`DuckDB query execution timed out after ${L}ms`))},L)}),t=(async()=>(await this.getConnection()).query(e))();try{let i=await Promise.race([t,s]);return clearTimeout(o),i}catch(i){if(clearTimeout(o),n){let a=this.connectionInstance;this.connectionInstance=null,this.connectionPromise=null,a&&a.close().catch(()=>{})}throw c.error("\u274C Failed to execute SQL query:",i),i}}async executeQuery(e){return this.enqueue(()=>this.runQueryWithTimeout(e))}async executeQueries(e){return this.enqueue(async()=>{let n=[];for(let o of e)n.push(await this.runQueryWithTimeout(o));return n})}collectColumnNames(e){let n=new Set,o=[];for(let s of e)if(s)for(let t of Object.keys(s))n.has(t)||(n.add(t),o.push(t));return o}looksLikeTimestamp(e){return Z.test(e)?!Number.isNaN(new Date(e).getTime()):!1}inferColumnTypes(e,n){let o={};for(let s of n){let t=e.map(a=>a?.[s]).filter(a=>a!=null);if(t.length===0){o[s]="VARCHAR";continue}let i={number:0,integer:0,boolean:0,date:0,string:0};for(let a of t)typeof a=="number"?Number.isFinite(a)?(i.number+=1,Number.isInteger(a)&&(i.integer+=1)):i.string+=1:typeof a=="bigint"?(i.number+=1,i.integer+=1):typeof a=="boolean"?i.boolean+=1:a instanceof Date||typeof a=="string"&&this.looksLikeTimestamp(a)?i.date+=1:i.string+=1;i.number===t.length?o[s]=i.integer===t.length?"BIGINT":"DOUBLE":i.boolean===t.length?o[s]="BOOLEAN":i.date===t.length?o[s]="TIMESTAMP":o[s]="VARCHAR"}return o}formatValueForSQL(e){if(e==null)return"NULL";if(typeof e=="string")return`'${e.replace(/'/g,"''")}'`;if(e instanceof Date)return`'${e.toISOString()}'`;if(typeof e=="boolean")return e?"TRUE":"FALSE";if(typeof e=="bigint")return e.toString();if(typeof e=="number")return Number.isFinite(e)?String(e):"NULL";try{let n=JSON.stringify(e);return n===void 0?"NULL":`'${n.replace(/'/g,"''")}'`}catch{return"NULL"}}quoteIdentifier(e){if(typeof e!="string"||e.length===0)throw new Error("Invalid SQL identifier");return`"${e.replace(/"/g,'""')}"`}async createTableFromData(e,n,o={}){if(!n||n.length===0)throw new Error("Data array is empty");let s=`create_table_${e}`,t=o.verbose??!0,i=this.operationFlags.get(s);if(i)return t&&c.info(`\u23F3 Table creation for '${e}' is already in progress, awaiting existing operation...`),i;let a=this.enqueue(()=>this.buildTable(e,n,o,t));this.operationFlags.set(s,a);try{await a}finally{this.operationFlags.delete(s)}}async buildTable(e,n,o,s){try{let t=await this.getConnection(),i=this.quoteIdentifier(e),a=this.collectColumnNames(n);if(a.length===0)throw new Error("Data rows have no columns");let d=Math.min(n.length,Y),p=this.inferColumnTypes(n.slice(0,d),a),m=a.map(u=>`${this.quoteIdentifier(u)} ${p[u]}`),f=o.primaryKey?`, PRIMARY KEY (${this.quoteIdentifier(o.primaryKey)})`:"",g=`CREATE TABLE ${i} (${m.join(", ")}${f})`,D=a.map(u=>this.quoteIdentifier(u)).join(", ");s&&c.info(`\u{1F4E5} Building table '${e}' with ${n.length} rows`),await t.query("BEGIN TRANSACTION");try{o.dropIfExists&&(s&&c.info(`\u{1F5D1}\uFE0F Dropping table '${e}' if exists`),await t.query(`DROP TABLE IF EXISTS ${i}`)),s&&c.info("\u{1F528} Creating table with SQL:",g),await t.query(g);for(let u=0;u<n.length;u+=B){let w=n.slice(u,u+B),v=w.map($=>`(${a.map(Q=>this.formatValueForSQL($?.[Q])).join(", ")})`),U=`INSERT INTO ${i} (${D}) VALUES ${v.join(", ")}`;await t.query(U),s&&c.info(`\u{1F4CA} Inserted batch ${Math.floor(u/B)+1} (${w.length} rows)`)}await t.query("COMMIT")}catch(u){try{await t.query("ROLLBACK")}catch(w){c.warn("\u26A0\uFE0F Rollback failed:",w)}throw u}s&&c.info(`\u{1F389} Table '${e}' created successfully with ${n.length} rows`)}catch(t){throw c.error(`\u274C Failed to create table '${e}':`,t),t}}async getTableInfo(e){return this.enqueue(async()=>(await this.getConnection()).query(`DESCRIBE ${this.quoteIdentifier(e)}`))}async listTables(){return this.enqueue(async()=>(await this.getConnection()).query("SHOW TABLES"))}isReady(){return this.workerInstance!==null}async cleanup(){try{this.connectionInstance&&(await this.connectionInstance.close(),this.connectionInstance=null),this.workerInstance&&(await this.workerInstance.terminate(),this.workerInstance=null),this.abortPendingWorker(),this.isInitializing=!1,this.hasError=!1,this.initPromise=null,this.connectionPromise=null,this.operationQueue=Promise.resolve(),this.operationFlags.clear(),this.notifyListeners(),this.listeners.clear()}catch(e){c.error("\u26A0\uFE0F Error during cleanup:",e)}}static resetInstance(){h.instance&&(h.instance.cleanup(),h.instance=null)}};h.instance=null;var b=h;var A=b.getInstance();var J=r=>{let e=(0,l.useRef)({deps:r,version:0}),n=e.current.deps;return(n.length!==r.length||r.some((s,t)=>!Object.is(s,n[t])))&&(e.current={deps:r,version:e.current.version+1}),e.current.version},P=(r=!0,e)=>{let[n,o]=(0,l.useState)("not-initialized"),[s,t]=(0,l.useState)(null),[i]=(0,l.useState)(()=>b.getInstance()),a=(0,l.useCallback)(()=>{let u=i.getStatus();c.info("\u{1F504} DuckDB status updated:",u),o(u),u==="error"?t("DuckDB initialization failed"):u==="ready"&&t(null)},[i]);(0,l.useEffect)(()=>(i.addStatusListener(a),a(),()=>{i.removeStatusListener(a)}),[i,a]);let d=(0,l.useCallback)(async()=>{try{await i.initialize(e)}catch(u){let w=u instanceof Error?u.message:"Unknown error occurred";t(w),c.error("\u274C DuckDB initialization failed:",u)}},[i,e]);(0,l.useEffect)(()=>{r&&n==="not-initialized"&&(c.info("\u{1F680} Auto-initializing DuckDB..."),d())},[r,n,d]);let p=(0,l.useCallback)(async u=>{if(n!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return i.executeQuery(u)},[i,n]),m=(0,l.useCallback)(async u=>{if(n!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return i.executeQueries(u)},[i,n]),f=(0,l.useCallback)(async(u,w,v)=>{if(n!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return i.createTableFromData(u,w,v)},[i,n]),g=(0,l.useCallback)(async u=>{if(n!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return i.getTableInfo(u)},[i,n]),D=(0,l.useCallback)(async()=>{if(n!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return i.listTables()},[i,n]);return{status:n,error:s,executeQuery:p,executeQueries:m,createTableFromData:f,getTableInfo:g,listTables:D,isReady:n==="ready",initialize:d}},W=(r,e=[])=>{let{executeQuery:n,isReady:o}=P(),[s,t]=(0,l.useState)(null),[i,a]=(0,l.useState)(!1),[d,p]=(0,l.useState)(null),m=(0,l.useCallback)(async()=>{if(o&&r.trim())try{a(!0),p(null);let g=await n(r);t(g)}catch(g){let D=g instanceof Error?g.message:"Query execution failed";p(D),t(null)}finally{a(!1)}},[n,o,r]),f=J(e);return(0,l.useEffect)(()=>{m()},[m,f]),{data:s,loading:i,error:d,refetch:m}};var z=r=>!r||typeof r!="object"?[]:"toArray"in r&&typeof r.toArray=="function"?r.toArray():[],O=r=>!r||typeof r!="object"?0:"numRows"in r&&typeof r.numRows=="number"?r.numRows:0,C=r=>!r||typeof r!="object"?0:"numCols"in r&&typeof r.numCols=="number"?r.numCols:0,M=r=>!r||typeof r!="object"?!1:"toArray"in r&&typeof r.toArray=="function"&&"numRows"in r&&typeof r.numRows=="number",N=()=>typeof navigator<"u"&&typeof navigator.storage<"u"&&typeof navigator.storage.getDirectory=="function";0&&(module.exports={DuckDBService,LogLevel,Logger,duckDBService,duckdbTableToArray,getDuckDBColumnCount,getDuckDBRowCount,isDuckDBTable,isOpfsSupported,useDuckDB,useDuckDBQuery});
2
2
  //# sourceMappingURL=index.js.map