From 849a4886f70d60a1eed0a8cfb988fbbd5fc3ac80 Mon Sep 17 00:00:00 2001 From: Santo Shakil Date: Wed, 5 Aug 2026 18:55:17 +0600 Subject: [PATCH] simplify the created date pick and rework the migration test --- .../alextran/immich/sync/MessagesImplBase.kt | 8 +- mobile/test/medium/repository_context.dart | 2 + mobile/test/modules/utils/migration_test.dart | 124 ++++++------------ 3 files changed, 44 insertions(+), 90 deletions(-) diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/MessagesImplBase.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/MessagesImplBase.kt index 450f748156..d6d8e2283d 100644 --- a/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/MessagesImplBase.kt +++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/MessagesImplBase.kt @@ -176,15 +176,11 @@ open class NativeSyncApiImplBase(context: Context) : ImmichPlugin(), ActivityAwa else -> 0L } // Date taken is in ms; added/modified are in seconds, and modified can be 0 when unset. - // No-EXIF assets use the earliest positive added/modified date, or raw added if neither is positive. + // If EXIF date taken exists use it, else if modified is empty use added, else the earliest of the two. val modifiedAt = c.getLong(dateModifiedColumn) val addedAt = c.getLong(dateAddedColumn) val createdAt = (c.getLong(dateTakenColumn).takeIf { it > 0 }?.div(1000)) - ?: when { - modifiedAt <= 0 -> addedAt - addedAt <= 0 -> modifiedAt - else -> minOf(modifiedAt, addedAt) - } + ?: if (modifiedAt <= 0) addedAt else minOf(modifiedAt, addedAt) val width = c.getInt(widthColumn).toLong() val height = c.getInt(heightColumn).toLong() // Duration is milliseconds diff --git a/mobile/test/medium/repository_context.dart b/mobile/test/medium/repository_context.dart index 09b8e2c7eb..494de75808 100644 --- a/mobile/test/medium/repository_context.dart +++ b/mobile/test/medium/repository_context.dart @@ -313,6 +313,7 @@ class MediumRepositoryContext { TrashOrigin? source, AssetType? type, DateTime? createdAt, + DateTime? updatedAt, bool? isFavorite, }) async { id ??= TestUtils.uuid(); @@ -328,6 +329,7 @@ class MediumRepositoryContext { source: .new(source ?? TrashOrigin.remoteSync), isFavorite: .new(isFavorite ?? false), createdAt: .new(TestUtils.date(createdAt)), + updatedAt: .new(TestUtils.date(updatedAt)), ), ); } diff --git a/mobile/test/modules/utils/migration_test.dart b/mobile/test/modules/utils/migration_test.dart index fb7999d5c2..dba05dff5f 100644 --- a/mobile/test/modules/utils/migration_test.dart +++ b/mobile/test/modules/utils/migration_test.dart @@ -1,65 +1,49 @@ -import 'package:drift/drift.dart' as drift; -import 'package:drift/native.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/domain/services/store.service.dart'; import 'package:immich_mobile/entities/store.entity.dart'; -import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart'; import 'package:immich_mobile/infrastructure/entities/trashed_local_asset.entity.dart'; -import 'package:immich_mobile/infrastructure/entities/trashed_local_asset.entity.drift.dart'; -import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/store.repository.dart'; import 'package:immich_mobile/utils/migration.dart'; +import '../../medium/repository_context.dart'; + void main() { TestWidgetsFlutterBinding.ensureInitialized(); - late Drift db; - late DriftStoreRepository storeRepository; + late MediumRepositoryContext ctx; setUpAll(() async { debugDefaultTargetPlatformOverride = TargetPlatform.android; - db = Drift(drift.DatabaseConnection(NativeDatabase.memory(), closeStreamsSynchronously: true)); - storeRepository = DriftStoreRepository(db); - await StoreService.init(storeRepository: storeRepository, listenUpdates: false); + ctx = MediumRepositoryContext(); + await StoreService.init(storeRepository: DriftStoreRepository(ctx.db), listenUpdates: false); }); setUp(() async { await Store.clear(); - await db.delete(db.localAssetEntity).go(); - await db.delete(db.trashedLocalAssetEntity).go(); - await db.customStatement('DROP TRIGGER IF EXISTS fail_migration'); + await ctx.db.delete(ctx.db.localAssetEntity).go(); + await ctx.db.delete(ctx.db.trashedLocalAssetEntity).go(); + await ctx.db.customStatement('DROP TRIGGER IF EXISTS fail_migration'); }); tearDownAll(() async { debugDefaultTargetPlatformOverride = null; await Store.clear(); - await db.close(); + await ctx.dispose(); }); test('stores version 26 when migration 27 fails', () async { await Store.put(StoreKey.version, 25); - await db - .into(db.localAssetEntity) - .insert( - LocalAssetEntityCompanion.insert( - id: 'asset', - name: 'asset.jpg', - type: AssetType.image, - createdAt: drift.Value(DateTime(2026)), - updatedAt: drift.Value(DateTime(2025)), - ), - ); - await db.customStatement( + await ctx.newLocalAsset(id: 'asset', createdAt: DateTime(2026), updatedAt: DateTime(2025)); + await ctx.db.customStatement( "CREATE TRIGGER fail_migration BEFORE UPDATE OF created_at ON local_asset_entity " "BEGIN SELECT RAISE(FAIL, 'migration failed'); END", ); - await migrateDatabaseIfNeeded(db); + await migrateDatabaseIfNeeded(ctx.db); - expect(await storeRepository.tryGet(StoreKey.version), 26); + expect(Store.tryGet(StoreKey.version), 26); }); test('fixes dates in active and trashed assets', () async { @@ -67,67 +51,39 @@ void main() { final updatedAt = DateTime(2025); final epoch = DateTime.fromMillisecondsSinceEpoch(0); await Store.put(StoreKey.version, 26); - await db - .into(db.localAssetEntity) - .insert( - LocalAssetEntityCompanion.insert( - id: 'local', - name: 'local.jpg', - type: AssetType.image, - createdAt: drift.Value(createdAt), - updatedAt: drift.Value(updatedAt), - ), - ); - await db - .into(db.localAssetEntity) - .insert( - LocalAssetEntityCompanion.insert( - id: 'epoch', - name: 'epoch.jpg', - type: AssetType.image, - createdAt: drift.Value(createdAt), - updatedAt: drift.Value(epoch), - ), - ); - await db - .into(db.trashedLocalAssetEntity) - .insert( - TrashedLocalAssetEntityCompanion.insert( - id: 'trashed', - albumId: 'album', - name: 'trashed.jpg', - type: AssetType.image, - createdAt: drift.Value(createdAt), - updatedAt: drift.Value(updatedAt), - source: TrashOrigin.localSync, - ), - ); - await db - .into(db.trashedLocalAssetEntity) - .insert( - TrashedLocalAssetEntityCompanion.insert( - id: 'trashed-epoch', - albumId: 'album', - name: 'trashed-epoch.jpg', - type: AssetType.image, - createdAt: drift.Value(createdAt), - updatedAt: drift.Value(epoch), - source: TrashOrigin.localSync, - ), - ); + await ctx.newLocalAsset(id: 'local', createdAt: createdAt, updatedAt: updatedAt); + await ctx.newLocalAsset(id: 'epoch', createdAt: createdAt, updatedAt: epoch); + await ctx.newTrashedLocalAsset( + id: 'trashed', + albumId: 'album', + createdAt: createdAt, + updatedAt: updatedAt, + source: TrashOrigin.localSync, + ); + await ctx.newTrashedLocalAsset( + id: 'trashed-epoch', + albumId: 'album', + createdAt: createdAt, + updatedAt: epoch, + source: TrashOrigin.localSync, + ); - await migrateDatabaseIfNeeded(db); + await migrateDatabaseIfNeeded(ctx.db); - final local = await (db.select(db.localAssetEntity)..where((row) => row.id.equals('local'))).getSingle(); - final unchanged = await (db.select(db.localAssetEntity)..where((row) => row.id.equals('epoch'))).getSingle(); - final trashed = await (db.select(db.trashedLocalAssetEntity)..where((row) => row.id.equals('trashed'))).getSingle(); - final trashedUnchanged = await (db.select( - db.trashedLocalAssetEntity, + final local = await (ctx.db.select(ctx.db.localAssetEntity)..where((row) => row.id.equals('local'))).getSingle(); + final unchanged = await (ctx.db.select( + ctx.db.localAssetEntity, + )..where((row) => row.id.equals('epoch'))).getSingle(); + final trashed = await (ctx.db.select( + ctx.db.trashedLocalAssetEntity, + )..where((row) => row.id.equals('trashed'))).getSingle(); + final trashedUnchanged = await (ctx.db.select( + ctx.db.trashedLocalAssetEntity, )..where((row) => row.id.equals('trashed-epoch'))).getSingle(); expect(local.createdAt, updatedAt); expect(unchanged.createdAt, createdAt); expect(trashed.createdAt, updatedAt); expect(trashedUnchanged.createdAt, createdAt); - expect(await storeRepository.tryGet(StoreKey.version), 27); + expect(Store.tryGet(StoreKey.version), 27); }); }