11import { beforeEach , describe , expect , test , vi } from 'vitest' ;
22
33import type { Middleware , Store } from 'tinybase' ;
4- import { createMiddleware , createStore } from 'tinybase' ;
4+ import { createCheckpoints , createMiddleware , createStore } from 'tinybase' ;
55
66let store : Store ;
77let middleware : Middleware ;
@@ -99,7 +99,6 @@ describe('willSetContent', () => {
9999 store . setContent ( [ { t1 : { r1 : { c1 : 'a' } } } , { } ] ) ;
100100 expect ( store . getTables ( ) ) . toEqual ( { t1 : { r1 : { c1 : 'a' } } } ) ;
101101 store . setContent ( [ { banned : { r1 : { c1 : 1 } } , t2 : { r1 : { c1 : 'b' } } } , { } ] ) ;
102- // blocked, so t1 from previous setContent remains
103102 expect ( store . getTables ( ) ) . toEqual ( { t1 : { r1 : { c1 : 'a' } } } ) ;
104103 } ) ;
105104 } ) ;
@@ -363,7 +362,6 @@ describe('willSetTables', () => {
363362 store . setTables ( { t1 : { r1 : { c1 : 'a' } } } ) ;
364363 expect ( store . getTables ( ) ) . toEqual ( { t1 : { r1 : { c1 : 'a' } } } ) ;
365364 store . setTables ( { banned : { r1 : { c1 : 1 } } , t2 : { r1 : { c1 : 'b' } } } ) ;
366- // blocked, so t1 from previous setTables remains
367365 expect ( store . getTables ( ) ) . toEqual ( { t1 : { r1 : { c1 : 'a' } } } ) ;
368366 } ) ;
369367 } ) ;
@@ -1138,7 +1136,6 @@ describe('willSetCell', () => {
11381136 return typeof cell === 'number' ? cell * 10 : cell ;
11391137 } ) ;
11401138 store . setCell ( 't1' , 'r1' , 'c1' , 1 ) ;
1141- // (1 + 1) * 10 = 20
11421139 expect ( store . getCell ( 't1' , 'r1' , 'c1' ) ) . toBe ( 20 ) ;
11431140 } ) ;
11441141
@@ -1341,8 +1338,6 @@ describe('willSetValues', () => {
13411338 store . setValues ( { v1 : 'a' } ) ;
13421339 expect ( store . getValues ( ) ) . toEqual ( { v1 : 'a' } ) ;
13431340 store . setValues ( { locked : true , v2 : 'b' } ) ;
1344- // blocked, so v1 from previous setValues is deleted by the
1345- // mapMatch since the blocked values resolve to undefined
13461341 expect ( store . getValues ( ) ) . toEqual ( { v1 : 'a' } ) ;
13471342 } ) ;
13481343 } ) ;
@@ -1568,7 +1563,6 @@ describe('willSetValue', () => {
15681563 return typeof value === 'number' ? value * 2 : value ;
15691564 } ) ;
15701565 store . setValue ( 'v1' , 1 ) ;
1571- // (1 + 1) * 2 = 4
15721566 expect ( store . getValue ( 'v1' ) ) . toBe ( 4 ) ;
15731567 } ) ;
15741568
@@ -1874,7 +1868,7 @@ describe('willDelTable', () => {
18741868 store . setTables ( { t1 : { r1 : { c1 : 'a' } } , t2 : { r1 : { c1 : 'b' } } } ) ;
18751869 delCalls . length = 0 ;
18761870 store . setTables ( { t1 : { r1 : { c1 : 'A' } } } ) ;
1877- // t2 should be deleted
1871+
18781872 expect ( delCalls ) . toEqual ( [ 't2' ] ) ;
18791873 expect ( store . getTables ( ) ) . toEqual ( { t1 : { r1 : { c1 : 'A' } } } ) ;
18801874 } ) ;
@@ -1883,7 +1877,7 @@ describe('willDelTable', () => {
18831877 middleware . addWillDelTableCallback ( ( ) => false ) ;
18841878 store . setTables ( { t1 : { r1 : { c1 : 'a' } } , t2 : { r1 : { c1 : 'b' } } } ) ;
18851879 store . setTables ( { t1 : { r1 : { c1 : 'A' } } } ) ;
1886- // t2 should be preserved because delete was blocked
1880+
18871881 expect ( store . getTables ( ) ) . toEqual ( {
18881882 t1 : { r1 : { c1 : 'A' } } ,
18891883 t2 : { r1 : { c1 : 'b' } } ,
@@ -2033,7 +2027,7 @@ describe('willDelRow', () => {
20332027 store . setTable ( 't1' , { r1 : { c1 : 'a' } , r2 : { c1 : 'b' } } ) ;
20342028 delCalls . length = 0 ;
20352029 store . setTable ( 't1' , { r1 : { c1 : 'A' } } ) ;
2036- // r2 should be deleted
2030+
20372031 expect ( delCalls ) . toEqual ( [ 't1/r2' ] ) ;
20382032 expect ( store . getTable ( 't1' ) ) . toEqual ( { r1 : { c1 : 'A' } } ) ;
20392033 } ) ;
@@ -2042,7 +2036,7 @@ describe('willDelRow', () => {
20422036 middleware . addWillDelRowCallback ( ( ) => false ) ;
20432037 store . setTable ( 't1' , { r1 : { c1 : 'a' } , r2 : { c1 : 'b' } } ) ;
20442038 store . setTable ( 't1' , { r1 : { c1 : 'A' } } ) ;
2045- // r2 should be preserved because delete was blocked
2039+
20462040 expect ( store . getTable ( 't1' ) ) . toEqual ( {
20472041 r1 : { c1 : 'A' } ,
20482042 r2 : { c1 : 'b' } ,
@@ -2210,7 +2204,7 @@ describe('willDelCell', () => {
22102204 store . setRow ( 't1' , 'r1' , { c1 : 'a' , c2 : 'b' } ) ;
22112205 delCalls . length = 0 ;
22122206 store . setRow ( 't1' , 'r1' , { c1 : 'A' } ) ;
2213- // c2 should be deleted
2207+
22142208 expect ( delCalls ) . toEqual ( [ 't1/r1/c2' ] ) ;
22152209 expect ( store . getRow ( 't1' , 'r1' ) ) . toEqual ( { c1 : 'A' } ) ;
22162210 } ) ;
@@ -2219,7 +2213,7 @@ describe('willDelCell', () => {
22192213 middleware . addWillDelCellCallback ( ( ) => false ) ;
22202214 store . setRow ( 't1' , 'r1' , { c1 : 'a' , c2 : 'b' } ) ;
22212215 store . setRow ( 't1' , 'r1' , { c1 : 'A' } ) ;
2222- // c2 should be preserved because delete was blocked
2216+
22232217 expect ( store . getRow ( 't1' , 'r1' ) ) . toEqual ( { c1 : 'A' , c2 : 'b' } ) ;
22242218 } ) ;
22252219 } ) ;
@@ -2434,7 +2428,7 @@ describe('willDelValue', () => {
24342428 store . setValues ( { v1 : 'a' , v2 : 'b' } ) ;
24352429 delCalls . length = 0 ;
24362430 store . setValues ( { v1 : 'A' } ) ;
2437- // v2 should be deleted
2431+
24382432 expect ( delCalls ) . toEqual ( [ 'v2' ] ) ;
24392433 expect ( store . getValues ( ) ) . toEqual ( { v1 : 'A' } ) ;
24402434 } ) ;
@@ -2443,7 +2437,7 @@ describe('willDelValue', () => {
24432437 middleware . addWillDelValueCallback ( ( ) => false ) ;
24442438 store . setValues ( { v1 : 'a' , v2 : 'b' } ) ;
24452439 store . setValues ( { v1 : 'A' } ) ;
2446- // v2 should be preserved because delete was blocked
2440+
24472441 expect ( store . getValues ( ) ) . toEqual ( { v1 : 'A' , v2 : 'b' } ) ;
24482442 } ) ;
24492443 } ) ;
@@ -2530,7 +2524,7 @@ describe('willApplyChanges', () => {
25302524 store . applyChanges ( [ { t1 : { r1 : { c1 : 'a' } } } , { } , 1 ] ) ;
25312525 expect ( store . getTables ( ) ) . toEqual ( { t1 : { r1 : { c1 : 'a' } } } ) ;
25322526 store . applyChanges ( [ { banned : { r1 : { c1 : 1 } } } , { } , 1 ] ) ;
2533- // blocked, so t1 from previous applyChanges remains
2527+
25342528 expect ( store . getTables ( ) ) . toEqual ( { t1 : { r1 : { c1 : 'a' } } } ) ;
25352529 } ) ;
25362530
@@ -2813,9 +2807,9 @@ describe('schema interaction', () => {
28132807 store . setTablesSchema ( {
28142808 t1 : { c1 : { type : 'string' } , c2 : { type : 'number' } } ,
28152809 } ) ;
2816- // c1 valid string, c2 invalid (string instead of number) - gets removed
2810+
28172811 store . setRow ( 't1' , 'r1' , { c1 : 'a' , c2 : 'b' as any } ) ;
2818- // Only c1 reaches the callback; c2 is rejected by schema validation
2812+
28192813 expect ( calls ) . toEqual ( [ 't1/r1/c1=a' ] ) ;
28202814 } ) ;
28212815 } ) ;
@@ -2868,7 +2862,7 @@ describe('schema interaction', () => {
28682862 } ,
28692863 } ) ;
28702864 store . setRow ( 't1' , 'r1' , { c1 : 'a' } ) ;
2871- // c2 should be defaulted to 1, and the callback should see it
2865+
28722866 expect ( calls ) . toEqual ( [
28732867 { tableId : 't1' , rowId : 'r1' , cellId : 'c1' , cell : 'a' } ,
28742868 { tableId : 't1' , rowId : 'r1' , cellId : 'c2' , cell : 1 } ,
@@ -3405,3 +3399,201 @@ describe('callback granularity', () => {
34053399 } ) ;
34063400 } ) ;
34073401} ) ;
3402+
3403+ describe ( 'middleware not called during doRollback' , ( ) => {
3404+ let calls : Record < string , number > ;
3405+
3406+ const registerAllCallbacks = ( ) => {
3407+ calls = { } ;
3408+ middleware . addWillSetCellCallback ( ( _tId , _rId , _cId , cell ) => {
3409+ calls [ 'willSetCell' ] = ( calls [ 'willSetCell' ] ?? 0 ) + 1 ;
3410+ return cell ;
3411+ } ) ;
3412+ middleware . addWillSetValueCallback ( ( _vId , value ) => {
3413+ calls [ 'willSetValue' ] = ( calls [ 'willSetValue' ] ?? 0 ) + 1 ;
3414+ return value ;
3415+ } ) ;
3416+ middleware . addWillDelCellCallback ( ( ) => {
3417+ calls [ 'willDelCell' ] = ( calls [ 'willDelCell' ] ?? 0 ) + 1 ;
3418+ return true ;
3419+ } ) ;
3420+ middleware . addWillDelValueCallback ( ( ) => {
3421+ calls [ 'willDelValue' ] = ( calls [ 'willDelValue' ] ?? 0 ) + 1 ;
3422+ return true ;
3423+ } ) ;
3424+ } ;
3425+
3426+ test ( 'rolling back cell changes does not trigger middleware' , ( ) => {
3427+ store . setTables ( { t1 : { r1 : { c1 : 'a' } } } ) ;
3428+ registerAllCallbacks ( ) ;
3429+ store . transaction (
3430+ ( ) => {
3431+ store . setCell ( 't1' , 'r1' , 'c1' , 'b' ) ;
3432+ } ,
3433+ ( ) => true ,
3434+ ) ;
3435+
3436+ expect ( calls ) . toEqual ( { willSetCell : 1 } ) ;
3437+ expect ( store . getCell ( 't1' , 'r1' , 'c1' ) ) . toBe ( 'a' ) ;
3438+ } ) ;
3439+
3440+ test ( 'rolling back new cell does not trigger middleware' , ( ) => {
3441+ registerAllCallbacks ( ) ;
3442+ store . transaction (
3443+ ( ) => {
3444+ store . setCell ( 't1' , 'r1' , 'c1' , 'a' ) ;
3445+ } ,
3446+ ( ) => true ,
3447+ ) ;
3448+
3449+ expect ( calls ) . toEqual ( { willSetCell : 1 } ) ;
3450+ expect ( store . getTables ( ) ) . toEqual ( { } ) ;
3451+ } ) ;
3452+
3453+ test ( 'rolling back value changes does not trigger middleware' , ( ) => {
3454+ store . setValues ( { v1 : 'a' } ) ;
3455+ registerAllCallbacks ( ) ;
3456+ store . transaction (
3457+ ( ) => {
3458+ store . setValue ( 'v1' , 'b' ) ;
3459+ } ,
3460+ ( ) => true ,
3461+ ) ;
3462+ expect ( calls ) . toEqual ( { willSetValue : 1 } ) ;
3463+ expect ( store . getValue ( 'v1' ) ) . toBe ( 'a' ) ;
3464+ } ) ;
3465+
3466+ test ( 'rolling back new value does not trigger middleware' , ( ) => {
3467+ registerAllCallbacks ( ) ;
3468+ store . transaction (
3469+ ( ) => {
3470+ store . setValue ( 'v1' , 'a' ) ;
3471+ } ,
3472+ ( ) => true ,
3473+ ) ;
3474+ expect ( calls ) . toEqual ( { willSetValue : 1 } ) ;
3475+ expect ( store . getValues ( ) ) . toEqual ( { } ) ;
3476+ } ) ;
3477+
3478+ test ( 'rolling back cell deletion does not trigger middleware' , ( ) => {
3479+ store . setTables ( { t1 : { r1 : { c1 : 'a' , c2 : 'b' } } } ) ;
3480+ registerAllCallbacks ( ) ;
3481+ store . transaction (
3482+ ( ) => {
3483+ store . delCell ( 't1' , 'r1' , 'c2' ) ;
3484+ } ,
3485+ ( ) => true ,
3486+ ) ;
3487+ expect ( calls ) . toEqual ( { willDelCell : 1 } ) ;
3488+ expect ( store . getRow ( 't1' , 'r1' ) ) . toEqual ( { c1 : 'a' , c2 : 'b' } ) ;
3489+ } ) ;
3490+
3491+ test ( 'rolling back value deletion does not trigger middleware' , ( ) => {
3492+ store . setValues ( { v1 : 'a' , v2 : 'b' } ) ;
3493+ registerAllCallbacks ( ) ;
3494+ store . transaction (
3495+ ( ) => {
3496+ store . delValue ( 'v2' ) ;
3497+ } ,
3498+ ( ) => true ,
3499+ ) ;
3500+ expect ( calls ) . toEqual ( { willDelValue : 1 } ) ;
3501+ expect ( store . getValues ( ) ) . toEqual ( { v1 : 'a' , v2 : 'b' } ) ;
3502+ } ) ;
3503+ } ) ;
3504+
3505+ describe ( 'middleware not called during checkpoint undo/redo' , ( ) => {
3506+ let calls : Record < string , number > ;
3507+
3508+ const registerAllCallbacks = ( ) => {
3509+ calls = { } ;
3510+ middleware . addWillSetRowCallback ( ( _tId , _rId , row ) => {
3511+ calls [ 'willSetRow' ] = ( calls [ 'willSetRow' ] ?? 0 ) + 1 ;
3512+ return row ;
3513+ } ) ;
3514+ middleware . addWillSetCellCallback ( ( _tId , _rId , _cId , cell ) => {
3515+ calls [ 'willSetCell' ] = ( calls [ 'willSetCell' ] ?? 0 ) + 1 ;
3516+ return cell ;
3517+ } ) ;
3518+ middleware . addWillSetValueCallback ( ( _vId , value ) => {
3519+ calls [ 'willSetValue' ] = ( calls [ 'willSetValue' ] ?? 0 ) + 1 ;
3520+ return value ;
3521+ } ) ;
3522+ middleware . addWillDelCellCallback ( ( ) => {
3523+ calls [ 'willDelCell' ] = ( calls [ 'willDelCell' ] ?? 0 ) + 1 ;
3524+ return true ;
3525+ } ) ;
3526+ middleware . addWillDelValueCallback ( ( ) => {
3527+ calls [ 'willDelValue' ] = ( calls [ 'willDelValue' ] ?? 0 ) + 1 ;
3528+ return true ;
3529+ } ) ;
3530+ } ;
3531+
3532+ test ( 'undo does not trigger middleware' , ( ) => {
3533+ const checkpoints = createCheckpoints ( store ) ;
3534+ store . setTables ( { t1 : { r1 : { c1 : 'a' } } } ) ;
3535+ checkpoints . addCheckpoint ( 'initial' ) ;
3536+ registerAllCallbacks ( ) ;
3537+ store . setCell ( 't1' , 'r1' , 'c1' , 'b' ) ;
3538+ checkpoints . addCheckpoint ( 'changed' ) ;
3539+ expect ( calls ) . toEqual ( { willSetCell : 1 } ) ;
3540+ calls = { } ;
3541+ checkpoints . goBackward ( ) ;
3542+ expect ( calls ) . toEqual ( { } ) ;
3543+ expect ( store . getCell ( 't1' , 'r1' , 'c1' ) ) . toBe ( 'a' ) ;
3544+ } ) ;
3545+
3546+ test ( 'redo does not trigger middleware' , ( ) => {
3547+ const checkpoints = createCheckpoints ( store ) ;
3548+ store . setTables ( { t1 : { r1 : { c1 : 'a' } } } ) ;
3549+ checkpoints . addCheckpoint ( 'initial' ) ;
3550+ registerAllCallbacks ( ) ;
3551+ store . setCell ( 't1' , 'r1' , 'c1' , 'b' ) ;
3552+ checkpoints . addCheckpoint ( 'changed' ) ;
3553+ calls = { } ;
3554+ checkpoints . goBackward ( ) ;
3555+ checkpoints . goForward ( ) ;
3556+ expect ( calls ) . toEqual ( { } ) ;
3557+ expect ( store . getCell ( 't1' , 'r1' , 'c1' ) ) . toBe ( 'b' ) ;
3558+ } ) ;
3559+
3560+ test ( 'undo of new row does not trigger middleware' , ( ) => {
3561+ const checkpoints = createCheckpoints ( store ) ;
3562+ checkpoints . addCheckpoint ( 'empty' ) ;
3563+ registerAllCallbacks ( ) ;
3564+ store . setRow ( 't1' , 'r1' , { c1 : 'a' } ) ;
3565+ checkpoints . addCheckpoint ( 'added' ) ;
3566+ expect ( calls ) . toEqual ( { willSetRow : 1 , willSetCell : 1 } ) ;
3567+ calls = { } ;
3568+ checkpoints . goBackward ( ) ;
3569+ expect ( calls ) . toEqual ( { } ) ;
3570+ expect ( store . getTables ( ) ) . toEqual ( { } ) ;
3571+ } ) ;
3572+
3573+ test ( 'undo of value change does not trigger middleware' , ( ) => {
3574+ const checkpoints = createCheckpoints ( store ) ;
3575+ store . setValues ( { v1 : 'a' } ) ;
3576+ checkpoints . addCheckpoint ( 'initial' ) ;
3577+ registerAllCallbacks ( ) ;
3578+ store . setValue ( 'v1' , 'b' ) ;
3579+ checkpoints . addCheckpoint ( 'changed' ) ;
3580+ expect ( calls ) . toEqual ( { willSetValue : 1 } ) ;
3581+ calls = { } ;
3582+ checkpoints . goBackward ( ) ;
3583+ expect ( calls ) . toEqual ( { } ) ;
3584+ expect ( store . getValue ( 'v1' ) ) . toBe ( 'a' ) ;
3585+ } ) ;
3586+
3587+ test ( 'undo of new value does not trigger middleware' , ( ) => {
3588+ const checkpoints = createCheckpoints ( store ) ;
3589+ checkpoints . addCheckpoint ( 'empty' ) ;
3590+ registerAllCallbacks ( ) ;
3591+ store . setValue ( 'v1' , 'a' ) ;
3592+ checkpoints . addCheckpoint ( 'added' ) ;
3593+ expect ( calls ) . toEqual ( { willSetValue : 1 } ) ;
3594+ calls = { } ;
3595+ checkpoints . goBackward ( ) ;
3596+ expect ( calls ) . toEqual ( { } ) ;
3597+ expect ( store . getValues ( ) ) . toEqual ( { } ) ;
3598+ } ) ;
3599+ } ) ;
0 commit comments