feat(mobile): drift user metadata sync (#19894)

* feat(mobile): drift user metadata sync

* change text to jsonb

* update primary key

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
Daimolean
2025-07-15 22:17:35 +08:00
committed by GitHub
parent daea57f7d2
commit 0acbf1199a
10 changed files with 495 additions and 106 deletions
@@ -56,6 +56,7 @@ class SyncApiRepository {
SyncRequestType.memoryToAssetsV1,
SyncRequestType.stacksV1,
SyncRequestType.partnerStacksV1,
SyncRequestType.userMetadataV1,
],
).toJson(),
);
@@ -170,6 +171,8 @@ const _kResponseMap = <SyncEntityType, Function(Object)>{
SyncEntityType.partnerStackV1: SyncStackV1.fromJson,
SyncEntityType.partnerStackBackfillV1: SyncStackV1.fromJson,
SyncEntityType.partnerStackDeleteV1: SyncStackDeleteV1.fromJson,
SyncEntityType.userMetadataV1: SyncUserMetadataV1.fromJson,
SyncEntityType.userMetadataDeleteV1: SyncUserMetadataDeleteV1.fromJson,
};
class _SyncAckV1 {
@@ -4,6 +4,7 @@ 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/domain/models/user_metadata.model.dart';
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.dart';
@@ -14,6 +15,7 @@ import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.d
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/user_metadata.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, AlbumUserRole;
@@ -461,6 +463,53 @@ class SyncStreamRepository extends DriftDatabaseRepository {
rethrow;
}
}
Future<void> updateUserMetadatasV1(
Iterable<SyncUserMetadataV1> data,
) async {
try {
await _db.batch((batch) {
for (final userMetadata in data) {
final companion = UserMetadataEntityCompanion(
value: Value(userMetadata.value as Map<String, Object?>),
);
batch.insert(
_db.userMetadataEntity,
companion.copyWith(
userId: Value(userMetadata.userId),
key: Value(userMetadata.key.toUserMetadataKey()),
),
onConflict: DoUpdate((_) => companion),
);
}
});
} catch (error, stack) {
_logger.severe('Error: deleteUserMetadatasV1', error, stack);
rethrow;
}
}
Future<void> deleteUserMetadatasV1(
Iterable<SyncUserMetadataDeleteV1> data,
) async {
try {
await _db.batch((batch) {
for (final userMetadata in data) {
batch.delete(
_db.userMetadataEntity,
UserMetadataEntityCompanion(
userId: Value(userMetadata.userId),
key: Value(userMetadata.key.toUserMetadataKey()),
),
);
}
});
} catch (error, stack) {
_logger.severe('Error: deleteUserMetadatasV1', error, stack);
rethrow;
}
}
}
extension on AssetTypeEnum {
@@ -506,6 +555,15 @@ extension on api.AssetVisibility {
};
}
extension on String {
UserMetadataKey toUserMetadataKey() => switch (this) {
"onboarding" => UserMetadataKey.onboarding,
"preferences" => UserMetadataKey.preferences,
"license" => UserMetadataKey.license,
_ => throw Exception('Unknown UserMetadataKey value: $this'),
};
}
extension on String {
Duration? toDuration() {
try {
@@ -0,0 +1,38 @@
import 'package:drift/drift.dart';
import 'package:immich_mobile/domain/models/user_metadata.model.dart';
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift.dart';
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
class DriftUserMetadataRepository extends DriftDatabaseRepository {
final Drift _db;
const DriftUserMetadataRepository(this._db) : super(_db);
Future<List<UserMetadata>> getUserMetadata(String userId) {
final query = _db.userMetadataEntity.select()
..where((e) => e.userId.equals(userId));
return query.map((userMetadata) {
return userMetadata.toDto();
}).get();
}
}
extension on UserMetadataEntityData {
UserMetadata toDto() => switch (key) {
UserMetadataKey.onboarding => UserMetadata(
userId: userId,
key: key,
onboarding: Onboarding.fromMap(value),
),
UserMetadataKey.preferences => UserMetadata(
userId: userId,
key: key,
preferences: Preferences.fromMap(value),
),
UserMetadataKey.license => UserMetadata(
userId: userId,
key: key,
license: License.fromMap(value),
),
};
}