@@ -422,4 +422,133 @@ for (const [key, factory] of FACTORIES) {
422422 expect ( calls ) . toEqual ( [ [ 23 , "main" , "t" , 1n ] ] ) ;
423423 } ) ;
424424 } ) ;
425+
426+ describe ( `${ key } commit_hook` , function ( ) {
427+ let db ;
428+ beforeEach ( async function ( ) {
429+ db = await sqlite3 . open_v2 ( ':memory:' ) ;
430+ } ) ;
431+
432+ afterEach ( async function ( ) {
433+ await sqlite3 . close ( db ) ;
434+ } ) ;
435+
436+ it ( 'should call commit hook' , async function ( ) {
437+ let rc ;
438+
439+ let callsCount = 0 ;
440+ const resetCallsCount = ( ) => callsCount = 0 ;
441+
442+ sqlite3 . commit_hook ( db , ( ) => {
443+ callsCount ++ ;
444+ return 0 ;
445+ } ) ;
446+ expect ( callsCount ) . toEqual ( 0 ) ;
447+ resetCallsCount ( ) ;
448+
449+ rc = await sqlite3 . exec ( db , `
450+ CREATE TABLE t(i integer primary key, x);
451+ ` ) ;
452+ expect ( rc ) . toEqual ( SQLite . SQLITE_OK ) ;
453+ expect ( callsCount ) . toEqual ( 1 ) ;
454+ resetCallsCount ( ) ;
455+
456+ rc = await sqlite3 . exec ( db , `
457+ SELECT * FROM t;
458+ ` ) ;
459+ expect ( callsCount ) . toEqual ( 0 ) ;
460+ resetCallsCount ( ) ;
461+
462+ rc = await sqlite3 . exec ( db , `
463+ BEGIN TRANSACTION;
464+ INSERT INTO t VALUES (1, 'foo');
465+ ROLLBACK;
466+ ` ) ;
467+ expect ( callsCount ) . toEqual ( 0 ) ;
468+ resetCallsCount ( ) ;
469+
470+ rc = await sqlite3 . exec ( db , `
471+ BEGIN TRANSACTION;
472+ INSERT INTO t VALUES (1, 'foo');
473+ INSERT INTO t VALUES (2, 'bar');
474+ COMMIT;
475+ ` ) ;
476+ expect ( callsCount ) . toEqual ( 1 ) ;
477+ resetCallsCount ( ) ;
478+ } ) ;
479+
480+ it ( 'can change commit hook' , async function ( ) {
481+ let rc ;
482+ rc = await sqlite3 . exec ( db , `
483+ CREATE TABLE t(i integer primary key, x);
484+ ` ) ;
485+ expect ( rc ) . toEqual ( SQLite . SQLITE_OK ) ;
486+
487+ let a = 0 ;
488+ let b = 0 ;
489+
490+ // set hook to increment `a` on commit
491+ sqlite3 . commit_hook ( db , ( ) => {
492+ a ++ ;
493+ return 0 ;
494+ } ) ;
495+ rc = await sqlite3 . exec ( db , `
496+ INSERT INTO t VALUES (1, 'foo');
497+ ` ) ;
498+ expect ( a ) . toEqual ( 1 ) ;
499+ expect ( b ) . toEqual ( 0 ) ;
500+
501+ // switch to increment `b`
502+ sqlite3 . commit_hook ( db , ( ) => {
503+ b ++ ;
504+ return 0 ;
505+ } ) ;
506+
507+ rc = await sqlite3 . exec ( db , `
508+ INSERT INTO t VALUES (2, 'bar');
509+ ` ) ;
510+ expect ( rc ) . toEqual ( SQLite . SQLITE_OK ) ;
511+ expect ( a ) . toEqual ( 1 ) ;
512+ expect ( b ) . toEqual ( 1 ) ;
513+
514+ // disable hook by passing null
515+ sqlite3 . commit_hook ( db , null ) ;
516+
517+ rc = await sqlite3 . exec ( db , `
518+ INSERT INTO t VALUES (3, 'qux');
519+ ` ) ;
520+ expect ( rc ) . toEqual ( SQLite . SQLITE_OK ) ;
521+ expect ( a ) . toEqual ( 1 ) ;
522+ expect ( b ) . toEqual ( 1 ) ;
523+ } ) ;
524+
525+ it ( 'can rollback based on return value' , async function ( ) {
526+ let rc ;
527+ rc = await sqlite3 . exec ( db , `
528+ CREATE TABLE t(i integer primary key, x);
529+ ` ) ;
530+ expect ( rc ) . toEqual ( SQLite . SQLITE_OK ) ;
531+
532+ // accept commit by returning 0
533+ sqlite3 . commit_hook ( db , ( ) => 0 ) ;
534+ rc = await sqlite3 . exec ( db , `
535+ INSERT INTO t VALUES (1, 'foo');
536+ ` ) ;
537+ expect ( rc ) . toEqual ( SQLite . SQLITE_OK ) ;
538+
539+ // reject commit by returning 1, causing rollback
540+ sqlite3 . commit_hook ( db , ( ) => 1 ) ;
541+ await expectAsync (
542+ sqlite3 . exec ( db , `INSERT INTO t VALUES (2, 'bar');` )
543+ ) . toBeRejected ( ) ;
544+
545+ // double-check that the insert was rolled back
546+ let hasRow = false ;
547+ rc = await sqlite3 . exec ( db , `
548+ SELECT * FROM t WHERE i = 2;
549+ ` , ( ) => hasRow = true ) ;
550+ expect ( rc ) . toEqual ( SQLite . SQLITE_OK ) ;
551+ expect ( hasRow ) . toBeFalse ( ) ;
552+ } ) ;
553+ } ) ;
425554}
0 commit comments