feat(mobile): add album asset sync (#19522)
* feat(mobile): add album asset sync * add SyncAlbumToAssetDeleteV1 to openapi-spec * update delete queries to use where in statements * clear remote album when clear remote data * fix: bad merge * fix: bad merge * fix: _SyncAckV1 return type --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> Co-authored-by: wuzihao051119 <wuzihao051119@outlook.com> Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
@@ -8,6 +8,9 @@ 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';
|
||||
import 'package:immich_mobile/infrastructure/entities/partner.entity.dart';
|
||||
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';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.dart';
|
||||
@@ -40,6 +43,9 @@ class IsarDatabaseRepository implements IDatabaseRepository {
|
||||
LocalAlbumAssetEntity,
|
||||
RemoteAssetEntity,
|
||||
RemoteExifEntity,
|
||||
RemoteAlbumEntity,
|
||||
RemoteAlbumAssetEntity,
|
||||
RemoteAlbumUserEntity,
|
||||
],
|
||||
include: {
|
||||
'package:immich_mobile/infrastructure/entities/merged_asset.drift',
|
||||
|
||||
+73
-5
@@ -17,9 +17,15 @@ import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.d
|
||||
as i7;
|
||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart'
|
||||
as i8;
|
||||
import 'package:immich_mobile/infrastructure/entities/merged_asset.drift.dart'
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart'
|
||||
as i9;
|
||||
import 'package:drift/internal/modular.dart' as i10;
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.drift.dart'
|
||||
as i10;
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart'
|
||||
as i11;
|
||||
import 'package:immich_mobile/infrastructure/entities/merged_asset.drift.dart'
|
||||
as i12;
|
||||
import 'package:drift/internal/modular.dart' as i13;
|
||||
|
||||
abstract class $Drift extends i0.GeneratedDatabase {
|
||||
$Drift(i0.QueryExecutor e) : super(e);
|
||||
@@ -39,8 +45,14 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
||||
i7.$LocalAlbumAssetEntityTable(this);
|
||||
late final i8.$RemoteExifEntityTable remoteExifEntity =
|
||||
i8.$RemoteExifEntityTable(this);
|
||||
i9.MergedAssetDrift get mergedAssetDrift => i10.ReadDatabaseContainer(this)
|
||||
.accessor<i9.MergedAssetDrift>(i9.MergedAssetDrift.new);
|
||||
late final i9.$RemoteAlbumEntityTable remoteAlbumEntity =
|
||||
i9.$RemoteAlbumEntityTable(this);
|
||||
late final i10.$RemoteAlbumAssetEntityTable remoteAlbumAssetEntity =
|
||||
i10.$RemoteAlbumAssetEntityTable(this);
|
||||
late final i11.$RemoteAlbumUserEntityTable remoteAlbumUserEntity =
|
||||
i11.$RemoteAlbumUserEntityTable(this);
|
||||
i12.MergedAssetDrift get mergedAssetDrift => i13.ReadDatabaseContainer(this)
|
||||
.accessor<i12.MergedAssetDrift>(i12.MergedAssetDrift.new);
|
||||
@override
|
||||
Iterable<i0.TableInfo<i0.Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>();
|
||||
@@ -56,7 +68,10 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
||||
partnerEntity,
|
||||
localAlbumEntity,
|
||||
localAlbumAssetEntity,
|
||||
remoteExifEntity
|
||||
remoteExifEntity,
|
||||
remoteAlbumEntity,
|
||||
remoteAlbumAssetEntity,
|
||||
remoteAlbumUserEntity
|
||||
];
|
||||
@override
|
||||
i0.StreamQueryUpdateRules get streamUpdateRules =>
|
||||
@@ -114,6 +129,52 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
||||
i0.TableUpdate('remote_exif_entity', kind: i0.UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
i0.WritePropagation(
|
||||
on: i0.TableUpdateQuery.onTableName('user_entity',
|
||||
limitUpdateKind: i0.UpdateKind.delete),
|
||||
result: [
|
||||
i0.TableUpdate('remote_album_entity', kind: i0.UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
i0.WritePropagation(
|
||||
on: i0.TableUpdateQuery.onTableName('remote_asset_entity',
|
||||
limitUpdateKind: i0.UpdateKind.delete),
|
||||
result: [
|
||||
i0.TableUpdate('remote_album_entity', kind: i0.UpdateKind.update),
|
||||
],
|
||||
),
|
||||
i0.WritePropagation(
|
||||
on: i0.TableUpdateQuery.onTableName('remote_asset_entity',
|
||||
limitUpdateKind: i0.UpdateKind.delete),
|
||||
result: [
|
||||
i0.TableUpdate('remote_album_asset_entity',
|
||||
kind: i0.UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
i0.WritePropagation(
|
||||
on: i0.TableUpdateQuery.onTableName('remote_album_entity',
|
||||
limitUpdateKind: i0.UpdateKind.delete),
|
||||
result: [
|
||||
i0.TableUpdate('remote_album_asset_entity',
|
||||
kind: i0.UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
i0.WritePropagation(
|
||||
on: i0.TableUpdateQuery.onTableName('remote_album_entity',
|
||||
limitUpdateKind: i0.UpdateKind.delete),
|
||||
result: [
|
||||
i0.TableUpdate('remote_album_user_entity',
|
||||
kind: i0.UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
i0.WritePropagation(
|
||||
on: i0.TableUpdateQuery.onTableName('user_entity',
|
||||
limitUpdateKind: i0.UpdateKind.delete),
|
||||
result: [
|
||||
i0.TableUpdate('remote_album_user_entity',
|
||||
kind: i0.UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
@override
|
||||
@@ -140,4 +201,11 @@ class $DriftManager {
|
||||
.$$LocalAlbumAssetEntityTableTableManager(_db, _db.localAlbumAssetEntity);
|
||||
i8.$$RemoteExifEntityTableTableManager get remoteExifEntity =>
|
||||
i8.$$RemoteExifEntityTableTableManager(_db, _db.remoteExifEntity);
|
||||
i9.$$RemoteAlbumEntityTableTableManager get remoteAlbumEntity =>
|
||||
i9.$$RemoteAlbumEntityTableTableManager(_db, _db.remoteAlbumEntity);
|
||||
i10.$$RemoteAlbumAssetEntityTableTableManager get remoteAlbumAssetEntity =>
|
||||
i10.$$RemoteAlbumAssetEntityTableTableManager(
|
||||
_db, _db.remoteAlbumAssetEntity);
|
||||
i11.$$RemoteAlbumUserEntityTableTableManager get remoteAlbumUserEntity => i11
|
||||
.$$RemoteAlbumUserEntityTableTableManager(_db, _db.remoteAlbumUserEntity);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:immich_mobile/domain/models/album/album.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
|
||||
enum SortRemoteAlbumsBy { id }
|
||||
|
||||
class DriftRemoteAlbumRepository extends DriftDatabaseRepository {
|
||||
final Drift _db;
|
||||
const DriftRemoteAlbumRepository(this._db) : super(_db);
|
||||
|
||||
Future<List<Album>> getAll({Set<SortRemoteAlbumsBy> sortBy = const {}}) {
|
||||
final query = _db.remoteAlbumEntity.select();
|
||||
|
||||
if (sortBy.isNotEmpty) {
|
||||
final orderings = <OrderClauseGenerator<$RemoteAlbumEntityTable>>[];
|
||||
for (final sort in sortBy) {
|
||||
orderings.add(
|
||||
switch (sort) {
|
||||
SortRemoteAlbumsBy.id => (row) => OrderingTerm.asc(row.id),
|
||||
},
|
||||
);
|
||||
}
|
||||
query.orderBy(orderings);
|
||||
}
|
||||
|
||||
return query.map((row) => row.toDto()).get();
|
||||
}
|
||||
}
|
||||
|
||||
extension on RemoteAlbumEntityData {
|
||||
Album toDto() {
|
||||
return Album(
|
||||
id: id,
|
||||
name: name,
|
||||
ownerId: ownerId,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
description: description,
|
||||
thumbnailAssetId: thumbnailAssetId,
|
||||
isActivityEnabled: isActivityEnabled,
|
||||
order: order,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -42,11 +42,16 @@ class SyncApiRepository {
|
||||
SyncStreamDto(
|
||||
types: [
|
||||
SyncRequestType.usersV1,
|
||||
SyncRequestType.partnersV1,
|
||||
SyncRequestType.assetsV1,
|
||||
SyncRequestType.partnerAssetsV1,
|
||||
SyncRequestType.assetExifsV1,
|
||||
SyncRequestType.partnersV1,
|
||||
SyncRequestType.partnerAssetsV1,
|
||||
SyncRequestType.partnerAssetExifsV1,
|
||||
SyncRequestType.albumsV1,
|
||||
SyncRequestType.albumUsersV1,
|
||||
SyncRequestType.albumAssetsV1,
|
||||
SyncRequestType.albumAssetExifsV1,
|
||||
SyncRequestType.albumToAssetsV1,
|
||||
],
|
||||
).toJson(),
|
||||
);
|
||||
@@ -135,6 +140,25 @@ const _kResponseMap = <SyncEntityType, Function(Object)>{
|
||||
SyncEntityType.assetDeleteV1: SyncAssetDeleteV1.fromJson,
|
||||
SyncEntityType.assetExifV1: SyncAssetExifV1.fromJson,
|
||||
SyncEntityType.partnerAssetV1: SyncAssetV1.fromJson,
|
||||
SyncEntityType.partnerAssetBackfillV1: SyncAssetV1.fromJson,
|
||||
SyncEntityType.partnerAssetDeleteV1: SyncAssetDeleteV1.fromJson,
|
||||
SyncEntityType.partnerAssetExifV1: SyncAssetExifV1.fromJson,
|
||||
SyncEntityType.partnerAssetExifBackfillV1: SyncAssetExifV1.fromJson,
|
||||
SyncEntityType.albumV1: SyncAlbumV1.fromJson,
|
||||
SyncEntityType.albumDeleteV1: SyncAlbumDeleteV1.fromJson,
|
||||
SyncEntityType.albumUserV1: SyncAlbumUserV1.fromJson,
|
||||
SyncEntityType.albumUserBackfillV1: SyncAlbumUserV1.fromJson,
|
||||
SyncEntityType.albumUserDeleteV1: SyncAlbumUserDeleteV1.fromJson,
|
||||
SyncEntityType.albumAssetV1: SyncAssetV1.fromJson,
|
||||
SyncEntityType.albumAssetBackfillV1: SyncAssetV1.fromJson,
|
||||
SyncEntityType.albumAssetExifV1: SyncAssetExifV1.fromJson,
|
||||
SyncEntityType.albumAssetExifBackfillV1: SyncAssetExifV1.fromJson,
|
||||
SyncEntityType.albumToAssetV1: SyncAlbumToAssetV1.fromJson,
|
||||
SyncEntityType.albumToAssetBackfillV1: SyncAlbumToAssetV1.fromJson,
|
||||
SyncEntityType.albumToAssetDeleteV1: SyncAlbumToAssetDeleteV1.fromJson,
|
||||
SyncEntityType.syncAckV1: _SyncAckV1.fromJson,
|
||||
};
|
||||
|
||||
class _SyncAckV1 {
|
||||
static _SyncAckV1? fromJson(dynamic _) => _SyncAckV1();
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:immich_mobile/domain/models/album/album.model.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:openapi/api.dart' as api show AssetVisibility;
|
||||
import 'package:openapi/api.dart' hide AssetVisibility;
|
||||
import 'package:openapi/api.dart' as api show AssetVisibility, AlbumUserRole;
|
||||
import 'package:openapi/api.dart' hide AssetVisibility, AlbumUserRole;
|
||||
|
||||
class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
final Logger _logger = Logger('DriftSyncStreamRepository');
|
||||
@@ -17,16 +21,10 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
|
||||
Future<void> deleteUsersV1(Iterable<SyncUserDeleteV1> data) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final user in data) {
|
||||
batch.delete(
|
||||
_db.userEntity,
|
||||
UserEntityCompanion(id: Value(user.userId)),
|
||||
);
|
||||
}
|
||||
});
|
||||
await _db.userEntity
|
||||
.deleteWhere((row) => row.id.isIn(data.map((e) => e.userId)));
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Error while processing SyncUserDeleteV1', error, stack);
|
||||
_logger.severe('Error: SyncUserDeleteV1', error, stack);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
@@ -48,7 +46,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
}
|
||||
});
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Error while processing SyncUserV1', error, stack);
|
||||
_logger.severe('Error: SyncUserV1', error, stack);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
@@ -67,7 +65,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error while processing SyncPartnerDeleteV1', e, s);
|
||||
_logger.severe('Error: SyncPartnerDeleteV1', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
@@ -90,67 +88,30 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error while processing SyncPartnerV1', e, s);
|
||||
_logger.severe('Error: SyncPartnerV1', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteAssetsV1(Iterable<SyncAssetDeleteV1> data) async {
|
||||
Future<void> deleteAssetsV1(
|
||||
Iterable<SyncAssetDeleteV1> data, {
|
||||
String debugLabel = 'user',
|
||||
}) async {
|
||||
try {
|
||||
await _deleteAssetsV1(data);
|
||||
await _db.remoteAssetEntity
|
||||
.deleteWhere((row) => row.id.isIn(data.map((e) => e.assetId)));
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error while processing deleteAssetsV1', e, s);
|
||||
_logger.severe('Error: deleteAssetsV1 - $debugLabel', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateAssetsV1(Iterable<SyncAssetV1> data) async {
|
||||
Future<void> updateAssetsV1(
|
||||
Iterable<SyncAssetV1> data, {
|
||||
String debugLabel = 'user',
|
||||
}) async {
|
||||
try {
|
||||
await _updateAssetsV1(data);
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error while processing updateAssetsV1', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deletePartnerAssetsV1(Iterable<SyncAssetDeleteV1> data) async {
|
||||
try {
|
||||
await _deleteAssetsV1(data);
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error while processing deletePartnerAssetsV1', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updatePartnerAssetsV1(Iterable<SyncAssetV1> data) async {
|
||||
try {
|
||||
await _updateAssetsV1(data);
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error while processing updatePartnerAssetsV1', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateAssetsExifV1(Iterable<SyncAssetExifV1> data) async {
|
||||
try {
|
||||
await _updateAssetExifV1(data);
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error while processing updateAssetsExifV1', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updatePartnerAssetsExifV1(Iterable<SyncAssetExifV1> data) async {
|
||||
try {
|
||||
await _updateAssetExifV1(data);
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error while processing updatePartnerAssetsExifV1', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _updateAssetsV1(Iterable<SyncAssetV1> data) =>
|
||||
_db.batch((batch) {
|
||||
await _db.batch((batch) {
|
||||
for (final asset in data) {
|
||||
final companion = RemoteAssetEntityCompanion(
|
||||
name: Value(asset.originalFileName),
|
||||
@@ -175,19 +136,18 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: updateAssetsV1 - $debugLabel', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _deleteAssetsV1(Iterable<SyncAssetDeleteV1> assets) =>
|
||||
_db.batch((batch) {
|
||||
for (final asset in assets) {
|
||||
batch.delete(
|
||||
_db.remoteAssetEntity,
|
||||
RemoteAssetEntityCompanion(id: Value(asset.assetId)),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Future<void> _updateAssetExifV1(Iterable<SyncAssetExifV1> data) =>
|
||||
_db.batch((batch) {
|
||||
Future<void> updateAssetsExifV1(
|
||||
Iterable<SyncAssetExifV1> data, {
|
||||
String debugLabel = 'user',
|
||||
}) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final exif in data) {
|
||||
final companion = RemoteExifEntityCompanion(
|
||||
city: Value(exif.city),
|
||||
@@ -219,6 +179,141 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: updateAssetsExifV1 - $debugLabel', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteAlbumsV1(Iterable<SyncAlbumDeleteV1> data) async {
|
||||
try {
|
||||
await _db.remoteAlbumEntity
|
||||
.deleteWhere((row) => row.id.isIn(data.map((e) => e.albumId)));
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: deleteAlbumsV1', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateAlbumsV1(Iterable<SyncAlbumV1> data) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final album in data) {
|
||||
final companion = RemoteAlbumEntityCompanion(
|
||||
name: Value(album.name),
|
||||
description: Value(album.description),
|
||||
isActivityEnabled: Value(album.isActivityEnabled),
|
||||
order: Value(album.order.toAlbumAssetOrder()),
|
||||
thumbnailAssetId: Value(album.thumbnailAssetId),
|
||||
ownerId: Value(album.ownerId),
|
||||
createdAt: Value(album.createdAt),
|
||||
updatedAt: Value(album.updatedAt),
|
||||
);
|
||||
|
||||
batch.insert(
|
||||
_db.remoteAlbumEntity,
|
||||
companion.copyWith(id: Value(album.id)),
|
||||
onConflict: DoUpdate((_) => companion),
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: updateAlbumsV1', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteAlbumUsersV1(Iterable<SyncAlbumUserDeleteV1> data) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final album in data) {
|
||||
batch.delete(
|
||||
_db.remoteAlbumUserEntity,
|
||||
RemoteAlbumUserEntityCompanion(
|
||||
albumId: Value(album.albumId),
|
||||
userId: Value(album.userId),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: deleteAlbumUsersV1', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateAlbumUsersV1(
|
||||
Iterable<SyncAlbumUserV1> data, {
|
||||
String debugLabel = 'user',
|
||||
}) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final album in data) {
|
||||
final companion = RemoteAlbumUserEntityCompanion(
|
||||
role: Value(album.role.toAlbumUserRole()),
|
||||
);
|
||||
|
||||
batch.insert(
|
||||
_db.remoteAlbumUserEntity,
|
||||
companion.copyWith(
|
||||
albumId: Value(album.albumId),
|
||||
userId: Value(album.userId),
|
||||
),
|
||||
onConflict: DoUpdate((_) => companion),
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: updateAlbumUsersV1 - $debugLabel', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteAlbumToAssetsV1(
|
||||
Iterable<SyncAlbumToAssetDeleteV1> data,
|
||||
) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final album in data) {
|
||||
batch.delete(
|
||||
_db.remoteAlbumAssetEntity,
|
||||
RemoteAlbumAssetEntityCompanion(
|
||||
albumId: Value(album.albumId),
|
||||
assetId: Value(album.assetId),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: deleteAlbumToAssetsV1', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateAlbumToAssetsV1(
|
||||
Iterable<SyncAlbumToAssetV1> data, {
|
||||
String debugLabel = 'user',
|
||||
}) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final album in data) {
|
||||
final companion = RemoteAlbumAssetEntityCompanion(
|
||||
albumId: Value(album.albumId),
|
||||
assetId: Value(album.assetId),
|
||||
);
|
||||
|
||||
batch.insert(
|
||||
_db.remoteAlbumAssetEntity,
|
||||
companion,
|
||||
onConflict: DoNothing(),
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: updateAlbumToAssetsV1 - $debugLabel', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension on AssetTypeEnum {
|
||||
@@ -231,6 +326,22 @@ extension on AssetTypeEnum {
|
||||
};
|
||||
}
|
||||
|
||||
extension on AssetOrder {
|
||||
AlbumAssetOrder toAlbumAssetOrder() => switch (this) {
|
||||
AssetOrder.asc => AlbumAssetOrder.asc,
|
||||
AssetOrder.desc => AlbumAssetOrder.desc,
|
||||
_ => throw Exception('Unknown AssetOrder value: $this'),
|
||||
};
|
||||
}
|
||||
|
||||
extension on api.AlbumUserRole {
|
||||
AlbumUserRole toAlbumUserRole() => switch (this) {
|
||||
api.AlbumUserRole.editor => AlbumUserRole.editor,
|
||||
api.AlbumUserRole.viewer => AlbumUserRole.viewer,
|
||||
_ => throw Exception('Unknown AlbumUserRole value: $this'),
|
||||
};
|
||||
}
|
||||
|
||||
extension on api.AssetVisibility {
|
||||
AssetVisibility toAssetVisibility() => switch (this) {
|
||||
api.AssetVisibility.timeline => AssetVisibility.timeline,
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:immich_mobile/constants/constants.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/domain/models/timeline.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
import 'package:stream_transform/stream_transform.dart';
|
||||
|
||||
@@ -139,6 +140,62 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
.map((row) => row.readTable(_db.localAssetEntity).toDto())
|
||||
.get();
|
||||
}
|
||||
|
||||
Stream<List<Bucket>> watchRemoteBucket(
|
||||
String albumId, {
|
||||
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||
}) {
|
||||
if (groupBy == GroupAssetsBy.none) {
|
||||
return _db.remoteAlbumAssetEntity
|
||||
.count(where: (row) => row.albumId.equals(albumId))
|
||||
.map(_generateBuckets)
|
||||
.watchSingle();
|
||||
}
|
||||
|
||||
final assetCountExp = _db.remoteAssetEntity.id.count();
|
||||
final dateExp = _db.remoteAssetEntity.createdAt.dateFmt(groupBy);
|
||||
|
||||
final query = _db.remoteAssetEntity.selectOnly()
|
||||
..addColumns([assetCountExp, dateExp])
|
||||
..join([
|
||||
innerJoin(
|
||||
_db.remoteAlbumAssetEntity,
|
||||
_db.remoteAlbumAssetEntity.assetId
|
||||
.equalsExp(_db.remoteAssetEntity.id),
|
||||
),
|
||||
])
|
||||
..where(_db.remoteAlbumAssetEntity.albumId.equals(albumId))
|
||||
..groupBy([dateExp])
|
||||
..orderBy([OrderingTerm.desc(dateExp)]);
|
||||
|
||||
return query.map((row) {
|
||||
final timeline = row.read(dateExp)!.dateFmt(groupBy);
|
||||
final assetCount = row.read(assetCountExp)!;
|
||||
return TimeBucket(date: timeline, assetCount: assetCount);
|
||||
}).watch();
|
||||
}
|
||||
|
||||
Future<List<BaseAsset>> getRemoteBucketAssets(
|
||||
String albumId, {
|
||||
required int offset,
|
||||
required int count,
|
||||
}) {
|
||||
final query = _db.remoteAssetEntity.select().join(
|
||||
[
|
||||
innerJoin(
|
||||
_db.remoteAlbumAssetEntity,
|
||||
_db.remoteAlbumAssetEntity.assetId
|
||||
.equalsExp(_db.remoteAssetEntity.id),
|
||||
),
|
||||
],
|
||||
)
|
||||
..where(_db.remoteAlbumAssetEntity.albumId.equals(albumId))
|
||||
..orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)])
|
||||
..limit(count, offset: offset);
|
||||
return query
|
||||
.map((row) => row.readTable(_db.remoteAssetEntity).toDto())
|
||||
.get();
|
||||
}
|
||||
}
|
||||
|
||||
extension on Expression<DateTime> {
|
||||
|
||||
Reference in New Issue
Block a user