import 'package:idb_shim/idb_client.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/ci_string.dart'; import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/object_extension.dart'; class DbCompatV5 { static Future isNeedMigration(AppDb appDb) async { final dbItem = await appDb.use( (db) => db.transaction(AppDb.metaStoreName, idbModeReadOnly), (transaction) async { final metaStore = transaction.objectStore(AppDb.metaStoreName); return await metaStore.getObject(AppDbMetaEntryDbCompatV5.key) as Map?; }, ); if (dbItem == null) { return false; } try { final dbEntry = AppDbMetaEntry.fromJson(dbItem.cast()); final compatV35 = AppDbMetaEntryDbCompatV5.fromJson(dbEntry.obj); return !compatV35.isMigrated; } catch (e, stackTrace) { _log.shout("[isNeedMigration] Failed", e, stackTrace); return true; } } static Future migrate(AppDb appDb) async { _log.info("[migrate] Migrate AppDb"); try { await appDb.use( (db) => db.transaction( [AppDb.file2StoreName, AppDb.metaStoreName], idbModeReadWrite), (transaction) async { try { final fileStore = transaction.objectStore(AppDb.file2StoreName); await for (final c in fileStore.openCursor()) { final item = c.value as Map; // migrate file entry: add bestDateTime final fileEntry = item.cast().run((json) { final f = File.fromJson(json["file"].cast()); return AppDbFile2Entry( json["server"], (json["userId"] as String).toCi(), json["strippedPath"], f.bestDateTime.millisecondsSinceEpoch, File.fromJson(json["file"].cast()), ); }); await c.update(fileEntry.toJson()); c.next(); } final metaStore = transaction.objectStore(AppDb.metaStoreName); await metaStore .put(const AppDbMetaEntryDbCompatV5(true).toEntry().toJson()); } catch (_) { transaction.abort(); rethrow; } }, ); } catch (e, stackTrace) { _log.shout( "[migrate] Failed while migrating, drop db instead", e, stackTrace); await appDb.delete(); rethrow; } } static final _log = Logger("use_case.db_compat.v5.DbCompatV5"); }