fix(mobile): add partial index based on library ID to remote assets (#20214)

* feat: add libraryId to SyncAssetV1

* add partial index

# Conflicts:
#	mobile/drift_schemas/main/drift_schema_v5.json
#	mobile/lib/infrastructure/repositories/db.repository.dart
#	mobile/lib/infrastructure/repositories/db.repository.steps.dart
#	mobile/test/drift/main/generated/schema_v5.dart

* chore: make build

* rebase

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
shenlong 2025-07-30 23:59:00 +05:30 committed by GitHub
parent f85d8add01
commit 641a3baadd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 43 additions and 2 deletions

Binary file not shown.

View file

@ -5,7 +5,17 @@ import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
import 'package:immich_mobile/infrastructure/utils/asset.mixin.dart';
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
@TableIndex(name: 'UQ_remote_asset_owner_checksum', columns: {#checksum, #ownerId}, unique: true)
@TableIndex(name: 'idx_remote_asset_owner_checksum', columns: {#ownerId, #checksum})
@TableIndex.sql('''
CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum
ON remote_asset_entity (owner_id, checksum)
WHERE (library_id IS NULL);
''')
@TableIndex.sql('''
CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_library_checksum
ON remote_asset_entity (owner_id, library_id, checksum)
WHERE (library_id IS NOT NULL);
''')
@TableIndex(name: 'idx_remote_asset_checksum', columns: {#checksum})
class RemoteAssetEntity extends Table with DriftDefaultsMixin, AssetEntityMixin {
const RemoteAssetEntity();
@ -30,6 +40,8 @@ class RemoteAssetEntity extends Table with DriftDefaultsMixin, AssetEntityMixin
TextColumn get stackId => text().nullable()();
TextColumn get libraryId => text().nullable()();
@override
Set<Column> get primaryKey => {id};
}

View file

@ -66,7 +66,7 @@ class Drift extends $Drift implements IDatabaseRepository {
: super(executor ?? driftDatabase(name: 'immich', native: const DriftNativeOptions(shareAcrossIsolates: true)));
@override
int get schemaVersion => 5;
int get schemaVersion => 6;
@override
MigrationStrategy get migration => MigrationStrategy(
@ -103,6 +103,15 @@ class Drift extends $Drift implements IDatabaseRepository {
),
);
},
from5To6: (m, v6) async {
// Drops the (checksum, ownerId) and adds it back as (ownerId, checksum)
await customStatement('DROP INDEX IF EXISTS UQ_remote_asset_owner_checksum');
await m.create(v6.idxRemoteAssetOwnerChecksum);
// Adds libraryId to remote_asset_entity
await m.addColumn(v6.remoteAssetEntity, v6.remoteAssetEntity.libraryId);
await m.create(v6.uQRemoteAssetsOwnerChecksum);
await m.create(v6.uQRemoteAssetsOwnerLibraryChecksum);
},
),
);

View file

@ -121,6 +121,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
visibility: Value(asset.visibility.toAssetVisibility()),
livePhotoVideoId: Value(asset.livePhotoVideoId),
stackId: Value(asset.stackId),
libraryId: Value(asset.libraryId),
);
batch.insert(

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -14786,6 +14786,10 @@
"isFavorite": {
"type": "boolean"
},
"libraryId": {
"nullable": true,
"type": "string"
},
"livePhotoVideoId": {
"nullable": true,
"type": "string"
@ -14832,6 +14836,7 @@
"fileModifiedAt",
"id",
"isFavorite",
"libraryId",
"livePhotoVideoId",
"localDateTime",
"originalFileName",

View file

@ -354,6 +354,7 @@ export const columns = {
'asset.duration',
'asset.livePhotoVideoId',
'asset.stackId',
'asset.libraryId',
],
syncAlbumUser: ['album_user.albumsId as albumId', 'album_user.usersId as userId', 'album_user.role'],
syncStack: ['stack.id', 'stack.createdAt', 'stack.updatedAt', 'stack.primaryAssetId', 'stack.ownerId'],

View file

@ -115,6 +115,7 @@ export class SyncAssetV1 {
visibility!: AssetVisibility;
livePhotoVideoId!: string | null;
stackId!: string | null;
libraryId!: string | null;
}
@ExtraModel()

View file

@ -66,6 +66,7 @@ select
"asset"."duration",
"asset"."livePhotoVideoId",
"asset"."stackId",
"asset"."libraryId",
"asset"."updateId"
from
"asset"
@ -95,6 +96,7 @@ select
"asset"."duration",
"asset"."livePhotoVideoId",
"asset"."stackId",
"asset"."libraryId",
"asset"."updateId"
from
"asset"
@ -357,6 +359,7 @@ select
"asset"."duration",
"asset"."livePhotoVideoId",
"asset"."stackId",
"asset"."libraryId",
"asset"."updateId"
from
"asset"
@ -605,6 +608,7 @@ select
"asset"."duration",
"asset"."livePhotoVideoId",
"asset"."stackId",
"asset"."libraryId",
"asset"."updateId"
from
"asset"
@ -652,6 +656,7 @@ select
"asset"."duration",
"asset"."livePhotoVideoId",
"asset"."stackId",
"asset"."libraryId",
"asset"."updateId"
from
"asset"

View file

@ -382,6 +382,7 @@ export class JobService extends BaseService {
visibility: asset.visibility,
livePhotoVideoId: asset.livePhotoVideoId,
stackId: asset.stackId,
libraryId: asset.libraryId,
},
exif: {
assetId: exif.assetId,

View file

@ -38,6 +38,7 @@ describe(SyncRequestType.AlbumAssetsV1, () => {
duration: '0:10:00.00000',
livePhotoVideoId: null,
stackId: null,
libraryId: null,
});
const { album } = await ctx.newAlbum({ ownerId: user2.id });
await ctx.newAlbumAsset({ albumId: album.id, assetId: asset.id });
@ -64,6 +65,7 @@ describe(SyncRequestType.AlbumAssetsV1, () => {
duration: asset.duration,
livePhotoVideoId: asset.livePhotoVideoId,
stackId: asset.stackId,
libraryId: asset.libraryId,
},
type: SyncEntityType.AlbumAssetV1,
},

View file

@ -36,6 +36,7 @@ describe(SyncEntityType.AssetV1, () => {
localDateTime: date,
deletedAt: null,
duration: '0:10:00.00000',
libraryId: null,
});
const response = await ctx.syncStream(auth, [SyncRequestType.AssetsV1]);
@ -59,6 +60,7 @@ describe(SyncEntityType.AssetV1, () => {
duration: asset.duration,
stackId: null,
livePhotoVideoId: null,
libraryId: asset.libraryId,
},
type: 'AssetV1',
},

View file

@ -40,6 +40,7 @@ describe(SyncRequestType.PartnerAssetsV1, () => {
localDateTime: date,
deletedAt: null,
duration: '0:10:00.00000',
libraryId: null,
});
await ctx.newPartner({ sharedById: user2.id, sharedWithId: auth.user.id });
@ -65,6 +66,7 @@ describe(SyncRequestType.PartnerAssetsV1, () => {
duration: asset.duration,
stackId: null,
livePhotoVideoId: null,
libraryId: asset.libraryId,
},
type: SyncEntityType.PartnerAssetV1,
},