1- import { promisify } from "node:util" ;
21import { DatabaseSync } from "../src/index" ;
32
43// Optional dependencies - loaded lazily to allow running tests without them
54// Use any types to avoid TypeScript issues with optional deps
65let Database : any = null ;
7- let deasync : any = null ;
8- let sqlite3Module : any = null ;
96
107// Try to load optional dependencies
118try {
@@ -14,33 +11,20 @@ try {
1411 // better-sqlite3 not available
1512}
1613
17- try {
18- deasync = require ( "deasync" ) ;
19- } catch {
20- // deasync not available
21- }
22-
23- try {
24- sqlite3Module = require ( "sqlite3" ) ;
25- } catch {
26- // sqlite3 not available
27- }
28-
2914// Track if node:sqlite is available
3015let nodeSqliteAvailable = false ;
3116let NodeSqliteDatabase : any = null ;
3217
33- // Initialize node:sqlite availability asynchronously
34- ( async ( ) => {
35- try {
36- // Try to import node:sqlite
37- const nodeSqlite = await import ( "node:sqlite" ) ;
38- NodeSqliteDatabase = nodeSqlite . DatabaseSync ;
39- nodeSqliteAvailable = true ;
40- } catch ( e ) {
41- // node:sqlite not available
42- }
43- } ) ( ) ;
18+ try {
19+ // Use require() for synchronous loading so the driver is available
20+ // when the `drivers` map is built at module-load time.
21+ // eslint-disable-next-line @typescript-eslint/no-require-imports
22+ const nodeSqlite = require ( "node:sqlite" ) ;
23+ NodeSqliteDatabase = nodeSqlite . DatabaseSync ;
24+ nodeSqliteAvailable = true ;
25+ } catch {
26+ // node:sqlite not available
27+ }
4428
4529// Types
4630export interface Statement {
@@ -236,178 +220,6 @@ class NodeSqliteDriver extends BaseDriver {
236220 }
237221}
238222
239- // sqlite3 driver (async, needs wrapper)
240- class Sqlite3Driver extends BaseDriver {
241- declare protected db : any ;
242- private stmtCache = new Map < string , any > ( ) ;
243- private dbRun ! : ( sql : string , ...params : any [ ] ) => Promise < void > ;
244- private dbGet ! : ( sql : string , ...params : any [ ] ) => Promise < any > ;
245- private dbAll ! : ( sql : string , ...params : any [ ] ) => Promise < any [ ] > ;
246- private dbExec ! : ( sql : string ) => Promise < void > ;
247-
248- constructor ( ) {
249- super ( "sqlite3" ) ;
250- }
251-
252- async initialize ( filename : string ) : Promise < Driver > {
253- if ( ! sqlite3Module || ! deasync ) {
254- throw new Error (
255- "sqlite3 and deasync are not available - run 'npm install' in benchmark/" ,
256- ) ;
257- }
258- const Database = sqlite3Module . verbose ( ) . Database ;
259- this . db = new Database ( filename ) ;
260-
261- // Promisify common methods
262- this . dbRun = promisify ( this . db . run . bind ( this . db ) ) ;
263- this . dbGet = promisify ( this . db . get . bind ( this . db ) ) ;
264- this . dbAll = promisify ( this . db . all . bind ( this . db ) ) ;
265- this . dbExec = promisify ( this . db . exec . bind ( this . db ) ) ;
266-
267- return this ;
268- }
269-
270- async close ( ) : Promise < void > {
271- if ( this . db ) {
272- // Clean up cached statements
273- for ( const stmt of this . stmtCache . values ( ) ) {
274- await new Promise < void > ( ( resolve ) => stmt . finalize ( ( ) => resolve ( ) ) ) ;
275- }
276- this . stmtCache . clear ( ) ;
277-
278- await new Promise < void > ( ( resolve , reject ) => {
279- this . db . close ( ( err : any ) => {
280- if ( err ) reject ( err ) ;
281- else resolve ( ) ;
282- } ) ;
283- } ) ;
284- this . db = null as any ;
285- }
286- }
287-
288- prepare ( sql : string ) : Statement {
289- // For sqlite3, we'll create a wrapper that makes async operations look sync
290- // This is not ideal for performance but allows fair comparison
291-
292- // Cache prepared statements
293- let stmt = this . stmtCache . get ( sql ) ;
294- if ( ! stmt ) {
295- stmt = this . db . prepare ( sql ) ;
296- this . stmtCache . set ( sql , stmt ) ;
297- }
298-
299- return {
300- get : ( ...params ) => {
301- // Run synchronously using deasync
302- let result : any ;
303- let error : Error | null = null ;
304- let done = false ;
305-
306- stmt ! . get ( ...params , ( err : Error | null , row : any ) => {
307- error = err ;
308- result = row ;
309- done = true ;
310- } ) ;
311-
312- // Busy wait using deasync
313- deasync ! . loopWhile ( ( ) => ! done ) ;
314-
315- if ( error ) throw error ;
316- return result ! ;
317- } ,
318-
319- all : ( ...params ) => {
320- let result : any [ ] ;
321- let error : Error | null = null ;
322- let done = false ;
323-
324- stmt ! . all ( ...params , ( err : Error | null , rows : any [ ] ) => {
325- error = err ;
326- result = rows ;
327- done = true ;
328- } ) ;
329-
330- deasync ! . loopWhile ( ( ) => ! done ) ;
331-
332- if ( error ) throw error ;
333- return result ! ;
334- } ,
335-
336- run : ( ...params ) => {
337- let result : any ;
338- let error : Error | null = null ;
339- let done = false ;
340-
341- stmt ! . run ( ...params , function ( this : any , err : Error | null ) {
342- error = err ;
343- result = { changes : this . changes , lastInsertRowid : this . lastID } ;
344- done = true ;
345- } ) ;
346-
347- deasync ! . loopWhile ( ( ) => ! done ) ;
348-
349- if ( error ) throw error ;
350- return result ! ;
351- } ,
352-
353- iterate : function * ( ...params ) {
354- // sqlite3 doesn't have built-in iterator, simulate with all()
355- let rows : any [ ] ;
356- let error : Error | null = null ;
357- let done = false ;
358-
359- stmt ! . all ( ...params , ( err : Error | null , allRows : any [ ] ) => {
360- error = err ;
361- rows = allRows ;
362- done = true ;
363- } ) ;
364-
365- deasync ! . loopWhile ( ( ) => ! done ) ;
366-
367- if ( error ) throw error ;
368-
369- for ( const row of rows ! ) {
370- yield row ;
371- }
372- } ,
373-
374- finalize : ( ) => {
375- // Don't finalize cached statements
376- } ,
377- } ;
378- }
379-
380- transaction < T > ( fn : ( ...args : any [ ] ) => T ) : ( ...args : any [ ] ) => T {
381- // sqlite3 doesn't have built-in transaction support, simulate it
382- const self = this ;
383- return ( ...args : any [ ] ) => {
384- self . exec ( "BEGIN" ) ;
385- try {
386- const result = fn ( ...args ) ;
387- self . exec ( "COMMIT" ) ;
388- return result ;
389- } catch ( err ) {
390- self . exec ( "ROLLBACK" ) ;
391- throw err ;
392- }
393- } ;
394- }
395-
396- exec ( sql : string ) : void {
397- let error : Error | null = null ;
398- let done = false ;
399-
400- this . db . exec ( sql , ( err : any ) => {
401- error = err ;
402- done = true ;
403- } ) ;
404-
405- deasync ! . loopWhile ( ( ) => ! done ) ;
406-
407- if ( error ) throw error ;
408- }
409- }
410-
411223// Driver class map
412224type DriverConstructor = new ( ) => BaseDriver ;
413225
@@ -416,7 +228,6 @@ export const drivers: Record<string, DriverConstructor> = {
416228 "@photostructure/sqlite" : PhotostructureDriver ,
417229 ...( Database ? { "better-sqlite3" : BetterSqlite3Driver } : { } ) ,
418230 ...( nodeSqliteAvailable ? { "node:sqlite" : NodeSqliteDriver } : { } ) ,
419- ...( sqlite3Module && deasync ? { sqlite3 : Sqlite3Driver } : { } ) ,
420231} ;
421232
422233// Helper to create driver instance
0 commit comments