rebase main

This commit is contained in:
shenlong-tanwen 2025-08-29 13:22:39 +05:30
parent 36680e4279
commit b93b07f461
7 changed files with 121 additions and 67 deletions

View File

@ -235,7 +235,9 @@ open class NativeSyncApiImplBase(context: Context) {
}
}
// This method is only implemented on iOS; on Android, we do not have a concept of cloud IDs
@Suppress("unused", "UNUSED_PARAMETER")
fun getCloudIdForAssetIds(assetIds: List<String>): Map<String, String?> {
throw IllegalStateException("Method not supported on Android.")
return emptyMap()
}
}

View File

@ -21,6 +21,7 @@ typedef $$LocalAssetEntityTableCreateCompanionBuilder =
i0.Value<String?> checksum,
i0.Value<bool> isFavorite,
i0.Value<int> orientation,
i0.Value<String?> cloudId,
});
typedef $$LocalAssetEntityTableUpdateCompanionBuilder =
i1.LocalAssetEntityCompanion Function({
@ -35,6 +36,7 @@ typedef $$LocalAssetEntityTableUpdateCompanionBuilder =
i0.Value<String?> checksum,
i0.Value<bool> isFavorite,
i0.Value<int> orientation,
i0.Value<String?> cloudId,
});
class $$LocalAssetEntityTableFilterComposer
@ -101,6 +103,11 @@ class $$LocalAssetEntityTableFilterComposer
column: $table.orientation,
builder: (column) => i0.ColumnFilters(column),
);
i0.ColumnFilters<String> get cloudId => $composableBuilder(
column: $table.cloudId,
builder: (column) => i0.ColumnFilters(column),
);
}
class $$LocalAssetEntityTableOrderingComposer
@ -166,6 +173,11 @@ class $$LocalAssetEntityTableOrderingComposer
column: $table.orientation,
builder: (column) => i0.ColumnOrderings(column),
);
i0.ColumnOrderings<String> get cloudId => $composableBuilder(
column: $table.cloudId,
builder: (column) => i0.ColumnOrderings(column),
);
}
class $$LocalAssetEntityTableAnnotationComposer
@ -215,6 +227,9 @@ class $$LocalAssetEntityTableAnnotationComposer
column: $table.orientation,
builder: (column) => column,
);
i0.GeneratedColumn<String> get cloudId =>
$composableBuilder(column: $table.cloudId, builder: (column) => column);
}
class $$LocalAssetEntityTableTableManager
@ -268,6 +283,7 @@ class $$LocalAssetEntityTableTableManager
i0.Value<String?> checksum = const i0.Value.absent(),
i0.Value<bool> isFavorite = const i0.Value.absent(),
i0.Value<int> orientation = const i0.Value.absent(),
i0.Value<String?> cloudId = const i0.Value.absent(),
}) => i1.LocalAssetEntityCompanion(
name: name,
type: type,
@ -280,6 +296,7 @@ class $$LocalAssetEntityTableTableManager
checksum: checksum,
isFavorite: isFavorite,
orientation: orientation,
cloudId: cloudId,
),
createCompanionCallback:
({
@ -294,6 +311,7 @@ class $$LocalAssetEntityTableTableManager
i0.Value<String?> checksum = const i0.Value.absent(),
i0.Value<bool> isFavorite = const i0.Value.absent(),
i0.Value<int> orientation = const i0.Value.absent(),
i0.Value<String?> cloudId = const i0.Value.absent(),
}) => i1.LocalAssetEntityCompanion.insert(
name: name,
type: type,
@ -306,6 +324,7 @@ class $$LocalAssetEntityTableTableManager
checksum: checksum,
isFavorite: isFavorite,
orientation: orientation,
cloudId: cloudId,
),
withReferenceMapper: (p0) => p0
.map((e) => (e.readTable(table), i0.BaseReferences(db, table, e)))
@ -473,6 +492,17 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
requiredDuringInsert: false,
defaultValue: const i4.Constant(0),
);
static const i0.VerificationMeta _cloudIdMeta = const i0.VerificationMeta(
'cloudId',
);
@override
late final i0.GeneratedColumn<String> cloudId = i0.GeneratedColumn<String>(
'cloud_id',
aliasedName,
true,
type: i0.DriftSqlType.string,
requiredDuringInsert: false,
);
@override
List<i0.GeneratedColumn> get $columns => [
name,
@ -486,6 +516,7 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
checksum,
isFavorite,
orientation,
cloudId,
];
@override
String get aliasedName => _alias ?? actualTableName;
@ -566,6 +597,12 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
),
);
}
if (data.containsKey('cloud_id')) {
context.handle(
_cloudIdMeta,
cloudId.isAcceptableOrUnknown(data['cloud_id']!, _cloudIdMeta),
);
}
return context;
}
@ -624,6 +661,10 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
i0.DriftSqlType.int,
data['${effectivePrefix}orientation'],
)!,
cloudId: attachedDatabase.typeMapping.read(
i0.DriftSqlType.string,
data['${effectivePrefix}cloud_id'],
),
);
}
@ -653,6 +694,7 @@ class LocalAssetEntityData extends i0.DataClass
final String? checksum;
final bool isFavorite;
final int orientation;
final String? cloudId;
const LocalAssetEntityData({
required this.name,
required this.type,
@ -665,6 +707,7 @@ class LocalAssetEntityData extends i0.DataClass
this.checksum,
required this.isFavorite,
required this.orientation,
this.cloudId,
});
@override
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
@ -692,6 +735,9 @@ class LocalAssetEntityData extends i0.DataClass
}
map['is_favorite'] = i0.Variable<bool>(isFavorite);
map['orientation'] = i0.Variable<int>(orientation);
if (!nullToAbsent || cloudId != null) {
map['cloud_id'] = i0.Variable<String>(cloudId);
}
return map;
}
@ -714,6 +760,7 @@ class LocalAssetEntityData extends i0.DataClass
checksum: serializer.fromJson<String?>(json['checksum']),
isFavorite: serializer.fromJson<bool>(json['isFavorite']),
orientation: serializer.fromJson<int>(json['orientation']),
cloudId: serializer.fromJson<String?>(json['cloudId']),
);
}
@override
@ -733,6 +780,7 @@ class LocalAssetEntityData extends i0.DataClass
'checksum': serializer.toJson<String?>(checksum),
'isFavorite': serializer.toJson<bool>(isFavorite),
'orientation': serializer.toJson<int>(orientation),
'cloudId': serializer.toJson<String?>(cloudId),
};
}
@ -748,6 +796,7 @@ class LocalAssetEntityData extends i0.DataClass
i0.Value<String?> checksum = const i0.Value.absent(),
bool? isFavorite,
int? orientation,
i0.Value<String?> cloudId = const i0.Value.absent(),
}) => i1.LocalAssetEntityData(
name: name ?? this.name,
type: type ?? this.type,
@ -762,6 +811,7 @@ class LocalAssetEntityData extends i0.DataClass
checksum: checksum.present ? checksum.value : this.checksum,
isFavorite: isFavorite ?? this.isFavorite,
orientation: orientation ?? this.orientation,
cloudId: cloudId.present ? cloudId.value : this.cloudId,
);
LocalAssetEntityData copyWithCompanion(i1.LocalAssetEntityCompanion data) {
return LocalAssetEntityData(
@ -782,6 +832,7 @@ class LocalAssetEntityData extends i0.DataClass
orientation: data.orientation.present
? data.orientation.value
: this.orientation,
cloudId: data.cloudId.present ? data.cloudId.value : this.cloudId,
);
}
@ -798,7 +849,8 @@ class LocalAssetEntityData extends i0.DataClass
..write('id: $id, ')
..write('checksum: $checksum, ')
..write('isFavorite: $isFavorite, ')
..write('orientation: $orientation')
..write('orientation: $orientation, ')
..write('cloudId: $cloudId')
..write(')'))
.toString();
}
@ -816,6 +868,7 @@ class LocalAssetEntityData extends i0.DataClass
checksum,
isFavorite,
orientation,
cloudId,
);
@override
bool operator ==(Object other) =>
@ -831,7 +884,8 @@ class LocalAssetEntityData extends i0.DataClass
other.id == this.id &&
other.checksum == this.checksum &&
other.isFavorite == this.isFavorite &&
other.orientation == this.orientation);
other.orientation == this.orientation &&
other.cloudId == this.cloudId);
}
class LocalAssetEntityCompanion
@ -847,6 +901,7 @@ class LocalAssetEntityCompanion
final i0.Value<String?> checksum;
final i0.Value<bool> isFavorite;
final i0.Value<int> orientation;
final i0.Value<String?> cloudId;
const LocalAssetEntityCompanion({
this.name = const i0.Value.absent(),
this.type = const i0.Value.absent(),
@ -859,6 +914,7 @@ class LocalAssetEntityCompanion
this.checksum = const i0.Value.absent(),
this.isFavorite = const i0.Value.absent(),
this.orientation = const i0.Value.absent(),
this.cloudId = const i0.Value.absent(),
});
LocalAssetEntityCompanion.insert({
required String name,
@ -872,6 +928,7 @@ class LocalAssetEntityCompanion
this.checksum = const i0.Value.absent(),
this.isFavorite = const i0.Value.absent(),
this.orientation = const i0.Value.absent(),
this.cloudId = const i0.Value.absent(),
}) : name = i0.Value(name),
type = i0.Value(type),
id = i0.Value(id);
@ -887,6 +944,7 @@ class LocalAssetEntityCompanion
i0.Expression<String>? checksum,
i0.Expression<bool>? isFavorite,
i0.Expression<int>? orientation,
i0.Expression<String>? cloudId,
}) {
return i0.RawValuesInsertable({
if (name != null) 'name': name,
@ -900,6 +958,7 @@ class LocalAssetEntityCompanion
if (checksum != null) 'checksum': checksum,
if (isFavorite != null) 'is_favorite': isFavorite,
if (orientation != null) 'orientation': orientation,
if (cloudId != null) 'cloud_id': cloudId,
});
}
@ -915,6 +974,7 @@ class LocalAssetEntityCompanion
i0.Value<String?>? checksum,
i0.Value<bool>? isFavorite,
i0.Value<int>? orientation,
i0.Value<String?>? cloudId,
}) {
return i1.LocalAssetEntityCompanion(
name: name ?? this.name,
@ -928,6 +988,7 @@ class LocalAssetEntityCompanion
checksum: checksum ?? this.checksum,
isFavorite: isFavorite ?? this.isFavorite,
orientation: orientation ?? this.orientation,
cloudId: cloudId ?? this.cloudId,
);
}
@ -969,6 +1030,9 @@ class LocalAssetEntityCompanion
if (orientation.present) {
map['orientation'] = i0.Variable<int>(orientation.value);
}
if (cloudId.present) {
map['cloud_id'] = i0.Variable<String>(cloudId.value);
}
return map;
}
@ -985,7 +1049,8 @@ class LocalAssetEntityCompanion
..write('id: $id, ')
..write('checksum: $checksum, ')
..write('isFavorite: $isFavorite, ')
..write('orientation: $orientation')
..write('orientation: $orientation, ')
..write('cloudId: $cloudId')
..write(')'))
.toString();
}

