Skip to content

Commit 0778b06

Browse files
authored
Merge pull request #39 from powersync-ja/fix-reverting-deletes
Fix reverting failed deletes
2 parents f320401 + 71613af commit 0778b06

File tree

2 files changed

+122
-0
lines changed

2 files changed

+122
-0
lines changed

packages/powersync/lib/src/schema_logic.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@ FOR EACH ROW
5353
BEGIN
5454
DELETE FROM $internalNameE WHERE id = OLD.id;
5555
INSERT INTO ps_crud(tx_id, data) SELECT current_tx, json_object('op', 'DELETE', 'type', ${quoteString(type)}, 'id', OLD.id) FROM ps_tx WHERE id = 1;
56+
INSERT INTO ps_oplog(bucket, op_id, op, row_type, row_id, hash, superseded)
57+
SELECT '\$local',
58+
1,
59+
'REMOVE',
60+
${quoteString(type)},
61+
OLD.id,
62+
0,
63+
0;
64+
INSERT OR REPLACE INTO ps_buckets(name, pending_delete, last_op, target_op) VALUES('\$local', 1, 0, $maxOpId);
5665
END""",
5766
"""
5867
CREATE TRIGGER ${quoteIdentifier('ps_view_insert_$viewName')}

packages/powersync/test/bucket_storage_test.dart

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,5 +674,118 @@ void main() {
674674
{'description': 'server updated'}
675675
]));
676676
});
677+
678+
test('should revert a failing update', () async {
679+
await bucketStorage.saveSyncData(SyncDataBatch([
680+
SyncBucketData(
681+
bucket: 'bucket1',
682+
data: [putAsset1_1, putAsset2_2, putAsset1_3],
683+
),
684+
]));
685+
686+
await syncLocalChecked(Checkpoint(
687+
lastOpId: '3',
688+
writeCheckpoint: '3',
689+
checksums: [BucketChecksum(bucket: 'bucket1', checksum: 6)]));
690+
691+
// Local save
692+
db.execute('INSERT INTO assets(id, description) VALUES(?, ?)',
693+
['O3', 'inserted']);
694+
final batch = bucketStorage.getCrudBatch();
695+
await batch!.complete();
696+
await bucketStorage.updateLocalTarget(() async {
697+
return '4';
698+
});
699+
700+
expect(
701+
db.select('SELECT description FROM assets WHERE id = \'O3\''),
702+
equals([
703+
{'description': 'inserted'}
704+
]));
705+
706+
await syncLocalChecked(Checkpoint(
707+
lastOpId: '3',
708+
writeCheckpoint: '4',
709+
checksums: [BucketChecksum(bucket: 'bucket1', checksum: 6)]));
710+
711+
expect(db.select('SELECT description FROM assets WHERE id = \'O3\''),
712+
equals([]));
713+
});
714+
715+
test('should revert a failing delete', () async {
716+
await bucketStorage.saveSyncData(SyncDataBatch([
717+
SyncBucketData(
718+
bucket: 'bucket1',
719+
data: [putAsset1_1, putAsset2_2, putAsset1_3],
720+
),
721+
]));
722+
723+
await syncLocalChecked(Checkpoint(
724+
lastOpId: '3',
725+
writeCheckpoint: '3',
726+
checksums: [BucketChecksum(bucket: 'bucket1', checksum: 6)]));
727+
728+
// Local save
729+
db.execute('DELETE FROM assets WHERE id = ?', ['O2']);
730+
731+
expect(db.select('SELECT description FROM assets WHERE id = \'O2\''),
732+
equals([]));
733+
// Simulate a permissions error when uploading - data should be preserved.
734+
final batch = bucketStorage.getCrudBatch();
735+
await batch!.complete();
736+
737+
await bucketStorage.updateLocalTarget(() async {
738+
return '4';
739+
});
740+
741+
await syncLocalChecked(Checkpoint(
742+
lastOpId: '3',
743+
writeCheckpoint: '4',
744+
checksums: [BucketChecksum(bucket: 'bucket1', checksum: 6)]));
745+
746+
expect(
747+
db.select('SELECT description FROM assets WHERE id = \'O2\''),
748+
equals([
749+
{'description': 'bar'}
750+
]));
751+
});
752+
753+
test('should revert a failing insert', () async {
754+
await bucketStorage.saveSyncData(SyncDataBatch([
755+
SyncBucketData(
756+
bucket: 'bucket1',
757+
data: [putAsset1_1, putAsset2_2, putAsset1_3],
758+
),
759+
]));
760+
761+
await syncLocalChecked(Checkpoint(
762+
lastOpId: '3',
763+
writeCheckpoint: '3',
764+
checksums: [BucketChecksum(bucket: 'bucket1', checksum: 6)]));
765+
766+
// Local save
767+
db.execute('DELETE FROM assets WHERE id = ?', ['O2']);
768+
769+
expect(db.select('SELECT description FROM assets WHERE id = \'O2\''),
770+
equals([]));
771+
// Simulate a permissions error when uploading - data should be preserved.
772+
final batch = bucketStorage.getCrudBatch();
773+
await batch!.complete();
774+
775+
await bucketStorage.updateLocalTarget(() async {
776+
return '4';
777+
});
778+
779+
await syncLocalChecked(Checkpoint(
780+
lastOpId: '3',
781+
writeCheckpoint: '4',
782+
checksums: [BucketChecksum(bucket: 'bucket1', checksum: 6)]));
783+
784+
expect(
785+
db.select('SELECT description FROM assets WHERE id = \'O2\''),
786+
equals([
787+
{'description': 'bar'}
788+
]));
789+
});
677790
});
678791
}

0 commit comments

Comments
 (0)