feat: full local assets / album sync
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:immich_mobile/domain/entities/album.entity.drift.dart';
|
||||
import 'package:immich_mobile/domain/interfaces/album.interface.dart';
|
||||
import 'package:immich_mobile/domain/models/album.model.dart';
|
||||
import 'package:immich_mobile/domain/repositories/database.repository.dart';
|
||||
import 'package:immich_mobile/utils/mixins/log.mixin.dart';
|
||||
|
||||
class AlbumRepository with LogMixin implements IAlbumRepository {
|
||||
final DriftDatabaseRepository _db;
|
||||
|
||||
const AlbumRepository(this._db);
|
||||
|
||||
@override
|
||||
FutureOr<Album?> upsert(Album album) async {
|
||||
try {
|
||||
final albumData = _toEntity(album);
|
||||
final data = await _db.into(_db.album).insertReturningOrNull(
|
||||
albumData,
|
||||
onConflict: DoUpdate((_) => albumData, target: [_db.album.localId]),
|
||||
);
|
||||
if (data != null) {
|
||||
return _toModel(data);
|
||||
}
|
||||
} catch (e, s) {
|
||||
log.e("Error while adding an album to the DB", e, s);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<List<Album>> getAll({
|
||||
bool localOnly = false,
|
||||
bool remoteOnly = false,
|
||||
}) async {
|
||||
final query = _db.album.select();
|
||||
|
||||
if (localOnly == true) {
|
||||
query.where((album) => album.localId.isNotNull());
|
||||
}
|
||||
|
||||
if (remoteOnly == true) {
|
||||
query.where((album) => album.remoteId.isNotNull());
|
||||
}
|
||||
|
||||
query.orderBy([(album) => OrderingTerm.asc(album.name)]);
|
||||
return await query.map(_toModel).get();
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<void> deleteId(int id) async {
|
||||
await _db.asset.deleteWhere((row) => row.id.equals(id));
|
||||
}
|
||||
}
|
||||
|
||||
AlbumCompanion _toEntity(Album album) {
|
||||
return AlbumCompanion.insert(
|
||||
id: Value.absentIfNull(album.id),
|
||||
localId: Value(album.localId),
|
||||
remoteId: Value(album.remoteId),
|
||||
name: album.name,
|
||||
modifiedTime: Value(album.modifiedTime),
|
||||
thumbnailAssetId: Value(album.thumbnailAssetId),
|
||||
);
|
||||
}
|
||||
|
||||
Album _toModel(AlbumData album) {
|
||||
return Album(
|
||||
id: album.id,
|
||||
localId: album.localId,
|
||||
remoteId: album.remoteId,
|
||||
name: album.name,
|
||||
modifiedTime: album.modifiedTime,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:immich_mobile/domain/entities/album_asset.entity.drift.dart';
|
||||
import 'package:immich_mobile/domain/interfaces/album_asset.interface.dart';
|
||||
import 'package:immich_mobile/domain/models/asset.model.dart';
|
||||
import 'package:immich_mobile/domain/repositories/database.repository.dart';
|
||||
import 'package:immich_mobile/domain/utils/drift_model_converters.dart';
|
||||
import 'package:immich_mobile/utils/mixins/log.mixin.dart';
|
||||
|
||||
class AlbumToAssetRepository with LogMixin implements IAlbumToAssetRepository {
|
||||
final DriftDatabaseRepository _db;
|
||||
|
||||
const AlbumToAssetRepository(this._db);
|
||||
|
||||
@override
|
||||
FutureOr<bool> addAssetIds(int albumId, Iterable<int> assetIds) async {
|
||||
try {
|
||||
await _db.albumToAsset.insertAll(
|
||||
assetIds.map((a) => AlbumToAssetCompanion.insert(
|
||||
assetId: a,
|
||||
albumId: albumId,
|
||||
)),
|
||||
onConflict: DoNothing(
|
||||
target: [_db.albumToAsset.assetId, _db.albumToAsset.albumId],
|
||||
),
|
||||
);
|
||||
return true;
|
||||
} catch (e, s) {
|
||||
log.e("Error while adding assets to albumId - $albumId", e, s);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<List<int>> getAssetIdsOnlyInAlbum(int albumId) async {
|
||||
final assetId = _db.asset.id;
|
||||
final query = _db.asset.selectOnly()
|
||||
..addColumns([assetId])
|
||||
..join([
|
||||
innerJoin(
|
||||
_db.albumToAsset,
|
||||
_db.albumToAsset.assetId.equalsExp(_db.asset.id) &
|
||||
_db.asset.remoteId.isNull(),
|
||||
useColumns: false,
|
||||
),
|
||||
])
|
||||
..groupBy(
|
||||
[assetId],
|
||||
having: _db.albumToAsset.albumId.count().equals(1) &
|
||||
_db.albumToAsset.albumId.max().equals(albumId),
|
||||
);
|
||||
|
||||
return await query.map((row) => row.read(assetId)!).get();
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<List<Asset>> getAssetsForAlbum(int albumId) async {
|
||||
final query = _db.asset.select().join([
|
||||
innerJoin(
|
||||
_db.albumToAsset,
|
||||
_db.albumToAsset.assetId.equalsExp(_db.asset.id) &
|
||||
_db.albumToAsset.albumId.equals(albumId),
|
||||
useColumns: false,
|
||||
),
|
||||
]);
|
||||
|
||||
return await query
|
||||
.map((row) =>
|
||||
DriftModelConverters.toAssetModel(row.readTable(_db.asset)))
|
||||
.get();
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<void> deleteAlbumId(int albumId) async {
|
||||
await _db.albumToAsset.deleteWhere((row) => row.albumId.equals(albumId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:immich_mobile/domain/entities/album_etag.entity.drift.dart';
|
||||
import 'package:immich_mobile/domain/interfaces/album_etag.interface.dart';
|
||||
import 'package:immich_mobile/domain/models/album_etag.model.dart';
|
||||
import 'package:immich_mobile/domain/repositories/database.repository.dart';
|
||||
import 'package:immich_mobile/utils/mixins/log.mixin.dart';
|
||||
|
||||
class AlbumETagRepository with LogMixin implements IAlbumETagRepository {
|
||||
final DriftDatabaseRepository _db;
|
||||
|
||||
const AlbumETagRepository(this._db);
|
||||
|
||||
@override
|
||||
FutureOr<bool> upsert(AlbumETag albumETag) async {
|
||||
try {
|
||||
final entity = _toEntity(albumETag);
|
||||
await _db.into(_db.albumETag).insert(
|
||||
entity,
|
||||
onConflict:
|
||||
DoUpdate((_) => entity, target: [_db.albumETag.albumId]),
|
||||
);
|
||||
return true;
|
||||
} catch (e, s) {
|
||||
log.e("Error while adding an album etag to the DB", e, s);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<AlbumETag?> get(int albumId) async {
|
||||
return await _db.managers.albumETag
|
||||
.filter((r) => r.albumId.id.equals(albumId))
|
||||
.map(_toModel)
|
||||
.getSingleOrNull();
|
||||
}
|
||||
}
|
||||
|
||||
AlbumETagCompanion _toEntity(AlbumETag albumETag) {
|
||||
return AlbumETagCompanion.insert(
|
||||
id: Value.absentIfNull(albumETag.id),
|
||||
modifiedTime: Value(albumETag.modifiedTime),
|
||||
albumId: albumETag.albumId,
|
||||
assetCount: Value(albumETag.assetCount),
|
||||
);
|
||||
}
|
||||
|
||||
AlbumETag _toModel(AlbumETagData albumETag) {
|
||||
return AlbumETag(
|
||||
albumId: albumETag.albumId,
|
||||
assetCount: albumETag.assetCount,
|
||||
modifiedTime: albumETag.modifiedTime,
|
||||
id: albumETag.id,
|
||||
);
|
||||
}
|
||||
@@ -5,24 +5,31 @@ import 'package:immich_mobile/domain/entities/asset.entity.drift.dart';
|
||||
import 'package:immich_mobile/domain/interfaces/asset.interface.dart';
|
||||
import 'package:immich_mobile/domain/models/asset.model.dart';
|
||||
import 'package:immich_mobile/domain/repositories/database.repository.dart';
|
||||
import 'package:immich_mobile/domain/utils/drift_model_converters.dart';
|
||||
import 'package:immich_mobile/utils/mixins/log.mixin.dart';
|
||||
|
||||
class AssetDriftRepository with LogMixin implements IAssetRepository {
|
||||
class AssetRepository with LogMixin implements IAssetRepository {
|
||||
final DriftDatabaseRepository _db;
|
||||
|
||||
const AssetDriftRepository(this._db);
|
||||
const AssetRepository(this._db);
|
||||
|
||||
@override
|
||||
Future<bool> upsertAll(Iterable<Asset> assets) async {
|
||||
try {
|
||||
await _db.batch((batch) => batch.insertAllOnConflictUpdate(
|
||||
await _db.batch((batch) {
|
||||
final rows = assets.map(_toEntity);
|
||||
for (final row in rows) {
|
||||
batch.insert(
|
||||
_db.asset,
|
||||
assets.map(_toEntity),
|
||||
));
|
||||
row,
|
||||
onConflict: DoUpdate((_) => row, target: [_db.asset.hash]),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (e, s) {
|
||||
log.e("Cannot insert remote assets into table", e, s);
|
||||
log.e("Cannot insert assets into table", e, s);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -33,7 +40,7 @@ class AssetDriftRepository with LogMixin implements IAssetRepository {
|
||||
await _db.asset.deleteAll();
|
||||
return true;
|
||||
} catch (e, s) {
|
||||
log.e("Cannot clear remote assets", e, s);
|
||||
log.e("Cannot clear assets", e, s);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -47,35 +54,45 @@ class AssetDriftRepository with LogMixin implements IAssetRepository {
|
||||
query.limit(limit, offset: offset);
|
||||
}
|
||||
|
||||
return (await query.get()).map(_toModel).toList();
|
||||
return (await query.map(DriftModelConverters.toAssetModel).get()).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Asset>> getForLocalIds(List<String> localIds) async {
|
||||
Future<List<Asset>> getForLocalIds(Iterable<String> localIds) async {
|
||||
final query = _db.asset.select()
|
||||
..where((row) => row.localId.isIn(localIds))
|
||||
..orderBy([(asset) => OrderingTerm.asc(asset.localId)]);
|
||||
..orderBy([(asset) => OrderingTerm.asc(asset.hash)]);
|
||||
|
||||
return (await query.get()).map(_toModel).toList();
|
||||
return (await query.get()).map(DriftModelConverters.toAssetModel).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Asset>> getForRemoteIds(List<String> remoteIds) async {
|
||||
Future<List<Asset>> getForRemoteIds(Iterable<String> remoteIds) async {
|
||||
final query = _db.asset.select()
|
||||
..where((row) => row.remoteId.isIn(remoteIds))
|
||||
..orderBy([(asset) => OrderingTerm.asc(asset.remoteId)]);
|
||||
..orderBy([(asset) => OrderingTerm.asc(asset.hash)]);
|
||||
|
||||
return (await query.get()).map(_toModel).toList();
|
||||
return (await query.get()).map(DriftModelConverters.toAssetModel).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<void> deleteIds(List<int> ids) async {
|
||||
Future<List<Asset>> getForHashes(Iterable<String> hashes) async {
|
||||
final query = _db.asset.select()
|
||||
..where((row) => row.hash.isIn(hashes))
|
||||
..orderBy([(asset) => OrderingTerm.asc(asset.hash)]);
|
||||
|
||||
return (await query.get()).map(DriftModelConverters.toAssetModel).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<void> deleteIds(Iterable<int> ids) async {
|
||||
await _db.asset.deleteWhere((row) => row.id.isIn(ids));
|
||||
}
|
||||
}
|
||||
|
||||
AssetCompanion _toEntity(Asset asset) {
|
||||
return AssetCompanion.insert(
|
||||
id: Value.absentIfNull(asset.id),
|
||||
localId: Value(asset.localId),
|
||||
remoteId: Value(asset.remoteId),
|
||||
name: asset.name,
|
||||
@@ -89,20 +106,3 @@ AssetCompanion _toEntity(Asset asset) {
|
||||
livePhotoVideoId: Value(asset.livePhotoVideoId),
|
||||
);
|
||||
}
|
||||
|
||||
Asset _toModel(AssetData asset) {
|
||||
return Asset(
|
||||
id: asset.id,
|
||||
localId: asset.localId,
|
||||
remoteId: asset.remoteId,
|
||||
name: asset.name,
|
||||
type: asset.type,
|
||||
hash: asset.hash,
|
||||
createdTime: asset.createdTime,
|
||||
modifiedTime: asset.modifiedTime,
|
||||
height: asset.height,
|
||||
width: asset.width,
|
||||
livePhotoVideoId: asset.livePhotoVideoId,
|
||||
duration: asset.duration,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,36 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
// ignore: depend_on_referenced_packages
|
||||
import 'package:drift_dev/api/migrations.dart';
|
||||
import 'package:drift_flutter/drift_flutter.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:immich_mobile/domain/entities/album.entity.dart';
|
||||
import 'package:immich_mobile/domain/entities/album_asset.entity.dart';
|
||||
import 'package:immich_mobile/domain/entities/album_etag.entity.dart';
|
||||
import 'package:immich_mobile/domain/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/domain/entities/device_asset_hash.entity.dart';
|
||||
import 'package:immich_mobile/domain/entities/log.entity.dart';
|
||||
import 'package:immich_mobile/domain/entities/store.entity.dart';
|
||||
import 'package:immich_mobile/domain/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/domain/interfaces/database.interface.dart';
|
||||
|
||||
import 'database.repository.drift.dart';
|
||||
|
||||
@DriftDatabase(tables: [Logs, Store, LocalAlbum, Asset, User])
|
||||
class DriftDatabaseRepository extends $DriftDatabaseRepository {
|
||||
@DriftDatabase(
|
||||
tables: [
|
||||
Logs,
|
||||
Store,
|
||||
User,
|
||||
Asset,
|
||||
DeviceAssetToHash,
|
||||
Album,
|
||||
AlbumToAsset,
|
||||
AlbumETag,
|
||||
],
|
||||
)
|
||||
class DriftDatabaseRepository extends $DriftDatabaseRepository
|
||||
implements IDatabaseRepository {
|
||||
DriftDatabaseRepository([QueryExecutor? executor])
|
||||
: super(executor ??
|
||||
driftDatabase(
|
||||
@@ -37,4 +55,7 @@ class DriftDatabaseRepository extends $DriftDatabaseRepository {
|
||||
// ignore: no-empty-block
|
||||
onUpgrade: (m, from, to) async {},
|
||||
);
|
||||
|
||||
@override
|
||||
Future<T> txn<T>(Future<T> Function() action) => transaction(action);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:immich_mobile/domain/interfaces/device_album.interface.dart';
|
||||
import 'package:immich_mobile/domain/interfaces/device_asset.interface.dart';
|
||||
import 'package:immich_mobile/domain/models/album.model.dart';
|
||||
import 'package:immich_mobile/domain/models/asset.model.dart';
|
||||
import 'package:immich_mobile/service_locator.dart';
|
||||
import 'package:immich_mobile/utils/mixins/log.mixin.dart';
|
||||
import 'package:photo_manager/photo_manager.dart';
|
||||
|
||||
class DeviceAlbumRepository with LogMixin implements IDeviceAlbumRepository {
|
||||
const DeviceAlbumRepository();
|
||||
|
||||
@override
|
||||
Future<List<Album>> getAll() async {
|
||||
final List<AssetPathEntity> assetPathEntities =
|
||||
await PhotoManager.getAssetPathList(
|
||||
hasAll: Platform.isIOS,
|
||||
filterOption: FilterOptionGroup(containsPathModified: true),
|
||||
);
|
||||
return assetPathEntities.map(_toModel).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Asset>> getAssetsForAlbum(
|
||||
String albumId, {
|
||||
int start = 0,
|
||||
int end = 0x7fffffffffffffff,
|
||||
DateTime? modifiedFrom,
|
||||
DateTime? modifiedUntil,
|
||||
bool orderByModificationDate = false,
|
||||
}) async {
|
||||
final album = await _getDeviceAlbum(
|
||||
albumId,
|
||||
modifiedFrom: modifiedFrom,
|
||||
modifiedUntil: modifiedUntil,
|
||||
orderByModificationDate: orderByModificationDate,
|
||||
);
|
||||
final List<AssetEntity> assets =
|
||||
await album.getAssetListRange(start: start, end: end);
|
||||
return await Future.wait(
|
||||
assets.map((a) async => await di<IDeviceAssetRepository>().toAsset(a)),
|
||||
);
|
||||
}
|
||||
|
||||
Future<AssetPathEntity> _getDeviceAlbum(
|
||||
String albumId, {
|
||||
DateTime? modifiedFrom,
|
||||
DateTime? modifiedUntil,
|
||||
bool orderByModificationDate = false,
|
||||
}) async {
|
||||
return await AssetPathEntity.fromId(
|
||||
albumId,
|
||||
filterOption: FilterOptionGroup(
|
||||
containsPathModified: true,
|
||||
orders: orderByModificationDate
|
||||
? [const OrderOption(type: OrderOptionType.updateDate)]
|
||||
: [],
|
||||
imageOption: const FilterOption(needTitle: true),
|
||||
videoOption: const FilterOption(needTitle: true),
|
||||
updateTimeCond: DateTimeCond(
|
||||
min: modifiedFrom ?? DateTime.utc(-271820),
|
||||
max: modifiedUntil ?? DateTime.utc(275760),
|
||||
ignore: modifiedFrom != null || modifiedUntil != null,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> getAssetCount(String albumId) async {
|
||||
final album = await _getDeviceAlbum(albumId);
|
||||
return await album.assetCountAsync;
|
||||
}
|
||||
}
|
||||
|
||||
Album _toModel(AssetPathEntity album) {
|
||||
return Album(
|
||||
localId: album.id,
|
||||
name: album.name,
|
||||
modifiedTime: album.lastModified ?? DateTime.now(),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:immich_mobile/domain/interfaces/device_asset.interface.dart';
|
||||
import 'package:immich_mobile/domain/models/asset.model.dart';
|
||||
import 'package:immich_mobile/domain/models/device_asset_download.model.dart';
|
||||
import 'package:immich_mobile/utils/constants/globals.dart';
|
||||
import 'package:immich_mobile/utils/mixins/log.mixin.dart';
|
||||
import 'package:photo_manager/photo_manager.dart' as ph;
|
||||
|
||||
class DeviceAssetRepository
|
||||
with LogMixin
|
||||
implements IDeviceAssetRepository<ph.AssetEntity> {
|
||||
const DeviceAssetRepository();
|
||||
|
||||
@override
|
||||
Future<Asset> toAsset(ph.AssetEntity entity) async {
|
||||
var asset = Asset(
|
||||
hash: '',
|
||||
name: await entity.titleAsync,
|
||||
type: _toAssetType(entity.type),
|
||||
createdTime: entity.createDateTime,
|
||||
modifiedTime: entity.modifiedDateTime,
|
||||
duration: entity.duration,
|
||||
height: entity.height,
|
||||
width: entity.width,
|
||||
localId: entity.id,
|
||||
);
|
||||
if (asset.createdTime.year == 1970) {
|
||||
asset = asset.copyWith(createdTime: asset.modifiedTime);
|
||||
}
|
||||
return asset;
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<File?> getOriginalFile(String localId) async {
|
||||
try {
|
||||
final entity = await ph.AssetEntity.fromId(localId);
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await entity.originFile;
|
||||
} catch (e, s) {
|
||||
log.e("Exception while fetching file for localId - $localId", e, s);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<Uint8List?> getThumbnail(
|
||||
String assetId, {
|
||||
int width = kGridThumbnailSize,
|
||||
int height = kGridThumbnailSize,
|
||||
int quality = kGridThumbnailQuality,
|
||||
DeviceAssetDownloadHandler? downloadHandler,
|
||||
}) async {
|
||||
try {
|
||||
final entity = await ph.AssetEntity.fromId(assetId);
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ph.PMProgressHandler? progressHandler;
|
||||
if (downloadHandler != null) {
|
||||
progressHandler = ph.PMProgressHandler();
|
||||
downloadHandler.stream = progressHandler.stream.map(_toDownloadState);
|
||||
}
|
||||
|
||||
return await entity.thumbnailDataWithSize(
|
||||
ph.ThumbnailSize(width, height),
|
||||
quality: quality,
|
||||
progressHandler: progressHandler,
|
||||
);
|
||||
} catch (e, s) {
|
||||
log.e("Exception while fetching thumbnail for assetId - $assetId", e, s);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
AssetType _toAssetType(ph.AssetType type) => switch (type) {
|
||||
ph.AssetType.audio => AssetType.audio,
|
||||
ph.AssetType.image => AssetType.image,
|
||||
ph.AssetType.video => AssetType.video,
|
||||
ph.AssetType.other => AssetType.other,
|
||||
};
|
||||
|
||||
DeviceAssetDownloadState _toDownloadState(ph.PMProgressState state) {
|
||||
return DeviceAssetDownloadState(
|
||||
progress: state.progress,
|
||||
status: switch (state.state) {
|
||||
ph.PMRequestState.prepare => DeviceAssetRequestStatus.preparing,
|
||||
ph.PMRequestState.loading => DeviceAssetRequestStatus.downloading,
|
||||
ph.PMRequestState.success => DeviceAssetRequestStatus.success,
|
||||
ph.PMRequestState.failed => DeviceAssetRequestStatus.failed,
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:immich_mobile/domain/entities/device_asset_hash.entity.drift.dart';
|
||||
import 'package:immich_mobile/domain/interfaces/device_asset_hash.interface.dart';
|
||||
import 'package:immich_mobile/domain/models/device_asset_hash.model.dart';
|
||||
import 'package:immich_mobile/domain/repositories/database.repository.dart';
|
||||
import 'package:immich_mobile/utils/mixins/log.mixin.dart';
|
||||
|
||||
class DeviceAssetToHashRepository
|
||||
with LogMixin
|
||||
implements IDeviceAssetToHashRepository {
|
||||
final DriftDatabaseRepository _db;
|
||||
|
||||
const DeviceAssetToHashRepository(this._db);
|
||||
|
||||
@override
|
||||
FutureOr<bool> upsertAll(Iterable<DeviceAssetToHash> assetHash) async {
|
||||
try {
|
||||
await _db.batch((batch) => batch.insertAllOnConflictUpdate(
|
||||
_db.deviceAssetToHash,
|
||||
assetHash.map(_toEntity),
|
||||
));
|
||||
|
||||
return true;
|
||||
} catch (e, s) {
|
||||
log.e("Cannot add device assets to hash entry", e, s);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<DeviceAssetToHash>> getForIds(Iterable<String> localIds) async {
|
||||
return await _db.managers.deviceAssetToHash
|
||||
.filter((f) => f.localId.isIn(localIds))
|
||||
.map(_toModel)
|
||||
.get();
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<void> deleteIds(Iterable<int> ids) async {
|
||||
await _db.deviceAssetToHash.deleteWhere((row) => row.id.isIn(ids));
|
||||
}
|
||||
}
|
||||
|
||||
DeviceAssetToHashCompanion _toEntity(DeviceAssetToHash asset) {
|
||||
return DeviceAssetToHashCompanion.insert(
|
||||
id: Value.absentIfNull(asset.id),
|
||||
localId: asset.localId,
|
||||
hash: asset.hash,
|
||||
modifiedTime: Value(asset.modifiedTime),
|
||||
);
|
||||
}
|
||||
|
||||
DeviceAssetToHash _toModel(DeviceAssetToHashData asset) {
|
||||
return DeviceAssetToHash(
|
||||
id: asset.id,
|
||||
localId: asset.localId,
|
||||
hash: asset.hash,
|
||||
modifiedTime: asset.modifiedTime,
|
||||
);
|
||||
}
|
||||
@@ -7,10 +7,10 @@ import 'package:immich_mobile/domain/interfaces/log.interface.dart';
|
||||
import 'package:immich_mobile/domain/models/log.model.dart';
|
||||
import 'package:immich_mobile/domain/repositories/database.repository.dart';
|
||||
|
||||
class LogDriftRepository implements ILogRepository {
|
||||
class LogRepository implements ILogRepository {
|
||||
final DriftDatabaseRepository _db;
|
||||
|
||||
const LogDriftRepository(this._db);
|
||||
const LogRepository(this._db);
|
||||
|
||||
@override
|
||||
Future<List<LogMessage>> getAll() async {
|
||||
@@ -32,14 +32,7 @@ class LogDriftRepository implements ILogRepository {
|
||||
@override
|
||||
FutureOr<bool> create(LogMessage log) async {
|
||||
try {
|
||||
await _db.into(_db.logs).insert(LogsCompanion.insert(
|
||||
content: log.content,
|
||||
level: log.level,
|
||||
createdAt: Value(log.createdAt),
|
||||
error: Value(log.error),
|
||||
logger: Value(log.logger),
|
||||
stack: Value(log.stack),
|
||||
));
|
||||
await _db.into(_db.logs).insert(_toEntity(log));
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint("Error while adding a log to the DB - $e");
|
||||
@@ -48,20 +41,10 @@ class LogDriftRepository implements ILogRepository {
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<bool> createAll(List<LogMessage> logs) async {
|
||||
FutureOr<bool> createAll(Iterable<LogMessage> logs) async {
|
||||
try {
|
||||
await _db.batch((b) {
|
||||
b.insertAll(
|
||||
_db.logs,
|
||||
logs.map((log) => LogsCompanion.insert(
|
||||
content: log.content,
|
||||
level: log.level,
|
||||
createdAt: Value(log.createdAt),
|
||||
error: Value(log.error),
|
||||
logger: Value(log.logger),
|
||||
stack: Value(log.stack),
|
||||
)),
|
||||
);
|
||||
b.insertAll(_db.logs, logs.map(_toEntity));
|
||||
});
|
||||
return true;
|
||||
} catch (e) {
|
||||
@@ -82,6 +65,17 @@ class LogDriftRepository implements ILogRepository {
|
||||
}
|
||||
}
|
||||
|
||||
LogsCompanion _toEntity(LogMessage log) {
|
||||
return LogsCompanion.insert(
|
||||
content: log.content,
|
||||
level: log.level,
|
||||
createdAt: Value(log.createdAt),
|
||||
error: Value(log.error),
|
||||
logger: Value(log.logger),
|
||||
stack: Value(log.stack),
|
||||
);
|
||||
}
|
||||
|
||||
LogMessage _toModel(Log log) {
|
||||
return LogMessage(
|
||||
content: log.content,
|
||||
|
||||
@@ -6,10 +6,10 @@ import 'package:immich_mobile/domain/repositories/database.repository.dart';
|
||||
import 'package:immich_mobile/utils/extensions/drift.extension.dart';
|
||||
import 'package:immich_mobile/utils/mixins/log.mixin.dart';
|
||||
|
||||
class RenderListDriftRepository with LogMixin implements IRenderListRepository {
|
||||
class RenderListRepository with LogMixin implements IRenderListRepository {
|
||||
final DriftDatabaseRepository _db;
|
||||
|
||||
const RenderListDriftRepository(this._db);
|
||||
const RenderListRepository(this._db);
|
||||
|
||||
@override
|
||||
Stream<RenderList> watchAll() {
|
||||
|
||||
@@ -7,10 +7,10 @@ import 'package:immich_mobile/domain/models/store.model.dart';
|
||||
import 'package:immich_mobile/domain/repositories/database.repository.dart';
|
||||
import 'package:immich_mobile/utils/mixins/log.mixin.dart';
|
||||
|
||||
class StoreDriftRepository with LogMixin implements IStoreRepository {
|
||||
class StoreRepository with LogMixin implements IStoreRepository {
|
||||
final DriftDatabaseRepository _db;
|
||||
|
||||
const StoreDriftRepository(this._db);
|
||||
const StoreRepository(this._db);
|
||||
|
||||
@override
|
||||
FutureOr<T?> tryGet<T, U>(StoreKey<T, U> key) async {
|
||||
|
||||
@@ -7,10 +7,10 @@ import 'package:immich_mobile/domain/models/user.model.dart';
|
||||
import 'package:immich_mobile/domain/repositories/database.repository.dart';
|
||||
import 'package:immich_mobile/utils/mixins/log.mixin.dart';
|
||||
|
||||
class UserDriftRepository with LogMixin implements IUserRepository {
|
||||
class UserRepository with LogMixin implements IUserRepository {
|
||||
final DriftDatabaseRepository _db;
|
||||
|
||||
const UserDriftRepository(this._db);
|
||||
const UserRepository(this._db);
|
||||
|
||||
@override
|
||||
FutureOr<User?> getForId(String userId) async {
|
||||
|
||||
Reference in New Issue
Block a user