View File

@ -122,8 +122,10 @@ class Drift extends $Drift implements IDatabaseRepository {
},
from7To8: (m, v8) async {
await m.create(v8.storeEntity);
},
from8To9: (m, v9) async {
// Add cloudId column to local_asset_entity
await m.addColumn(v6.localAssetEntity, v6.localAssetEntity.cloudId);
await m.addColumn(v9.localAssetEntity, v9.localAssetEntity.cloudId);
},
from8To9: (m, v9) async {
await m.addColumn(v9.localAlbumEntity, v9.localAlbumEntity.linkedRemoteAlbumId);

View File

@ -495,4 +495,32 @@ class NativeSyncApi {
return (pigeonVar_replyList[0] as List<Object?>?)!.cast<Uint8List?>();
}
}
Future<Map<String, String?>> getCloudIdForAssetIds(List<String> assetIds) async {
final String pigeonVar_channelName =
'dev.flutter.pigeon.immich_mobile.NativeSyncApi.getCloudIdForAssetIds$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[assetIds]);
final List<Object?>? pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
throw PlatformException(
code: pigeonVar_replyList[0]! as String,
message: pigeonVar_replyList[1] as String?,
details: pigeonVar_replyList[2],
);
} else if (pigeonVar_replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
return (pigeonVar_replyList[0] as Map<Object?, Object?>?)!.cast<String, String?>();
}
}
}

