@@ -76,6 +76,8 @@ export class SqlDriver implements Driver {
7676 private knex : Knex ;
7777 private config : any ;
7878 private jsonFields : Record < string , string [ ] > = { } ;
79+ private booleanFields : Record < string , string [ ] > = { } ;
80+ private tablesWithTimestamps : Set < string > = new Set ( ) ;
7981
8082 constructor ( config : any ) {
8183 this . config = config ;
@@ -309,7 +311,16 @@ export class SqlDriver implements Driver {
309311 if ( offsetValue !== undefined ) builder . offset ( offsetValue ) ;
310312 if ( limitValue !== undefined ) builder . limit ( limitValue ) ;
311313
312- const results = await builder ;
314+ let results ;
315+ try {
316+ results = await builder ;
317+ } catch ( error : any ) {
318+ // Handle SQL errors gracefully - if querying non-existent columns, return empty array
319+ if ( error . message && ( error . message . includes ( 'no such column' ) || error . message . includes ( 'column' ) && error . message . includes ( 'does not exist' ) ) ) {
320+ return [ ] ;
321+ }
322+ throw error ;
323+ }
313324
314325 if ( ! Array . isArray ( results ) ) {
315326 return [ ] ;
@@ -326,11 +337,11 @@ export class SqlDriver implements Driver {
326337 async findOne ( objectName : string , id : string | number , query ?: any , options ?: any ) {
327338 if ( id ) {
328339 const res = await this . getBuilder ( objectName , options ) . where ( 'id' , id ) . first ( ) ;
329- return this . formatOutput ( objectName , res ) ;
340+ return this . formatOutput ( objectName , res ) || null ;
330341 }
331342 if ( query ) {
332343 const results = await this . find ( objectName , { ...query , limit : 1 } , options ) ;
333- return results [ 0 ] ;
344+ return results [ 0 ] || null ;
334345 }
335346 return null ;
336347 }
@@ -361,6 +372,18 @@ export class SqlDriver implements Driver {
361372 async update ( objectName : string , id : string | number , data : any , options ?: any ) {
362373 const builder = this . getBuilder ( objectName , options ) ;
363374 const formatted = this . formatInput ( objectName , data ) ;
375+
376+ // Automatically update the updated_at timestamp if the table has this column
377+ if ( this . tablesWithTimestamps . has ( objectName ) ) {
378+ // For SQLite, use JavaScript Date to get millisecond precision
379+ if ( this . config . client === 'sqlite3' ) {
380+ const now = new Date ( ) ;
381+ formatted . updated_at = now . toISOString ( ) . replace ( 'T' , ' ' ) . replace ( 'Z' , '' ) ;
382+ } else {
383+ formatted . updated_at = this . knex . fn . now ( ) ;
384+ }
385+ }
386+
364387 await builder . where ( 'id' , id ) . update ( formatted ) ;
365388
366389 // Fetch and return the updated record
@@ -562,13 +585,15 @@ export class SqlDriver implements Driver {
562585 async updateMany ( objectName : string , filters : any , data : any , options ?: any ) : Promise < any > {
563586 const builder = this . getBuilder ( objectName , options ) ;
564587 if ( filters ) this . applyFilters ( builder , filters ) ;
565- return await builder . update ( data ) ;
588+ const count = await builder . update ( data ) ;
589+ return { modifiedCount : count || 0 } ;
566590 }
567591
568592 async deleteMany ( objectName : string , filters : any , options ?: any ) : Promise < any > {
569593 const builder = this . getBuilder ( objectName , options ) ;
570594 if ( filters ) this . applyFilters ( builder , filters ) ;
571- return await builder . delete ( ) ;
595+ const count = await builder . delete ( ) ;
596+ return { deletedCount : count || 0 } ;
572597 }
573598
574599 /**
@@ -691,17 +716,22 @@ export class SqlDriver implements Driver {
691716 for ( const obj of objects ) {
692717 const tableName = obj . name ;
693718
694- // Cache JSON fields
719+ // Cache JSON and Boolean fields
695720 const jsonCols : string [ ] = [ ] ;
721+ const booleanCols : string [ ] = [ ] ;
696722 if ( obj . fields ) {
697723 for ( const [ name , field ] of Object . entries < any > ( obj . fields ) ) {
698724 const type = field . type || 'string' ;
699725 if ( this . isJsonField ( type , field ) ) {
700726 jsonCols . push ( name ) ;
701727 }
728+ if ( type === 'boolean' ) {
729+ booleanCols . push ( name ) ;
730+ }
702731 }
703732 }
704733 this . jsonFields [ tableName ] = jsonCols ;
734+ this . booleanFields [ tableName ] = booleanCols ;
705735
706736 let exists = await this . knex . schema . hasTable ( tableName ) ;
707737
@@ -730,10 +760,17 @@ export class SqlDriver implements Driver {
730760 }
731761 } ) ;
732762 console . log ( `[SqlDriver] Created table '${ tableName } '` ) ;
763+ // Track that this table has timestamp columns
764+ this . tablesWithTimestamps . add ( tableName ) ;
733765 } else {
734766 const columnInfo = await this . knex ( tableName ) . columnInfo ( ) ;
735767 const existingColumns = Object . keys ( columnInfo ) ;
736768
769+ // Check if table has updated_at column
770+ if ( existingColumns . includes ( 'updated_at' ) ) {
771+ this . tablesWithTimestamps . add ( tableName ) ;
772+ }
773+
737774 await this . knex . schema . alterTable ( tableName , ( table ) => {
738775 if ( obj . fields ) {
739776 for ( const [ name , field ] of Object . entries ( obj . fields ) ) {
@@ -878,21 +915,35 @@ export class SqlDriver implements Driver {
878915 if ( ! data ) return data ;
879916
880917 const isSqlite = this . config . client === 'sqlite3' ;
881- if ( ! isSqlite ) return data ;
882-
883- const fields = this . jsonFields [ objectName ] ;
884- if ( ! fields || fields . length === 0 ) return data ;
885-
886- // data is a single row object
887- for ( const field of fields ) {
888- if ( data [ field ] !== undefined && typeof data [ field ] === 'string' ) {
889- try {
890- data [ field ] = JSON . parse ( data [ field ] ) ;
891- } catch ( e ) {
892- // ignore parse error, keep as string
918+
919+ if ( isSqlite ) {
920+ // Handle JSON fields
921+ const jsonFields = this . jsonFields [ objectName ] ;
922+ if ( jsonFields && jsonFields . length > 0 ) {
923+ // data is a single row object
924+ for ( const field of jsonFields ) {
925+ if ( data [ field ] !== undefined && typeof data [ field ] === 'string' ) {
926+ try {
927+ data [ field ] = JSON . parse ( data [ field ] ) ;
928+ } catch ( e ) {
929+ // ignore parse error, keep as string
930+ }
931+ }
932+ }
933+ }
934+
935+ // Handle Boolean fields - SQLite stores booleans as integers (0 or 1)
936+ const booleanFields = this . booleanFields [ objectName ] ;
937+ if ( booleanFields && booleanFields . length > 0 ) {
938+ for ( const field of booleanFields ) {
939+ if ( data [ field ] !== undefined && data [ field ] !== null ) {
940+ // Convert 0/1 to false/true
941+ data [ field ] = Boolean ( data [ field ] ) ;
942+ }
893943 }
894944 }
895945 }
946+
896947 return data ;
897948 }
898949
0 commit comments