@@ -170,6 +170,50 @@ void main() {
170170 await expectNoAssets ();
171171 });
172172
173+ test ('put then remove' , () async {
174+ await bucketStorage.saveSyncData (SyncDataBatch ([
175+ SyncBucketData (bucket: 'bucket1' , data: [putAsset1_3]),
176+ ]));
177+
178+ await syncLocalChecked (Checkpoint (lastOpId: '3' , checksums: [
179+ BucketChecksum (bucket: 'bucket1' , checksum: 3 ),
180+ ]));
181+
182+ await expectAsset1_3 ();
183+
184+ await bucketStorage.saveSyncData (SyncDataBatch ([
185+ SyncBucketData (bucket: 'bucket1' , data: [removeAsset1_5])
186+ ]));
187+
188+ await syncLocalChecked (Checkpoint (lastOpId: '5' , checksums: [
189+ BucketChecksum (bucket: 'bucket1' , checksum: 8 ),
190+ ]));
191+
192+ await expectNoAssets ();
193+ });
194+
195+ test ('blank remove' , () async {
196+ await bucketStorage.saveSyncData (SyncDataBatch ([
197+ SyncBucketData (bucket: 'bucket1' , data: [putAsset1_3, removeAsset1_4]),
198+ ]));
199+
200+ await syncLocalChecked (Checkpoint (lastOpId: '4' , checksums: [
201+ BucketChecksum (bucket: 'bucket1' , checksum: 7 ),
202+ ]));
203+
204+ await expectNoAssets ();
205+
206+ await bucketStorage.saveSyncData (SyncDataBatch ([
207+ SyncBucketData (bucket: 'bucket1' , data: [removeAsset1_5])
208+ ]));
209+
210+ await syncLocalChecked (Checkpoint (lastOpId: '5' , checksums: [
211+ BucketChecksum (bucket: 'bucket1' , checksum: 12 ),
212+ ]));
213+
214+ await expectNoAssets ();
215+ });
216+
173217 test ('should use subkeys' , () async {
174218 // subkeys cause this to be treated as a separate entity in the oplog,
175219 // but same entity in the local db.
@@ -313,23 +357,10 @@ void main() {
313357 await bucketStorage.saveSyncData (SyncDataBatch ([
314358 SyncBucketData (
315359 bucket: 'bucket1' ,
316- data: [
317- OplogEntry (
318- opId: '1' ,
319- op: OpType .move,
320- checksum: 1 ,
321- data: '{"target": "3"}' )
322- ],
360+ data: [OplogEntry (opId: '1' , op: OpType .move, checksum: 1 )],
323361 ),
324362 ]));
325363
326- // At this point, we have target: 3, but don't have that op yet, so we cannot sync.
327- final result = await bucketStorage.syncLocalDatabase (Checkpoint (
328- lastOpId: '2' ,
329- checksums: [BucketChecksum (bucket: 'bucket1' , checksum: 1 )]));
330- // Checksum passes, but we don't have a complete checkpoint
331- expect (result, equals (SyncLocalDatabaseResult (ready: false )));
332-
333364 await bucketStorage.saveSyncData (SyncDataBatch ([
334365 SyncBucketData (
335366 bucket: 'bucket1' ,
@@ -491,6 +522,99 @@ void main() {
491522 ]));
492523 });
493524
525+ test ('should compact with checksum wrapping' , () async {
526+ await bucketStorage.saveSyncData (SyncDataBatch ([
527+ SyncBucketData (bucket: 'bucket1' , data: [
528+ OplogEntry (
529+ opId: '1' ,
530+ op: OpType .put,
531+ rowType: 'assets' ,
532+ rowId: 'O1' ,
533+ data: '{"description": "b1"}' ,
534+ checksum: 2147483647 ),
535+ OplogEntry (
536+ opId: '2' ,
537+ op: OpType .put,
538+ rowType: 'assets' ,
539+ rowId: 'O1' ,
540+ data: '{"description": "b2"}' ,
541+ checksum: 2147483646 ),
542+ OplogEntry (
543+ opId: '3' ,
544+ op: OpType .put,
545+ rowType: 'assets' ,
546+ rowId: 'O1' ,
547+ data: '{"description": "b3"}' ,
548+ checksum: 2147483645 )
549+ ])
550+ ]));
551+
552+ await syncLocalChecked (Checkpoint (
553+ lastOpId: '4' ,
554+ writeCheckpoint: '4' ,
555+ checksums: [
556+ BucketChecksum (bucket: 'bucket1' , checksum: 2147483642 )
557+ ]));
558+
559+ await bucketStorage.forceCompact ();
560+
561+ await syncLocalChecked (Checkpoint (
562+ lastOpId: '4' ,
563+ writeCheckpoint: '4' ,
564+ checksums: [
565+ BucketChecksum (bucket: 'bucket1' , checksum: 2147483642 )
566+ ]));
567+
568+ final stats = await powersync.execute (
569+ 'SELECT row_type as type, row_id as id, count(*) as count FROM ps_oplog GROUP BY row_type, row_id ORDER BY row_type, row_id' );
570+ expect (
571+ stats,
572+ equals ([
573+ {'type' : 'assets' , 'id' : 'O1' , 'count' : 1 }
574+ ]));
575+ });
576+
577+ test ('should compact with checksum wrapping (2)' , () async {
578+ await bucketStorage.saveSyncData (SyncDataBatch ([
579+ SyncBucketData (bucket: 'bucket1' , data: [
580+ OplogEntry (
581+ opId: '1' ,
582+ op: OpType .put,
583+ rowType: 'assets' ,
584+ rowId: 'O1' ,
585+ data: '{"description": "b1"}' ,
586+ checksum: 2147483647 ),
587+ OplogEntry (
588+ opId: '2' ,
589+ op: OpType .put,
590+ rowType: 'assets' ,
591+ rowId: 'O1' ,
592+ data: '{"description": "b2"}' ,
593+ checksum: 2147483646 ),
594+ ])
595+ ]));
596+
597+ await syncLocalChecked (Checkpoint (
598+ lastOpId: '4' ,
599+ writeCheckpoint: '4' ,
600+ checksums: [BucketChecksum (bucket: 'bucket1' , checksum: - 3 )]));
601+
602+ await bucketStorage.forceCompact ();
603+
604+ await syncLocalChecked (Checkpoint (
605+ lastOpId: '4' ,
606+ writeCheckpoint: '4' ,
607+ checksums: [BucketChecksum (bucket: 'bucket1' , checksum: - 3 )]));
608+
609+ final stats = await powersync.execute (
610+ 'SELECT row_type as type, row_id as id, count(*) as count FROM ps_oplog GROUP BY row_type, row_id ORDER BY row_type, row_id' );
611+ expect (
612+ stats,
613+ equals ([
614+ {'type' : 'assets' , 'id' : 'O1' , 'count' : 1 }
615+ ]));
616+ });
617+
494618 test ('should not sync local db with pending crud - server removed' ,
495619 () async {
496620 await bucketStorage.saveSyncData (SyncDataBatch ([
0 commit comments