You've already forked immich
mirror of
https://github.com/immich-app/immich.git
synced 2025-08-08 23:07:06 +02:00
refactor(mobile): DB repository for asset, backup, sync service (#12953)
* refactor(mobile): DB repository for asset, backup, sync service * review feedback * fix bug found by Alex --------- Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
committed by
GitHub
parent
a2d457b01d
commit
15c04d3056
@ -5,78 +5,145 @@ import 'package:immich_mobile/entities/album.entity.dart';
|
||||
import 'package:immich_mobile/entities/android_device_asset.entity.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/entities/device_asset.entity.dart';
|
||||
import 'package:immich_mobile/entities/duplicated_asset.entity.dart';
|
||||
import 'package:immich_mobile/entities/exif_info.entity.dart';
|
||||
import 'package:immich_mobile/entities/ios_device_asset.entity.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/interfaces/asset.interface.dart';
|
||||
import 'package:immich_mobile/providers/db.provider.dart';
|
||||
import 'package:immich_mobile/repositories/database.repository.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
final assetRepositoryProvider =
|
||||
Provider((ref) => AssetRepository(ref.watch(dbProvider)));
|
||||
|
||||
class AssetRepository implements IAssetRepository {
|
||||
final Isar _db;
|
||||
|
||||
AssetRepository(
|
||||
this._db,
|
||||
);
|
||||
class AssetRepository extends DatabaseRepository implements IAssetRepository {
|
||||
AssetRepository(super.db);
|
||||
|
||||
@override
|
||||
Future<List<Asset>> getByAlbum(Album album, {User? notOwnedBy}) {
|
||||
Future<List<Asset>> getByAlbum(
|
||||
Album album, {
|
||||
Iterable<int> notOwnedBy = const [],
|
||||
int? ownerId,
|
||||
AssetState? state,
|
||||
AssetSort? sortBy,
|
||||
}) {
|
||||
var query = album.assets.filter();
|
||||
if (notOwnedBy != null) {
|
||||
query = query.not().ownerIdEqualTo(notOwnedBy.isarId);
|
||||
if (notOwnedBy.length == 1) {
|
||||
query = query.not().ownerIdEqualTo(notOwnedBy.first);
|
||||
} else if (notOwnedBy.isNotEmpty) {
|
||||
query =
|
||||
query.not().anyOf(notOwnedBy, (q, int id) => q.ownerIdEqualTo(id));
|
||||
}
|
||||
return query.findAll();
|
||||
if (ownerId != null) {
|
||||
query = query.ownerIdEqualTo(ownerId);
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case null:
|
||||
break;
|
||||
case AssetState.local:
|
||||
query = query.remoteIdIsNull();
|
||||
case AssetState.remote:
|
||||
query = query.localIdIsNull();
|
||||
case AssetState.merged:
|
||||
query = query.localIdIsNotNull().remoteIdIsNotNull();
|
||||
}
|
||||
|
||||
final QueryBuilder<Asset, Asset, QAfterSortBy> sortedQuery;
|
||||
|
||||
switch (sortBy) {
|
||||
case null:
|
||||
sortedQuery = query.noOp();
|
||||
case AssetSort.checksum:
|
||||
sortedQuery = query.sortByChecksum();
|
||||
case AssetSort.ownerIdChecksum:
|
||||
sortedQuery = query.sortByOwnerId().thenByChecksum();
|
||||
}
|
||||
|
||||
return sortedQuery.findAll();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deleteById(List<int> ids) =>
|
||||
_db.writeTxn(() => _db.assets.deleteAll(ids));
|
||||
Future<void> deleteById(List<int> ids) => txn(() async {
|
||||
await db.assets.deleteAll(ids);
|
||||
await db.exifInfos.deleteAll(ids);
|
||||
});
|
||||
|
||||
@override
|
||||
Future<Asset?> getByRemoteId(String id) => _db.assets.getByRemoteId(id);
|
||||
Future<Asset?> getByRemoteId(String id) => db.assets.getByRemoteId(id);
|
||||
|
||||
@override
|
||||
Future<List<Asset>> getAllByRemoteId(Iterable<String> ids) =>
|
||||
_db.assets.getAllByRemoteId(ids);
|
||||
Future<List<Asset>> getAllByRemoteId(
|
||||
Iterable<String> ids, {
|
||||
AssetState? state,
|
||||
}) =>
|
||||
_getAllByRemoteIdImpl(ids, state).findAll();
|
||||
|
||||
QueryBuilder<Asset, Asset, QAfterFilterCondition> _getAllByRemoteIdImpl(
|
||||
Iterable<String> ids,
|
||||
AssetState? state,
|
||||
) {
|
||||
final query = db.assets.remote(ids).filter();
|
||||
switch (state) {
|
||||
case null:
|
||||
return query.noOp();
|
||||
case AssetState.local:
|
||||
return query.remoteIdIsNull();
|
||||
case AssetState.remote:
|
||||
return query.localIdIsNull();
|
||||
case AssetState.merged:
|
||||
return query.localIdIsNotEmpty().remoteIdIsNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Asset>> getAll({
|
||||
required int ownerId,
|
||||
bool? remote,
|
||||
int limit = 100,
|
||||
AssetState? state,
|
||||
AssetSort? sortBy,
|
||||
int? limit,
|
||||
}) {
|
||||
if (remote == null) {
|
||||
return _db.assets
|
||||
.where()
|
||||
.ownerIdEqualToAnyChecksum(ownerId)
|
||||
.limit(limit)
|
||||
.findAll();
|
||||
}
|
||||
final QueryBuilder<Asset, Asset, QAfterFilterCondition> query;
|
||||
if (remote) {
|
||||
query = _db.assets
|
||||
.where()
|
||||
.localIdIsNull()
|
||||
.filter()
|
||||
.remoteIdIsNotNull()
|
||||
.ownerIdEqualTo(ownerId);
|
||||
} else {
|
||||
query = _db.assets
|
||||
.where()
|
||||
.remoteIdIsNull()
|
||||
.filter()
|
||||
.localIdIsNotNull()
|
||||
.ownerIdEqualTo(ownerId);
|
||||
final baseQuery = db.assets.where();
|
||||
final QueryBuilder<Asset, Asset, QAfterFilterCondition> filteredQuery;
|
||||
switch (state) {
|
||||
case null:
|
||||
filteredQuery = baseQuery.ownerIdEqualToAnyChecksum(ownerId).noOp();
|
||||
case AssetState.local:
|
||||
filteredQuery = baseQuery
|
||||
.remoteIdIsNull()
|
||||
.filter()
|
||||
.localIdIsNotNull()
|
||||
.ownerIdEqualTo(ownerId);
|
||||
case AssetState.remote:
|
||||
filteredQuery = baseQuery
|
||||
.localIdIsNull()
|
||||
.filter()
|
||||
.remoteIdIsNotNull()
|
||||
.ownerIdEqualTo(ownerId);
|
||||
case AssetState.merged:
|
||||
filteredQuery = baseQuery
|
||||
.ownerIdEqualToAnyChecksum(ownerId)
|
||||
.filter()
|
||||
.remoteIdIsNotNull()
|
||||
.localIdIsNotNull();
|
||||
}
|
||||
|
||||
return query.limit(limit).findAll();
|
||||
final QueryBuilder<Asset, Asset, QAfterSortBy> query;
|
||||
switch (sortBy) {
|
||||
case null:
|
||||
query = filteredQuery.noOp();
|
||||
case AssetSort.checksum:
|
||||
query = filteredQuery.sortByChecksum();
|
||||
case AssetSort.ownerIdChecksum:
|
||||
query = filteredQuery.sortByOwnerId().thenByChecksum();
|
||||
}
|
||||
|
||||
return limit == null ? query.findAll() : query.limit(limit).findAll();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Asset>> updateAll(List<Asset> assets) async {
|
||||
await _db.writeTxn(() => _db.assets.putAll(assets));
|
||||
await txn(() => db.assets.putAll(assets));
|
||||
return assets;
|
||||
}
|
||||
|
||||
@ -84,16 +151,20 @@ class AssetRepository implements IAssetRepository {
|
||||
Future<List<Asset>> getMatches({
|
||||
required List<Asset> assets,
|
||||
required int ownerId,
|
||||
bool? remote,
|
||||
AssetState? state,
|
||||
int limit = 100,
|
||||
}) {
|
||||
final baseQuery = db.assets.where();
|
||||
final QueryBuilder<Asset, Asset, QAfterFilterCondition> query;
|
||||
if (remote == null) {
|
||||
query = _db.assets.filter().remoteIdIsNotNull().or().localIdIsNotNull();
|
||||
} else if (remote) {
|
||||
query = _db.assets.where().localIdIsNull().filter().remoteIdIsNotNull();
|
||||
} else {
|
||||
query = _db.assets.where().remoteIdIsNull().filter().localIdIsNotNull();
|
||||
switch (state) {
|
||||
case null:
|
||||
query = baseQuery.noOp();
|
||||
case AssetState.local:
|
||||
query = baseQuery.remoteIdIsNull().filter().localIdIsNotNull();
|
||||
case AssetState.remote:
|
||||
query = baseQuery.localIdIsNull().filter().remoteIdIsNotNull();
|
||||
case AssetState.merged:
|
||||
query = baseQuery.localIdIsNotNull().filter().remoteIdIsNotNull();
|
||||
}
|
||||
return _getMatchesImpl(query, ownerId, assets, limit);
|
||||
}
|
||||
@ -101,16 +172,50 @@ class AssetRepository implements IAssetRepository {
|
||||
@override
|
||||
Future<List<DeviceAsset?>> getDeviceAssetsById(List<Object> ids) =>
|
||||
Platform.isAndroid
|
||||
? _db.androidDeviceAssets.getAll(ids.cast())
|
||||
: _db.iOSDeviceAssets.getAllById(ids.cast());
|
||||
? db.androidDeviceAssets.getAll(ids.cast())
|
||||
: db.iOSDeviceAssets.getAllById(ids.cast());
|
||||
|
||||
@override
|
||||
Future<void> upsertDeviceAssets(List<DeviceAsset> deviceAssets) =>
|
||||
_db.writeTxn(
|
||||
Future<void> upsertDeviceAssets(List<DeviceAsset> deviceAssets) => txn(
|
||||
() => Platform.isAndroid
|
||||
? _db.androidDeviceAssets.putAll(deviceAssets.cast())
|
||||
: _db.iOSDeviceAssets.putAll(deviceAssets.cast()),
|
||||
? db.androidDeviceAssets.putAll(deviceAssets.cast())
|
||||
: db.iOSDeviceAssets.putAll(deviceAssets.cast()),
|
||||
);
|
||||
|
||||
@override
|
||||
Future<Asset> update(Asset asset) async {
|
||||
await txn(() => asset.put(db));
|
||||
return asset;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> upsertDuplicatedAssets(Iterable<String> duplicatedAssets) => txn(
|
||||
() => db.duplicatedAssets
|
||||
.putAll(duplicatedAssets.map(DuplicatedAsset.new).toList()),
|
||||
);
|
||||
|
||||
@override
|
||||
Future<List<String>> getAllDuplicatedAssetIds() =>
|
||||
db.duplicatedAssets.where().idProperty().findAll();
|
||||
|
||||
@override
|
||||
Future<Asset?> getByOwnerIdChecksum(int ownerId, String checksum) =>
|
||||
db.assets.getByOwnerIdChecksum(ownerId, checksum);
|
||||
|
||||
@override
|
||||
Future<List<Asset?>> getAllByOwnerIdChecksum(
|
||||
List<int> ids,
|
||||
List<String> checksums,
|
||||
) =>
|
||||
db.assets.getAllByOwnerIdChecksum(ids, checksums);
|
||||
|
||||
@override
|
||||
Future<List<Asset>> getAllLocal() =>
|
||||
db.assets.where().localIdIsNotNull().findAll();
|
||||
|
||||
@override
|
||||
Future<void> deleteAllByRemoteId(List<String> ids, {AssetState? state}) =>
|
||||
txn(() => _getAllByRemoteIdImpl(ids, state).deleteAll());
|
||||
}
|
||||
|
||||
Future<List<Asset>> _getMatchesImpl(
|
||||
|
Reference in New Issue
Block a user