mirror of
https://github.com/immich-app/immich
synced 2026-08-22 13:13:05 +00:00
run the dedupe deletes before the inserts and keep only the last duplicate per payload
This commit is contained in:
parent
037b6238f2
commit
c32426240c
2 changed files with 44 additions and 3 deletions
|
|
@ -198,9 +198,15 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||
Future<void> updateAssetsV1(Iterable<SyncAssetV1> data, {String debugLabel = 'user'}) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
// Keep only the last asset per partial-index key; server order is authoritative
|
||||
final deduped = <(String, String, String?), SyncAssetV1>{};
|
||||
for (final asset in data) {
|
||||
// Avoid SqliteException(2067) when server re-issues a new id for
|
||||
// the same (ownerId, checksum). #22522 #27186
|
||||
deduped[(asset.ownerId, asset.checksum, asset.libraryId)] = asset;
|
||||
}
|
||||
|
||||
// Avoid SqliteException(2067) when server re-issues a new id for
|
||||
// the same (ownerId, checksum). #22522 #27186
|
||||
for (final asset in deduped.values) {
|
||||
_enqueueRemoteAssetDedupe(
|
||||
batch,
|
||||
id: asset.id,
|
||||
|
|
@ -208,7 +214,9 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||
checksum: asset.checksum,
|
||||
libraryId: asset.libraryId,
|
||||
);
|
||||
}
|
||||
|
||||
for (final asset in deduped.values) {
|
||||
final companion = RemoteAssetEntityCompanion(
|
||||
name: Value(asset.originalFileName),
|
||||
type: Value(asset.type.toAssetType()),
|
||||
|
|
@ -247,8 +255,14 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||
Future<void> updateAssetsV2(Iterable<SyncAssetV2> data, {String debugLabel = 'user'}) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
// Keep only the last asset per partial-index key; server order is authoritative
|
||||
final deduped = <(String, String, String?), SyncAssetV2>{};
|
||||
for (final asset in data) {
|
||||
// See updateAssetsV1 for why this dedupe is required. #22522 #27186
|
||||
deduped[(asset.ownerId, asset.checksum, asset.libraryId)] = asset;
|
||||
}
|
||||
|
||||
// See updateAssetsV1 for why this dedupe is required. #22522 #27186
|
||||
for (final asset in deduped.values) {
|
||||
_enqueueRemoteAssetDedupe(
|
||||
batch,
|
||||
id: asset.id,
|
||||
|
|
@ -256,7 +270,9 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||
checksum: asset.checksum,
|
||||
libraryId: asset.libraryId,
|
||||
);
|
||||
}
|
||||
|
||||
for (final asset in deduped.values) {
|
||||
final companion = RemoteAssetEntityCompanion(
|
||||
name: Value(asset.originalFileName),
|
||||
type: Value(asset.type.toAssetType()),
|
||||
|
|
|
|||
|
|
@ -349,5 +349,30 @@ void main() {
|
|||
expect(rows, hasLength(1));
|
||||
expect(rows.single.id, equals('new-id'));
|
||||
});
|
||||
|
||||
test('one payload with duplicate (ownerId, checksum) and null library keeps the last asset', () async {
|
||||
await sut.updateUsersV1([_createUser()]);
|
||||
await sut.updateAssetsV1([
|
||||
_createAsset(id: 'first-id', checksum: 'AAA', fileName: 'photo.jpg'),
|
||||
_createAsset(id: 'last-id', checksum: 'AAA', fileName: 'photo.jpg'),
|
||||
]);
|
||||
|
||||
final rows = await db.remoteAssetEntity.select().get();
|
||||
expect(rows, hasLength(1));
|
||||
expect(rows.single.id, equals('last-id'));
|
||||
});
|
||||
|
||||
test('one payload with duplicate (ownerId, libraryId, checksum) keeps the last asset', () async {
|
||||
await sut.updateUsersV1([_createUser()]);
|
||||
await sut.updateAssetsV1([
|
||||
_createAsset(id: 'first-id', checksum: 'AAA', fileName: 'photo.jpg', libraryId: 'lib-1'),
|
||||
_createAsset(id: 'last-id', checksum: 'AAA', fileName: 'photo.jpg', libraryId: 'lib-1'),
|
||||
]);
|
||||
|
||||
final rows = await db.remoteAssetEntity.select().get();
|
||||
expect(rows, hasLength(1));
|
||||
expect(rows.single.id, equals('last-id'));
|
||||
expect(rows.single.libraryId, equals('lib-1'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue