@@ -187,15 +187,14 @@ IDB.attachDatabase = async function (ixdbid, dbid, args, params, cb) {
187187 db . tables [ stores [ i ] ] = { } ;
188188 }
189189
190- /*/*
191- if (!alasql.options.autocommit) {
192- if (db.tables) {
193- for(var tbid in db.tables) {
194- db.tables[tbid].data = LS.get(db.lsdbid+'.'+tbid);
195- }
190+ // IF AUTOCOMMIT IS OFF then copy data to memory
191+ if ( ! alasql . options . autocommit ) {
192+ if ( db . tables ) {
193+ for ( var tbid in db . tables ) {
194+ IDB . restoreTable ( dbid || ixdbid , tbid ) ;
196195 }
197196 }
198- */
197+ }
199198
200199 if ( cb ) cb ( 1 ) ;
201200} ;
@@ -333,11 +332,59 @@ IDB.dropTable = async function (databaseid, tableid, ifexists, cb) {
333332*/
334333
335334IDB . intoTable = function ( databaseid , tableid , value , columns , cb ) {
336- const ixdbid = alasql . databases [ databaseid ] . ixdbid ;
337- const request = indexedDB . open ( ixdbid ) ;
338335 var db = alasql . databases [ databaseid ] ;
339336 var table = db . tables [ tableid ] ;
340337
338+ // In autocommit mode, work with in-memory data
339+ if ( ! alasql . options . autocommit ) {
340+ // Ensure table data is loaded
341+ if ( ! table . data ) {
342+ IDB . restoreTable ( databaseid , tableid , ( ) => {
343+ // After loading, add values
344+ if ( ! table . data ) table . data = [ ] ;
345+ table . data = table . data . concat ( value ) ;
346+
347+ // Execute triggers
348+ for ( var tr in table . afterinsert ) {
349+ if ( table . afterinsert [ tr ] ) {
350+ var trigger = table . afterinsert [ tr ] ;
351+ if ( trigger . funcid ) {
352+ alasql . fn [ trigger . funcid ] ( value ) ;
353+ } else if ( trigger . statement ) {
354+ trigger . statement . execute ( databaseid ) ;
355+ }
356+ }
357+ }
358+
359+ if ( cb ) cb ( value . length ) ;
360+ } ) ;
361+ return ;
362+ }
363+
364+ // Table already loaded, just add to memory
365+ if ( ! table . data ) table . data = [ ] ;
366+ table . data = table . data . concat ( value ) ;
367+
368+ // Execute triggers
369+ for ( var tr in table . afterinsert ) {
370+ if ( table . afterinsert [ tr ] ) {
371+ var trigger = table . afterinsert [ tr ] ;
372+ if ( trigger . funcid ) {
373+ alasql . fn [ trigger . funcid ] ( value ) ;
374+ } else if ( trigger . statement ) {
375+ trigger . statement . execute ( databaseid ) ;
376+ }
377+ }
378+ }
379+
380+ if ( cb ) cb ( value . length ) ;
381+ return ;
382+ }
383+
384+ // In autocommit mode, write directly to IndexedDB
385+ const ixdbid = db . ixdbid ;
386+ const request = indexedDB . open ( ixdbid ) ;
387+
341388 request . onupgradeneeded = evt => {
342389 evt . target . transaction . abort ( ) ;
343390 const err = new Error (
@@ -371,7 +418,27 @@ IDB.intoTable = function (databaseid, tableid, value, columns, cb) {
371418} ;
372419
373420IDB . fromTable = function ( databaseid , tableid , cb , idx , query ) {
374- const ixdbid = alasql . databases [ databaseid ] . ixdbid ;
421+ var db = alasql . databases [ databaseid ] ;
422+ var table = db . tables [ tableid ] ;
423+
424+ // In transaction mode (autocommit OFF), read from memory
425+ if ( ! alasql . options . autocommit ) {
426+ // Ensure table data is loaded
427+ if ( ! table . data ) {
428+ IDB . restoreTable ( databaseid , tableid , ( ) => {
429+ const res = table . data || [ ] ;
430+ if ( cb ) cb ( res , idx , query ) ;
431+ } ) ;
432+ return ;
433+ }
434+
435+ const res = table . data || [ ] ;
436+ if ( cb ) cb ( res , idx , query ) ;
437+ return ;
438+ }
439+
440+ // In autocommit mode, read directly from IndexedDB
441+ const ixdbid = db . ixdbid ;
375442 const request = indexedDB . open ( ixdbid ) ;
376443
377444 request . onupgradeneeded = evt => {
@@ -454,34 +521,236 @@ IDB.updateTable = function (databaseid, tableid, assignfn, wherefn, params, cb)
454521 } ;
455522} ;
456523
524+ /**
525+ * Store table structure and data into IndexedDB
526+ * @param databaseid {string} AlaSQL database id
527+ * @param tableid {string} Table name
528+ * @param cb {function} Optional callback
529+ */
530+ IDB . storeTable = function ( databaseid , tableid , cb ) {
531+ const db = alasql . databases [ databaseid ] ;
532+ const table = db . tables [ tableid ] ;
533+ const ixdbid = db . ixdbid ;
534+
535+ if ( ! table || ! table . data ) {
536+ if ( cb ) cb ( 0 ) ;
537+ return ;
538+ }
539+
540+ const request = indexedDB . open ( ixdbid ) ;
541+
542+ request . onerror = ( ) => {
543+ if ( cb ) cb ( null , new Error ( 'Failed to open IndexedDB' ) ) ;
544+ } ;
545+
546+ request . onsuccess = ( ) => {
547+ const ixdb = request . result ;
548+
549+ // Clear existing data first
550+ const clearTx = ixdb . transaction ( [ tableid ] , 'readwrite' ) ;
551+ const clearStore = clearTx . objectStore ( tableid ) ;
552+ const clearReq = clearStore . clear ( ) ;
553+
554+ clearReq . onsuccess = ( ) => {
555+ // Now add all data
556+ const tx = ixdb . transaction ( [ tableid ] , 'readwrite' ) ;
557+ const tb = tx . objectStore ( tableid ) ;
558+
559+ for ( let i = 0 ; i < table . data . length ; i ++ ) {
560+ tb . add ( table . data [ i ] ) ;
561+ }
562+
563+ tx . oncomplete = ( ) => {
564+ ixdb . close ( ) ;
565+ if ( cb ) cb ( table . data . length ) ;
566+ } ;
567+
568+ tx . onerror = ( ) => {
569+ ixdb . close ( ) ;
570+ if ( cb ) cb ( null , new Error ( 'Failed to store table data' ) ) ;
571+ } ;
572+ } ;
573+
574+ clearReq . onerror = ( ) => {
575+ ixdb . close ( ) ;
576+ if ( cb ) cb ( null , new Error ( 'Failed to clear table' ) ) ;
577+ } ;
578+ } ;
579+ } ;
580+
581+ /**
582+ * Restore table structure and data from IndexedDB to memory
583+ * @param databaseid {string} AlaSQL database id
584+ * @param tableid {string} Table name
585+ * @param cb {function} Optional callback
586+ */
587+ IDB . restoreTable = function ( databaseid , tableid , cb ) {
588+ const db = alasql . databases [ databaseid ] ;
589+ const ixdbid = db . ixdbid ;
590+
591+ // Initialize table if it doesn't exist
592+ if ( ! db . tables [ tableid ] ) {
593+ db . tables [ tableid ] = new alasql . Table ( ) ;
594+ }
595+
596+ const table = db . tables [ tableid ] ;
597+
598+ const request = indexedDB . open ( ixdbid ) ;
599+
600+ request . onerror = ( ) => {
601+ if ( cb ) cb ( null , new Error ( 'Failed to open IndexedDB' ) ) ;
602+ } ;
603+
604+ request . onsuccess = ( ) => {
605+ const ixdb = request . result ;
606+ const tx = ixdb . transaction ( [ tableid ] ) ;
607+ const store = tx . objectStore ( tableid ) ;
608+ const getAllReq = store . getAll ( ) ;
609+
610+ getAllReq . onsuccess = ( ) => {
611+ table . data = getAllReq . result || [ ] ;
612+ ixdb . close ( ) ;
613+ if ( cb ) cb ( table . data . length ) ;
614+ } ;
615+
616+ getAllReq . onerror = ( ) => {
617+ ixdb . close ( ) ;
618+ if ( cb ) cb ( null , new Error ( 'Failed to restore table data' ) ) ;
619+ } ;
620+ } ;
621+
622+ return table ;
623+ } ;
624+
457625/**
458626 * Begin transaction for IndexedDB
459- * Note: IndexedDB handles transactions internally, so this is a no-op
460- * that just acknowledges the transaction start
627+ * Implements transaction state management similar to LOCALSTORAGE
461628 */
462629IDB . begin = function ( databaseid , cb ) {
463- // IndexedDB manages transactions internally at the operation level
464- // This method is here for compatibility with the transaction API
465- return cb ? cb ( 1 ) : 1 ;
630+ const db = alasql . databases [ databaseid ] ;
631+
632+ // Store snapshot of current state for rollback
633+ if ( ! db . engineid || db . engineid !== 'INDEXEDDB' ) {
634+ return cb ? cb ( 1 ) : 1 ;
635+ }
636+
637+ // In autocommit mode, begin just commits current state
638+ if ( alasql . options . autocommit ) {
639+ return IDB . commit ( databaseid , cb ) ;
640+ }
641+
642+ // In transaction mode, ensure data is loaded in memory
643+ const tablesToLoad = [ ] ;
644+ for ( const tbid in db . tables ) {
645+ if ( db . tables [ tbid ] && ! db . tables [ tbid ] . data ) {
646+ tablesToLoad . push ( tbid ) ;
647+ }
648+ }
649+
650+ if ( tablesToLoad . length === 0 ) {
651+ return cb ? cb ( 1 ) : 1 ;
652+ }
653+
654+ // Load all tables that aren't already in memory
655+ let loaded = 0 ;
656+ const checkComplete = ( ) => {
657+ loaded ++ ;
658+ if ( loaded === tablesToLoad . length ) {
659+ if ( cb ) cb ( 1 ) ;
660+ }
661+ } ;
662+
663+ tablesToLoad . forEach ( tbid => {
664+ IDB . restoreTable ( databaseid , tbid , checkComplete ) ;
665+ } ) ;
666+
667+ if ( tablesToLoad . length === 0 ) {
668+ return cb ? cb ( 1 ) : 1 ;
669+ }
466670} ;
467671
468672/**
469673 * Commit transaction for IndexedDB
470- * Note: IndexedDB handles commits internally, so this is a no-op
674+ * Persists in-memory data to IndexedDB
471675 */
472676IDB . commit = function ( databaseid , cb ) {
473- // IndexedDB automatically commits transactions when operations complete
474- // This method is here for compatibility with the transaction API
475- return cb ? cb ( 1 ) : 1 ;
677+ const db = alasql . databases [ databaseid ] ;
678+
679+ if ( ! db . engineid || db . engineid !== 'INDEXEDDB' ) {
680+ return cb ? cb ( 1 ) : 1 ;
681+ }
682+
683+ const tablesToStore = [ ] ;
684+ for ( const tbid in db . tables ) {
685+ if ( db . tables [ tbid ] && db . tables [ tbid ] . data ) {
686+ tablesToStore . push ( tbid ) ;
687+ }
688+ }
689+
690+ if ( tablesToStore . length === 0 ) {
691+ return cb ? cb ( 1 ) : 1 ;
692+ }
693+
694+ let stored = 0 ;
695+ let hasError = false ;
696+
697+ const checkComplete = ( res , err ) => {
698+ if ( err && ! hasError ) {
699+ hasError = true ;
700+ if ( cb ) cb ( null , err ) ;
701+ return ;
702+ }
703+
704+ stored ++ ;
705+ if ( stored === tablesToStore . length && ! hasError ) {
706+ if ( cb ) cb ( 1 ) ;
707+ }
708+ } ;
709+
710+ tablesToStore . forEach ( tbid => {
711+ IDB . storeTable ( databaseid , tbid , checkComplete ) ;
712+ } ) ;
476713} ;
477714
478715/**
479716 * Rollback transaction for IndexedDB
480- * Note: IndexedDB handles rollbacks internally, so this is a no-op
717+ * Restores data from IndexedDB, discarding in-memory changes
481718 */
482719IDB . rollback = function ( databaseid , cb ) {
483- // IndexedDB automatically rolls back transactions on errors
484- // Manual rollback is not supported in the same way as other engines
485- // This method is here for compatibility with the transaction API
486- return cb ? cb ( 1 ) : 1 ;
720+ const db = alasql . databases [ databaseid ] ;
721+
722+ if ( ! db . engineid || db . engineid !== 'INDEXEDDB' ) {
723+ return cb ? cb ( 1 ) : 1 ;
724+ }
725+
726+ const tablesToRestore = [ ] ;
727+ for ( const tbid in db . tables ) {
728+ if ( db . tables [ tbid ] ) {
729+ tablesToRestore . push ( tbid ) ;
730+ }
731+ }
732+
733+ if ( tablesToRestore . length === 0 ) {
734+ return cb ? cb ( 1 ) : 1 ;
735+ }
736+
737+ let restored = 0 ;
738+ let hasError = false ;
739+
740+ const checkComplete = ( res , err ) => {
741+ if ( err && ! hasError ) {
742+ hasError = true ;
743+ if ( cb ) cb ( null , err ) ;
744+ return ;
745+ }
746+
747+ restored ++ ;
748+ if ( restored === tablesToRestore . length && ! hasError ) {
749+ if ( cb ) cb ( 1 ) ;
750+ }
751+ } ;
752+
753+ tablesToRestore . forEach ( tbid => {
754+ IDB . restoreTable ( databaseid , tbid , checkComplete ) ;
755+ } ) ;
487756} ;
0 commit comments