2025-02-20 00:35:24 +05:30
|
|
|
import 'dart:async';
|
|
|
|
|
|
2025-04-02 19:28:17 +05:30
|
|
|
import 'package:drift/drift.dart';
|
|
|
|
|
import 'package:drift_flutter/drift_flutter.dart';
|
2025-07-17 21:42:29 +05:30
|
|
|
import 'package:flutter/foundation.dart';
|
2025-02-20 00:35:24 +05:30
|
|
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
2025-06-03 21:31:50 +05:30
|
|
|
import 'package:immich_mobile/infrastructure/entities/exif.entity.dart';
|
2025-05-29 21:12:00 +05:30
|
|
|
import 'package:immich_mobile/infrastructure/entities/local_album.entity.dart';
|
|
|
|
|
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.dart';
|
|
|
|
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
2025-07-02 14:18:37 -05:00
|
|
|
import 'package:immich_mobile/infrastructure/entities/memory.entity.dart';
|
|
|
|
|
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.dart';
|
2025-06-09 23:09:14 +08:00
|
|
|
import 'package:immich_mobile/infrastructure/entities/partner.entity.dart';
|
2025-07-18 22:21:39 +08:00
|
|
|
import 'package:immich_mobile/infrastructure/entities/person.entity.dart';
|
2025-06-26 19:20:39 +05:30
|
|
|
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.dart';
|
|
|
|
|
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.dart';
|
|
|
|
|
import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.dart';
|
2025-06-13 11:15:39 -05:00
|
|
|
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
|
2025-07-07 11:01:09 +08:00
|
|
|
import 'package:immich_mobile/infrastructure/entities/stack.entity.dart';
|
2025-04-02 19:28:17 +05:30
|
|
|
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
|
|
|
|
|
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.dart';
|
2025-07-17 21:42:29 +05:30
|
|
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.steps.dart';
|
2025-02-20 00:35:24 +05:30
|
|
|
import 'package:isar/isar.dart';
|
|
|
|
|
|
2025-04-02 19:28:17 +05:30
|
|
|
import 'db.repository.drift.dart';
|
|
|
|
|
|
2025-02-20 00:35:24 +05:30
|
|
|
// #zoneTxn is the symbol used by Isar to mark a transaction within the current zone
|
|
|
|
|
// ref: isar/isar_common.dart
|
|
|
|
|
const Symbol _kzoneTxn = #zoneTxn;
|
|
|
|
|
|
|
|
|
|
class IsarDatabaseRepository implements IDatabaseRepository {
|
|
|
|
|
final Isar _db;
|
|
|
|
|
const IsarDatabaseRepository(Isar db) : _db = db;
|
|
|
|
|
|
|
|
|
|
// Isar do not support nested transactions. This is a workaround to prevent us from making nested transactions
|
|
|
|
|
// Reuse the current transaction if it is already active, else start a new transaction
|
|
|
|
|
@override
|
|
|
|
|
Future<T> transaction<T>(Future<T> Function() callback) =>
|
|
|
|
|
Zone.current[_kzoneTxn] == null ? _db.writeTxn(callback) : callback();
|
|
|
|
|
}
|
2025-04-02 19:28:17 +05:30
|
|
|
|
2025-05-29 21:12:00 +05:30
|
|
|
@DriftDatabase(
|
|
|
|
|
tables: [
|
|
|
|
|
UserEntity,
|
|
|
|
|
UserMetadataEntity,
|
|
|
|
|
PartnerEntity,
|
|
|
|
|
LocalAlbumEntity,
|
|
|
|
|
LocalAssetEntity,
|
|
|
|
|
LocalAlbumAssetEntity,
|
2025-06-09 23:09:14 +08:00
|
|
|
RemoteAssetEntity,
|
2025-06-13 11:15:39 -05:00
|
|
|
RemoteExifEntity,
|
2025-06-26 19:20:39 +05:30
|
|
|
RemoteAlbumEntity,
|
|
|
|
|
RemoteAlbumAssetEntity,
|
|
|
|
|
RemoteAlbumUserEntity,
|
2025-07-02 14:18:37 -05:00
|
|
|
MemoryEntity,
|
|
|
|
|
MemoryAssetEntity,
|
2025-07-07 11:01:09 +08:00
|
|
|
StackEntity,
|
2025-07-18 22:21:39 +08:00
|
|
|
PersonEntity,
|
2025-05-29 21:12:00 +05:30
|
|
|
],
|
2025-06-16 20:37:45 +05:30
|
|
|
include: {
|
|
|
|
|
'package:immich_mobile/infrastructure/entities/merged_asset.drift',
|
|
|
|
|
},
|
2025-05-29 21:12:00 +05:30
|
|
|
)
|
2025-04-02 19:28:17 +05:30
|
|
|
class Drift extends $Drift implements IDatabaseRepository {
|
|
|
|
|
Drift([QueryExecutor? executor])
|
|
|
|
|
: super(
|
|
|
|
|
executor ??
|
|
|
|
|
driftDatabase(
|
|
|
|
|
name: 'immich',
|
|
|
|
|
native: const DriftNativeOptions(shareAcrossIsolates: true),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
@override
|
2025-07-22 01:50:41 +05:30
|
|
|
int get schemaVersion => 3;
|
2025-04-02 19:28:17 +05:30
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
MigrationStrategy get migration => MigrationStrategy(
|
2025-07-17 21:42:29 +05:30
|
|
|
onUpgrade: (m, from, to) async {
|
|
|
|
|
// Run migration steps without foreign keys and re-enable them later
|
|
|
|
|
await customStatement('PRAGMA foreign_keys = OFF');
|
|
|
|
|
|
|
|
|
|
await m.runMigrationSteps(
|
|
|
|
|
from: from,
|
|
|
|
|
to: to,
|
|
|
|
|
steps: migrationSteps(
|
2025-07-22 01:50:41 +05:30
|
|
|
from1To2: (m, v2) async {
|
|
|
|
|
for (final entity in v2.entities) {
|
2025-07-17 21:42:29 +05:30
|
|
|
await m.drop(entity);
|
|
|
|
|
await m.create(entity);
|
|
|
|
|
}
|
|
|
|
|
},
|
2025-07-22 01:50:41 +05:30
|
|
|
from2To3: (m, v3) async {
|
|
|
|
|
// Removed foreign key constraint on stack.primaryAssetId
|
|
|
|
|
await m.alterTable(TableMigration(v3.stackEntity));
|
|
|
|
|
},
|
2025-07-17 21:42:29 +05:30
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (kDebugMode) {
|
|
|
|
|
// Fail if the migration broke foreign keys
|
|
|
|
|
final wrongFKs =
|
|
|
|
|
await customSelect('PRAGMA foreign_key_check').get();
|
|
|
|
|
assert(wrongFKs.isEmpty, '${wrongFKs.map((e) => e.data)}');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await customStatement('PRAGMA foreign_keys = ON;');
|
|
|
|
|
},
|
2025-04-02 19:28:17 +05:30
|
|
|
beforeOpen: (details) async {
|
|
|
|
|
await customStatement('PRAGMA foreign_keys = ON');
|
2025-05-29 21:12:00 +05:30
|
|
|
await customStatement('PRAGMA synchronous = NORMAL');
|
|
|
|
|
await customStatement('PRAGMA journal_mode = WAL');
|
2025-04-02 19:28:17 +05:30
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class DriftDatabaseRepository implements IDatabaseRepository {
|
|
|
|
|
final Drift _db;
|
|
|
|
|
const DriftDatabaseRepository(this._db);
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Future<T> transaction<T>(Future<T> Function() callback) =>
|
|
|
|
|
_db.transaction(callback);
|
|
|
|
|
}
|