more fixes

This commit is contained in:
shenlong-tanwen 2025-09-04 18:28:02 +05:30
parent 254ca4a13d
commit 9cf5d83707
6 changed files with 41 additions and 29 deletions

View File

@ -1,5 +1,3 @@
import 'dart:convert';
enum RemoteAssetMetadataKey { enum RemoteAssetMetadataKey {
mobileApp("mobile-app"); mobileApp("mobile-app");
@ -8,25 +6,30 @@ enum RemoteAssetMetadataKey {
const RemoteAssetMetadataKey(this.key); const RemoteAssetMetadataKey(this.key);
} }
abstract class RemoteAssetMetadataValue {
const RemoteAssetMetadataValue();
Map<String, dynamic> toJson();
}
class RemoteAssetMetadataItem { class RemoteAssetMetadataItem {
final RemoteAssetMetadataKey key; final RemoteAssetMetadataKey key;
final Object value; final RemoteAssetMetadataValue value;
const RemoteAssetMetadataItem({required this.key, required this.value}); const RemoteAssetMetadataItem({required this.key, required this.value});
Map<String, Object?> toMap() { Map<String, Object?> toJson() {
return {'key': key.key, 'value': value}; return {'key': key.key, 'value': value};
} }
String toJson() => json.encode(toMap());
} }
class RemoteAssetMobileAppMetadata { class RemoteAssetMobileAppMetadata extends RemoteAssetMetadataValue {
final String? cloudId; final String? cloudId;
const RemoteAssetMobileAppMetadata({this.cloudId}); const RemoteAssetMobileAppMetadata({this.cloudId});
Map<String, Object?> toMap() { @override
Map<String, dynamic> toJson() {
final map = <String, Object?>{}; final map = <String, Object?>{};
if (cloudId != null) { if (cloudId != null) {
map["iCloudId"] = cloudId; map["iCloudId"] = cloudId;
@ -34,6 +37,4 @@ class RemoteAssetMobileAppMetadata {
return map; return map;
} }
String toJson() => json.encode(toMap());
} }

View File

@ -7,6 +7,8 @@ import 'package:immich_mobile/platform/native_sync_api.g.dart';
import 'package:immich_mobile/providers/api.provider.dart'; import 'package:immich_mobile/providers/api.provider.dart';
import 'package:immich_mobile/providers/infrastructure/db.provider.dart'; import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
import 'package:immich_mobile/providers/infrastructure/sync.provider.dart'; import 'package:immich_mobile/providers/infrastructure/sync.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart';
import 'package:logging/logging.dart';
// ignore: import_rule_openapi // ignore: import_rule_openapi
import 'package:openapi/api.dart'; import 'package:openapi/api.dart';
@ -19,14 +21,24 @@ Future<void> migrateCloudIds(ProviderContainer ref) async {
await ref.read(syncStreamServiceProvider).sync(); await ref.read(syncStreamServiceProvider).sync();
// Fetch the mapping for backed up assets that have a cloud ID locally but do not have a cloud ID on the server // Fetch the mapping for backed up assets that have a cloud ID locally but do not have a cloud ID on the server
final mappingsToUpdate = await _fetchCloudIdMappings(db); final currentUser = ref.read(currentUserProvider);
if (currentUser == null) {
Logger('migrateCloudIds').warning('Current user is null. Aborting cloudId migration.');
return;
}
final mappingsToUpdate = await _fetchCloudIdMappings(db, currentUser.id);
final assetApi = ref.read(apiServiceProvider).assetsApi; final assetApi = ref.read(apiServiceProvider).assetsApi;
for (final mapping in mappingsToUpdate) { for (final mapping in mappingsToUpdate) {
final mobileMeta = AssetMetadataUpsertItemDto( final mobileMeta = AssetMetadataUpsertItemDto(
key: AssetMetadataKey.mobileApp, key: AssetMetadataKey.mobileApp,
value: RemoteAssetMobileAppMetadata(cloudId: mapping.cloudId).toMap(), value: RemoteAssetMobileAppMetadata(cloudId: mapping.cloudId),
); );
await assetApi.updateAssetMetadata(mapping.assetId, AssetMetadataUpsertDto(items: [mobileMeta])); try {
await assetApi.updateAssetMetadata(mapping.assetId, AssetMetadataUpsertDto(items: [mobileMeta]));
} catch (error, stack) {
Logger('migrateCloudIds').warning('Failed to update metadata for asset ${mapping.assetId}', error, stack);
}
} }
} }
@ -41,7 +53,7 @@ Future<void> _populateCloudIds(Drift drift) async {
typedef _CloudIdMapping = ({String assetId, String cloudId}); typedef _CloudIdMapping = ({String assetId, String cloudId});
Future<List<_CloudIdMapping>> _fetchCloudIdMappings(Drift drift) async { Future<List<_CloudIdMapping>> _fetchCloudIdMappings(Drift drift, String userId) async {
final query = final query =
drift.remoteAssetEntity.selectOnly().join([ drift.remoteAssetEntity.selectOnly().join([
leftOuterJoin( leftOuterJoin(
@ -58,7 +70,8 @@ Future<List<_CloudIdMapping>> _fetchCloudIdMappings(Drift drift) async {
]) ])
..addColumns([drift.remoteAssetEntity.id, drift.localAssetEntity.cloudId]) ..addColumns([drift.remoteAssetEntity.id, drift.localAssetEntity.cloudId])
..where( ..where(
drift.localAssetEntity.id.isNotNull() & drift.remoteAssetEntity.ownerId.equals(userId) &
drift.localAssetEntity.id.isNotNull() &
drift.localAssetEntity.cloudId.isNotNull() & drift.localAssetEntity.cloudId.isNotNull() &
drift.remoteAssetMetadataEntity.cloudId.isNull(), drift.remoteAssetMetadataEntity.cloudId.isNull(),
); );

View File

@ -37,5 +37,6 @@ extension LocalAssetEntityDataDomainExtension on LocalAssetEntityData {
width: width, width: width,
remoteId: null, remoteId: null,
orientation: orientation, orientation: orientation,
cloudId: cloudId,
); );
} }

View File

@ -1,5 +1,3 @@
import 'dart:convert';
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:drift/extensions/json1.dart'; import 'package:drift/extensions/json1.dart';
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart'; import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
@ -17,7 +15,7 @@ class RemoteAssetMetadataEntity extends Table with DriftDefaultsMixin {
BlobColumn get value => blob().map(assetMetadataConverter)(); BlobColumn get value => blob().map(assetMetadataConverter)();
TextColumn get cloudId => text().generatedAs(key.jsonExtract(r'$.iCloudId'), stored: true)(); TextColumn get cloudId => text().generatedAs(value.jsonExtract(r'$.iCloudId'), stored: true).nullable()();
@override @override
Set<Column> get primaryKey => {assetId, key}; Set<Column> get primaryKey => {assetId, key};
@ -25,5 +23,4 @@ class RemoteAssetMetadataEntity extends Table with DriftDefaultsMixin {
final JsonTypeConverter2<Map<String, Object?>, Uint8List, Object?> assetMetadataConverter = TypeConverter.jsonb( final JsonTypeConverter2<Map<String, Object?>, Uint8List, Object?> assetMetadataConverter = TypeConverter.jsonb(
fromJson: (json) => json as Map<String, Object?>, fromJson: (json) => json as Map<String, Object?>,
toJson: (value) => jsonEncode(value),
); );

View File

@ -425,9 +425,9 @@ class $RemoteAssetMetadataEntityTable extends i3.RemoteAssetMetadataEntity
late final i0.GeneratedColumn<String> cloudId = i0.GeneratedColumn<String>( late final i0.GeneratedColumn<String> cloudId = i0.GeneratedColumn<String>(
'cloud_id', 'cloud_id',
aliasedName, aliasedName,
false, true,
generatedAs: i0.GeneratedAs( generatedAs: i0.GeneratedAs(
i4.JsonExtensions(key).jsonExtract(r'$.iCloudId'), i4.JsonbExtensions(value).jsonExtract(r'$.iCloudId'),
true, true,
), ),
type: i0.DriftSqlType.string, type: i0.DriftSqlType.string,
@ -498,7 +498,7 @@ class $RemoteAssetMetadataEntityTable extends i3.RemoteAssetMetadataEntity
cloudId: attachedDatabase.typeMapping.read( cloudId: attachedDatabase.typeMapping.read(
i0.DriftSqlType.string, i0.DriftSqlType.string,
data['${effectivePrefix}cloud_id'], data['${effectivePrefix}cloud_id'],
)!, ),
); );
} }
@ -520,12 +520,12 @@ class RemoteAssetMetadataEntityData extends i0.DataClass
final String assetId; final String assetId;
final String key; final String key;
final Map<String, Object?> value; final Map<String, Object?> value;
final String cloudId; final String? cloudId;
const RemoteAssetMetadataEntityData({ const RemoteAssetMetadataEntityData({
required this.assetId, required this.assetId,
required this.key, required this.key,
required this.value, required this.value,
required this.cloudId, this.cloudId,
}); });
@override @override
Map<String, i0.Expression> toColumns(bool nullToAbsent) { Map<String, i0.Expression> toColumns(bool nullToAbsent) {
@ -551,7 +551,7 @@ class RemoteAssetMetadataEntityData extends i0.DataClass
value: i1.$RemoteAssetMetadataEntityTable.$convertervalue.fromJson( value: i1.$RemoteAssetMetadataEntityTable.$convertervalue.fromJson(
serializer.fromJson<Object?>(json['value']), serializer.fromJson<Object?>(json['value']),
), ),
cloudId: serializer.fromJson<String>(json['cloudId']), cloudId: serializer.fromJson<String?>(json['cloudId']),
); );
} }
@override @override
@ -563,7 +563,7 @@ class RemoteAssetMetadataEntityData extends i0.DataClass
'value': serializer.toJson<Object?>( 'value': serializer.toJson<Object?>(
i1.$RemoteAssetMetadataEntityTable.$convertervalue.toJson(value), i1.$RemoteAssetMetadataEntityTable.$convertervalue.toJson(value),
), ),
'cloudId': serializer.toJson<String>(cloudId), 'cloudId': serializer.toJson<String?>(cloudId),
}; };
} }
@ -571,12 +571,12 @@ class RemoteAssetMetadataEntityData extends i0.DataClass
String? assetId, String? assetId,
String? key, String? key,
Map<String, Object?>? value, Map<String, Object?>? value,
String? cloudId, i0.Value<String?> cloudId = const i0.Value.absent(),
}) => i1.RemoteAssetMetadataEntityData( }) => i1.RemoteAssetMetadataEntityData(
assetId: assetId ?? this.assetId, assetId: assetId ?? this.assetId,
key: key ?? this.key, key: key ?? this.key,
value: value ?? this.value, value: value ?? this.value,
cloudId: cloudId ?? this.cloudId, cloudId: cloudId.present ? cloudId.value : this.cloudId,
); );
@override @override
String toString() { String toString() {

View File

@ -368,7 +368,7 @@ class UploadService {
'metadata': jsonEncode([ 'metadata': jsonEncode([
RemoteAssetMetadataItem( RemoteAssetMetadataItem(
key: RemoteAssetMetadataKey.mobileApp, key: RemoteAssetMetadataKey.mobileApp,
value: RemoteAssetMobileAppMetadata(cloudId: cloudId).toMap(), value: RemoteAssetMobileAppMetadata(cloudId: cloudId),
), ),
]), ]),
if (fields != null) ...fields, if (fields != null) ...fields,