From 44ec7744ba6d82f5f2f99484d57e90cd3fc50226 Mon Sep 17 00:00:00 2001 From: Peter Ombodi Date: Mon, 6 Oct 2025 18:28:31 +0300 Subject: [PATCH] reuse exist checksums on trash data update handle restoration errors fix import --- .../domain/services/local_sync.service.dart | 11 +++++-- .../trashed_local_asset.repository.dart | 32 +++++++++++++++---- mobile/test/fixtures/asset.stub.dart | 1 - 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/mobile/lib/domain/services/local_sync.service.dart b/mobile/lib/domain/services/local_sync.service.dart index b522fa423f..579eba15d4 100644 --- a/mobile/lib/domain/services/local_sync.service.dart +++ b/mobile/lib/domain/services/local_sync.service.dart @@ -300,7 +300,6 @@ class LocalSyncService { return Future.value(); } final trashedAssets = []; - //todo try to reuse exist checksums from local assets table before they updated for (final update in trashUpdates) { final albums = delta.assetAlbums.cast>(); for (final String id in albums[update.id]!.cast().nonNulls) { @@ -329,13 +328,19 @@ class LocalSyncService { Future _applyRemoteRestoreToLocal() async { final remoteAssetsToRestore = await _trashedLocalAssetRepository.getToRestore(); + final toRestoreIds = []; if (remoteAssetsToRestore.isNotEmpty) { _log.info("remoteAssetsToRestore: $remoteAssetsToRestore"); for (final asset in remoteAssetsToRestore) { _log.info("Restoring from trash, localId: ${asset.id}, remoteId: ${asset.checksum}"); - await _localFilesManager.restoreFromTrashById(asset.id, asset.type.index); + try { + await _localFilesManager.restoreFromTrashById(asset.id, asset.type.index); + toRestoreIds.add(asset.id); + } catch (e) { + _log.warning("Restoring failure: $e"); + } } - await _trashedLocalAssetRepository.restoreLocalAssets(remoteAssetsToRestore.map((e) => e.id)); + await _trashedLocalAssetRepository.restoreLocalAssets(toRestoreIds); } else { _log.info("No remote assets found for restoration"); } diff --git a/mobile/lib/infrastructure/repositories/trashed_local_asset.repository.dart b/mobile/lib/infrastructure/repositories/trashed_local_asset.repository.dart index 47d8fe2042..ab5cb4e4da 100644 --- a/mobile/lib/infrastructure/repositories/trashed_local_asset.repository.dart +++ b/mobile/lib/infrastructure/repositories/trashed_local_asset.repository.dart @@ -63,14 +63,15 @@ class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository { await _db.delete(_db.trashedLocalAssetEntity).go(); return; } - + Map localChecksumById = await _getCachedChecksums(assets); return _db.transaction(() async { await _db.batch((batch) { for (final asset in assets) { + final effectiveChecksum = localChecksumById[asset.id] ?? asset.checksum; final companion = TrashedLocalAssetEntityCompanion.insert( id: asset.id, albumId: albumId, - checksum: asset.checksum == null ? const Value.absent() : Value(asset.checksum), + checksum: effectiveChecksum == null ? const Value.absent() : Value(effectiveChecksum), name: asset.name, type: asset.type, createdAt: Value(asset.createdAt), @@ -109,19 +110,22 @@ class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository { }); } - Future saveTrashedAssets(Iterable trashUpdates) async { - if (trashUpdates.isEmpty) { + Future saveTrashedAssets(Iterable assets) async { + if (assets.isEmpty) { return; } + Map localChecksumById = await _getCachedChecksums(assets); + await _db.batch((batch) { - for (final asset in trashUpdates) { + for (final asset in assets) { + final effectiveChecksum = localChecksumById[asset.id] ?? asset.checksum; final companion = TrashedLocalAssetEntityCompanion.insert( id: asset.id, albumId: asset.albumId, name: asset.name, type: asset.type, - checksum: asset.checksum == null ? const Value.absent() : Value(asset.checksum), + checksum: effectiveChecksum == null ? const Value.absent() : Value(effectiveChecksum), createdAt: Value(asset.createdAt), width: Value(asset.width), height: Value(asset.height), @@ -175,6 +179,8 @@ class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository { durationInSeconds: Value(asset.durationInSeconds), isFavorite: Value(asset.isFavorite), orientation: Value(asset.orientation), + createdAt: Value(asset.createdAt), + updatedAt: Value(asset.updatedAt), ), ); } @@ -229,4 +235,18 @@ class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository { }); }); } + + //attempt to reuse existing checksums + Future> _getCachedChecksums(Iterable trashUpdates) async { + final ids = trashUpdates.map((e) => e.id).toSet(); + final rows = await (_db.selectOnly(_db.localAssetEntity) + ..where(_db.localAssetEntity.id.isIn(ids) & _db.localAssetEntity.checksum.isNotNull()) + ..addColumns([_db.localAssetEntity.id, _db.localAssetEntity.checksum])) + .get(); + + final localChecksumById = { + for (final r in rows) r.read(_db.localAssetEntity.id)!: r.read(_db.localAssetEntity.checksum)! + }; + return localChecksumById; + } } diff --git a/mobile/test/fixtures/asset.stub.dart b/mobile/test/fixtures/asset.stub.dart index 507c9da689..8d92011999 100644 --- a/mobile/test/fixtures/asset.stub.dart +++ b/mobile/test/fixtures/asset.stub.dart @@ -1,5 +1,4 @@ import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; -import 'package:immich_mobile/domain/models/asset/trashed_asset.model.dart'; import 'package:immich_mobile/domain/models/exif.model.dart'; import 'package:immich_mobile/entities/asset.entity.dart' as old;