1- import { type DuckDBConnection , DuckDBInstance } from "@ duckdb/node-api "
1+ import { type Connection , Database } from "duckdb-async "
22
3- let instance : DuckDBInstance | null = null
4- let connection : DuckDBConnection | null = null
3+ let db : Database | null = null
4+ let connection : Connection | null = null
55
66/**
77 * Initializes an in-memory DuckDB database
88 * @returns A reference to the initialized database
99 */
10- export async function initializeDuckDB ( databaseFile ?: string ) {
11- if ( instance !== null ) {
12- return { success : true , databaseInstance : instance }
13- }
14-
10+ export async function initializeDuckDB (
11+ file ?: string ,
12+ ) : Promise < { success : boolean ; databaseInstance ?: Database ; error ?: string } > {
1513 try {
16- // Create a new DuckDB instance with a persistent database file
17- instance = await DuckDBInstance . create ( databaseFile || ":memory:" )
18- connection = await instance . connect ( )
14+ // Create a new DuckDB instance with a persistent database file or in-memory
15+ db = await Database . create ( file || ":memory:" )
16+ connection = await db . connect ( )
17+
18+ // Verify connection is working
19+ await connection . exec ( "SELECT 1" )
1920
20- return { success : true , databaseInstance : instance }
21+ return { success : true , databaseInstance : db }
2122 } catch ( error ) {
2223 return { success : false , error : `Failed to initialize DuckDB: ${ error } ` }
2324 }
2425}
2526
27+ export async function closeDuckDB ( ) {
28+ if ( db ) {
29+ await db . close ( )
30+ }
31+ }
32+
2633/**
2734 * Creates a table in the DuckDB database using raw SQL
2835 * @param createTableSQL The SQL CREATE TABLE statement
2936 * @returns Object indicating success or failure
3037 */
31- export async function createTableWithSQL ( createTableSQL : string ) {
32- if ( ! instance || ! connection ) {
38+ export async function createTableWithSQL ( createTableSQL : string ) : Promise < { success : boolean ; message : string } > {
39+ if ( ! db || ! connection ) {
3340 return {
3441 success : false ,
3542 message : "Database not initialized. Call initializeDuckDB first." ,
3643 }
3744 }
3845
3946 try {
40- await connection . run ( createTableSQL )
41-
47+ await connection . exec ( createTableSQL )
4248 return {
4349 success : true ,
4450 message : "Table created successfully" ,
@@ -61,8 +67,8 @@ export async function createTableWithSQL(createTableSQL: string) {
6167export async function createProjectionTable (
6268 tableName : string ,
6369 columns : Array < { name : string ; type : string ; constraints ?: string } > ,
64- ) {
65- if ( ! instance || ! connection ) {
70+ ) : Promise < { success : boolean ; message : string } > {
71+ if ( ! db || ! connection ) {
6672 return {
6773 success : false ,
6874 message : "Database not initialized. Call initializeDuckDB first." ,
@@ -77,7 +83,7 @@ export async function createProjectionTable(
7783
7884 const createTableSQL = `CREATE TABLE IF NOT EXISTS ${ tableName } (${ columnsSQL } )`
7985
80- await connection . run ( createTableSQL )
86+ await connection . exec ( createTableSQL )
8187
8288 return {
8389 success : true ,
@@ -97,8 +103,11 @@ export async function createProjectionTable(
97103 * @param record Record to insert
98104 * @returns Object indicating success or failure
99105 */
100- export async function insertRecordIntoTable ( tableName : string , record : Record < string , unknown > ) {
101- if ( ! instance || ! connection ) {
106+ export async function insertRecordIntoTable (
107+ tableName : string ,
108+ record : Record < string , unknown > ,
109+ ) : Promise < { success : boolean ; message : string } > {
110+ if ( ! db || ! connection ) {
102111 return {
103112 success : false ,
104113 message : "Database not initialized. Call initializeDuckDB first." ,
@@ -107,46 +116,35 @@ export async function insertRecordIntoTable(tableName: string, record: Record<st
107116
108117 try {
109118 const columnNames = Object . keys ( record ) . join ( ", " )
110- const placeholders = Object . keys ( record )
111- . map ( ( _ , index ) => `$${ index + 1 } ` )
112- . join ( ", " )
113- const values = Object . values ( record )
114119
115- const insertSQL = `INSERT INTO ${ tableName } (${ columnNames } ) VALUES (${ placeholders } )`
116-
117- try {
118- const prepared = await connection . prepare ( insertSQL )
120+ // Format values according to their type
121+ const formattedValues = Object . values ( record )
122+ . map ( ( value ) => {
123+ if ( value === null ) {
124+ return "NULL"
125+ }
119126
120- // Bind values based on their types
121- values . forEach ( ( value , index ) => {
122- const paramIndex = index + 1
123127 if ( typeof value === "string" ) {
124- prepared . bindVarchar ( paramIndex , value )
125- } else if ( typeof value === "number" ) {
126- if ( Number . isInteger ( value ) ) {
127- prepared . bindInteger ( paramIndex , value )
128- } else {
129- prepared . bindDouble ( paramIndex , value )
130- }
131- } else if ( typeof value === "boolean" ) {
132- prepared . bindBoolean ( paramIndex , value )
133- } else if ( value === null ) {
134- prepared . bindNull ( paramIndex )
135- } else if ( typeof value === "bigint" ) {
136- prepared . bindBigInt ( paramIndex , value )
137- } else {
138- // For other types, convert to string
139- prepared . bindVarchar ( paramIndex , String ( value ) )
128+ // Escape single quotes in strings
129+ return `'${ String ( value ) . replace ( / ' / g, "''" ) } '`
140130 }
131+
132+ if ( typeof value === "boolean" ) {
133+ return value ? "TRUE" : "FALSE"
134+ }
135+
136+ if ( value instanceof Date ) {
137+ return `'${ value . toISOString ( ) } '`
138+ }
139+
140+ return String ( value )
141141 } )
142+ . join ( ", " )
143+
144+ const insertSQL = `INSERT INTO ${ tableName } (${ columnNames } ) VALUES (${ formattedValues } )`
145+
146+ await connection . exec ( insertSQL )
142147
143- await prepared . run ( )
144- } catch ( error ) {
145- return {
146- success : false ,
147- message : `Failed to insert record into ${ tableName } : ${ error } ` ,
148- }
149- }
150148 return {
151149 success : true ,
152150 message : `Record inserted into ${ tableName } successfully` ,
@@ -164,8 +162,10 @@ export async function insertRecordIntoTable(tableName: string, record: Record<st
164162 * @param query SQL query to execute
165163 * @returns Object with query results or error
166164 */
167- export async function queryDatabase ( query : string ) {
168- if ( ! instance || ! connection ) {
165+ export async function queryDatabase (
166+ query : string ,
167+ ) : Promise < { success : boolean ; message : string ; results : unknown [ ] | null } > {
168+ if ( ! db || ! connection ) {
169169 return {
170170 success : false ,
171171 message : "Database not initialized. Call initializeDuckDB first." ,
@@ -174,11 +174,12 @@ export async function queryDatabase(query: string) {
174174 }
175175
176176 try {
177- const result = await connection . run ( query )
177+ const rows = await connection . all ( query )
178+
178179 return {
179180 success : true ,
180181 message : "Query executed successfully" ,
181- results : result ,
182+ results : rows ,
182183 }
183184 } catch ( error ) {
184185 return {
@@ -194,7 +195,7 @@ export async function queryDatabase(query: string) {
194195 * @returns The database instance or null if not initialized
195196 */
196197export function getDatabaseInstance ( ) {
197- return instance
198+ return db
198199}
199200
200201/**
0 commit comments