feat: memories sync (#19644)
* feat: memories sync * Update mobile/lib/infrastructure/repositories/sync_stream.repository.dart Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update mobile/lib/infrastructure/repositories/sync_stream.repository.dart Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * show sync information * tests and pr feedback * pr feedback --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -7,6 +7,8 @@ import 'package:immich_mobile/infrastructure/entities/exif.entity.dart';
|
||||
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/memory.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/memory_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';
|
||||
@@ -46,6 +48,8 @@ class IsarDatabaseRepository implements IDatabaseRepository {
|
||||
RemoteAlbumEntity,
|
||||
RemoteAlbumAssetEntity,
|
||||
RemoteAlbumUserEntity,
|
||||
MemoryEntity,
|
||||
MemoryAssetEntity,
|
||||
],
|
||||
include: {
|
||||
'package:immich_mobile/infrastructure/entities/merged_asset.drift',
|
||||
|
||||
+39
-5
@@ -23,9 +23,13 @@ import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.
|
||||
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'
|
||||
import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart'
|
||||
as i12;
|
||||
import 'package:drift/internal/modular.dart' as i13;
|
||||
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.dart'
|
||||
as i13;
|
||||
import 'package:immich_mobile/infrastructure/entities/merged_asset.drift.dart'
|
||||
as i14;
|
||||
import 'package:drift/internal/modular.dart' as i15;
|
||||
|
||||
abstract class $Drift extends i0.GeneratedDatabase {
|
||||
$Drift(i0.QueryExecutor e) : super(e);
|
||||
@@ -51,8 +55,11 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
||||
i10.$RemoteAlbumAssetEntityTable(this);
|
||||
late final i11.$RemoteAlbumUserEntityTable remoteAlbumUserEntity =
|
||||
i11.$RemoteAlbumUserEntityTable(this);
|
||||
i12.MergedAssetDrift get mergedAssetDrift => i13.ReadDatabaseContainer(this)
|
||||
.accessor<i12.MergedAssetDrift>(i12.MergedAssetDrift.new);
|
||||
late final i12.$MemoryEntityTable memoryEntity = i12.$MemoryEntityTable(this);
|
||||
late final i13.$MemoryAssetEntityTable memoryAssetEntity =
|
||||
i13.$MemoryAssetEntityTable(this);
|
||||
i14.MergedAssetDrift get mergedAssetDrift => i15.ReadDatabaseContainer(this)
|
||||
.accessor<i14.MergedAssetDrift>(i14.MergedAssetDrift.new);
|
||||
@override
|
||||
Iterable<i0.TableInfo<i0.Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>();
|
||||
@@ -71,7 +78,9 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
||||
remoteExifEntity,
|
||||
remoteAlbumEntity,
|
||||
remoteAlbumAssetEntity,
|
||||
remoteAlbumUserEntity
|
||||
remoteAlbumUserEntity,
|
||||
memoryEntity,
|
||||
memoryAssetEntity
|
||||
];
|
||||
@override
|
||||
i0.StreamQueryUpdateRules get streamUpdateRules =>
|
||||
@@ -175,6 +184,27 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
||||
kind: i0.UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
i0.WritePropagation(
|
||||
on: i0.TableUpdateQuery.onTableName('user_entity',
|
||||
limitUpdateKind: i0.UpdateKind.delete),
|
||||
result: [
|
||||
i0.TableUpdate('memory_entity', kind: i0.UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
i0.WritePropagation(
|
||||
on: i0.TableUpdateQuery.onTableName('remote_asset_entity',
|
||||
limitUpdateKind: i0.UpdateKind.delete),
|
||||
result: [
|
||||
i0.TableUpdate('memory_asset_entity', kind: i0.UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
i0.WritePropagation(
|
||||
on: i0.TableUpdateQuery.onTableName('memory_entity',
|
||||
limitUpdateKind: i0.UpdateKind.delete),
|
||||
result: [
|
||||
i0.TableUpdate('memory_asset_entity', kind: i0.UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
@override
|
||||
@@ -208,4 +238,8 @@ class $DriftManager {
|
||||
_db, _db.remoteAlbumAssetEntity);
|
||||
i11.$$RemoteAlbumUserEntityTableTableManager get remoteAlbumUserEntity => i11
|
||||
.$$RemoteAlbumUserEntityTableTableManager(_db, _db.remoteAlbumUserEntity);
|
||||
i12.$$MemoryEntityTableTableManager get memoryEntity =>
|
||||
i12.$$MemoryEntityTableTableManager(_db, _db.memoryEntity);
|
||||
i13.$$MemoryAssetEntityTableTableManager get memoryAssetEntity =>
|
||||
i13.$$MemoryAssetEntityTableTableManager(_db, _db.memoryAssetEntity);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:immich_mobile/domain/models/memory.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
|
||||
class DriftMemoryRepository extends DriftDatabaseRepository {
|
||||
final Drift _db;
|
||||
const DriftMemoryRepository(this._db) : super(_db);
|
||||
|
||||
Future<List<Memory>> getAll(String userId) {
|
||||
final query = _db.memoryEntity.select()
|
||||
..where((e) => e.ownerId.equals(userId));
|
||||
|
||||
return query.map((memory) {
|
||||
return memory.toDto();
|
||||
}).get();
|
||||
}
|
||||
}
|
||||
|
||||
extension on MemoryEntityData {
|
||||
Memory toDto() {
|
||||
return Memory(
|
||||
id: id,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
deletedAt: deletedAt,
|
||||
ownerId: ownerId,
|
||||
type: type,
|
||||
data: MemoryData.fromJson(data),
|
||||
isSaved: isSaved,
|
||||
memoryAt: memoryAt,
|
||||
seenAt: seenAt,
|
||||
showAt: showAt,
|
||||
hideAt: hideAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,8 @@ class SyncApiRepository {
|
||||
SyncRequestType.albumAssetsV1,
|
||||
SyncRequestType.albumAssetExifsV1,
|
||||
SyncRequestType.albumToAssetsV1,
|
||||
SyncRequestType.memoriesV1,
|
||||
SyncRequestType.memoryToAssetsV1,
|
||||
],
|
||||
).toJson(),
|
||||
);
|
||||
@@ -157,6 +159,10 @@ const _kResponseMap = <SyncEntityType, Function(Object)>{
|
||||
SyncEntityType.albumToAssetBackfillV1: SyncAlbumToAssetV1.fromJson,
|
||||
SyncEntityType.albumToAssetDeleteV1: SyncAlbumToAssetDeleteV1.fromJson,
|
||||
SyncEntityType.syncAckV1: _SyncAckV1.fromJson,
|
||||
SyncEntityType.memoryV1: SyncMemoryV1.fromJson,
|
||||
SyncEntityType.memoryDeleteV1: SyncMemoryDeleteV1.fromJson,
|
||||
SyncEntityType.memoryToAssetV1: SyncMemoryAssetV1.fromJson,
|
||||
SyncEntityType.memoryToAssetDeleteV1: SyncMemoryAssetDeleteV1.fromJson,
|
||||
};
|
||||
|
||||
class _SyncAckV1 {
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import 'dart:convert';
|
||||
|
||||
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/domain/models/memory.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/memory_asset.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/memory.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';
|
||||
@@ -64,8 +69,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: SyncPartnerDeleteV1', e, s);
|
||||
} catch (error, stackTrace) {
|
||||
_logger.severe('Error: SyncPartnerDeleteV1', error, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
@@ -87,8 +92,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: SyncPartnerV1', e, s);
|
||||
} catch (error, stackTrace) {
|
||||
_logger.severe('Error: SyncPartnerV1', error, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
@@ -98,10 +103,11 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
String debugLabel = 'user',
|
||||
}) async {
|
||||
try {
|
||||
await _db.remoteAssetEntity
|
||||
.deleteWhere((row) => row.id.isIn(data.map((e) => e.assetId)));
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: deleteAssetsV1 - $debugLabel', e, s);
|
||||
await _db.remoteAssetEntity.deleteWhere(
|
||||
(row) => row.id.isIn(data.map((error) => error.assetId)),
|
||||
);
|
||||
} catch (error, stackTrace) {
|
||||
_logger.severe('Error: deleteAssetsV1 - $debugLabel', error, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
@@ -136,8 +142,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: updateAssetsV1 - $debugLabel', e, s);
|
||||
} catch (error, stackTrace) {
|
||||
_logger.severe('Error: updateAssetsV1 - $debugLabel', error, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
@@ -180,18 +186,23 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: updateAssetsExifV1 - $debugLabel', e, s);
|
||||
} catch (error, stackTrace) {
|
||||
_logger.severe(
|
||||
'Error: updateAssetsExifV1 - $debugLabel',
|
||||
error,
|
||||
stackTrace,
|
||||
);
|
||||
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);
|
||||
await _db.remoteAlbumEntity.deleteWhere(
|
||||
(row) => row.id.isIn(data.map((e) => e.albumId)),
|
||||
);
|
||||
} catch (error, stackTrace) {
|
||||
_logger.severe('Error: deleteAlbumsV1', error, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
@@ -218,8 +229,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: updateAlbumsV1', e, s);
|
||||
} catch (error, stackTrace) {
|
||||
_logger.severe('Error: updateAlbumsV1', error, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
@@ -237,8 +248,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: deleteAlbumUsersV1', e, s);
|
||||
} catch (error, stackTrace) {
|
||||
_logger.severe('Error: deleteAlbumUsersV1', error, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
@@ -264,8 +275,12 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: updateAlbumUsersV1 - $debugLabel', e, s);
|
||||
} catch (error, stackTrace) {
|
||||
_logger.severe(
|
||||
'Error: updateAlbumUsersV1 - $debugLabel',
|
||||
error,
|
||||
stackTrace,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
@@ -285,8 +300,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: deleteAlbumToAssetsV1', e, s);
|
||||
} catch (error, stackTrace) {
|
||||
_logger.severe('Error: deleteAlbumToAssetsV1', error, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
@@ -310,8 +325,96 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error: updateAlbumToAssetsV1 - $debugLabel', e, s);
|
||||
} catch (error, stackTrace) {
|
||||
_logger.severe(
|
||||
'Error: updateAlbumToAssetsV1 - $debugLabel',
|
||||
error,
|
||||
stackTrace,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateMemoriesV1(Iterable<SyncMemoryV1> data) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final memory in data) {
|
||||
final companion = MemoryEntityCompanion(
|
||||
createdAt: Value(memory.createdAt),
|
||||
deletedAt: Value(memory.deletedAt),
|
||||
ownerId: Value(memory.ownerId),
|
||||
type: Value(memory.type.toMemoryType()),
|
||||
data: Value(jsonEncode(memory.data)),
|
||||
isSaved: Value(memory.isSaved),
|
||||
memoryAt: Value(memory.memoryAt),
|
||||
seenAt: Value.absentIfNull(memory.seenAt),
|
||||
showAt: Value.absentIfNull(memory.showAt),
|
||||
hideAt: Value.absentIfNull(memory.hideAt),
|
||||
);
|
||||
|
||||
batch.insert(
|
||||
_db.memoryEntity,
|
||||
companion.copyWith(id: Value(memory.id)),
|
||||
onConflict: DoUpdate((_) => companion),
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (error, stackTrace) {
|
||||
_logger.severe('Error: updateMemoriesV1', error, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteMemoriesV1(Iterable<SyncMemoryDeleteV1> data) async {
|
||||
try {
|
||||
await _db.memoryEntity.deleteWhere(
|
||||
(row) => row.id.isIn(data.map((e) => e.memoryId)),
|
||||
);
|
||||
} catch (error, stackTrace) {
|
||||
_logger.severe('Error: deleteMemoriesV1', error, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateMemoryAssetsV1(Iterable<SyncMemoryAssetV1> data) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final asset in data) {
|
||||
final companion = MemoryAssetEntityCompanion(
|
||||
memoryId: Value(asset.memoryId),
|
||||
assetId: Value(asset.assetId),
|
||||
);
|
||||
|
||||
batch.insert(
|
||||
_db.memoryAssetEntity,
|
||||
companion,
|
||||
onConflict: DoNothing(),
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (error, stackTrace) {
|
||||
_logger.severe('Error: updateMemoryAssetsV1', error, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteMemoryAssetsV1(
|
||||
Iterable<SyncMemoryAssetDeleteV1> data,
|
||||
) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final asset in data) {
|
||||
batch.delete(
|
||||
_db.memoryAssetEntity,
|
||||
MemoryAssetEntityCompanion(
|
||||
memoryId: Value(asset.memoryId),
|
||||
assetId: Value(asset.assetId),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (error, stackTrace) {
|
||||
_logger.severe('Error: deleteMemoryAssetsV1', error, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
@@ -335,6 +438,13 @@ extension on AssetOrder {
|
||||
};
|
||||
}
|
||||
|
||||
extension on MemoryType {
|
||||
MemoryTypeEnum toMemoryType() => switch (this) {
|
||||
MemoryType.onThisDay => MemoryTypeEnum.onThisDay,
|
||||
_ => throw Exception('Unknown MemoryType value: $this'),
|
||||
};
|
||||
}
|
||||
|
||||
extension on api.AlbumUserRole {
|
||||
AlbumUserRole toAlbumUserRole() => switch (this) {
|
||||
api.AlbumUserRole.editor => AlbumUserRole.editor,
|
||||
@@ -357,7 +467,7 @@ extension on String {
|
||||
Duration? toDuration() {
|
||||
try {
|
||||
final parts = split(':')
|
||||
.map((e) => double.parse(e).toInt())
|
||||
.map((error) => double.parse(error).toInt())
|
||||
.toList(growable: false);
|
||||
|
||||
return Duration(hours: parts[0], minutes: parts[1], seconds: parts[2]);
|
||||
|
||||
Reference in New Issue
Block a user