@aiquants/duckdb-helper 1.1.0 → 1.3.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/dist/index.d.mts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -10
package/dist/index.d.mts
CHANGED
|
@@ -9,13 +9,14 @@ import * as duckdb from '@duckdb/duckdb-wasm';
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
interface UseDuckDBResult {
|
|
12
|
-
status:
|
|
12
|
+
status: "not-initialized" | "initializing" | "ready" | "error";
|
|
13
13
|
error: string | null;
|
|
14
14
|
executeQuery: (sql: string) => Promise<unknown>;
|
|
15
15
|
executeQueries: (queries: string[]) => Promise<unknown[]>;
|
|
16
16
|
createTableFromData: <T extends Record<string, unknown>>(tableName: string, data: T[], options?: {
|
|
17
17
|
dropIfExists?: boolean;
|
|
18
18
|
primaryKey?: string;
|
|
19
|
+
verbose?: boolean;
|
|
19
20
|
}) => Promise<void>;
|
|
20
21
|
getTableInfo: (tableName: string) => Promise<unknown>;
|
|
21
22
|
listTables: () => Promise<unknown>;
|
|
@@ -89,7 +90,7 @@ declare class DuckDBService {
|
|
|
89
90
|
* Get current status.
|
|
90
91
|
* 現在のステータスを取得します。
|
|
91
92
|
*/
|
|
92
|
-
getStatus():
|
|
93
|
+
getStatus(): "not-initialized" | "initializing" | "ready" | "error";
|
|
93
94
|
/**
|
|
94
95
|
* Initialize DuckDB Worker instance.
|
|
95
96
|
* DuckDB Worker インスタンスを初期化します。
|
|
@@ -132,6 +133,7 @@ declare class DuckDBService {
|
|
|
132
133
|
createTableFromData<T extends Record<string, unknown>>(tableName: string, data: T[], options?: {
|
|
133
134
|
dropIfExists?: boolean;
|
|
134
135
|
primaryKey?: string;
|
|
136
|
+
verbose?: boolean;
|
|
135
137
|
}): Promise<void>;
|
|
136
138
|
/**
|
|
137
139
|
* Get table information.
|
|
@@ -223,4 +225,4 @@ declare const getDuckDBColumnCount: (result: unknown) => number;
|
|
|
223
225
|
*/
|
|
224
226
|
declare const isDuckDBTable: (result: unknown) => result is DuckDBQueryResult;
|
|
225
227
|
|
|
226
|
-
export { type DuckDBQueryResult, type DuckDBRow, DuckDBService, _default as duckDBService, duckdbTableToArray, getDuckDBColumnCount, getDuckDBRowCount, isDuckDBTable, useDuckDB, useDuckDBQuery };
|
|
228
|
+
export { type DuckDBQueryResult, type DuckDBRow, DuckDBService, type UseDuckDBResult, _default as duckDBService, duckdbTableToArray, getDuckDBColumnCount, getDuckDBRowCount, isDuckDBTable, useDuckDB, useDuckDBQuery };
|
package/dist/index.d.ts
CHANGED
|
@@ -9,13 +9,14 @@ import * as duckdb from '@duckdb/duckdb-wasm';
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
interface UseDuckDBResult {
|
|
12
|
-
status:
|
|
12
|
+
status: "not-initialized" | "initializing" | "ready" | "error";
|
|
13
13
|
error: string | null;
|
|
14
14
|
executeQuery: (sql: string) => Promise<unknown>;
|
|
15
15
|
executeQueries: (queries: string[]) => Promise<unknown[]>;
|
|
16
16
|
createTableFromData: <T extends Record<string, unknown>>(tableName: string, data: T[], options?: {
|
|
17
17
|
dropIfExists?: boolean;
|
|
18
18
|
primaryKey?: string;
|
|
19
|
+
verbose?: boolean;
|
|
19
20
|
}) => Promise<void>;
|
|
20
21
|
getTableInfo: (tableName: string) => Promise<unknown>;
|
|
21
22
|
listTables: () => Promise<unknown>;
|
|
@@ -89,7 +90,7 @@ declare class DuckDBService {
|
|
|
89
90
|
* Get current status.
|
|
90
91
|
* 現在のステータスを取得します。
|
|
91
92
|
*/
|
|
92
|
-
getStatus():
|
|
93
|
+
getStatus(): "not-initialized" | "initializing" | "ready" | "error";
|
|
93
94
|
/**
|
|
94
95
|
* Initialize DuckDB Worker instance.
|
|
95
96
|
* DuckDB Worker インスタンスを初期化します。
|
|
@@ -132,6 +133,7 @@ declare class DuckDBService {
|
|
|
132
133
|
createTableFromData<T extends Record<string, unknown>>(tableName: string, data: T[], options?: {
|
|
133
134
|
dropIfExists?: boolean;
|
|
134
135
|
primaryKey?: string;
|
|
136
|
+
verbose?: boolean;
|
|
135
137
|
}): Promise<void>;
|
|
136
138
|
/**
|
|
137
139
|
* Get table information.
|
|
@@ -223,4 +225,4 @@ declare const getDuckDBColumnCount: (result: unknown) => number;
|
|
|
223
225
|
*/
|
|
224
226
|
declare const isDuckDBTable: (result: unknown) => result is DuckDBQueryResult;
|
|
225
227
|
|
|
226
|
-
export { type DuckDBQueryResult, type DuckDBRow, DuckDBService, _default as duckDBService, duckdbTableToArray, getDuckDBColumnCount, getDuckDBRowCount, isDuckDBTable, useDuckDB, useDuckDBQuery };
|
|
228
|
+
export { type DuckDBQueryResult, type DuckDBRow, DuckDBService, type UseDuckDBResult, _default as duckDBService, duckdbTableToArray, getDuckDBColumnCount, getDuckDBRowCount, isDuckDBTable, useDuckDB, useDuckDBQuery };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var A=Object.create;var b=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var Q=Object.getPrototypeOf,F=Object.prototype.hasOwnProperty;var O=(t,e)=>{for(var n in e)b(t,n,{get:e[n],enumerable:!0})},T=(t,e,n,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of $(e))!F.call(t,a)&&a!==n&&b(t,a,{get:()=>e[a],enumerable:!(s=v(e,a))||s.enumerable});return t};var W=(t,e,n)=>(n=t!=null?A(Q(t)):{},T(e||!t||!t.__esModule?b(n,"default",{value:t,enumerable:!0}):n,t)),M=t=>T(b({},"__esModule",{value:!0}),t);var U={};O(U,{DuckDBService:()=>h,duckDBService:()=>B,duckdbTableToArray:()=>S,getDuckDBColumnCount:()=>L,getDuckDBRowCount:()=>R,isDuckDBTable:()=>x,useDuckDB:()=>I,useDuckDBQuery:()=>E});module.exports=M(U);var c=require("react");var m=W(require("@duckdb/duckdb-wasm")),g=class g{constructor(){this.operationFlags=new Map;this.workerInstance=null;this.connectionInstance=null;this.isInitializing=!1;this.initPromise=null;this.hasError=!1;this.listeners=new Set}static getInstance(){return g.instance||(g.instance=new g),g.instance}addStatusListener(e){this.listeners.add(e)}removeStatusListener(e){this.listeners.delete(e)}notifyListeners(){for(let e of this.listeners)try{e()}catch(n){console.error("Error in status listener:",n)}}getStatus(){return this.hasError?"error":this.isInitializing?"initializing":this.workerInstance?"ready":"not-initialized"}async initialize(){if(this.workerInstance)return this.workerInstance;if(this.isInitializing&&this.initPromise)return this.initPromise;this.isInitializing=!0,this.hasError=!1,this.notifyListeners(),this.initPromise=this.internalInitializeWorker();try{let e=await this.initPromise;return this.isInitializing=!1,this.notifyListeners(),e}catch(e){throw this.isInitializing=!1,this.hasError=!0,this.notifyListeners(),this.initPromise=null,e}}async internalInitializeWorker(){try{console.log("\u{1F527} Starting DuckDB Worker initialization..."),console.log("\u{1F4E6} Getting DuckDB bundles from CDN...");let e=m.getJsDelivrBundles();console.log("\u{1F50D} Selecting appropriate bundle for browser...");let n=await m.selectBundle(e);console.log("\u2705 Bundle selected:",{mainWorker:n.mainWorker,mainModule:n.mainModule,pthreadWorker:n.pthreadWorker}),console.log("\u{1F680} Creating Worker with Blob URL...");let s=URL.createObjectURL(new Blob([`importScripts("${n.mainWorker}");`],{type:"text/javascript"}));console.log("\u{1F477} Creating Worker instance...");let a=new Worker(s),r=new m.ConsoleLogger;console.log("\u{1F5C4}\uFE0F Creating DuckDB instance..."),this.workerInstance=new m.AsyncDuckDB(r,a),console.log("\u26A1 Instantiating DuckDB with modules..."),await this.workerInstance.instantiate(n.mainModule,n.pthreadWorker),console.log("\u{1F4E6} Installing splink_udfs from community...");let u=await this.workerInstance.connect();try{await u.query("INSTALL splink_udfs FROM community;"),console.log("\u2705 splink_udfs installed successfully"),await u.query("LOAD splink_udfs;"),console.log("\u2705 splink_udfs loaded successfully")}catch(o){console.warn("\u26A0\uFE0F Failed to install/load splink_udfs:",o)}finally{await u.close()}return URL.revokeObjectURL(s),console.log("\u2705 DuckDB Worker initialized successfully"),this.workerInstance}catch(e){throw console.error("\u274C Failed to initialize DuckDB Worker:",e),e instanceof Error&&(console.error("Error name:",e.name),console.error("Error message:",e.message),console.error("Error stack:",e.stack)),e}}async getConnection(){if(!this.connectionInstance){let e=await this.initialize();this.connectionInstance=await e.connect()}return this.connectionInstance}async executeQuery(e){try{return await(await this.getConnection()).query(e)}catch(n){throw console.error("Failed to execute SQL query:",n),n}}async executeQueries(e){let n=[];for(let s of e){let a=await this.executeQuery(s);n.push(a)}return n}inferColumnTypes(e){let n={},s=e.slice(0,Math.min(e.length,10)),a=Object.keys(s[0]||{});for(let r of a){let u=s.map(l=>l[r]).filter(l=>l!=null);if(u.length===0){n[r]="VARCHAR";continue}let o={number:0,integer:0,bigint:0,boolean:0,date:0,string:0};for(let l of u)if(typeof l=="number")o.number+=1,Number.isInteger(l)&&(o.integer+=1,(l<-2147483648||l>2147483647)&&(o.bigint+=1));else if(typeof l=="boolean")o.boolean+=1;else if(l instanceof Date)o.date+=1;else if(typeof l=="string"){let p=new Date(l);!Number.isNaN(p.getTime())&&l.includes("-")?o.date+=1:o.string+=1}else o.string+=1;o.number===u.length?o.integer===u.length?o.bigint>0?n[r]="BIGINT":n[r]="INTEGER":n[r]="DOUBLE":o.boolean===u.length?n[r]="BOOLEAN":o.date===u.length?n[r]="TIMESTAMP":n[r]="VARCHAR"}return n}formatValueForSQL(e){return e==null?"NULL":typeof e=="string"?`'${e.replace(/'/g,"''")}'`:e instanceof Date?`'${e.toISOString()}'`:typeof e=="boolean"?e?"TRUE":"FALSE":(typeof e=="number"&&Number.isInteger(e)&&(e<-2147483648||e>2147483647),String(e))}async createTableFromData(e,n,s={}){if(!n||n.length===0)throw new Error("Data array is empty");let a=`create_table_${e}`;if(this.operationFlags.has(a)){console.log(`\u23F3 Table creation for '${e}' is already in progress, skipping...`);return}this.operationFlags.set(a,!0);try{let r=await this.getConnection();s.dropIfExists&&(console.log(`\u{1F5D1}\uFE0F Dropping table '${e}' if exists`),await r.query(`DROP TABLE IF EXISTS ${e}`));try{let i=await r.query("SHOW TABLES");console.log("\u{1F4CB} Existing tables before creation:",i)}catch(i){console.log("\u26A0\uFE0F Could not list existing tables:",i)}let u=Math.min(n.length,100),o=this.inferColumnTypes(n.slice(0,u)),l=Object.keys(o).map(i=>`"${i}" ${o[i]}`),p=s.primaryKey?`, PRIMARY KEY ("${s.primaryKey}")`:"",k=`CREATE TABLE ${e} (${l.join(", ")}${p})`;console.log("\u{1F528} Creating table with SQL:",k),await r.query(k);try{let i=await r.query("SHOW TABLES");console.log("\u{1F4CB} Tables after creation:",i);let f=await r.query(`SELECT COUNT(*) as count FROM information_schema.tables WHERE table_name = '${e}'`);console.log(`\u2705 Table '${e}' exists check:`,f)}catch(i){console.log("\u26A0\uFE0F Could not verify table creation:",i)}console.log(`\u{1F4E5} Inserting ${n.length} rows into table '${e}'`);let y=Object.keys(n[0]),w=1e3;for(let i=0;i<n.length;i+=w){let f=n.slice(i,i+w);try{let d=f.map(D=>`(${y.map(P=>{let C=D[P];return this.formatValueForSQL(C)}).join(", ")})`),z=`INSERT INTO ${e} (${y.map(D=>`"${D}"`).join(", ")}) VALUES ${d.join(", ")}`;await r.query(z),console.log(`\u{1F4CA} Inserted batch ${Math.floor(i/w)+1} (${f.length} rows)`)}catch(d){throw console.error(`\u274C Failed to insert batch ${Math.floor(i/w)+1}:`,d),d}}console.log(`\u{1F389} Table '${e}' created successfully with ${n.length} rows`)}catch(r){throw console.error(`\u274C Failed to create table '${e}':`,r),r}finally{this.operationFlags.delete(a)}}async getTableInfo(e){return await(await this.getConnection()).query(`DESCRIBE ${e}`)}async listTables(){return await(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.isInitializing=!1,this.hasError=!1,this.initPromise=null,this.listeners.clear(),this.operationFlags.clear()}catch(e){console.error("Error during cleanup:",e)}}static resetInstance(){g.instance&&(g.instance.cleanup(),g.instance=null)}};g.instance=null;var h=g;var B=h.getInstance();var I=(t=!0)=>{let[e,n]=(0,c.useState)("not-initialized"),[s,a]=(0,c.useState)(null),[r]=(0,c.useState)(()=>h.getInstance()),u=(0,c.useCallback)(()=>{let i=r.getStatus();console.info("\u{1F504} DuckDB status updated:",i),n(i),i==="error"?a("DuckDB initialization failed"):i==="ready"&&a(null)},[r]);(0,c.useEffect)(()=>(r.addStatusListener(u),u(),()=>{r.removeStatusListener(u)}),[r,u]);let o=(0,c.useCallback)(async()=>{try{await r.initialize()}catch(i){let f=i instanceof Error?i.message:"Unknown error occurred";a(f),console.error("DuckDB initialization failed:",i)}},[r]);(0,c.useEffect)(()=>{t&&e==="not-initialized"&&(console.info("\u{1F680} Auto-initializing DuckDB..."),o())},[t,e,o]);let l=(0,c.useCallback)(async i=>{if(e!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return r.executeQuery(i)},[r,e]),p=(0,c.useCallback)(async i=>{if(e!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return r.executeQueries(i)},[r,e]),k=(0,c.useCallback)(async(i,f,d)=>{if(e!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return r.createTableFromData(i,f,d)},[r,e]),y=(0,c.useCallback)(async i=>{if(e!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return r.getTableInfo(i)},[r,e]),w=(0,c.useCallback)(async()=>{if(e!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return r.listTables()},[r,e]);return(0,c.useEffect)(()=>{let i=()=>{let d=r.getStatus();d!==e&&d!=="initializing"&&n(d)};if(typeof window>"u"){i();return}let f=window.setInterval(i,1e3);return i(),()=>window.clearInterval(f)},[r,e]),{status:e,error:s,executeQuery:l,executeQueries:p,createTableFromData:k,getTableInfo:y,listTables:w,isReady:e==="ready",initialize:o}},E=(t,e=[])=>{let{executeQuery:n,isReady:s}=I(),[a,r]=(0,c.useState)(null),[u,o]=(0,c.useState)(!1),[l,p]=(0,c.useState)(null),k=(0,c.useCallback)(async()=>{if(s&&t.trim())try{o(!0),p(null);let y=await n(t);r(y)}catch(y){let w=y instanceof Error?y.message:"Query execution failed";p(w),r(null)}finally{o(!1)}},[n,s,t]);return(0,c.useEffect)(()=>{k()},[k,...e]),{data:a,loading:u,error:l,refetch:k}};var S=t=>!t||typeof t!="object"?[]:"toArray"in t&&typeof t.toArray=="function"?t.toArray():[],R=t=>!t||typeof t!="object"?0:"numRows"in t&&typeof t.numRows=="number"?t.numRows:0,L=t=>!t||typeof t!="object"?0:"numCols"in t&&typeof t.numCols=="number"?t.numCols:0,x=t=>!t||typeof t!="object"?!1:"toArray"in t&&typeof t.toArray=="function"&&"numRows"in t&&typeof t.numRows=="number";0&&(module.exports={DuckDBService,duckDBService,duckdbTableToArray,getDuckDBColumnCount,getDuckDBRowCount,isDuckDBTable,useDuckDB,useDuckDBQuery});
|
|
1
|
+
"use strict";var M=Object.create;var T=Object.defineProperty;var O=Object.getOwnPropertyDescriptor;var Q=Object.getOwnPropertyNames;var F=Object.getPrototypeOf,U=Object.prototype.hasOwnProperty;var W=(r,e)=>{for(var n in e)T(r,n,{get:e[n],enumerable:!0})},S=(r,e,n,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Q(e))!U.call(r,o)&&o!==n&&T(r,o,{get:()=>e[o],enumerable:!(s=O(e,o))||s.enumerable});return r};var j=(r,e,n)=>(n=r!=null?M(F(r)):{},S(e||!r||!r.__esModule?T(n,"default",{value:r,enumerable:!0}):n,r)),q=r=>S(T({},"__esModule",{value:!0}),r);var _={};W(_,{DuckDBService:()=>h,duckDBService:()=>R,duckdbTableToArray:()=>L,getDuckDBColumnCount:()=>v,getDuckDBRowCount:()=>x,isDuckDBTable:()=>z,useDuckDB:()=>B,useDuckDBQuery:()=>P});module.exports=q(_);var d=require("react");var m=j(require("@duckdb/duckdb-wasm")),i="[duckdb-helper]",g=class g{constructor(){this.operationFlags=new Map;this.workerInstance=null;this.connectionInstance=null;this.isInitializing=!1;this.initPromise=null;this.hasError=!1;this.listeners=new Set}static getInstance(){return g.instance||(g.instance=new g),g.instance}addStatusListener(e){this.listeners.add(e)}removeStatusListener(e){this.listeners.delete(e)}notifyListeners(){for(let e of this.listeners)try{e()}catch(n){console.error(i,"\u26A0\uFE0F Error in status listener:",n)}}getStatus(){return this.hasError?"error":this.isInitializing?"initializing":this.workerInstance?"ready":"not-initialized"}async initialize(){if(this.workerInstance)return this.workerInstance;if(this.isInitializing&&this.initPromise)return this.initPromise;this.isInitializing=!0,this.hasError=!1,this.notifyListeners();let e=12e4,n=new Promise((s,o)=>{setTimeout(()=>o(new Error(`DuckDB initialization timed out after ${e}ms`)),e)});this.initPromise=(async()=>await Promise.race([this.internalInitializeWorker(),n]))();try{let s=await this.initPromise;return this.isInitializing=!1,this.notifyListeners(),s}catch(s){throw this.isInitializing=!1,this.hasError=!0,this.notifyListeners(),this.initPromise=null,s}}async internalInitializeWorker(){try{console.log(i,"\u{1F527} Starting DuckDB Worker initialization..."),console.log(i,"\u{1F4E6} Getting DuckDB bundles from CDN...");let e=m.getJsDelivrBundles();console.log(i,"\u{1F50D} Selecting appropriate bundle for browser...");let n=await m.selectBundle(e);console.log(i,"\u2705 Bundle selected:",{mainWorker:n.mainWorker,mainModule:n.mainModule,pthreadWorker:n.pthreadWorker}),console.log(i,"\u{1F680} Creating Worker with Blob URL...");let s=URL.createObjectURL(new Blob([`importScripts("${n.mainWorker}");`],{type:"text/javascript"}));console.log(i,"\u{1F477} Creating Worker instance...");let o=new Worker(s),t=new m.ConsoleLogger;console.log(i,"\u{1F5C4}\uFE0F Creating DuckDB instance..."),this.workerInstance=new m.AsyncDuckDB(t,o),console.log(i,"\u26A1 Instantiating DuckDB with modules..."),await this.workerInstance.instantiate(n.mainModule,n.pthreadWorker),console.log(i,"\u{1F4E6} Installing splink_udfs from community...");let a=await this.workerInstance.connect();try{await a.query("INSTALL splink_udfs FROM community;"),console.log(i,"\u2705 splink_udfs installed successfully"),await a.query("LOAD splink_udfs;"),console.log(i,"\u2705 splink_udfs loaded successfully")}catch(l){console.warn(i,"\u26A0\uFE0F Failed to install/load splink_udfs:",l)}finally{await a.close()}return URL.revokeObjectURL(s),console.log(i,"\u2705 DuckDB Worker initialized successfully"),this.workerInstance}catch(e){throw console.error(i,"\u274C Failed to initialize DuckDB Worker:",e),e instanceof Error&&(console.error(i,"\u274C Error name:",e.name),console.error(i,"\u274C Error message:",e.message),console.error(i,"\u274C Error stack:",e.stack)),e}}async getConnection(){if(!this.connectionInstance){let e=await this.initialize();this.connectionInstance=await e.connect()}return this.connectionInstance}async executeQuery(e){let s=new Promise((o,t)=>{setTimeout(()=>t(new Error("DuckDB query execution timed out after 60000ms")),6e4)});try{let o=(async()=>await(await this.getConnection()).query(e))();return await Promise.race([o,s])}catch(o){throw console.error(i,"\u274C Failed to execute SQL query:",o),o}}async executeQueries(e){let n=[];for(let s of e){let o=await this.executeQuery(s);n.push(o)}return n}inferColumnTypes(e){let n={},s=e.slice(0,Math.min(e.length,10)),o=Object.keys(s[0]||{});for(let t of o){let a=s.map(f=>f[t]).filter(f=>f!=null);if(a.length===0){n[t]="VARCHAR";continue}let l={number:0,integer:0,bigint:0,boolean:0,date:0,string:0};for(let f of a)if(typeof f=="number")l.number+=1,Number.isInteger(f)&&(l.integer+=1,(f<-2147483648||f>2147483647)&&(l.bigint+=1));else if(typeof f=="boolean")l.boolean+=1;else if(f instanceof Date)l.date+=1;else if(typeof f=="string"){let k=new Date(f);!Number.isNaN(k.getTime())&&f.includes("-")?l.date+=1:l.string+=1}else l.string+=1;l.number===a.length?l.integer===a.length?l.bigint>0?n[t]="BIGINT":n[t]="INTEGER":n[t]="DOUBLE":l.boolean===a.length?n[t]="BOOLEAN":l.date===a.length?n[t]="TIMESTAMP":n[t]="VARCHAR"}return n}formatValueForSQL(e){return e==null?"NULL":typeof e=="string"?`'${e.replace(/'/g,"''")}'`:e instanceof Date?`'${e.toISOString()}'`:typeof e=="boolean"?e?"TRUE":"FALSE":(typeof e=="number"&&Number.isInteger(e)&&(e<-2147483648||e>2147483647),String(e))}async createTableFromData(e,n,s={}){if(!n||n.length===0)throw new Error("Data array is empty");let o=`create_table_${e}`,t=s.verbose??!0;if(this.operationFlags.has(o)){t&&console.log(i,`\u23F3 Table creation for '${e}' is already in progress, skipping...`);return}this.operationFlags.set(o,!0);try{let a=await this.getConnection();s.dropIfExists&&(t&&console.log(i,`\u{1F5D1}\uFE0F Dropping table '${e}' if exists`),await a.query(`DROP TABLE IF EXISTS ${e}`));try{let u=await a.query("SHOW TABLES");t&&console.log(i,"\u{1F4CB} Existing tables before creation:",u)}catch(u){t&&console.log(i,"\u26A0\uFE0F Could not list existing tables:",u)}let l=Math.min(n.length,100),f=this.inferColumnTypes(n.slice(0,l)),k=Object.keys(f).map(u=>`"${u}" ${f[u]}`),w=s.primaryKey?`, PRIMARY KEY ("${s.primaryKey}")`:"",p=`CREATE TABLE ${e} (${k.join(", ")}${w})`;t&&console.log(i,"\u{1F528} Creating table with SQL:",p),await a.query(p);try{let u=await a.query("SHOW TABLES");t&&console.log(i,"\u{1F4CB} Tables after creation:",u);let y=await a.query(`SELECT COUNT(*) as count FROM information_schema.tables WHERE table_name = '${e}'`);t&&console.log(i,`\u2705 Table '${e}' exists check:`,y)}catch(u){t&&console.log(i,"\u26A0\uFE0F Could not verify table creation:",u)}t&&console.log(i,`\u{1F4E5} Inserting ${n.length} rows into table '${e}'`);let b=Object.keys(n[0]),c=1e3;for(let u=0;u<n.length;u+=c){let y=n.slice(u,u+c);try{let D=y.map(I=>`(${b.map(A=>{let $=I[A];return this.formatValueForSQL($)}).join(", ")})`),C=`INSERT INTO ${e} (${b.map(I=>`"${I}"`).join(", ")}) VALUES ${D.join(", ")}`;await a.query(C),t&&console.log(i,`\u{1F4CA} Inserted batch ${Math.floor(u/c)+1} (${y.length} rows)`)}catch(D){throw console.error(i,`\u274C Failed to insert batch ${Math.floor(u/c)+1}:`,D),D}}t&&console.log(i,`\u{1F389} Table '${e}' created successfully with ${n.length} rows`)}catch(a){throw console.error(i,`\u274C Failed to create table '${e}':`,a),a}finally{this.operationFlags.delete(o)}}async getTableInfo(e){return await(await this.getConnection()).query(`DESCRIBE ${e}`)}async listTables(){return await(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.isInitializing=!1,this.hasError=!1,this.initPromise=null,this.listeners.clear(),this.operationFlags.clear()}catch(e){console.error(i,"\u26A0\uFE0F Error during cleanup:",e)}}static resetInstance(){g.instance&&(g.instance.cleanup(),g.instance=null)}};g.instance=null;var h=g;var R=h.getInstance();var E="[duckdb-helper]",B=(r=!0)=>{let[e,n]=(0,d.useState)("not-initialized"),[s,o]=(0,d.useState)(null),[t]=(0,d.useState)(()=>h.getInstance()),a=(0,d.useCallback)(()=>{let c=t.getStatus();console.info(E,"\u{1F504} DuckDB status updated:",c),n(c),c==="error"?o("DuckDB initialization failed"):c==="ready"&&o(null)},[t]);(0,d.useEffect)(()=>(t.addStatusListener(a),a(),()=>{t.removeStatusListener(a)}),[t,a]);let l=(0,d.useCallback)(async()=>{try{await t.initialize()}catch(c){let u=c instanceof Error?c.message:"Unknown error occurred";o(u),console.error(E,"\u274C DuckDB initialization failed:",c)}},[t]);(0,d.useEffect)(()=>{r&&e==="not-initialized"&&(console.info(E,"\u{1F680} Auto-initializing DuckDB..."),l())},[r,e,l]);let f=(0,d.useCallback)(async c=>{if(e!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return t.executeQuery(c)},[t,e]),k=(0,d.useCallback)(async c=>{if(e!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return t.executeQueries(c)},[t,e]),w=(0,d.useCallback)(async(c,u,y)=>{if(e!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return t.createTableFromData(c,u,y)},[t,e]),p=(0,d.useCallback)(async c=>{if(e!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return t.getTableInfo(c)},[t,e]),b=(0,d.useCallback)(async()=>{if(e!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return t.listTables()},[t,e]);return(0,d.useEffect)(()=>{let c=()=>{let y=t.getStatus();y!==e&&y!=="initializing"&&n(y)};if(typeof window>"u"){c();return}let u=window.setInterval(c,1e3);return c(),()=>window.clearInterval(u)},[t,e]),{status:e,error:s,executeQuery:f,executeQueries:k,createTableFromData:w,getTableInfo:p,listTables:b,isReady:e==="ready",initialize:l}},P=(r,e=[])=>{let{executeQuery:n,isReady:s}=B(),[o,t]=(0,d.useState)(null),[a,l]=(0,d.useState)(!1),[f,k]=(0,d.useState)(null),w=(0,d.useCallback)(async()=>{if(s&&r.trim())try{l(!0),k(null);let p=await n(r);t(p)}catch(p){let b=p instanceof Error?p.message:"Query execution failed";k(b),t(null)}finally{l(!1)}},[n,s,r]);return(0,d.useEffect)(()=>{w()},[w,...e]),{data:o,loading:a,error:f,refetch:w}};var L=r=>!r||typeof r!="object"?[]:"toArray"in r&&typeof r.toArray=="function"?r.toArray():[],x=r=>!r||typeof r!="object"?0:"numRows"in r&&typeof r.numRows=="number"?r.numRows:0,v=r=>!r||typeof r!="object"?0:"numCols"in r&&typeof r.numCols=="number"?r.numCols:0,z=r=>!r||typeof r!="object"?!1:"toArray"in r&&typeof r.toArray=="function"&&"numRows"in r&&typeof r.numRows=="number";0&&(module.exports={DuckDBService,duckDBService,duckdbTableToArray,getDuckDBColumnCount,getDuckDBRowCount,isDuckDBTable,useDuckDB,useDuckDBQuery});
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/hooks/useDuckDB.ts","../src/services/duckdb.ts","../src/utils/duckdb-helpers.ts"],"sourcesContent":["/**\n * DuckDB Helper Library Entry Point\n *\n * Provides React hooks, services, types, and utilities for working with DuckDB in web applications.\n * Web アプリケーションで DuckDB を扱うための React フック、サービス、型、ユーティリティを提供します。\n */\n\nexport { useDuckDB, useDuckDBQuery } from './hooks/useDuckDB'\nexport { DuckDBService, default as duckDBService } from './services/duckdb'\nexport type {\n DuckDBQueryResult,\n DuckDBRow\n} from './types/duckdb'\nexport {\n duckdbTableToArray, getDuckDBColumnCount, getDuckDBRowCount, isDuckDBTable\n} from './utils/duckdb-helpers'\n","/**\n * DuckDB React Hook\n *\n * React hook for using DuckDB functionality in components.\n * コンポーネントで DuckDB 機能を使用するための React フック。\n */\n\nimport { type DependencyList, useCallback, useEffect, useState } from 'react'\nimport { DuckDBService } from '../services/duckdb'\n\nexport interface UseDuckDBResult {\n status: 'not-initialized' | 'initializing' | 'ready' | 'error'\n error: string | null\n executeQuery: (sql: string) => Promise<unknown>\n executeQueries: (queries: string[]) => Promise<unknown[]>\n createTableFromData: <T extends Record<string, unknown>>(\n tableName: string,\n data: T[],\n options?: {\n dropIfExists?: boolean\n primaryKey?: string\n }\n ) => Promise<void>\n getTableInfo: (tableName: string) => Promise<unknown>\n listTables: () => Promise<unknown>\n isReady: boolean\n initialize: () => Promise<void>\n}\n\n/**\n * DuckDB functionality hook.\n * DuckDB 機能を提供するフック。\n *\n * @param autoInitialize - 自動初期化を行うかどうか\n * @returns DuckDB の状態と操作関数\n */\nexport const useDuckDB = (autoInitialize = true): UseDuckDBResult => {\n const [status, setStatus] = useState<'not-initialized' | 'initializing' | 'ready' | 'error'>('not-initialized')\n const [error, setError] = useState<string | null>(null)\n const [duckDBService] = useState(() => DuckDBService.getInstance())\n\n const updateStatus = useCallback(() => {\n const serviceStatus = duckDBService.getStatus()\n console.info('🔄 DuckDB status updated:', serviceStatus)\n setStatus(serviceStatus)\n\n if (serviceStatus === 'error') {\n setError('DuckDB initialization failed')\n } else if (serviceStatus === 'ready') {\n setError(null)\n }\n }, [duckDBService])\n\n useEffect(() => {\n duckDBService.addStatusListener(updateStatus)\n updateStatus()\n\n return () => {\n duckDBService.removeStatusListener(updateStatus)\n }\n }, [duckDBService, updateStatus])\n\n const initialize = useCallback(async () => {\n try {\n await duckDBService.initialize()\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred'\n setError(errorMessage)\n console.error('DuckDB initialization failed:', err)\n }\n }, [duckDBService])\n\n useEffect(() => {\n if (autoInitialize && status === 'not-initialized') {\n console.info('🚀 Auto-initializing DuckDB...')\n void initialize()\n }\n }, [autoInitialize, status, initialize])\n\n const executeQuery = useCallback(async (sql: string): Promise<unknown> => {\n if (status !== 'ready') {\n throw new Error('DuckDB is not ready. Please wait for initialization to complete.')\n }\n return duckDBService.executeQuery(sql)\n }, [duckDBService, status])\n\n const executeQueries = useCallback(async (queries: string[]): Promise<unknown[]> => {\n if (status !== 'ready') {\n throw new Error('DuckDB is not ready. Please wait for initialization to complete.')\n }\n return duckDBService.executeQueries(queries)\n }, [duckDBService, status])\n\n const createTableFromData = useCallback(async <T extends Record<string, unknown>>(\n tableName: string,\n data: T[],\n options?: {\n dropIfExists?: boolean\n primaryKey?: string\n }\n ): Promise<void> => {\n if (status !== 'ready') {\n throw new Error('DuckDB is not ready. Please wait for initialization to complete.')\n }\n return duckDBService.createTableFromData(tableName, data, options)\n }, [duckDBService, status])\n\n const getTableInfo = useCallback(async (tableName: string): Promise<unknown> => {\n if (status !== 'ready') {\n throw new Error('DuckDB is not ready. Please wait for initialization to complete.')\n }\n return duckDBService.getTableInfo(tableName)\n }, [duckDBService, status])\n\n const listTables = useCallback(async (): Promise<unknown> => {\n if (status !== 'ready') {\n throw new Error('DuckDB is not ready. Please wait for initialization to complete.')\n }\n return duckDBService.listTables()\n }, [duckDBService, status])\n\n useEffect(() => {\n const pollStatus = () => {\n const currentStatus = duckDBService.getStatus()\n if (currentStatus !== status && currentStatus !== 'initializing') {\n setStatus(currentStatus)\n }\n }\n\n if (typeof window === 'undefined') {\n pollStatus()\n return\n }\n\n const interval = window.setInterval(pollStatus, 1000)\n pollStatus()\n\n return () => window.clearInterval(interval)\n }, [duckDBService, status])\n\n return {\n status,\n error,\n executeQuery,\n executeQueries,\n createTableFromData,\n getTableInfo,\n listTables,\n isReady: status === 'ready',\n initialize\n }\n}\n\n/**\n * Hook for simple DuckDB query execution.\n * シンプルな DuckDB クエリ実行のためのフック。\n *\n * @param sql - 実行する SQL クエリ\n * @param dependencies - クエリを再実行するための依存配列\n * @returns クエリ結果と状態\n */\nexport const useDuckDBQuery = <T = unknown>(\n sql: string,\n dependencies: DependencyList = []\n): {\n data: T | null\n loading: boolean\n error: string | null\n refetch: () => Promise<void>\n} => {\n const { executeQuery, isReady } = useDuckDB()\n const [data, setData] = useState<T | null>(null)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const refetch = useCallback(async () => {\n if (!(isReady && sql.trim())) {\n return\n }\n\n try {\n setLoading(true)\n setError(null)\n const result = await executeQuery(sql)\n setData(result as T)\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Query execution failed'\n setError(errorMessage)\n setData(null)\n } finally {\n setLoading(false)\n }\n }, [executeQuery, isReady, sql])\n\n useEffect(() => {\n void refetch()\n }, [refetch, ...dependencies])\n\n return {\n data,\n loading,\n error,\n refetch\n }\n}\n","/**\n * DuckDB Web Worker Service\n *\n * Provides reusable DuckDB-wasm functionality across the application.\n * アプリケーション全体で再利用可能な DuckDB-wasm 機能を提供します。\n */\n\nimport * as duckdb from '@duckdb/duckdb-wasm'\n\n/**\n * DuckDB service for browser-based SQL operations.\n * ブラウザベースの SQL 操作のための DuckDB サービス。\n */\nclass DuckDBService {\n private static instance: DuckDBService | null = null\n private operationFlags: Map<string, boolean> = new Map()\n\n private workerInstance: duckdb.AsyncDuckDB | null = null\n private connectionInstance: duckdb.AsyncDuckDBConnection | null = null\n private isInitializing = false\n private initPromise: Promise<duckdb.AsyncDuckDB> | null = null\n private hasError = false\n\n private listeners: Set<() => void> = new Set()\n\n /**\n * Get singleton instance of DuckDBService.\n * DuckDBService のシングルトンインスタンスを取得します。\n */\n public static getInstance(): DuckDBService {\n if (!DuckDBService.instance) {\n DuckDBService.instance = new DuckDBService()\n }\n return DuckDBService.instance\n }\n\n /**\n * Add status change listener.\n * 状態変更リスナーを追加します。\n */\n public addStatusListener(listener: () => void): void {\n this.listeners.add(listener)\n }\n\n /**\n * Remove status change listener.\n * 状態変更リスナーを削除します。\n */\n public removeStatusListener(listener: () => void): void {\n this.listeners.delete(listener)\n }\n\n /**\n * Notify all listeners of status change.\n * すべてのリスナーに状態変更を通知します。\n */\n private notifyListeners(): void {\n for (const listener of this.listeners) {\n try {\n listener()\n } catch (error) {\n console.error('Error in status listener:', error)\n }\n }\n }\n\n /**\n * Get current status.\n * 現在のステータスを取得します。\n */\n public getStatus(): 'not-initialized' | 'initializing' | 'ready' | 'error' {\n if (this.hasError) {\n return 'error'\n }\n if (this.isInitializing) {\n return 'initializing'\n }\n if (this.workerInstance) {\n return 'ready'\n }\n return 'not-initialized'\n }\n\n /**\n * Initialize DuckDB Worker instance.\n * DuckDB Worker インスタンスを初期化します。\n */\n public async initialize(): Promise<duckdb.AsyncDuckDB> {\n if (this.workerInstance) {\n return this.workerInstance\n }\n\n if (this.isInitializing && this.initPromise) {\n return this.initPromise\n }\n\n this.isInitializing = true\n this.hasError = false\n this.notifyListeners()\n this.initPromise = this.internalInitializeWorker()\n\n try {\n const result = await this.initPromise\n this.isInitializing = false\n this.notifyListeners()\n return result\n } catch (error) {\n this.isInitializing = false\n this.hasError = true\n this.notifyListeners()\n this.initPromise = null\n throw error\n }\n }\n\n /**\n * Internal worker initialization method.\n * 内部的な Worker 初期化メソッド。\n */\n private async internalInitializeWorker(): Promise<duckdb.AsyncDuckDB> {\n try {\n console.log('🔧 Starting DuckDB Worker initialization...')\n console.log('📦 Getting DuckDB bundles from CDN...')\n const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles()\n\n console.log('🔍 Selecting appropriate bundle for browser...')\n const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES)\n console.log('✅ Bundle selected:', {\n mainWorker: bundle.mainWorker,\n mainModule: bundle.mainModule,\n pthreadWorker: bundle.pthreadWorker\n })\n\n console.log('🚀 Creating Worker with Blob URL...')\n const workerUrl = URL.createObjectURL(\n new Blob([`importScripts(\"${bundle.mainWorker}\");`], { type: 'text/javascript' })\n )\n\n console.log('👷 Creating Worker instance...')\n const worker = new Worker(workerUrl)\n const logger = new duckdb.ConsoleLogger()\n\n console.log('🗄️ Creating DuckDB instance...')\n this.workerInstance = new duckdb.AsyncDuckDB(logger, worker)\n\n console.log('⚡ Instantiating DuckDB with modules...')\n await this.workerInstance.instantiate(bundle.mainModule, bundle.pthreadWorker)\n\n console.log('📦 Installing splink_udfs from community...')\n const connection = await this.workerInstance.connect()\n try {\n await connection.query('INSTALL splink_udfs FROM community;')\n console.log('✅ splink_udfs installed successfully')\n\n await connection.query('LOAD splink_udfs;')\n console.log('✅ splink_udfs loaded successfully')\n } catch (error) {\n console.warn('⚠️ Failed to install/load splink_udfs:', error)\n } finally {\n await connection.close()\n }\n\n URL.revokeObjectURL(workerUrl)\n\n console.log('✅ DuckDB Worker initialized successfully')\n return this.workerInstance\n } catch (error) {\n console.error('❌ Failed to initialize DuckDB Worker:', error)\n\n if (error instanceof Error) {\n console.error('Error name:', error.name)\n console.error('Error message:', error.message)\n console.error('Error stack:', error.stack)\n }\n\n throw error\n }\n }\n\n /**\n * Get or create DuckDB connection.\n * DuckDB 接続を取得または作成します。\n */\n public async getConnection(): Promise<duckdb.AsyncDuckDBConnection> {\n if (!this.connectionInstance) {\n const db = await this.initialize()\n this.connectionInstance = await db.connect()\n }\n return this.connectionInstance\n }\n\n /**\n * Execute SQL query using DuckDB Worker.\n * DuckDB Worker を使用して SQL クエリを実行します。\n */\n public async executeQuery(sql: string): Promise<unknown> {\n try {\n const connection = await this.getConnection()\n const result = await connection.query(sql)\n return result\n } catch (error) {\n console.error('Failed to execute SQL query:', error)\n throw error\n }\n }\n\n /**\n * Execute multiple SQL queries.\n * 複数の SQL クエリを実行します。\n */\n public async executeQueries(queries: string[]): Promise<unknown[]> {\n const results: unknown[] = []\n for (const query of queries) {\n const result = await this.executeQuery(query)\n results.push(result)\n }\n return results\n }\n\n /**\n * Infer column types from data sample.\n * データサンプルから列の型を推定します。\n */\n private inferColumnTypes(data: Record<string, unknown>[]): Record<string, string> {\n const columnTypes: Record<string, string> = {}\n const sampleData = data.slice(0, Math.min(data.length, 10))\n\n const keys = Object.keys(sampleData[0] || {})\n for (const key of keys) {\n const values = sampleData.map(row => row[key]).filter(val => val !== null && val !== undefined)\n\n if (values.length === 0) {\n columnTypes[key] = 'VARCHAR'\n continue\n }\n\n const typeInfo = {\n number: 0,\n integer: 0,\n bigint: 0,\n boolean: 0,\n date: 0,\n string: 0\n }\n\n for (const value of values) {\n if (typeof value === 'number') {\n typeInfo.number += 1\n if (Number.isInteger(value)) {\n typeInfo.integer += 1\n if (value < -2147483648 || value > 2147483647) {\n typeInfo.bigint += 1\n }\n }\n } else if (typeof value === 'boolean') {\n typeInfo.boolean += 1\n } else if (value instanceof Date) {\n typeInfo.date += 1\n } else if (typeof value === 'string') {\n const dateValue = new Date(value)\n if (!Number.isNaN(dateValue.getTime()) && value.includes('-')) {\n typeInfo.date += 1\n } else {\n typeInfo.string += 1\n }\n } else {\n typeInfo.string += 1\n }\n }\n\n if (typeInfo.number === values.length) {\n if (typeInfo.integer === values.length) {\n if (typeInfo.bigint > 0) {\n columnTypes[key] = 'BIGINT'\n } else {\n columnTypes[key] = 'INTEGER'\n }\n } else {\n columnTypes[key] = 'DOUBLE'\n }\n } else if (typeInfo.boolean === values.length) {\n columnTypes[key] = 'BOOLEAN'\n } else if (typeInfo.date === values.length) {\n columnTypes[key] = 'TIMESTAMP'\n } else {\n columnTypes[key] = 'VARCHAR'\n }\n }\n\n return columnTypes\n }\n\n /**\n * Format value for SQL insertion.\n * SQL 挿入用に値をフォーマットします。\n */\n private formatValueForSQL(value: unknown): string {\n if (value === null || value === undefined) {\n return 'NULL'\n }\n if (typeof value === 'string') {\n return `'${value.replace(/'/g, \"''\")}'`\n }\n if (value instanceof Date) {\n return `'${value.toISOString()}'`\n }\n if (typeof value === 'boolean') {\n return value ? 'TRUE' : 'FALSE'\n }\n if (typeof value === 'number') {\n if (Number.isInteger(value) && (value < -2147483648 || value > 2147483647)) {\n return String(value)\n }\n return String(value)\n }\n return String(value)\n }\n\n /**\n * Create table from JavaScript array of objects.\n * JavaScript オブジェクトの配列からテーブルを作成します。\n */\n public async createTableFromData<T extends Record<string, unknown>>(\n tableName: string,\n data: T[],\n options: {\n dropIfExists?: boolean\n primaryKey?: string\n } = {}\n ): Promise<void> {\n if (!data || data.length === 0) {\n throw new Error('Data array is empty')\n }\n\n const operationKey = `create_table_${tableName}`\n if (this.operationFlags.has(operationKey)) {\n console.log(`⏳ Table creation for '${tableName}' is already in progress, skipping...`)\n return\n }\n this.operationFlags.set(operationKey, true)\n\n try {\n const connection = await this.getConnection()\n\n if (options.dropIfExists) {\n console.log(`🗑️ Dropping table '${tableName}' if exists`)\n await connection.query(`DROP TABLE IF EXISTS ${tableName}`)\n }\n\n try {\n const existingTables = await connection.query('SHOW TABLES')\n console.log('📋 Existing tables before creation:', existingTables)\n } catch (error) {\n console.log('⚠️ Could not list existing tables:', error)\n }\n\n const sampleSize = Math.min(data.length, 100)\n const columnTypes = this.inferColumnTypes(data.slice(0, sampleSize))\n\n const columns = Object.keys(columnTypes).map(key => {\n return `\"${key}\" ${columnTypes[key]}`\n })\n\n const primaryKeyClause = options.primaryKey ? `, PRIMARY KEY (\"${options.primaryKey}\")` : ''\n\n const createTableSQL = `CREATE TABLE ${tableName} (${columns.join(', ')}${primaryKeyClause})`\n console.log('🔨 Creating table with SQL:', createTableSQL)\n await connection.query(createTableSQL)\n\n try {\n const tablesAfterCreation = await connection.query('SHOW TABLES')\n console.log('📋 Tables after creation:', tablesAfterCreation)\n\n const tableExists = await connection.query(`SELECT COUNT(*) as count FROM information_schema.tables WHERE table_name = '${tableName}'`)\n console.log(`✅ Table '${tableName}' exists check:`, tableExists)\n } catch (error) {\n console.log('⚠️ Could not verify table creation:', error)\n }\n\n console.log(`📥 Inserting ${data.length} rows into table '${tableName}'`)\n const dataColumns = Object.keys(data[0])\n const batchSize = 1000\n\n for (let i = 0; i < data.length; i += batchSize) {\n const batch = data.slice(i, i + batchSize)\n\n try {\n const valueRows = batch.map(row => {\n const values = dataColumns.map(col => {\n const value = row[col]\n return this.formatValueForSQL(value)\n })\n return `(${values.join(', ')})`\n })\n\n const insertSQL = `INSERT INTO ${tableName} (${dataColumns.map(col => `\"${col}\"`).join(', ')}) VALUES ${valueRows.join(', ')}`\n await connection.query(insertSQL)\n console.log(`📊 Inserted batch ${Math.floor(i / batchSize) + 1} (${batch.length} rows)`)\n } catch (insertError) {\n console.error(`❌ Failed to insert batch ${Math.floor(i / batchSize) + 1}:`, insertError)\n throw insertError\n }\n }\n\n console.log(`🎉 Table '${tableName}' created successfully with ${data.length} rows`)\n } catch (error) {\n console.error(`❌ Failed to create table '${tableName}':`, error)\n throw error\n } finally {\n this.operationFlags.delete(operationKey)\n }\n }\n\n /**\n * Get table information.\n * テーブル情報を取得します。\n */\n public async getTableInfo(tableName: string): Promise<unknown> {\n const connection = await this.getConnection()\n const result = await connection.query(`DESCRIBE ${tableName}`)\n return result\n }\n\n /**\n * List all tables.\n * すべてのテーブルを一覧表示します。\n */\n public async listTables(): Promise<unknown> {\n const connection = await this.getConnection()\n const result = await connection.query('SHOW TABLES')\n return result\n }\n\n /**\n * Check if DuckDB is ready.\n * DuckDB が準備完了かどうかを確認します。\n */\n public isReady(): boolean {\n return this.workerInstance !== null\n }\n\n /**\n * Cleanup DuckDB Worker resources.\n * DuckDB Worker のリソースをクリーンアップします。\n */\n public async cleanup(): Promise<void> {\n try {\n if (this.connectionInstance) {\n await this.connectionInstance.close()\n this.connectionInstance = null\n }\n if (this.workerInstance) {\n await this.workerInstance.terminate()\n this.workerInstance = null\n }\n this.isInitializing = false\n this.hasError = false\n this.initPromise = null\n this.listeners.clear()\n this.operationFlags.clear()\n } catch (error) {\n console.error('Error during cleanup:', error)\n }\n }\n\n /**\n * Reset the service instance (useful for testing).\n * サービスインスタンスをリセットします(テスト用)。\n */\n public static resetInstance(): void {\n if (DuckDBService.instance) {\n DuckDBService.instance.cleanup()\n DuckDBService.instance = null\n }\n }\n}\n\nexport { DuckDBService }\n\nexport default DuckDBService.getInstance()\n","/**\n * DuckDB Helper Functions\n *\n * Utility functions for working with DuckDB query results.\n * DuckDB クエリ結果を扱うためのユーティリティ関数。\n */\n\nimport type { DuckDBQueryResult } from '../types/duckdb'\n\n/**\n * Safely convert DuckDB table to typed array\n * DuckDB テーブルを型付き配列に安全に変換します\n *\n * @param result - DuckDB query result\n * @returns Typed array of results\n */\nexport const duckdbTableToArray = <T>(result: unknown): T[] => {\n if (!result || typeof result !== 'object') {\n return []\n }\n\n if ('toArray' in result && typeof result.toArray === 'function') {\n return (result as DuckDBQueryResult<T>).toArray()\n }\n\n return []\n}\n\n/**\n * Get table row count\n * テーブルの行数を取得します\n *\n * @param result - DuckDB query result\n * @returns Number of rows in the table\n */\nexport const getDuckDBRowCount = (result: unknown): number => {\n if (!result || typeof result !== 'object') {\n return 0\n }\n\n if ('numRows' in result && typeof result.numRows === 'number') {\n return result.numRows\n }\n\n return 0\n}\n\n/**\n * Get table column count\n * テーブルの列数を取得します\n *\n * @param result - DuckDB query result\n * @returns Number of columns in the table\n */\nexport const getDuckDBColumnCount = (result: unknown): number => {\n if (!result || typeof result !== 'object') {\n return 0\n }\n\n if ('numCols' in result && typeof result.numCols === 'number') {\n return result.numCols\n }\n\n return 0\n}\n\n/**\n * Check if result is a valid DuckDB table\n * 結果が有効な DuckDB テーブルかどうかをチェックします\n *\n * @param result - DuckDB query result\n * @returns True if result is a valid DuckDB table\n */\nexport const isDuckDBTable = (result: unknown): result is DuckDBQueryResult => {\n if (!result || typeof result !== 'object') {\n return false\n }\n\n return (\n 'toArray' in result &&\n typeof result.toArray === 'function' &&\n 'numRows' in result &&\n typeof result.numRows === 'number'\n )\n}\n"],"mappings":"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","names":["index_exports","__export","DuckDBService","duckdb_default","duckdbTableToArray","getDuckDBColumnCount","getDuckDBRowCount","isDuckDBTable","useDuckDB","useDuckDBQuery","__toCommonJS","import_react","duckdb","_DuckDBService","listener","error","result","JSDELIVR_BUNDLES","bundle","workerUrl","worker","logger","connection","db","sql","queries","results","query","data","columnTypes","sampleData","keys","key","values","row","val","typeInfo","value","dateValue","tableName","options","operationKey","existingTables","sampleSize","columns","primaryKeyClause","createTableSQL","tablesAfterCreation","tableExists","dataColumns","batchSize","batch","valueRows","col","insertSQL","insertError","DuckDBService","duckdb_default","DuckDBService","useDuckDB","autoInitialize","status","setStatus","error","setError","duckDBService","DuckDBService","updateStatus","serviceStatus","initialize","err","errorMessage","executeQuery","sql","executeQueries","queries","createTableFromData","tableName","data","options","getTableInfo","listTables","pollStatus","currentStatus","interval","useDuckDBQuery","dependencies","isReady","setData","loading","setLoading","refetch","result","duckdbTableToArray","result","getDuckDBRowCount","getDuckDBColumnCount","isDuckDBTable"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/hooks/useDuckDB.ts","../src/services/duckdb.ts","../src/utils/duckdb-helpers.ts"],"sourcesContent":["/**\n * DuckDB Helper Library Entry Point\n *\n * Provides React hooks, services, types, and utilities for working with DuckDB in web applications.\n * Web アプリケーションで DuckDB を扱うための React フック、サービス、型、ユーティリティを提供します。\n */\n\nexport type { UseDuckDBResult } from \"./hooks/useDuckDB\"\nexport { useDuckDB, useDuckDBQuery } from \"./hooks/useDuckDB\"\nexport { DuckDBService, default as duckDBService } from \"./services/duckdb\"\nexport type {\n DuckDBQueryResult,\n DuckDBRow,\n} from \"./types/duckdb\"\nexport {\n duckdbTableToArray,\n getDuckDBColumnCount,\n getDuckDBRowCount,\n isDuckDBTable,\n} from \"./utils/duckdb-helpers\"\n","/**\n * DuckDB React Hook\n *\n * React hook for using DuckDB functionality in components.\n * コンポーネントで DuckDB 機能を使用するための React フック。\n */\n\nimport { type DependencyList, useCallback, useEffect, useState } from \"react\"\nimport { DuckDBService } from \"../services/duckdb\"\n\nconst LOG_PREFIX = \"[duckdb-helper]\"\n\nexport interface UseDuckDBResult {\n status: \"not-initialized\" | \"initializing\" | \"ready\" | \"error\"\n error: string | null\n executeQuery: (sql: string) => Promise<unknown>\n executeQueries: (queries: string[]) => Promise<unknown[]>\n createTableFromData: <T extends Record<string, unknown>>(\n tableName: string,\n data: T[],\n options?: {\n dropIfExists?: boolean\n primaryKey?: string\n verbose?: boolean\n },\n ) => Promise<void>\n getTableInfo: (tableName: string) => Promise<unknown>\n listTables: () => Promise<unknown>\n isReady: boolean\n initialize: () => Promise<void>\n}\n\n/**\n * DuckDB functionality hook.\n * DuckDB 機能を提供するフック。\n *\n * @param autoInitialize - 自動初期化を行うかどうか\n * @returns DuckDB の状態と操作関数\n */\nexport const useDuckDB = (autoInitialize = true): UseDuckDBResult => {\n const [status, setStatus] = useState<\"not-initialized\" | \"initializing\" | \"ready\" | \"error\">(\"not-initialized\")\n const [error, setError] = useState<string | null>(null)\n const [duckDBService] = useState(() => DuckDBService.getInstance())\n\n const updateStatus = useCallback(() => {\n const serviceStatus = duckDBService.getStatus()\n console.info(LOG_PREFIX, \"🔄 DuckDB status updated:\", serviceStatus)\n setStatus(serviceStatus)\n\n if (serviceStatus === \"error\") {\n setError(\"DuckDB initialization failed\")\n } else if (serviceStatus === \"ready\") {\n setError(null)\n }\n }, [duckDBService])\n\n useEffect(() => {\n duckDBService.addStatusListener(updateStatus)\n updateStatus()\n\n return () => {\n duckDBService.removeStatusListener(updateStatus)\n }\n }, [duckDBService, updateStatus])\n\n const initialize = useCallback(async () => {\n try {\n await duckDBService.initialize()\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : \"Unknown error occurred\"\n setError(errorMessage)\n console.error(LOG_PREFIX, \"❌ DuckDB initialization failed:\", err)\n }\n }, [duckDBService])\n\n useEffect(() => {\n if (autoInitialize && status === \"not-initialized\") {\n console.info(LOG_PREFIX, \"🚀 Auto-initializing DuckDB...\")\n void initialize()\n }\n }, [autoInitialize, status, initialize])\n\n const executeQuery = useCallback(\n async (sql: string): Promise<unknown> => {\n if (status !== \"ready\") {\n throw new Error(\"DuckDB is not ready. Please wait for initialization to complete.\")\n }\n return duckDBService.executeQuery(sql)\n },\n [duckDBService, status],\n )\n\n const executeQueries = useCallback(\n async (queries: string[]): Promise<unknown[]> => {\n if (status !== \"ready\") {\n throw new Error(\"DuckDB is not ready. Please wait for initialization to complete.\")\n }\n return duckDBService.executeQueries(queries)\n },\n [duckDBService, status],\n )\n\n const createTableFromData = useCallback(\n async <T extends Record<string, unknown>>(\n tableName: string,\n data: T[],\n options?: {\n dropIfExists?: boolean\n primaryKey?: string\n verbose?: boolean\n },\n ): Promise<void> => {\n if (status !== \"ready\") {\n throw new Error(\"DuckDB is not ready. Please wait for initialization to complete.\")\n }\n return duckDBService.createTableFromData(tableName, data, options)\n },\n [duckDBService, status],\n )\n\n const getTableInfo = useCallback(\n async (tableName: string): Promise<unknown> => {\n if (status !== \"ready\") {\n throw new Error(\"DuckDB is not ready. Please wait for initialization to complete.\")\n }\n return duckDBService.getTableInfo(tableName)\n },\n [duckDBService, status],\n )\n\n const listTables = useCallback(async (): Promise<unknown> => {\n if (status !== \"ready\") {\n throw new Error(\"DuckDB is not ready. Please wait for initialization to complete.\")\n }\n return duckDBService.listTables()\n }, [duckDBService, status])\n\n useEffect(() => {\n const pollStatus = () => {\n const currentStatus = duckDBService.getStatus()\n if (currentStatus !== status && currentStatus !== \"initializing\") {\n setStatus(currentStatus)\n }\n }\n\n if (typeof window === \"undefined\") {\n pollStatus()\n return\n }\n\n const interval = window.setInterval(pollStatus, 1000)\n pollStatus()\n\n return () => window.clearInterval(interval)\n }, [duckDBService, status])\n\n return {\n status,\n error,\n executeQuery,\n executeQueries,\n createTableFromData,\n getTableInfo,\n listTables,\n isReady: status === \"ready\",\n initialize,\n }\n}\n\n/**\n * Hook for simple DuckDB query execution.\n * シンプルな DuckDB クエリ実行のためのフック。\n *\n * @param sql - 実行する SQL クエリ\n * @param dependencies - クエリを再実行するための依存配列\n * @returns クエリ結果と状態\n */\nexport const useDuckDBQuery = <T = unknown>(\n sql: string,\n dependencies: DependencyList = [],\n): {\n data: T | null\n loading: boolean\n error: string | null\n refetch: () => Promise<void>\n} => {\n const { executeQuery, isReady } = useDuckDB()\n const [data, setData] = useState<T | null>(null)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const refetch = useCallback(async () => {\n if (!(isReady && sql.trim())) {\n return\n }\n\n try {\n setLoading(true)\n setError(null)\n const result = await executeQuery(sql)\n setData(result as T)\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : \"Query execution failed\"\n setError(errorMessage)\n setData(null)\n } finally {\n setLoading(false)\n }\n }, [executeQuery, isReady, sql])\n\n useEffect(() => {\n void refetch()\n }, [refetch, ...dependencies])\n\n return {\n data,\n loading,\n error,\n refetch,\n }\n}\n","/**\n * DuckDB Web Worker Service\n *\n * Provides reusable DuckDB-wasm functionality across the application.\n * アプリケーション全体で再利用可能な DuckDB-wasm 機能を提供します。\n */\n\nimport * as duckdb from \"@duckdb/duckdb-wasm\"\n\nconst LOG_PREFIX = \"[duckdb-helper]\"\n\n/**\n * DuckDB service for browser-based SQL operations.\n * ブラウザベースの SQL 操作のための DuckDB サービス。\n */\nclass DuckDBService {\n private static instance: DuckDBService | null = null\n private operationFlags: Map<string, boolean> = new Map()\n\n private workerInstance: duckdb.AsyncDuckDB | null = null\n private connectionInstance: duckdb.AsyncDuckDBConnection | null = null\n private isInitializing = false\n private initPromise: Promise<duckdb.AsyncDuckDB> | null = null\n private hasError = false\n\n private listeners: Set<() => void> = new Set()\n\n /**\n * Get singleton instance of DuckDBService.\n * DuckDBService のシングルトンインスタンスを取得します。\n */\n public static getInstance(): DuckDBService {\n if (!DuckDBService.instance) {\n DuckDBService.instance = new DuckDBService()\n }\n return DuckDBService.instance\n }\n\n /**\n * Add status change listener.\n * 状態変更リスナーを追加します。\n */\n public addStatusListener(listener: () => void): void {\n this.listeners.add(listener)\n }\n\n /**\n * Remove status change listener.\n * 状態変更リスナーを削除します。\n */\n public removeStatusListener(listener: () => void): void {\n this.listeners.delete(listener)\n }\n\n /**\n * Notify all listeners of status change.\n * すべてのリスナーに状態変更を通知します。\n */\n private notifyListeners(): void {\n for (const listener of this.listeners) {\n try {\n listener()\n } catch (error) {\n console.error(LOG_PREFIX, \"⚠️ Error in status listener:\", error)\n }\n }\n }\n\n /**\n * Get current status.\n * 現在のステータスを取得します。\n */\n public getStatus(): \"not-initialized\" | \"initializing\" | \"ready\" | \"error\" {\n if (this.hasError) {\n return \"error\"\n }\n if (this.isInitializing) {\n return \"initializing\"\n }\n if (this.workerInstance) {\n return \"ready\"\n }\n return \"not-initialized\"\n }\n\n /**\n * Initialize DuckDB Worker instance.\n * DuckDB Worker インスタンスを初期化します。\n */\n public async initialize(): Promise<duckdb.AsyncDuckDB> {\n if (this.workerInstance) {\n return this.workerInstance\n }\n\n if (this.isInitializing && this.initPromise) {\n return this.initPromise\n }\n\n this.isInitializing = true\n this.hasError = false\n this.notifyListeners()\n\n // タイムアウト設定 (120秒) - WASMのダウンロードなどを考慮して長めに設定\n const TIMEOUT_MS = 120000\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => reject(new Error(`DuckDB initialization timed out after ${TIMEOUT_MS}ms`)), TIMEOUT_MS)\n })\n\n this.initPromise = (async () => {\n return await Promise.race([this.internalInitializeWorker(), timeoutPromise])\n })()\n\n try {\n const result = await this.initPromise\n this.isInitializing = false\n this.notifyListeners()\n return result\n } catch (error) {\n this.isInitializing = false\n this.hasError = true\n this.notifyListeners()\n this.initPromise = null\n throw error\n }\n }\n\n /**\n * Internal worker initialization method.\n * 内部的な Worker 初期化メソッド。\n */\n private async internalInitializeWorker(): Promise<duckdb.AsyncDuckDB> {\n try {\n console.log(LOG_PREFIX, \"🔧 Starting DuckDB Worker initialization...\")\n console.log(LOG_PREFIX, \"📦 Getting DuckDB bundles from CDN...\")\n const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles()\n\n console.log(LOG_PREFIX, \"🔍 Selecting appropriate bundle for browser...\")\n const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES)\n console.log(LOG_PREFIX, \"✅ Bundle selected:\", {\n mainWorker: bundle.mainWorker,\n mainModule: bundle.mainModule,\n pthreadWorker: bundle.pthreadWorker,\n })\n\n console.log(LOG_PREFIX, \"🚀 Creating Worker with Blob URL...\")\n const workerUrl = URL.createObjectURL(new Blob([`importScripts(\"${bundle.mainWorker}\");`], { type: \"text/javascript\" }))\n\n console.log(LOG_PREFIX, \"👷 Creating Worker instance...\")\n const worker = new Worker(workerUrl)\n const logger = new duckdb.ConsoleLogger()\n\n console.log(LOG_PREFIX, \"🗄️ Creating DuckDB instance...\")\n this.workerInstance = new duckdb.AsyncDuckDB(logger, worker)\n\n console.log(LOG_PREFIX, \"⚡ Instantiating DuckDB with modules...\")\n await this.workerInstance.instantiate(bundle.mainModule, bundle.pthreadWorker)\n\n console.log(LOG_PREFIX, \"📦 Installing splink_udfs from community...\")\n const connection = await this.workerInstance.connect()\n try {\n await connection.query(\"INSTALL splink_udfs FROM community;\")\n console.log(LOG_PREFIX, \"✅ splink_udfs installed successfully\")\n\n await connection.query(\"LOAD splink_udfs;\")\n console.log(LOG_PREFIX, \"✅ splink_udfs loaded successfully\")\n } catch (error) {\n console.warn(LOG_PREFIX, \"⚠️ Failed to install/load splink_udfs:\", error)\n } finally {\n await connection.close()\n }\n\n URL.revokeObjectURL(workerUrl)\n\n console.log(LOG_PREFIX, \"✅ DuckDB Worker initialized successfully\")\n return this.workerInstance\n } catch (error) {\n console.error(LOG_PREFIX, \"❌ Failed to initialize DuckDB Worker:\", error)\n\n if (error instanceof Error) {\n console.error(LOG_PREFIX, \"❌ Error name:\", error.name)\n console.error(LOG_PREFIX, \"❌ Error message:\", error.message)\n console.error(LOG_PREFIX, \"❌ Error stack:\", error.stack)\n }\n\n throw error\n }\n }\n\n /**\n * Get or create DuckDB connection.\n * DuckDB 接続を取得または作成します。\n */\n public async getConnection(): Promise<duckdb.AsyncDuckDBConnection> {\n if (!this.connectionInstance) {\n const db = await this.initialize()\n this.connectionInstance = await db.connect()\n }\n return this.connectionInstance\n }\n\n /**\n * Execute SQL query using DuckDB Worker.\n * DuckDB Worker を使用して SQL クエリを実行します。\n */\n public async executeQuery(sql: string): Promise<unknown> {\n // タイムアウト設定 (60秒)\n const TIMEOUT_MS = 60000\n const timeoutPromise = new Promise((_, reject) => {\n setTimeout(() => reject(new Error(`DuckDB query execution timed out after ${TIMEOUT_MS}ms`)), TIMEOUT_MS)\n })\n\n try {\n const operationPromise = (async () => {\n const connection = await this.getConnection()\n return await connection.query(sql)\n })()\n\n const result = await Promise.race([operationPromise, timeoutPromise])\n return result\n } catch (error) {\n console.error(LOG_PREFIX, \"❌ Failed to execute SQL query:\", error)\n throw error\n }\n }\n\n /**\n * Execute multiple SQL queries.\n * 複数の SQL クエリを実行します。\n */\n public async executeQueries(queries: string[]): Promise<unknown[]> {\n const results: unknown[] = []\n for (const query of queries) {\n const result = await this.executeQuery(query)\n results.push(result)\n }\n return results\n }\n\n /**\n * Infer column types from data sample.\n * データサンプルから列の型を推定します。\n */\n private inferColumnTypes(data: Record<string, unknown>[]): Record<string, string> {\n const columnTypes: Record<string, string> = {}\n const sampleData = data.slice(0, Math.min(data.length, 10))\n\n const keys = Object.keys(sampleData[0] || {})\n for (const key of keys) {\n const values = sampleData.map((row) => row[key]).filter((val) => val !== null && val !== undefined)\n\n if (values.length === 0) {\n columnTypes[key] = \"VARCHAR\"\n continue\n }\n\n const typeInfo = {\n number: 0,\n integer: 0,\n bigint: 0,\n boolean: 0,\n date: 0,\n string: 0,\n }\n\n for (const value of values) {\n if (typeof value === \"number\") {\n typeInfo.number += 1\n if (Number.isInteger(value)) {\n typeInfo.integer += 1\n if (value < -2147483648 || value > 2147483647) {\n typeInfo.bigint += 1\n }\n }\n } else if (typeof value === \"boolean\") {\n typeInfo.boolean += 1\n } else if (value instanceof Date) {\n typeInfo.date += 1\n } else if (typeof value === \"string\") {\n const dateValue = new Date(value)\n if (!Number.isNaN(dateValue.getTime()) && value.includes(\"-\")) {\n typeInfo.date += 1\n } else {\n typeInfo.string += 1\n }\n } else {\n typeInfo.string += 1\n }\n }\n\n if (typeInfo.number === values.length) {\n if (typeInfo.integer === values.length) {\n if (typeInfo.bigint > 0) {\n columnTypes[key] = \"BIGINT\"\n } else {\n columnTypes[key] = \"INTEGER\"\n }\n } else {\n columnTypes[key] = \"DOUBLE\"\n }\n } else if (typeInfo.boolean === values.length) {\n columnTypes[key] = \"BOOLEAN\"\n } else if (typeInfo.date === values.length) {\n columnTypes[key] = \"TIMESTAMP\"\n } else {\n columnTypes[key] = \"VARCHAR\"\n }\n }\n\n return columnTypes\n }\n\n /**\n * Format value for SQL insertion.\n * SQL 挿入用に値をフォーマットします。\n */\n private formatValueForSQL(value: unknown): string {\n if (value === null || value === undefined) {\n return \"NULL\"\n }\n if (typeof value === \"string\") {\n return `'${value.replace(/'/g, \"''\")}'`\n }\n if (value instanceof Date) {\n return `'${value.toISOString()}'`\n }\n if (typeof value === \"boolean\") {\n return value ? \"TRUE\" : \"FALSE\"\n }\n if (typeof value === \"number\") {\n if (Number.isInteger(value) && (value < -2147483648 || value > 2147483647)) {\n return String(value)\n }\n return String(value)\n }\n return String(value)\n }\n\n /**\n * Create table from JavaScript array of objects.\n * JavaScript オブジェクトの配列からテーブルを作成します。\n */\n public async createTableFromData<T extends Record<string, unknown>>(\n tableName: string,\n data: T[],\n options: {\n dropIfExists?: boolean\n primaryKey?: string\n verbose?: boolean\n } = {},\n ): Promise<void> {\n if (!data || data.length === 0) {\n throw new Error(\"Data array is empty\")\n }\n\n const operationKey = `create_table_${tableName}`\n const verbose = options.verbose ?? true\n if (this.operationFlags.has(operationKey)) {\n if (verbose) {\n console.log(LOG_PREFIX, `⏳ Table creation for '${tableName}' is already in progress, skipping...`)\n }\n return\n }\n this.operationFlags.set(operationKey, true)\n\n try {\n const connection = await this.getConnection()\n\n if (options.dropIfExists) {\n if (verbose) {\n console.log(LOG_PREFIX, `🗑️ Dropping table '${tableName}' if exists`)\n }\n await connection.query(`DROP TABLE IF EXISTS ${tableName}`)\n }\n\n try {\n const existingTables = await connection.query(\"SHOW TABLES\")\n if (verbose) {\n console.log(LOG_PREFIX, \"📋 Existing tables before creation:\", existingTables)\n }\n } catch (error) {\n if (verbose) {\n console.log(LOG_PREFIX, \"⚠️ Could not list existing tables:\", error)\n }\n }\n\n const sampleSize = Math.min(data.length, 100)\n const columnTypes = this.inferColumnTypes(data.slice(0, sampleSize))\n\n const columns = Object.keys(columnTypes).map((key) => {\n return `\"${key}\" ${columnTypes[key]}`\n })\n\n const primaryKeyClause = options.primaryKey ? `, PRIMARY KEY (\"${options.primaryKey}\")` : \"\"\n\n const createTableSQL = `CREATE TABLE ${tableName} (${columns.join(\", \")}${primaryKeyClause})`\n if (verbose) {\n console.log(LOG_PREFIX, \"🔨 Creating table with SQL:\", createTableSQL)\n }\n await connection.query(createTableSQL)\n\n try {\n const tablesAfterCreation = await connection.query(\"SHOW TABLES\")\n if (verbose) {\n console.log(LOG_PREFIX, \"📋 Tables after creation:\", tablesAfterCreation)\n }\n\n const tableExists = await connection.query(`SELECT COUNT(*) as count FROM information_schema.tables WHERE table_name = '${tableName}'`)\n if (verbose) {\n console.log(LOG_PREFIX, `✅ Table '${tableName}' exists check:`, tableExists)\n }\n } catch (error) {\n if (verbose) {\n console.log(LOG_PREFIX, \"⚠️ Could not verify table creation:\", error)\n }\n }\n\n if (verbose) {\n console.log(LOG_PREFIX, `📥 Inserting ${data.length} rows into table '${tableName}'`)\n }\n const dataColumns = Object.keys(data[0])\n const batchSize = 1000\n\n for (let i = 0; i < data.length; i += batchSize) {\n const batch = data.slice(i, i + batchSize)\n\n try {\n const valueRows = batch.map((row) => {\n const values = dataColumns.map((col) => {\n const value = row[col]\n return this.formatValueForSQL(value)\n })\n return `(${values.join(\", \")})`\n })\n\n const insertSQL = `INSERT INTO ${tableName} (${dataColumns.map((col) => `\"${col}\"`).join(\", \")}) VALUES ${valueRows.join(\", \")}`\n await connection.query(insertSQL)\n if (verbose) {\n console.log(LOG_PREFIX, `📊 Inserted batch ${Math.floor(i / batchSize) + 1} (${batch.length} rows)`)\n }\n } catch (insertError) {\n console.error(LOG_PREFIX, `❌ Failed to insert batch ${Math.floor(i / batchSize) + 1}:`, insertError)\n throw insertError\n }\n }\n\n if (verbose) {\n console.log(LOG_PREFIX, `🎉 Table '${tableName}' created successfully with ${data.length} rows`)\n }\n } catch (error) {\n console.error(LOG_PREFIX, `❌ Failed to create table '${tableName}':`, error)\n throw error\n } finally {\n this.operationFlags.delete(operationKey)\n }\n }\n\n /**\n * Get table information.\n * テーブル情報を取得します。\n */\n public async getTableInfo(tableName: string): Promise<unknown> {\n const connection = await this.getConnection()\n const result = await connection.query(`DESCRIBE ${tableName}`)\n return result\n }\n\n /**\n * List all tables.\n * すべてのテーブルを一覧表示します。\n */\n public async listTables(): Promise<unknown> {\n const connection = await this.getConnection()\n const result = await connection.query(\"SHOW TABLES\")\n return result\n }\n\n /**\n * Check if DuckDB is ready.\n * DuckDB が準備完了かどうかを確認します。\n */\n public isReady(): boolean {\n return this.workerInstance !== null\n }\n\n /**\n * Cleanup DuckDB Worker resources.\n * DuckDB Worker のリソースをクリーンアップします。\n */\n public async cleanup(): Promise<void> {\n try {\n if (this.connectionInstance) {\n await this.connectionInstance.close()\n this.connectionInstance = null\n }\n if (this.workerInstance) {\n await this.workerInstance.terminate()\n this.workerInstance = null\n }\n this.isInitializing = false\n this.hasError = false\n this.initPromise = null\n this.listeners.clear()\n this.operationFlags.clear()\n } catch (error) {\n console.error(LOG_PREFIX, \"⚠️ Error during cleanup:\", error)\n }\n }\n\n /**\n * Reset the service instance (useful for testing).\n * サービスインスタンスをリセットします(テスト用)。\n */\n public static resetInstance(): void {\n if (DuckDBService.instance) {\n DuckDBService.instance.cleanup()\n DuckDBService.instance = null\n }\n }\n}\n\nexport { DuckDBService }\n\nexport default DuckDBService.getInstance()\n","/**\n * DuckDB Helper Functions\n *\n * Utility functions for working with DuckDB query results.\n * DuckDB クエリ結果を扱うためのユーティリティ関数。\n */\n\nimport type { DuckDBQueryResult } from \"../types/duckdb\"\n\n/**\n * Safely convert DuckDB table to typed array\n * DuckDB テーブルを型付き配列に安全に変換します\n *\n * @param result - DuckDB query result\n * @returns Typed array of results\n */\nexport const duckdbTableToArray = <T>(result: unknown): T[] => {\n if (!result || typeof result !== \"object\") {\n return []\n }\n\n if (\"toArray\" in result && typeof result.toArray === \"function\") {\n return (result as DuckDBQueryResult<T>).toArray()\n }\n\n return []\n}\n\n/**\n * Get table row count\n * テーブルの行数を取得します\n *\n * @param result - DuckDB query result\n * @returns Number of rows in the table\n */\nexport const getDuckDBRowCount = (result: unknown): number => {\n if (!result || typeof result !== \"object\") {\n return 0\n }\n\n if (\"numRows\" in result && typeof result.numRows === \"number\") {\n return result.numRows\n }\n\n return 0\n}\n\n/**\n * Get table column count\n * テーブルの列数を取得します\n *\n * @param result - DuckDB query result\n * @returns Number of columns in the table\n */\nexport const getDuckDBColumnCount = (result: unknown): number => {\n if (!result || typeof result !== \"object\") {\n return 0\n }\n\n if (\"numCols\" in result && typeof result.numCols === \"number\") {\n return result.numCols\n }\n\n return 0\n}\n\n/**\n * Check if result is a valid DuckDB table\n * 結果が有効な DuckDB テーブルかどうかをチェックします\n *\n * @param result - DuckDB query result\n * @returns True if result is a valid DuckDB table\n */\nexport const isDuckDBTable = (result: unknown): result is DuckDBQueryResult => {\n if (!result || typeof result !== \"object\") {\n return false\n }\n\n return \"toArray\" in result && typeof result.toArray === \"function\" && \"numRows\" in result && typeof result.numRows === \"number\"\n}\n"],"mappings":"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","names":["index_exports","__export","DuckDBService","duckdb_default","duckdbTableToArray","getDuckDBColumnCount","getDuckDBRowCount","isDuckDBTable","useDuckDB","useDuckDBQuery","__toCommonJS","import_react","duckdb","LOG_PREFIX","_DuckDBService","listener","error","TIMEOUT_MS","timeoutPromise","_","reject","result","JSDELIVR_BUNDLES","bundle","workerUrl","worker","logger","connection","db","sql","operationPromise","queries","results","query","data","columnTypes","sampleData","keys","key","values","row","val","typeInfo","value","dateValue","tableName","options","operationKey","verbose","existingTables","sampleSize","columns","primaryKeyClause","createTableSQL","tablesAfterCreation","tableExists","dataColumns","batchSize","i","batch","valueRows","col","insertSQL","insertError","DuckDBService","duckdb_default","DuckDBService","LOG_PREFIX","useDuckDB","autoInitialize","status","setStatus","error","setError","duckDBService","DuckDBService","updateStatus","serviceStatus","initialize","err","errorMessage","executeQuery","sql","executeQueries","queries","createTableFromData","tableName","data","options","getTableInfo","listTables","pollStatus","currentStatus","interval","useDuckDBQuery","dependencies","isReady","setData","loading","setLoading","refetch","result","duckdbTableToArray","result","getDuckDBRowCount","getDuckDBColumnCount","isDuckDBTable"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{useCallback as m,useEffect as
|
|
1
|
+
import{useCallback as m,useEffect as I,useState as D}from"react";import*as k from"@duckdb/duckdb-wasm";var r="[duckdb-helper]",y=class y{constructor(){this.operationFlags=new Map;this.workerInstance=null;this.connectionInstance=null;this.isInitializing=!1;this.initPromise=null;this.hasError=!1;this.listeners=new Set}static getInstance(){return y.instance||(y.instance=new y),y.instance}addStatusListener(e){this.listeners.add(e)}removeStatusListener(e){this.listeners.delete(e)}notifyListeners(){for(let e of this.listeners)try{e()}catch(t){console.error(r,"\u26A0\uFE0F Error in status listener:",t)}}getStatus(){return this.hasError?"error":this.isInitializing?"initializing":this.workerInstance?"ready":"not-initialized"}async initialize(){if(this.workerInstance)return this.workerInstance;if(this.isInitializing&&this.initPromise)return this.initPromise;this.isInitializing=!0,this.hasError=!1,this.notifyListeners();let e=12e4,t=new Promise((s,l)=>{setTimeout(()=>l(new Error(`DuckDB initialization timed out after ${e}ms`)),e)});this.initPromise=(async()=>await Promise.race([this.internalInitializeWorker(),t]))();try{let s=await this.initPromise;return this.isInitializing=!1,this.notifyListeners(),s}catch(s){throw this.isInitializing=!1,this.hasError=!0,this.notifyListeners(),this.initPromise=null,s}}async internalInitializeWorker(){try{console.log(r,"\u{1F527} Starting DuckDB Worker initialization..."),console.log(r,"\u{1F4E6} Getting DuckDB bundles from CDN...");let e=k.getJsDelivrBundles();console.log(r,"\u{1F50D} Selecting appropriate bundle for browser...");let t=await k.selectBundle(e);console.log(r,"\u2705 Bundle selected:",{mainWorker:t.mainWorker,mainModule:t.mainModule,pthreadWorker:t.pthreadWorker}),console.log(r,"\u{1F680} Creating Worker with Blob URL...");let s=URL.createObjectURL(new Blob([`importScripts("${t.mainWorker}");`],{type:"text/javascript"}));console.log(r,"\u{1F477} Creating Worker instance...");let l=new Worker(s),n=new k.ConsoleLogger;console.log(r,"\u{1F5C4}\uFE0F Creating DuckDB instance..."),this.workerInstance=new k.AsyncDuckDB(n,l),console.log(r,"\u26A1 Instantiating DuckDB with modules..."),await this.workerInstance.instantiate(t.mainModule,t.pthreadWorker),console.log(r,"\u{1F4E6} Installing splink_udfs from community...");let o=await this.workerInstance.connect();try{await o.query("INSTALL splink_udfs FROM community;"),console.log(r,"\u2705 splink_udfs installed successfully"),await o.query("LOAD splink_udfs;"),console.log(r,"\u2705 splink_udfs loaded successfully")}catch(c){console.warn(r,"\u26A0\uFE0F Failed to install/load splink_udfs:",c)}finally{await o.close()}return URL.revokeObjectURL(s),console.log(r,"\u2705 DuckDB Worker initialized successfully"),this.workerInstance}catch(e){throw console.error(r,"\u274C Failed to initialize DuckDB Worker:",e),e instanceof Error&&(console.error(r,"\u274C Error name:",e.name),console.error(r,"\u274C Error message:",e.message),console.error(r,"\u274C Error stack:",e.stack)),e}}async getConnection(){if(!this.connectionInstance){let e=await this.initialize();this.connectionInstance=await e.connect()}return this.connectionInstance}async executeQuery(e){let s=new Promise((l,n)=>{setTimeout(()=>n(new Error("DuckDB query execution timed out after 60000ms")),6e4)});try{let l=(async()=>await(await this.getConnection()).query(e))();return await Promise.race([l,s])}catch(l){throw console.error(r,"\u274C Failed to execute SQL query:",l),l}}async executeQueries(e){let t=[];for(let s of e){let l=await this.executeQuery(s);t.push(l)}return t}inferColumnTypes(e){let t={},s=e.slice(0,Math.min(e.length,10)),l=Object.keys(s[0]||{});for(let n of l){let o=s.map(f=>f[n]).filter(f=>f!=null);if(o.length===0){t[n]="VARCHAR";continue}let c={number:0,integer:0,bigint:0,boolean:0,date:0,string:0};for(let f of o)if(typeof f=="number")c.number+=1,Number.isInteger(f)&&(c.integer+=1,(f<-2147483648||f>2147483647)&&(c.bigint+=1));else if(typeof f=="boolean")c.boolean+=1;else if(f instanceof Date)c.date+=1;else if(typeof f=="string"){let p=new Date(f);!Number.isNaN(p.getTime())&&f.includes("-")?c.date+=1:c.string+=1}else c.string+=1;c.number===o.length?c.integer===o.length?c.bigint>0?t[n]="BIGINT":t[n]="INTEGER":t[n]="DOUBLE":c.boolean===o.length?t[n]="BOOLEAN":c.date===o.length?t[n]="TIMESTAMP":t[n]="VARCHAR"}return t}formatValueForSQL(e){return e==null?"NULL":typeof e=="string"?`'${e.replace(/'/g,"''")}'`:e instanceof Date?`'${e.toISOString()}'`:typeof e=="boolean"?e?"TRUE":"FALSE":(typeof e=="number"&&Number.isInteger(e)&&(e<-2147483648||e>2147483647),String(e))}async createTableFromData(e,t,s={}){if(!t||t.length===0)throw new Error("Data array is empty");let l=`create_table_${e}`,n=s.verbose??!0;if(this.operationFlags.has(l)){n&&console.log(r,`\u23F3 Table creation for '${e}' is already in progress, skipping...`);return}this.operationFlags.set(l,!0);try{let o=await this.getConnection();s.dropIfExists&&(n&&console.log(r,`\u{1F5D1}\uFE0F Dropping table '${e}' if exists`),await o.query(`DROP TABLE IF EXISTS ${e}`));try{let u=await o.query("SHOW TABLES");n&&console.log(r,"\u{1F4CB} Existing tables before creation:",u)}catch(u){n&&console.log(r,"\u26A0\uFE0F Could not list existing tables:",u)}let c=Math.min(t.length,100),f=this.inferColumnTypes(t.slice(0,c)),p=Object.keys(f).map(u=>`"${u}" ${f[u]}`),w=s.primaryKey?`, PRIMARY KEY ("${s.primaryKey}")`:"",g=`CREATE TABLE ${e} (${p.join(", ")}${w})`;n&&console.log(r,"\u{1F528} Creating table with SQL:",g),await o.query(g);try{let u=await o.query("SHOW TABLES");n&&console.log(r,"\u{1F4CB} Tables after creation:",u);let d=await o.query(`SELECT COUNT(*) as count FROM information_schema.tables WHERE table_name = '${e}'`);n&&console.log(r,`\u2705 Table '${e}' exists check:`,d)}catch(u){n&&console.log(r,"\u26A0\uFE0F Could not verify table creation:",u)}n&&console.log(r,`\u{1F4E5} Inserting ${t.length} rows into table '${e}'`);let h=Object.keys(t[0]),a=1e3;for(let u=0;u<t.length;u+=a){let d=t.slice(u,u+a);try{let T=d.map(E=>`(${h.map(P=>{let L=E[P];return this.formatValueForSQL(L)}).join(", ")})`),R=`INSERT INTO ${e} (${h.map(E=>`"${E}"`).join(", ")}) VALUES ${T.join(", ")}`;await o.query(R),n&&console.log(r,`\u{1F4CA} Inserted batch ${Math.floor(u/a)+1} (${d.length} rows)`)}catch(T){throw console.error(r,`\u274C Failed to insert batch ${Math.floor(u/a)+1}:`,T),T}}n&&console.log(r,`\u{1F389} Table '${e}' created successfully with ${t.length} rows`)}catch(o){throw console.error(r,`\u274C Failed to create table '${e}':`,o),o}finally{this.operationFlags.delete(l)}}async getTableInfo(e){return await(await this.getConnection()).query(`DESCRIBE ${e}`)}async listTables(){return await(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.isInitializing=!1,this.hasError=!1,this.initPromise=null,this.listeners.clear(),this.operationFlags.clear()}catch(e){console.error(r,"\u26A0\uFE0F Error during cleanup:",e)}}static resetInstance(){y.instance&&(y.instance.cleanup(),y.instance=null)}};y.instance=null;var b=y;var x=b.getInstance();var B="[duckdb-helper]",S=(i=!0)=>{let[e,t]=D("not-initialized"),[s,l]=D(null),[n]=D(()=>b.getInstance()),o=m(()=>{let a=n.getStatus();console.info(B,"\u{1F504} DuckDB status updated:",a),t(a),a==="error"?l("DuckDB initialization failed"):a==="ready"&&l(null)},[n]);I(()=>(n.addStatusListener(o),o(),()=>{n.removeStatusListener(o)}),[n,o]);let c=m(async()=>{try{await n.initialize()}catch(a){let u=a instanceof Error?a.message:"Unknown error occurred";l(u),console.error(B,"\u274C DuckDB initialization failed:",a)}},[n]);I(()=>{i&&e==="not-initialized"&&(console.info(B,"\u{1F680} Auto-initializing DuckDB..."),c())},[i,e,c]);let f=m(async a=>{if(e!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return n.executeQuery(a)},[n,e]),p=m(async a=>{if(e!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return n.executeQueries(a)},[n,e]),w=m(async(a,u,d)=>{if(e!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return n.createTableFromData(a,u,d)},[n,e]),g=m(async a=>{if(e!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return n.getTableInfo(a)},[n,e]),h=m(async()=>{if(e!=="ready")throw new Error("DuckDB is not ready. Please wait for initialization to complete.");return n.listTables()},[n,e]);return I(()=>{let a=()=>{let d=n.getStatus();d!==e&&d!=="initializing"&&t(d)};if(typeof window>"u"){a();return}let u=window.setInterval(a,1e3);return a(),()=>window.clearInterval(u)},[n,e]),{status:e,error:s,executeQuery:f,executeQueries:p,createTableFromData:w,getTableInfo:g,listTables:h,isReady:e==="ready",initialize:c}},v=(i,e=[])=>{let{executeQuery:t,isReady:s}=S(),[l,n]=D(null),[o,c]=D(!1),[f,p]=D(null),w=m(async()=>{if(s&&i.trim())try{c(!0),p(null);let g=await t(i);n(g)}catch(g){let h=g instanceof Error?g.message:"Query execution failed";p(h),n(null)}finally{c(!1)}},[t,s,i]);return I(()=>{w()},[w,...e]),{data:l,loading:o,error:f,refetch:w}};var z=i=>!i||typeof i!="object"?[]:"toArray"in i&&typeof i.toArray=="function"?i.toArray():[],C=i=>!i||typeof i!="object"?0:"numRows"in i&&typeof i.numRows=="number"?i.numRows:0,A=i=>!i||typeof i!="object"?0:"numCols"in i&&typeof i.numCols=="number"?i.numCols:0,$=i=>!i||typeof i!="object"?!1:"toArray"in i&&typeof i.toArray=="function"&&"numRows"in i&&typeof i.numRows=="number";export{b as DuckDBService,x as duckDBService,z as duckdbTableToArray,A as getDuckDBColumnCount,C as getDuckDBRowCount,$ as isDuckDBTable,S as useDuckDB,v as useDuckDBQuery};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useDuckDB.ts","../src/services/duckdb.ts","../src/utils/duckdb-helpers.ts"],"sourcesContent":["/**\n * DuckDB React Hook\n *\n * React hook for using DuckDB functionality in components.\n * コンポーネントで DuckDB 機能を使用するための React フック。\n */\n\nimport { type DependencyList, useCallback, useEffect, useState } from 'react'\nimport { DuckDBService } from '../services/duckdb'\n\nexport interface UseDuckDBResult {\n status: 'not-initialized' | 'initializing' | 'ready' | 'error'\n error: string | null\n executeQuery: (sql: string) => Promise<unknown>\n executeQueries: (queries: string[]) => Promise<unknown[]>\n createTableFromData: <T extends Record<string, unknown>>(\n tableName: string,\n data: T[],\n options?: {\n dropIfExists?: boolean\n primaryKey?: string\n }\n ) => Promise<void>\n getTableInfo: (tableName: string) => Promise<unknown>\n listTables: () => Promise<unknown>\n isReady: boolean\n initialize: () => Promise<void>\n}\n\n/**\n * DuckDB functionality hook.\n * DuckDB 機能を提供するフック。\n *\n * @param autoInitialize - 自動初期化を行うかどうか\n * @returns DuckDB の状態と操作関数\n */\nexport const useDuckDB = (autoInitialize = true): UseDuckDBResult => {\n const [status, setStatus] = useState<'not-initialized' | 'initializing' | 'ready' | 'error'>('not-initialized')\n const [error, setError] = useState<string | null>(null)\n const [duckDBService] = useState(() => DuckDBService.getInstance())\n\n const updateStatus = useCallback(() => {\n const serviceStatus = duckDBService.getStatus()\n console.info('🔄 DuckDB status updated:', serviceStatus)\n setStatus(serviceStatus)\n\n if (serviceStatus === 'error') {\n setError('DuckDB initialization failed')\n } else if (serviceStatus === 'ready') {\n setError(null)\n }\n }, [duckDBService])\n\n useEffect(() => {\n duckDBService.addStatusListener(updateStatus)\n updateStatus()\n\n return () => {\n duckDBService.removeStatusListener(updateStatus)\n }\n }, [duckDBService, updateStatus])\n\n const initialize = useCallback(async () => {\n try {\n await duckDBService.initialize()\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred'\n setError(errorMessage)\n console.error('DuckDB initialization failed:', err)\n }\n }, [duckDBService])\n\n useEffect(() => {\n if (autoInitialize && status === 'not-initialized') {\n console.info('🚀 Auto-initializing DuckDB...')\n void initialize()\n }\n }, [autoInitialize, status, initialize])\n\n const executeQuery = useCallback(async (sql: string): Promise<unknown> => {\n if (status !== 'ready') {\n throw new Error('DuckDB is not ready. Please wait for initialization to complete.')\n }\n return duckDBService.executeQuery(sql)\n }, [duckDBService, status])\n\n const executeQueries = useCallback(async (queries: string[]): Promise<unknown[]> => {\n if (status !== 'ready') {\n throw new Error('DuckDB is not ready. Please wait for initialization to complete.')\n }\n return duckDBService.executeQueries(queries)\n }, [duckDBService, status])\n\n const createTableFromData = useCallback(async <T extends Record<string, unknown>>(\n tableName: string,\n data: T[],\n options?: {\n dropIfExists?: boolean\n primaryKey?: string\n }\n ): Promise<void> => {\n if (status !== 'ready') {\n throw new Error('DuckDB is not ready. Please wait for initialization to complete.')\n }\n return duckDBService.createTableFromData(tableName, data, options)\n }, [duckDBService, status])\n\n const getTableInfo = useCallback(async (tableName: string): Promise<unknown> => {\n if (status !== 'ready') {\n throw new Error('DuckDB is not ready. Please wait for initialization to complete.')\n }\n return duckDBService.getTableInfo(tableName)\n }, [duckDBService, status])\n\n const listTables = useCallback(async (): Promise<unknown> => {\n if (status !== 'ready') {\n throw new Error('DuckDB is not ready. Please wait for initialization to complete.')\n }\n return duckDBService.listTables()\n }, [duckDBService, status])\n\n useEffect(() => {\n const pollStatus = () => {\n const currentStatus = duckDBService.getStatus()\n if (currentStatus !== status && currentStatus !== 'initializing') {\n setStatus(currentStatus)\n }\n }\n\n if (typeof window === 'undefined') {\n pollStatus()\n return\n }\n\n const interval = window.setInterval(pollStatus, 1000)\n pollStatus()\n\n return () => window.clearInterval(interval)\n }, [duckDBService, status])\n\n return {\n status,\n error,\n executeQuery,\n executeQueries,\n createTableFromData,\n getTableInfo,\n listTables,\n isReady: status === 'ready',\n initialize\n }\n}\n\n/**\n * Hook for simple DuckDB query execution.\n * シンプルな DuckDB クエリ実行のためのフック。\n *\n * @param sql - 実行する SQL クエリ\n * @param dependencies - クエリを再実行するための依存配列\n * @returns クエリ結果と状態\n */\nexport const useDuckDBQuery = <T = unknown>(\n sql: string,\n dependencies: DependencyList = []\n): {\n data: T | null\n loading: boolean\n error: string | null\n refetch: () => Promise<void>\n} => {\n const { executeQuery, isReady } = useDuckDB()\n const [data, setData] = useState<T | null>(null)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const refetch = useCallback(async () => {\n if (!(isReady && sql.trim())) {\n return\n }\n\n try {\n setLoading(true)\n setError(null)\n const result = await executeQuery(sql)\n setData(result as T)\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Query execution failed'\n setError(errorMessage)\n setData(null)\n } finally {\n setLoading(false)\n }\n }, [executeQuery, isReady, sql])\n\n useEffect(() => {\n void refetch()\n }, [refetch, ...dependencies])\n\n return {\n data,\n loading,\n error,\n refetch\n }\n}\n","/**\n * DuckDB Web Worker Service\n *\n * Provides reusable DuckDB-wasm functionality across the application.\n * アプリケーション全体で再利用可能な DuckDB-wasm 機能を提供します。\n */\n\nimport * as duckdb from '@duckdb/duckdb-wasm'\n\n/**\n * DuckDB service for browser-based SQL operations.\n * ブラウザベースの SQL 操作のための DuckDB サービス。\n */\nclass DuckDBService {\n private static instance: DuckDBService | null = null\n private operationFlags: Map<string, boolean> = new Map()\n\n private workerInstance: duckdb.AsyncDuckDB | null = null\n private connectionInstance: duckdb.AsyncDuckDBConnection | null = null\n private isInitializing = false\n private initPromise: Promise<duckdb.AsyncDuckDB> | null = null\n private hasError = false\n\n private listeners: Set<() => void> = new Set()\n\n /**\n * Get singleton instance of DuckDBService.\n * DuckDBService のシングルトンインスタンスを取得します。\n */\n public static getInstance(): DuckDBService {\n if (!DuckDBService.instance) {\n DuckDBService.instance = new DuckDBService()\n }\n return DuckDBService.instance\n }\n\n /**\n * Add status change listener.\n * 状態変更リスナーを追加します。\n */\n public addStatusListener(listener: () => void): void {\n this.listeners.add(listener)\n }\n\n /**\n * Remove status change listener.\n * 状態変更リスナーを削除します。\n */\n public removeStatusListener(listener: () => void): void {\n this.listeners.delete(listener)\n }\n\n /**\n * Notify all listeners of status change.\n * すべてのリスナーに状態変更を通知します。\n */\n private notifyListeners(): void {\n for (const listener of this.listeners) {\n try {\n listener()\n } catch (error) {\n console.error('Error in status listener:', error)\n }\n }\n }\n\n /**\n * Get current status.\n * 現在のステータスを取得します。\n */\n public getStatus(): 'not-initialized' | 'initializing' | 'ready' | 'error' {\n if (this.hasError) {\n return 'error'\n }\n if (this.isInitializing) {\n return 'initializing'\n }\n if (this.workerInstance) {\n return 'ready'\n }\n return 'not-initialized'\n }\n\n /**\n * Initialize DuckDB Worker instance.\n * DuckDB Worker インスタンスを初期化します。\n */\n public async initialize(): Promise<duckdb.AsyncDuckDB> {\n if (this.workerInstance) {\n return this.workerInstance\n }\n\n if (this.isInitializing && this.initPromise) {\n return this.initPromise\n }\n\n this.isInitializing = true\n this.hasError = false\n this.notifyListeners()\n this.initPromise = this.internalInitializeWorker()\n\n try {\n const result = await this.initPromise\n this.isInitializing = false\n this.notifyListeners()\n return result\n } catch (error) {\n this.isInitializing = false\n this.hasError = true\n this.notifyListeners()\n this.initPromise = null\n throw error\n }\n }\n\n /**\n * Internal worker initialization method.\n * 内部的な Worker 初期化メソッド。\n */\n private async internalInitializeWorker(): Promise<duckdb.AsyncDuckDB> {\n try {\n console.log('🔧 Starting DuckDB Worker initialization...')\n console.log('📦 Getting DuckDB bundles from CDN...')\n const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles()\n\n console.log('🔍 Selecting appropriate bundle for browser...')\n const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES)\n console.log('✅ Bundle selected:', {\n mainWorker: bundle.mainWorker,\n mainModule: bundle.mainModule,\n pthreadWorker: bundle.pthreadWorker\n })\n\n console.log('🚀 Creating Worker with Blob URL...')\n const workerUrl = URL.createObjectURL(\n new Blob([`importScripts(\"${bundle.mainWorker}\");`], { type: 'text/javascript' })\n )\n\n console.log('👷 Creating Worker instance...')\n const worker = new Worker(workerUrl)\n const logger = new duckdb.ConsoleLogger()\n\n console.log('🗄️ Creating DuckDB instance...')\n this.workerInstance = new duckdb.AsyncDuckDB(logger, worker)\n\n console.log('⚡ Instantiating DuckDB with modules...')\n await this.workerInstance.instantiate(bundle.mainModule, bundle.pthreadWorker)\n\n console.log('📦 Installing splink_udfs from community...')\n const connection = await this.workerInstance.connect()\n try {\n await connection.query('INSTALL splink_udfs FROM community;')\n console.log('✅ splink_udfs installed successfully')\n\n await connection.query('LOAD splink_udfs;')\n console.log('✅ splink_udfs loaded successfully')\n } catch (error) {\n console.warn('⚠️ Failed to install/load splink_udfs:', error)\n } finally {\n await connection.close()\n }\n\n URL.revokeObjectURL(workerUrl)\n\n console.log('✅ DuckDB Worker initialized successfully')\n return this.workerInstance\n } catch (error) {\n console.error('❌ Failed to initialize DuckDB Worker:', error)\n\n if (error instanceof Error) {\n console.error('Error name:', error.name)\n console.error('Error message:', error.message)\n console.error('Error stack:', error.stack)\n }\n\n throw error\n }\n }\n\n /**\n * Get or create DuckDB connection.\n * DuckDB 接続を取得または作成します。\n */\n public async getConnection(): Promise<duckdb.AsyncDuckDBConnection> {\n if (!this.connectionInstance) {\n const db = await this.initialize()\n this.connectionInstance = await db.connect()\n }\n return this.connectionInstance\n }\n\n /**\n * Execute SQL query using DuckDB Worker.\n * DuckDB Worker を使用して SQL クエリを実行します。\n */\n public async executeQuery(sql: string): Promise<unknown> {\n try {\n const connection = await this.getConnection()\n const result = await connection.query(sql)\n return result\n } catch (error) {\n console.error('Failed to execute SQL query:', error)\n throw error\n }\n }\n\n /**\n * Execute multiple SQL queries.\n * 複数の SQL クエリを実行します。\n */\n public async executeQueries(queries: string[]): Promise<unknown[]> {\n const results: unknown[] = []\n for (const query of queries) {\n const result = await this.executeQuery(query)\n results.push(result)\n }\n return results\n }\n\n /**\n * Infer column types from data sample.\n * データサンプルから列の型を推定します。\n */\n private inferColumnTypes(data: Record<string, unknown>[]): Record<string, string> {\n const columnTypes: Record<string, string> = {}\n const sampleData = data.slice(0, Math.min(data.length, 10))\n\n const keys = Object.keys(sampleData[0] || {})\n for (const key of keys) {\n const values = sampleData.map(row => row[key]).filter(val => val !== null && val !== undefined)\n\n if (values.length === 0) {\n columnTypes[key] = 'VARCHAR'\n continue\n }\n\n const typeInfo = {\n number: 0,\n integer: 0,\n bigint: 0,\n boolean: 0,\n date: 0,\n string: 0\n }\n\n for (const value of values) {\n if (typeof value === 'number') {\n typeInfo.number += 1\n if (Number.isInteger(value)) {\n typeInfo.integer += 1\n if (value < -2147483648 || value > 2147483647) {\n typeInfo.bigint += 1\n }\n }\n } else if (typeof value === 'boolean') {\n typeInfo.boolean += 1\n } else if (value instanceof Date) {\n typeInfo.date += 1\n } else if (typeof value === 'string') {\n const dateValue = new Date(value)\n if (!Number.isNaN(dateValue.getTime()) && value.includes('-')) {\n typeInfo.date += 1\n } else {\n typeInfo.string += 1\n }\n } else {\n typeInfo.string += 1\n }\n }\n\n if (typeInfo.number === values.length) {\n if (typeInfo.integer === values.length) {\n if (typeInfo.bigint > 0) {\n columnTypes[key] = 'BIGINT'\n } else {\n columnTypes[key] = 'INTEGER'\n }\n } else {\n columnTypes[key] = 'DOUBLE'\n }\n } else if (typeInfo.boolean === values.length) {\n columnTypes[key] = 'BOOLEAN'\n } else if (typeInfo.date === values.length) {\n columnTypes[key] = 'TIMESTAMP'\n } else {\n columnTypes[key] = 'VARCHAR'\n }\n }\n\n return columnTypes\n }\n\n /**\n * Format value for SQL insertion.\n * SQL 挿入用に値をフォーマットします。\n */\n private formatValueForSQL(value: unknown): string {\n if (value === null || value === undefined) {\n return 'NULL'\n }\n if (typeof value === 'string') {\n return `'${value.replace(/'/g, \"''\")}'`\n }\n if (value instanceof Date) {\n return `'${value.toISOString()}'`\n }\n if (typeof value === 'boolean') {\n return value ? 'TRUE' : 'FALSE'\n }\n if (typeof value === 'number') {\n if (Number.isInteger(value) && (value < -2147483648 || value > 2147483647)) {\n return String(value)\n }\n return String(value)\n }\n return String(value)\n }\n\n /**\n * Create table from JavaScript array of objects.\n * JavaScript オブジェクトの配列からテーブルを作成します。\n */\n public async createTableFromData<T extends Record<string, unknown>>(\n tableName: string,\n data: T[],\n options: {\n dropIfExists?: boolean\n primaryKey?: string\n } = {}\n ): Promise<void> {\n if (!data || data.length === 0) {\n throw new Error('Data array is empty')\n }\n\n const operationKey = `create_table_${tableName}`\n if (this.operationFlags.has(operationKey)) {\n console.log(`⏳ Table creation for '${tableName}' is already in progress, skipping...`)\n return\n }\n this.operationFlags.set(operationKey, true)\n\n try {\n const connection = await this.getConnection()\n\n if (options.dropIfExists) {\n console.log(`🗑️ Dropping table '${tableName}' if exists`)\n await connection.query(`DROP TABLE IF EXISTS ${tableName}`)\n }\n\n try {\n const existingTables = await connection.query('SHOW TABLES')\n console.log('📋 Existing tables before creation:', existingTables)\n } catch (error) {\n console.log('⚠️ Could not list existing tables:', error)\n }\n\n const sampleSize = Math.min(data.length, 100)\n const columnTypes = this.inferColumnTypes(data.slice(0, sampleSize))\n\n const columns = Object.keys(columnTypes).map(key => {\n return `\"${key}\" ${columnTypes[key]}`\n })\n\n const primaryKeyClause = options.primaryKey ? `, PRIMARY KEY (\"${options.primaryKey}\")` : ''\n\n const createTableSQL = `CREATE TABLE ${tableName} (${columns.join(', ')}${primaryKeyClause})`\n console.log('🔨 Creating table with SQL:', createTableSQL)\n await connection.query(createTableSQL)\n\n try {\n const tablesAfterCreation = await connection.query('SHOW TABLES')\n console.log('📋 Tables after creation:', tablesAfterCreation)\n\n const tableExists = await connection.query(`SELECT COUNT(*) as count FROM information_schema.tables WHERE table_name = '${tableName}'`)\n console.log(`✅ Table '${tableName}' exists check:`, tableExists)\n } catch (error) {\n console.log('⚠️ Could not verify table creation:', error)\n }\n\n console.log(`📥 Inserting ${data.length} rows into table '${tableName}'`)\n const dataColumns = Object.keys(data[0])\n const batchSize = 1000\n\n for (let i = 0; i < data.length; i += batchSize) {\n const batch = data.slice(i, i + batchSize)\n\n try {\n const valueRows = batch.map(row => {\n const values = dataColumns.map(col => {\n const value = row[col]\n return this.formatValueForSQL(value)\n })\n return `(${values.join(', ')})`\n })\n\n const insertSQL = `INSERT INTO ${tableName} (${dataColumns.map(col => `\"${col}\"`).join(', ')}) VALUES ${valueRows.join(', ')}`\n await connection.query(insertSQL)\n console.log(`📊 Inserted batch ${Math.floor(i / batchSize) + 1} (${batch.length} rows)`)\n } catch (insertError) {\n console.error(`❌ Failed to insert batch ${Math.floor(i / batchSize) + 1}:`, insertError)\n throw insertError\n }\n }\n\n console.log(`🎉 Table '${tableName}' created successfully with ${data.length} rows`)\n } catch (error) {\n console.error(`❌ Failed to create table '${tableName}':`, error)\n throw error\n } finally {\n this.operationFlags.delete(operationKey)\n }\n }\n\n /**\n * Get table information.\n * テーブル情報を取得します。\n */\n public async getTableInfo(tableName: string): Promise<unknown> {\n const connection = await this.getConnection()\n const result = await connection.query(`DESCRIBE ${tableName}`)\n return result\n }\n\n /**\n * List all tables.\n * すべてのテーブルを一覧表示します。\n */\n public async listTables(): Promise<unknown> {\n const connection = await this.getConnection()\n const result = await connection.query('SHOW TABLES')\n return result\n }\n\n /**\n * Check if DuckDB is ready.\n * DuckDB が準備完了かどうかを確認します。\n */\n public isReady(): boolean {\n return this.workerInstance !== null\n }\n\n /**\n * Cleanup DuckDB Worker resources.\n * DuckDB Worker のリソースをクリーンアップします。\n */\n public async cleanup(): Promise<void> {\n try {\n if (this.connectionInstance) {\n await this.connectionInstance.close()\n this.connectionInstance = null\n }\n if (this.workerInstance) {\n await this.workerInstance.terminate()\n this.workerInstance = null\n }\n this.isInitializing = false\n this.hasError = false\n this.initPromise = null\n this.listeners.clear()\n this.operationFlags.clear()\n } catch (error) {\n console.error('Error during cleanup:', error)\n }\n }\n\n /**\n * Reset the service instance (useful for testing).\n * サービスインスタンスをリセットします(テスト用)。\n */\n public static resetInstance(): void {\n if (DuckDBService.instance) {\n DuckDBService.instance.cleanup()\n DuckDBService.instance = null\n }\n }\n}\n\nexport { DuckDBService }\n\nexport default DuckDBService.getInstance()\n","/**\n * DuckDB Helper Functions\n *\n * Utility functions for working with DuckDB query results.\n * DuckDB クエリ結果を扱うためのユーティリティ関数。\n */\n\nimport type { DuckDBQueryResult } from '../types/duckdb'\n\n/**\n * Safely convert DuckDB table to typed array\n * DuckDB テーブルを型付き配列に安全に変換します\n *\n * @param result - DuckDB query result\n * @returns Typed array of results\n */\nexport const duckdbTableToArray = <T>(result: unknown): T[] => {\n if (!result || typeof result !== 'object') {\n return []\n }\n\n if ('toArray' in result && typeof result.toArray === 'function') {\n return (result as DuckDBQueryResult<T>).toArray()\n }\n\n return []\n}\n\n/**\n * Get table row count\n * テーブルの行数を取得します\n *\n * @param result - DuckDB query result\n * @returns Number of rows in the table\n */\nexport const getDuckDBRowCount = (result: unknown): number => {\n if (!result || typeof result !== 'object') {\n return 0\n }\n\n if ('numRows' in result && typeof result.numRows === 'number') {\n return result.numRows\n }\n\n return 0\n}\n\n/**\n * Get table column count\n * テーブルの列数を取得します\n *\n * @param result - DuckDB query result\n * @returns Number of columns in the table\n */\nexport const getDuckDBColumnCount = (result: unknown): number => {\n if (!result || typeof result !== 'object') {\n return 0\n }\n\n if ('numCols' in result && typeof result.numCols === 'number') {\n return result.numCols\n }\n\n return 0\n}\n\n/**\n * Check if result is a valid DuckDB table\n * 結果が有効な DuckDB テーブルかどうかをチェックします\n *\n * @param result - DuckDB query result\n * @returns True if result is a valid DuckDB table\n */\nexport const isDuckDBTable = (result: unknown): result is DuckDBQueryResult => {\n if (!result || typeof result !== 'object') {\n return false\n }\n\n return (\n 'toArray' in result &&\n typeof result.toArray === 'function' &&\n 'numRows' in result &&\n typeof result.numRows === 'number'\n )\n}\n"],"mappings":"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","names":["useCallback","useEffect","useState","duckdb","_DuckDBService","listener","error","result","JSDELIVR_BUNDLES","bundle","workerUrl","worker","logger","connection","db","sql","queries","results","query","data","columnTypes","sampleData","keys","key","values","row","val","typeInfo","value","dateValue","tableName","options","operationKey","existingTables","sampleSize","columns","primaryKeyClause","createTableSQL","tablesAfterCreation","tableExists","dataColumns","batchSize","i","batch","valueRows","col","insertSQL","insertError","DuckDBService","duckdb_default","DuckDBService","useDuckDB","autoInitialize","status","setStatus","useState","error","setError","duckDBService","DuckDBService","updateStatus","useCallback","serviceStatus","useEffect","initialize","err","errorMessage","executeQuery","sql","executeQueries","queries","createTableFromData","tableName","data","options","getTableInfo","listTables","pollStatus","currentStatus","interval","useDuckDBQuery","dependencies","isReady","setData","loading","setLoading","refetch","result","duckdbTableToArray","result","getDuckDBRowCount","getDuckDBColumnCount","isDuckDBTable"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useDuckDB.ts","../src/services/duckdb.ts","../src/utils/duckdb-helpers.ts"],"sourcesContent":["/**\n * DuckDB React Hook\n *\n * React hook for using DuckDB functionality in components.\n * コンポーネントで DuckDB 機能を使用するための React フック。\n */\n\nimport { type DependencyList, useCallback, useEffect, useState } from \"react\"\nimport { DuckDBService } from \"../services/duckdb\"\n\nconst LOG_PREFIX = \"[duckdb-helper]\"\n\nexport interface UseDuckDBResult {\n status: \"not-initialized\" | \"initializing\" | \"ready\" | \"error\"\n error: string | null\n executeQuery: (sql: string) => Promise<unknown>\n executeQueries: (queries: string[]) => Promise<unknown[]>\n createTableFromData: <T extends Record<string, unknown>>(\n tableName: string,\n data: T[],\n options?: {\n dropIfExists?: boolean\n primaryKey?: string\n verbose?: boolean\n },\n ) => Promise<void>\n getTableInfo: (tableName: string) => Promise<unknown>\n listTables: () => Promise<unknown>\n isReady: boolean\n initialize: () => Promise<void>\n}\n\n/**\n * DuckDB functionality hook.\n * DuckDB 機能を提供するフック。\n *\n * @param autoInitialize - 自動初期化を行うかどうか\n * @returns DuckDB の状態と操作関数\n */\nexport const useDuckDB = (autoInitialize = true): UseDuckDBResult => {\n const [status, setStatus] = useState<\"not-initialized\" | \"initializing\" | \"ready\" | \"error\">(\"not-initialized\")\n const [error, setError] = useState<string | null>(null)\n const [duckDBService] = useState(() => DuckDBService.getInstance())\n\n const updateStatus = useCallback(() => {\n const serviceStatus = duckDBService.getStatus()\n console.info(LOG_PREFIX, \"🔄 DuckDB status updated:\", serviceStatus)\n setStatus(serviceStatus)\n\n if (serviceStatus === \"error\") {\n setError(\"DuckDB initialization failed\")\n } else if (serviceStatus === \"ready\") {\n setError(null)\n }\n }, [duckDBService])\n\n useEffect(() => {\n duckDBService.addStatusListener(updateStatus)\n updateStatus()\n\n return () => {\n duckDBService.removeStatusListener(updateStatus)\n }\n }, [duckDBService, updateStatus])\n\n const initialize = useCallback(async () => {\n try {\n await duckDBService.initialize()\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : \"Unknown error occurred\"\n setError(errorMessage)\n console.error(LOG_PREFIX, \"❌ DuckDB initialization failed:\", err)\n }\n }, [duckDBService])\n\n useEffect(() => {\n if (autoInitialize && status === \"not-initialized\") {\n console.info(LOG_PREFIX, \"🚀 Auto-initializing DuckDB...\")\n void initialize()\n }\n }, [autoInitialize, status, initialize])\n\n const executeQuery = useCallback(\n async (sql: string): Promise<unknown> => {\n if (status !== \"ready\") {\n throw new Error(\"DuckDB is not ready. Please wait for initialization to complete.\")\n }\n return duckDBService.executeQuery(sql)\n },\n [duckDBService, status],\n )\n\n const executeQueries = useCallback(\n async (queries: string[]): Promise<unknown[]> => {\n if (status !== \"ready\") {\n throw new Error(\"DuckDB is not ready. Please wait for initialization to complete.\")\n }\n return duckDBService.executeQueries(queries)\n },\n [duckDBService, status],\n )\n\n const createTableFromData = useCallback(\n async <T extends Record<string, unknown>>(\n tableName: string,\n data: T[],\n options?: {\n dropIfExists?: boolean\n primaryKey?: string\n verbose?: boolean\n },\n ): Promise<void> => {\n if (status !== \"ready\") {\n throw new Error(\"DuckDB is not ready. Please wait for initialization to complete.\")\n }\n return duckDBService.createTableFromData(tableName, data, options)\n },\n [duckDBService, status],\n )\n\n const getTableInfo = useCallback(\n async (tableName: string): Promise<unknown> => {\n if (status !== \"ready\") {\n throw new Error(\"DuckDB is not ready. Please wait for initialization to complete.\")\n }\n return duckDBService.getTableInfo(tableName)\n },\n [duckDBService, status],\n )\n\n const listTables = useCallback(async (): Promise<unknown> => {\n if (status !== \"ready\") {\n throw new Error(\"DuckDB is not ready. Please wait for initialization to complete.\")\n }\n return duckDBService.listTables()\n }, [duckDBService, status])\n\n useEffect(() => {\n const pollStatus = () => {\n const currentStatus = duckDBService.getStatus()\n if (currentStatus !== status && currentStatus !== \"initializing\") {\n setStatus(currentStatus)\n }\n }\n\n if (typeof window === \"undefined\") {\n pollStatus()\n return\n }\n\n const interval = window.setInterval(pollStatus, 1000)\n pollStatus()\n\n return () => window.clearInterval(interval)\n }, [duckDBService, status])\n\n return {\n status,\n error,\n executeQuery,\n executeQueries,\n createTableFromData,\n getTableInfo,\n listTables,\n isReady: status === \"ready\",\n initialize,\n }\n}\n\n/**\n * Hook for simple DuckDB query execution.\n * シンプルな DuckDB クエリ実行のためのフック。\n *\n * @param sql - 実行する SQL クエリ\n * @param dependencies - クエリを再実行するための依存配列\n * @returns クエリ結果と状態\n */\nexport const useDuckDBQuery = <T = unknown>(\n sql: string,\n dependencies: DependencyList = [],\n): {\n data: T | null\n loading: boolean\n error: string | null\n refetch: () => Promise<void>\n} => {\n const { executeQuery, isReady } = useDuckDB()\n const [data, setData] = useState<T | null>(null)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const refetch = useCallback(async () => {\n if (!(isReady && sql.trim())) {\n return\n }\n\n try {\n setLoading(true)\n setError(null)\n const result = await executeQuery(sql)\n setData(result as T)\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : \"Query execution failed\"\n setError(errorMessage)\n setData(null)\n } finally {\n setLoading(false)\n }\n }, [executeQuery, isReady, sql])\n\n useEffect(() => {\n void refetch()\n }, [refetch, ...dependencies])\n\n return {\n data,\n loading,\n error,\n refetch,\n }\n}\n","/**\n * DuckDB Web Worker Service\n *\n * Provides reusable DuckDB-wasm functionality across the application.\n * アプリケーション全体で再利用可能な DuckDB-wasm 機能を提供します。\n */\n\nimport * as duckdb from \"@duckdb/duckdb-wasm\"\n\nconst LOG_PREFIX = \"[duckdb-helper]\"\n\n/**\n * DuckDB service for browser-based SQL operations.\n * ブラウザベースの SQL 操作のための DuckDB サービス。\n */\nclass DuckDBService {\n private static instance: DuckDBService | null = null\n private operationFlags: Map<string, boolean> = new Map()\n\n private workerInstance: duckdb.AsyncDuckDB | null = null\n private connectionInstance: duckdb.AsyncDuckDBConnection | null = null\n private isInitializing = false\n private initPromise: Promise<duckdb.AsyncDuckDB> | null = null\n private hasError = false\n\n private listeners: Set<() => void> = new Set()\n\n /**\n * Get singleton instance of DuckDBService.\n * DuckDBService のシングルトンインスタンスを取得します。\n */\n public static getInstance(): DuckDBService {\n if (!DuckDBService.instance) {\n DuckDBService.instance = new DuckDBService()\n }\n return DuckDBService.instance\n }\n\n /**\n * Add status change listener.\n * 状態変更リスナーを追加します。\n */\n public addStatusListener(listener: () => void): void {\n this.listeners.add(listener)\n }\n\n /**\n * Remove status change listener.\n * 状態変更リスナーを削除します。\n */\n public removeStatusListener(listener: () => void): void {\n this.listeners.delete(listener)\n }\n\n /**\n * Notify all listeners of status change.\n * すべてのリスナーに状態変更を通知します。\n */\n private notifyListeners(): void {\n for (const listener of this.listeners) {\n try {\n listener()\n } catch (error) {\n console.error(LOG_PREFIX, \"⚠️ Error in status listener:\", error)\n }\n }\n }\n\n /**\n * Get current status.\n * 現在のステータスを取得します。\n */\n public getStatus(): \"not-initialized\" | \"initializing\" | \"ready\" | \"error\" {\n if (this.hasError) {\n return \"error\"\n }\n if (this.isInitializing) {\n return \"initializing\"\n }\n if (this.workerInstance) {\n return \"ready\"\n }\n return \"not-initialized\"\n }\n\n /**\n * Initialize DuckDB Worker instance.\n * DuckDB Worker インスタンスを初期化します。\n */\n public async initialize(): Promise<duckdb.AsyncDuckDB> {\n if (this.workerInstance) {\n return this.workerInstance\n }\n\n if (this.isInitializing && this.initPromise) {\n return this.initPromise\n }\n\n this.isInitializing = true\n this.hasError = false\n this.notifyListeners()\n\n // タイムアウト設定 (120秒) - WASMのダウンロードなどを考慮して長めに設定\n const TIMEOUT_MS = 120000\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => reject(new Error(`DuckDB initialization timed out after ${TIMEOUT_MS}ms`)), TIMEOUT_MS)\n })\n\n this.initPromise = (async () => {\n return await Promise.race([this.internalInitializeWorker(), timeoutPromise])\n })()\n\n try {\n const result = await this.initPromise\n this.isInitializing = false\n this.notifyListeners()\n return result\n } catch (error) {\n this.isInitializing = false\n this.hasError = true\n this.notifyListeners()\n this.initPromise = null\n throw error\n }\n }\n\n /**\n * Internal worker initialization method.\n * 内部的な Worker 初期化メソッド。\n */\n private async internalInitializeWorker(): Promise<duckdb.AsyncDuckDB> {\n try {\n console.log(LOG_PREFIX, \"🔧 Starting DuckDB Worker initialization...\")\n console.log(LOG_PREFIX, \"📦 Getting DuckDB bundles from CDN...\")\n const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles()\n\n console.log(LOG_PREFIX, \"🔍 Selecting appropriate bundle for browser...\")\n const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES)\n console.log(LOG_PREFIX, \"✅ Bundle selected:\", {\n mainWorker: bundle.mainWorker,\n mainModule: bundle.mainModule,\n pthreadWorker: bundle.pthreadWorker,\n })\n\n console.log(LOG_PREFIX, \"🚀 Creating Worker with Blob URL...\")\n const workerUrl = URL.createObjectURL(new Blob([`importScripts(\"${bundle.mainWorker}\");`], { type: \"text/javascript\" }))\n\n console.log(LOG_PREFIX, \"👷 Creating Worker instance...\")\n const worker = new Worker(workerUrl)\n const logger = new duckdb.ConsoleLogger()\n\n console.log(LOG_PREFIX, \"🗄️ Creating DuckDB instance...\")\n this.workerInstance = new duckdb.AsyncDuckDB(logger, worker)\n\n console.log(LOG_PREFIX, \"⚡ Instantiating DuckDB with modules...\")\n await this.workerInstance.instantiate(bundle.mainModule, bundle.pthreadWorker)\n\n console.log(LOG_PREFIX, \"📦 Installing splink_udfs from community...\")\n const connection = await this.workerInstance.connect()\n try {\n await connection.query(\"INSTALL splink_udfs FROM community;\")\n console.log(LOG_PREFIX, \"✅ splink_udfs installed successfully\")\n\n await connection.query(\"LOAD splink_udfs;\")\n console.log(LOG_PREFIX, \"✅ splink_udfs loaded successfully\")\n } catch (error) {\n console.warn(LOG_PREFIX, \"⚠️ Failed to install/load splink_udfs:\", error)\n } finally {\n await connection.close()\n }\n\n URL.revokeObjectURL(workerUrl)\n\n console.log(LOG_PREFIX, \"✅ DuckDB Worker initialized successfully\")\n return this.workerInstance\n } catch (error) {\n console.error(LOG_PREFIX, \"❌ Failed to initialize DuckDB Worker:\", error)\n\n if (error instanceof Error) {\n console.error(LOG_PREFIX, \"❌ Error name:\", error.name)\n console.error(LOG_PREFIX, \"❌ Error message:\", error.message)\n console.error(LOG_PREFIX, \"❌ Error stack:\", error.stack)\n }\n\n throw error\n }\n }\n\n /**\n * Get or create DuckDB connection.\n * DuckDB 接続を取得または作成します。\n */\n public async getConnection(): Promise<duckdb.AsyncDuckDBConnection> {\n if (!this.connectionInstance) {\n const db = await this.initialize()\n this.connectionInstance = await db.connect()\n }\n return this.connectionInstance\n }\n\n /**\n * Execute SQL query using DuckDB Worker.\n * DuckDB Worker を使用して SQL クエリを実行します。\n */\n public async executeQuery(sql: string): Promise<unknown> {\n // タイムアウト設定 (60秒)\n const TIMEOUT_MS = 60000\n const timeoutPromise = new Promise((_, reject) => {\n setTimeout(() => reject(new Error(`DuckDB query execution timed out after ${TIMEOUT_MS}ms`)), TIMEOUT_MS)\n })\n\n try {\n const operationPromise = (async () => {\n const connection = await this.getConnection()\n return await connection.query(sql)\n })()\n\n const result = await Promise.race([operationPromise, timeoutPromise])\n return result\n } catch (error) {\n console.error(LOG_PREFIX, \"❌ Failed to execute SQL query:\", error)\n throw error\n }\n }\n\n /**\n * Execute multiple SQL queries.\n * 複数の SQL クエリを実行します。\n */\n public async executeQueries(queries: string[]): Promise<unknown[]> {\n const results: unknown[] = []\n for (const query of queries) {\n const result = await this.executeQuery(query)\n results.push(result)\n }\n return results\n }\n\n /**\n * Infer column types from data sample.\n * データサンプルから列の型を推定します。\n */\n private inferColumnTypes(data: Record<string, unknown>[]): Record<string, string> {\n const columnTypes: Record<string, string> = {}\n const sampleData = data.slice(0, Math.min(data.length, 10))\n\n const keys = Object.keys(sampleData[0] || {})\n for (const key of keys) {\n const values = sampleData.map((row) => row[key]).filter((val) => val !== null && val !== undefined)\n\n if (values.length === 0) {\n columnTypes[key] = \"VARCHAR\"\n continue\n }\n\n const typeInfo = {\n number: 0,\n integer: 0,\n bigint: 0,\n boolean: 0,\n date: 0,\n string: 0,\n }\n\n for (const value of values) {\n if (typeof value === \"number\") {\n typeInfo.number += 1\n if (Number.isInteger(value)) {\n typeInfo.integer += 1\n if (value < -2147483648 || value > 2147483647) {\n typeInfo.bigint += 1\n }\n }\n } else if (typeof value === \"boolean\") {\n typeInfo.boolean += 1\n } else if (value instanceof Date) {\n typeInfo.date += 1\n } else if (typeof value === \"string\") {\n const dateValue = new Date(value)\n if (!Number.isNaN(dateValue.getTime()) && value.includes(\"-\")) {\n typeInfo.date += 1\n } else {\n typeInfo.string += 1\n }\n } else {\n typeInfo.string += 1\n }\n }\n\n if (typeInfo.number === values.length) {\n if (typeInfo.integer === values.length) {\n if (typeInfo.bigint > 0) {\n columnTypes[key] = \"BIGINT\"\n } else {\n columnTypes[key] = \"INTEGER\"\n }\n } else {\n columnTypes[key] = \"DOUBLE\"\n }\n } else if (typeInfo.boolean === values.length) {\n columnTypes[key] = \"BOOLEAN\"\n } else if (typeInfo.date === values.length) {\n columnTypes[key] = \"TIMESTAMP\"\n } else {\n columnTypes[key] = \"VARCHAR\"\n }\n }\n\n return columnTypes\n }\n\n /**\n * Format value for SQL insertion.\n * SQL 挿入用に値をフォーマットします。\n */\n private formatValueForSQL(value: unknown): string {\n if (value === null || value === undefined) {\n return \"NULL\"\n }\n if (typeof value === \"string\") {\n return `'${value.replace(/'/g, \"''\")}'`\n }\n if (value instanceof Date) {\n return `'${value.toISOString()}'`\n }\n if (typeof value === \"boolean\") {\n return value ? \"TRUE\" : \"FALSE\"\n }\n if (typeof value === \"number\") {\n if (Number.isInteger(value) && (value < -2147483648 || value > 2147483647)) {\n return String(value)\n }\n return String(value)\n }\n return String(value)\n }\n\n /**\n * Create table from JavaScript array of objects.\n * JavaScript オブジェクトの配列からテーブルを作成します。\n */\n public async createTableFromData<T extends Record<string, unknown>>(\n tableName: string,\n data: T[],\n options: {\n dropIfExists?: boolean\n primaryKey?: string\n verbose?: boolean\n } = {},\n ): Promise<void> {\n if (!data || data.length === 0) {\n throw new Error(\"Data array is empty\")\n }\n\n const operationKey = `create_table_${tableName}`\n const verbose = options.verbose ?? true\n if (this.operationFlags.has(operationKey)) {\n if (verbose) {\n console.log(LOG_PREFIX, `⏳ Table creation for '${tableName}' is already in progress, skipping...`)\n }\n return\n }\n this.operationFlags.set(operationKey, true)\n\n try {\n const connection = await this.getConnection()\n\n if (options.dropIfExists) {\n if (verbose) {\n console.log(LOG_PREFIX, `🗑️ Dropping table '${tableName}' if exists`)\n }\n await connection.query(`DROP TABLE IF EXISTS ${tableName}`)\n }\n\n try {\n const existingTables = await connection.query(\"SHOW TABLES\")\n if (verbose) {\n console.log(LOG_PREFIX, \"📋 Existing tables before creation:\", existingTables)\n }\n } catch (error) {\n if (verbose) {\n console.log(LOG_PREFIX, \"⚠️ Could not list existing tables:\", error)\n }\n }\n\n const sampleSize = Math.min(data.length, 100)\n const columnTypes = this.inferColumnTypes(data.slice(0, sampleSize))\n\n const columns = Object.keys(columnTypes).map((key) => {\n return `\"${key}\" ${columnTypes[key]}`\n })\n\n const primaryKeyClause = options.primaryKey ? `, PRIMARY KEY (\"${options.primaryKey}\")` : \"\"\n\n const createTableSQL = `CREATE TABLE ${tableName} (${columns.join(\", \")}${primaryKeyClause})`\n if (verbose) {\n console.log(LOG_PREFIX, \"🔨 Creating table with SQL:\", createTableSQL)\n }\n await connection.query(createTableSQL)\n\n try {\n const tablesAfterCreation = await connection.query(\"SHOW TABLES\")\n if (verbose) {\n console.log(LOG_PREFIX, \"📋 Tables after creation:\", tablesAfterCreation)\n }\n\n const tableExists = await connection.query(`SELECT COUNT(*) as count FROM information_schema.tables WHERE table_name = '${tableName}'`)\n if (verbose) {\n console.log(LOG_PREFIX, `✅ Table '${tableName}' exists check:`, tableExists)\n }\n } catch (error) {\n if (verbose) {\n console.log(LOG_PREFIX, \"⚠️ Could not verify table creation:\", error)\n }\n }\n\n if (verbose) {\n console.log(LOG_PREFIX, `📥 Inserting ${data.length} rows into table '${tableName}'`)\n }\n const dataColumns = Object.keys(data[0])\n const batchSize = 1000\n\n for (let i = 0; i < data.length; i += batchSize) {\n const batch = data.slice(i, i + batchSize)\n\n try {\n const valueRows = batch.map((row) => {\n const values = dataColumns.map((col) => {\n const value = row[col]\n return this.formatValueForSQL(value)\n })\n return `(${values.join(\", \")})`\n })\n\n const insertSQL = `INSERT INTO ${tableName} (${dataColumns.map((col) => `\"${col}\"`).join(\", \")}) VALUES ${valueRows.join(\", \")}`\n await connection.query(insertSQL)\n if (verbose) {\n console.log(LOG_PREFIX, `📊 Inserted batch ${Math.floor(i / batchSize) + 1} (${batch.length} rows)`)\n }\n } catch (insertError) {\n console.error(LOG_PREFIX, `❌ Failed to insert batch ${Math.floor(i / batchSize) + 1}:`, insertError)\n throw insertError\n }\n }\n\n if (verbose) {\n console.log(LOG_PREFIX, `🎉 Table '${tableName}' created successfully with ${data.length} rows`)\n }\n } catch (error) {\n console.error(LOG_PREFIX, `❌ Failed to create table '${tableName}':`, error)\n throw error\n } finally {\n this.operationFlags.delete(operationKey)\n }\n }\n\n /**\n * Get table information.\n * テーブル情報を取得します。\n */\n public async getTableInfo(tableName: string): Promise<unknown> {\n const connection = await this.getConnection()\n const result = await connection.query(`DESCRIBE ${tableName}`)\n return result\n }\n\n /**\n * List all tables.\n * すべてのテーブルを一覧表示します。\n */\n public async listTables(): Promise<unknown> {\n const connection = await this.getConnection()\n const result = await connection.query(\"SHOW TABLES\")\n return result\n }\n\n /**\n * Check if DuckDB is ready.\n * DuckDB が準備完了かどうかを確認します。\n */\n public isReady(): boolean {\n return this.workerInstance !== null\n }\n\n /**\n * Cleanup DuckDB Worker resources.\n * DuckDB Worker のリソースをクリーンアップします。\n */\n public async cleanup(): Promise<void> {\n try {\n if (this.connectionInstance) {\n await this.connectionInstance.close()\n this.connectionInstance = null\n }\n if (this.workerInstance) {\n await this.workerInstance.terminate()\n this.workerInstance = null\n }\n this.isInitializing = false\n this.hasError = false\n this.initPromise = null\n this.listeners.clear()\n this.operationFlags.clear()\n } catch (error) {\n console.error(LOG_PREFIX, \"⚠️ Error during cleanup:\", error)\n }\n }\n\n /**\n * Reset the service instance (useful for testing).\n * サービスインスタンスをリセットします(テスト用)。\n */\n public static resetInstance(): void {\n if (DuckDBService.instance) {\n DuckDBService.instance.cleanup()\n DuckDBService.instance = null\n }\n }\n}\n\nexport { DuckDBService }\n\nexport default DuckDBService.getInstance()\n","/**\n * DuckDB Helper Functions\n *\n * Utility functions for working with DuckDB query results.\n * DuckDB クエリ結果を扱うためのユーティリティ関数。\n */\n\nimport type { DuckDBQueryResult } from \"../types/duckdb\"\n\n/**\n * Safely convert DuckDB table to typed array\n * DuckDB テーブルを型付き配列に安全に変換します\n *\n * @param result - DuckDB query result\n * @returns Typed array of results\n */\nexport const duckdbTableToArray = <T>(result: unknown): T[] => {\n if (!result || typeof result !== \"object\") {\n return []\n }\n\n if (\"toArray\" in result && typeof result.toArray === \"function\") {\n return (result as DuckDBQueryResult<T>).toArray()\n }\n\n return []\n}\n\n/**\n * Get table row count\n * テーブルの行数を取得します\n *\n * @param result - DuckDB query result\n * @returns Number of rows in the table\n */\nexport const getDuckDBRowCount = (result: unknown): number => {\n if (!result || typeof result !== \"object\") {\n return 0\n }\n\n if (\"numRows\" in result && typeof result.numRows === \"number\") {\n return result.numRows\n }\n\n return 0\n}\n\n/**\n * Get table column count\n * テーブルの列数を取得します\n *\n * @param result - DuckDB query result\n * @returns Number of columns in the table\n */\nexport const getDuckDBColumnCount = (result: unknown): number => {\n if (!result || typeof result !== \"object\") {\n return 0\n }\n\n if (\"numCols\" in result && typeof result.numCols === \"number\") {\n return result.numCols\n }\n\n return 0\n}\n\n/**\n * Check if result is a valid DuckDB table\n * 結果が有効な DuckDB テーブルかどうかをチェックします\n *\n * @param result - DuckDB query result\n * @returns True if result is a valid DuckDB table\n */\nexport const isDuckDBTable = (result: unknown): result is DuckDBQueryResult => {\n if (!result || typeof result !== \"object\") {\n return false\n }\n\n return \"toArray\" in result && typeof result.toArray === \"function\" && \"numRows\" in result && typeof result.numRows === \"number\"\n}\n"],"mappings":"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","names":["useCallback","useEffect","useState","duckdb","LOG_PREFIX","_DuckDBService","listener","error","TIMEOUT_MS","timeoutPromise","_","reject","result","JSDELIVR_BUNDLES","bundle","workerUrl","worker","logger","connection","db","sql","operationPromise","queries","results","query","data","columnTypes","sampleData","keys","key","values","row","val","typeInfo","value","dateValue","tableName","options","operationKey","verbose","existingTables","sampleSize","columns","primaryKeyClause","createTableSQL","tablesAfterCreation","tableExists","dataColumns","batchSize","i","batch","valueRows","col","insertSQL","insertError","DuckDBService","duckdb_default","DuckDBService","LOG_PREFIX","useDuckDB","autoInitialize","status","setStatus","useState","error","setError","duckDBService","DuckDBService","updateStatus","useCallback","serviceStatus","useEffect","initialize","err","errorMessage","executeQuery","sql","executeQueries","queries","createTableFromData","tableName","data","options","getTableInfo","listTables","pollStatus","currentStatus","interval","useDuckDBQuery","dependencies","isReady","setData","loading","setLoading","refetch","result","duckdbTableToArray","result","getDuckDBRowCount","getDuckDBColumnCount","isDuckDBTable"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiquants/duckdb-helper",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "DuckDB helper utilities with React hooks, worker initialization, and typed query helpers",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"prepare": "pnpm run build",
|
|
25
25
|
"build:watch": "tsup --watch",
|
|
26
26
|
"dev": "tsup --watch",
|
|
27
|
+
"watch": "tsup --watch",
|
|
27
28
|
"type-check": "tsc --noEmit",
|
|
28
29
|
"typecheck": "npm run type-check",
|
|
29
30
|
"clean": "rimraf dist",
|
|
@@ -55,20 +56,23 @@
|
|
|
55
56
|
"url": "https://x.com/fehdek"
|
|
56
57
|
},
|
|
57
58
|
"license": "MIT",
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@duckdb/duckdb-wasm": "^1.30.0"
|
|
61
|
+
},
|
|
58
62
|
"devDependencies": {
|
|
59
|
-
"@biomejs/biome": "^2.3.
|
|
60
|
-
"@types/react": "^18.3.
|
|
63
|
+
"@biomejs/biome": "^2.3.8",
|
|
64
|
+
"@types/react": "^18.3.27",
|
|
61
65
|
"@types/react-dom": "^18.3.7",
|
|
62
66
|
"react": "^18.3.1",
|
|
63
67
|
"react-dom": "^18.3.1",
|
|
64
|
-
"rimraf": "^6.
|
|
65
|
-
"tsup": "^8.5.
|
|
68
|
+
"rimraf": "^6.1.2",
|
|
69
|
+
"tsup": "^8.5.1",
|
|
66
70
|
"typescript": "^5.9.3",
|
|
67
71
|
"vitest": "^3.2.4"
|
|
68
72
|
},
|
|
69
73
|
"peerDependencies": {
|
|
70
|
-
"react": ">=
|
|
71
|
-
"react-dom": ">=
|
|
74
|
+
"react": ">=18.0.0",
|
|
75
|
+
"react-dom": ">=18.0.0"
|
|
72
76
|
},
|
|
73
77
|
"peerDependenciesMeta": {
|
|
74
78
|
"react": {
|
|
@@ -78,9 +82,6 @@
|
|
|
78
82
|
"optional": true
|
|
79
83
|
}
|
|
80
84
|
},
|
|
81
|
-
"dependencies": {
|
|
82
|
-
"@duckdb/duckdb-wasm": "^1.30.0"
|
|
83
|
-
},
|
|
84
85
|
"engines": {
|
|
85
86
|
"node": ">=16.0.0",
|
|
86
87
|
"pnpm": ">=8.0.0"
|