View File

@ -35,7 +35,7 @@ import 'package:logging/logging.dart';
// ignore: import_rule_photo_manager
import 'package:photo_manager/photo_manager.dart';
const int targetVersion = 14;
const int targetVersion = 15;
Future<void> migrateDatabaseIfNeeded(Isar db, Drift drift) async {
final hasVersion = Store.tryGet(StoreKey.version) != null;
@ -70,6 +70,10 @@ Future<void> migrateDatabaseIfNeeded(Isar db, Drift drift) async {
await Store.populateCache();
}
if (version < 15) {
await _updateCloudId(drift);
}
if (targetVersion >= 12) {
await Store.put(StoreKey.version, targetVersion);
return;
@ -179,6 +183,20 @@ Future<void> migrateDeviceAssetToSqlite(Isar db, Drift drift) async {
}
}
Future<void> _updateCloudId(Drift drift) async {
// Android do not have a concept of cloud IDs
if (Platform.isAndroid) {
return;
}
final query = drift.localAssetEntity.selectOnly()
..addColumns([drift.localAssetEntity.id])
..where(drift.localAssetEntity.cloudId.isNull());
final ids = await query.map((row) => row.read(drift.localAssetEntity.id)!).get();
final cloudMapping = await NativeSyncApi().getCloudIdForAssetIds(ids);
await DriftLocalAlbumRepository(drift).updateCloudMapping(cloudMapping);
}
Future<void> migrateBackupAlbumsToSqlite(Isar db, Drift drift) async {
try {
final isarBackupAlbums = await db.backupAlbums.where().findAll();

View File

@ -4797,9 +4797,6 @@ export enum Permission {
export enum AssetMetadataKey {
MobileApp = "mobile-app"
}
export enum AssetMetadataKey {
MobileApp = "mobile-app"
}
export enum AssetMediaStatus {
Created = "created",
Replaced = "replaced",

View File

@ -1,58 +0,0 @@
import { Kysely, sql } from 'kysely';
export async function up(db: Kysely<any>): Promise<void> {
await sql`CREATE OR REPLACE FUNCTION asset_metadata_audit()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS $$
BEGIN
INSERT INTO asset_metadata_audit ("assetId", "key")
SELECT "assetId", "key"
FROM OLD;
RETURN NULL;
END
$$;`.execute(db);
await sql`CREATE TABLE "asset_metadata_audit" (
"id" uuid NOT NULL DEFAULT immich_uuid_v7(),
"assetId" uuid NOT NULL,
"key" character varying NOT NULL,
"deletedAt" timestamp with time zone NOT NULL DEFAULT clock_timestamp(),
CONSTRAINT "asset_metadata_audit_pkey" PRIMARY KEY ("id")
);`.execute(db);
await sql`CREATE INDEX "asset_metadata_audit_assetId_idx" ON "asset_metadata_audit" ("assetId");`.execute(db);
await sql`CREATE INDEX "asset_metadata_audit_key_idx" ON "asset_metadata_audit" ("key");`.execute(db);
await sql`CREATE INDEX "asset_metadata_audit_deletedAt_idx" ON "asset_metadata_audit" ("deletedAt");`.execute(db);
await sql`CREATE TABLE "asset_metadata" (
"assetId" uuid NOT NULL,
"key" character varying NOT NULL,
"value" jsonb NOT NULL,
"updateId" uuid NOT NULL DEFAULT immich_uuid_v7(),
"updatedAt" timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT "asset_metadata_assetId_fkey" FOREIGN KEY ("assetId") REFERENCES "asset" ("id") ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT "asset_metadata_pkey" PRIMARY KEY ("assetId", "key")
);`.execute(db);
await sql`CREATE INDEX "asset_metadata_updateId_idx" ON "asset_metadata" ("updateId");`.execute(db);
await sql`CREATE INDEX "asset_metadata_updatedAt_idx" ON "asset_metadata" ("updatedAt");`.execute(db);
await sql`CREATE OR REPLACE TRIGGER "asset_metadata_audit"
AFTER DELETE ON "asset_metadata"
REFERENCING OLD TABLE AS "old"
FOR EACH STATEMENT
WHEN (pg_trigger_depth() = 0)
EXECUTE FUNCTION asset_metadata_audit();`.execute(db);
await sql`CREATE OR REPLACE TRIGGER "asset_metadata_updated_at"
BEFORE UPDATE ON "asset_metadata"
FOR EACH ROW
EXECUTE FUNCTION updated_at();`.execute(db);
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_asset_metadata_audit', '{"type":"function","name":"asset_metadata_audit","sql":"CREATE OR REPLACE FUNCTION asset_metadata_audit()\\n RETURNS TRIGGER\\n LANGUAGE PLPGSQL\\n AS $$\\n BEGIN\\n INSERT INTO asset_metadata_audit (\\"assetId\\", \\"key\\")\\n SELECT \\"assetId\\", \\"key\\"\\n FROM OLD;\\n RETURN NULL;\\n END\\n $$;"}'::jsonb);`.execute(db);
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_asset_metadata_audit', '{"type":"trigger","name":"asset_metadata_audit","sql":"CREATE OR REPLACE TRIGGER \\"asset_metadata_audit\\"\\n AFTER DELETE ON \\"asset_metadata\\"\\n REFERENCING OLD TABLE AS \\"old\\"\\n FOR EACH STATEMENT\\n WHEN (pg_trigger_depth() = 0)\\n EXECUTE FUNCTION asset_metadata_audit();"}'::jsonb);`.execute(db);
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_asset_metadata_updated_at', '{"type":"trigger","name":"asset_metadata_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"asset_metadata_updated_at\\"\\n BEFORE UPDATE ON \\"asset_metadata\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
}
export async function down(db: Kysely<any>): Promise<void> {
await sql`DROP TABLE "asset_metadata_audit";`.execute(db);
await sql`DROP TABLE "asset_metadata";`.execute(db);
await sql`DROP FUNCTION asset_metadata_audit;`.execute(db);
await sql`DELETE FROM "migration_overrides" WHERE "name" = 'function_asset_metadata_audit';`.execute(db);
await sql`DELETE FROM "migration_overrides" WHERE "name" = 'trigger_asset_metadata_audit';`.execute(db);
await sql`DELETE FROM "migration_overrides" WHERE "name" = 'trigger_asset_metadata_updated_at';`.execute(db);
}