replace trigger with manual pruning

pull/23189/head
shenlong-tanwen 2025-11-08 01:23:13 +05:30
parent 70300ad3d4
commit c8e6080ddc
11 changed files with 806 additions and 811 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,15 +0,0 @@
import 'remote_asset.entity.dart';
import 'local_asset.entity.dart';
import 'local_asset_upload_entity.dart';
CREATE TRIGGER delete_upload_error_on_remote_insert
AFTER INSERT ON remote_asset_entity
FOR EACH ROW
BEGIN
DELETE FROM local_asset_upload_entity
WHERE asset_id IN (
SELECT lae.id
FROM local_asset_entity lae
WHERE lae.checksum = NEW.checksum
);
END;

View File

@ -1,8 +0,0 @@
// dart format width=80
// ignore_for_file: type=lint
import 'package:drift/drift.dart' as i0;
i0.Trigger get deleteUploadErrorOnRemoteInsert => i0.Trigger(
'CREATE TRIGGER delete_upload_error_on_remote_insert AFTER INSERT ON remote_asset_entity BEGIN DELETE FROM local_asset_upload_entity WHERE asset_id IN (SELECT lae.id FROM local_asset_entity AS lae WHERE lae.checksum = NEW.checksum);END',
'delete_upload_error_on_remote_insert',
);

View File

@ -65,10 +65,7 @@ class IsarDatabaseRepository implements IDatabaseRepository {
AssetFaceEntity, AssetFaceEntity,
StoreEntity, StoreEntity,
], ],
include: { include: {'package:immich_mobile/infrastructure/entities/merged_asset.drift'},
'package:immich_mobile/infrastructure/entities/merged_asset.drift',
'package:immich_mobile/infrastructure/entities/local_asset_upload_trigger.drift',
},
) )
class Drift extends $Drift implements IDatabaseRepository { class Drift extends $Drift implements IDatabaseRepository {
Drift([QueryExecutor? executor]) Drift([QueryExecutor? executor])
@ -185,7 +182,6 @@ class Drift extends $Drift implements IDatabaseRepository {
}, },
from12To13: (m, v13) async { from12To13: (m, v13) async {
await m.createTable(v13.localAssetUploadEntity); await m.createTable(v13.localAssetUploadEntity);
await m.createTrigger(v13.deleteUploadErrorOnRemoteInsert);
}, },
), ),
); );

View File

@ -5,45 +5,43 @@ import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart'
as i1; as i1;
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'
as i2; as i2;
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart'
as i3;
import 'package:immich_mobile/infrastructure/entities/local_asset_upload_entity.drift.dart'
as i4;
import 'package:immich_mobile/infrastructure/entities/local_asset_upload_trigger.drift.dart'
as i5;
import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart'
as i6; as i3;
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart'
as i4;
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart'
as i7; as i5;
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart'
as i8; as i6;
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart'
as i9; as i7;
import 'package:immich_mobile/infrastructure/entities/auth_user.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/auth_user.entity.drift.dart'
as i10; as i8;
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift.dart'
as i11; as i9;
import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart'
as i12; as i10;
import 'package:immich_mobile/infrastructure/entities/local_asset_upload_entity.drift.dart'
as i11;
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart'
as i13; as i12;
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.drift.dart'
as i14; as i13;
import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart'
as i15; as i14;
import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart'
as i16; as i15;
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.dart'
as i17; as i16;
import 'package:immich_mobile/infrastructure/entities/person.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/person.entity.drift.dart'
as i18; as i17;
import 'package:immich_mobile/infrastructure/entities/asset_face.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/asset_face.entity.drift.dart'
as i19; as i18;
import 'package:immich_mobile/infrastructure/entities/store.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/store.entity.drift.dart'
as i20; as i19;
import 'package:immich_mobile/infrastructure/entities/merged_asset.drift.dart' import 'package:immich_mobile/infrastructure/entities/merged_asset.drift.dart'
as i21; as i20;
import 'package:drift/internal/modular.dart' as i22; import 'package:drift/internal/modular.dart' as i21;
abstract class $Drift extends i0.GeneratedDatabase { abstract class $Drift extends i0.GeneratedDatabase {
$Drift(i0.QueryExecutor e) : super(e); $Drift(i0.QueryExecutor e) : super(e);
@ -51,41 +49,41 @@ abstract class $Drift extends i0.GeneratedDatabase {
late final i1.$UserEntityTable userEntity = i1.$UserEntityTable(this); late final i1.$UserEntityTable userEntity = i1.$UserEntityTable(this);
late final i2.$RemoteAssetEntityTable remoteAssetEntity = i2 late final i2.$RemoteAssetEntityTable remoteAssetEntity = i2
.$RemoteAssetEntityTable(this); .$RemoteAssetEntityTable(this);
late final i3.$LocalAssetEntityTable localAssetEntity = i3 late final i3.$StackEntityTable stackEntity = i3.$StackEntityTable(this);
late final i4.$LocalAssetEntityTable localAssetEntity = i4
.$LocalAssetEntityTable(this); .$LocalAssetEntityTable(this);
late final i4.$LocalAssetUploadEntityTable localAssetUploadEntity = i4 late final i5.$RemoteAlbumEntityTable remoteAlbumEntity = i5
.$LocalAssetUploadEntityTable(this);
late final i6.$StackEntityTable stackEntity = i6.$StackEntityTable(this);
late final i7.$RemoteAlbumEntityTable remoteAlbumEntity = i7
.$RemoteAlbumEntityTable(this); .$RemoteAlbumEntityTable(this);
late final i8.$LocalAlbumEntityTable localAlbumEntity = i8 late final i6.$LocalAlbumEntityTable localAlbumEntity = i6
.$LocalAlbumEntityTable(this); .$LocalAlbumEntityTable(this);
late final i9.$LocalAlbumAssetEntityTable localAlbumAssetEntity = i9 late final i7.$LocalAlbumAssetEntityTable localAlbumAssetEntity = i7
.$LocalAlbumAssetEntityTable(this); .$LocalAlbumAssetEntityTable(this);
late final i10.$AuthUserEntityTable authUserEntity = i10.$AuthUserEntityTable( late final i8.$AuthUserEntityTable authUserEntity = i8.$AuthUserEntityTable(
this, this,
); );
late final i11.$UserMetadataEntityTable userMetadataEntity = i11 late final i9.$UserMetadataEntityTable userMetadataEntity = i9
.$UserMetadataEntityTable(this); .$UserMetadataEntityTable(this);
late final i12.$PartnerEntityTable partnerEntity = i12.$PartnerEntityTable( late final i10.$PartnerEntityTable partnerEntity = i10.$PartnerEntityTable(
this, this,
); );
late final i13.$RemoteExifEntityTable remoteExifEntity = i13 late final i11.$LocalAssetUploadEntityTable localAssetUploadEntity = i11
.$LocalAssetUploadEntityTable(this);
late final i12.$RemoteExifEntityTable remoteExifEntity = i12
.$RemoteExifEntityTable(this); .$RemoteExifEntityTable(this);
late final i14.$RemoteAlbumAssetEntityTable remoteAlbumAssetEntity = i14 late final i13.$RemoteAlbumAssetEntityTable remoteAlbumAssetEntity = i13
.$RemoteAlbumAssetEntityTable(this); .$RemoteAlbumAssetEntityTable(this);
late final i15.$RemoteAlbumUserEntityTable remoteAlbumUserEntity = i15 late final i14.$RemoteAlbumUserEntityTable remoteAlbumUserEntity = i14
.$RemoteAlbumUserEntityTable(this); .$RemoteAlbumUserEntityTable(this);
late final i16.$MemoryEntityTable memoryEntity = i16.$MemoryEntityTable(this); late final i15.$MemoryEntityTable memoryEntity = i15.$MemoryEntityTable(this);
late final i17.$MemoryAssetEntityTable memoryAssetEntity = i17 late final i16.$MemoryAssetEntityTable memoryAssetEntity = i16
.$MemoryAssetEntityTable(this); .$MemoryAssetEntityTable(this);
late final i18.$PersonEntityTable personEntity = i18.$PersonEntityTable(this); late final i17.$PersonEntityTable personEntity = i17.$PersonEntityTable(this);
late final i19.$AssetFaceEntityTable assetFaceEntity = i19 late final i18.$AssetFaceEntityTable assetFaceEntity = i18
.$AssetFaceEntityTable(this); .$AssetFaceEntityTable(this);
late final i20.$StoreEntityTable storeEntity = i20.$StoreEntityTable(this); late final i19.$StoreEntityTable storeEntity = i19.$StoreEntityTable(this);
i21.MergedAssetDrift get mergedAssetDrift => i22.ReadDatabaseContainer( i20.MergedAssetDrift get mergedAssetDrift => i21.ReadDatabaseContainer(
this, this,
).accessor<i21.MergedAssetDrift>(i21.MergedAssetDrift.new); ).accessor<i20.MergedAssetDrift>(i20.MergedAssetDrift.new);
@override @override
Iterable<i0.TableInfo<i0.Table, Object?>> get allTables => Iterable<i0.TableInfo<i0.Table, Object?>> get allTables =>
allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>(); allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>();
@ -93,21 +91,20 @@ abstract class $Drift extends i0.GeneratedDatabase {
List<i0.DatabaseSchemaEntity> get allSchemaEntities => [ List<i0.DatabaseSchemaEntity> get allSchemaEntities => [
userEntity, userEntity,
remoteAssetEntity, remoteAssetEntity,
stackEntity,
localAssetEntity, localAssetEntity,
localAssetUploadEntity, remoteAlbumEntity,
i5.deleteUploadErrorOnRemoteInsert, localAlbumEntity,
i3.idxLocalAssetChecksum, localAlbumAssetEntity,
i4.idxLocalAssetChecksum,
i2.idxRemoteAssetOwnerChecksum, i2.idxRemoteAssetOwnerChecksum,
i2.uQRemoteAssetsOwnerChecksum, i2.uQRemoteAssetsOwnerChecksum,
i2.uQRemoteAssetsOwnerLibraryChecksum, i2.uQRemoteAssetsOwnerLibraryChecksum,
i2.idxRemoteAssetChecksum, i2.idxRemoteAssetChecksum,
stackEntity,
remoteAlbumEntity,
localAlbumEntity,
localAlbumAssetEntity,
authUserEntity, authUserEntity,
userMetadataEntity, userMetadataEntity,
partnerEntity, partnerEntity,
localAssetUploadEntity,
remoteExifEntity, remoteExifEntity,
remoteAlbumAssetEntity, remoteAlbumAssetEntity,
remoteAlbumUserEntity, remoteAlbumUserEntity,
@ -116,7 +113,7 @@ abstract class $Drift extends i0.GeneratedDatabase {
personEntity, personEntity,
assetFaceEntity, assetFaceEntity,
storeEntity, storeEntity,
i13.idxLatLng, i12.idxLatLng,
]; ];
@override @override
i0.StreamQueryUpdateRules i0.StreamQueryUpdateRules
@ -130,24 +127,6 @@ abstract class $Drift extends i0.GeneratedDatabase {
i0.TableUpdate('remote_asset_entity', kind: i0.UpdateKind.delete), i0.TableUpdate('remote_asset_entity', kind: i0.UpdateKind.delete),
], ],
), ),
i0.WritePropagation(
on: i0.TableUpdateQuery.onTableName(
'local_asset_entity',
limitUpdateKind: i0.UpdateKind.delete,
),
result: [
i0.TableUpdate('local_asset_upload_entity', kind: i0.UpdateKind.delete),
],
),
i0.WritePropagation(
on: i0.TableUpdateQuery.onTableName(
'remote_asset_entity',
limitUpdateKind: i0.UpdateKind.insert,
),
result: [
i0.TableUpdate('local_asset_upload_entity', kind: i0.UpdateKind.delete),
],
),
i0.WritePropagation( i0.WritePropagation(
on: i0.TableUpdateQuery.onTableName( on: i0.TableUpdateQuery.onTableName(
'user_entity', 'user_entity',
@ -223,6 +202,15 @@ abstract class $Drift extends i0.GeneratedDatabase {
), ),
result: [i0.TableUpdate('partner_entity', kind: i0.UpdateKind.delete)], result: [i0.TableUpdate('partner_entity', kind: i0.UpdateKind.delete)],
), ),
i0.WritePropagation(
on: i0.TableUpdateQuery.onTableName(
'local_asset_entity',
limitUpdateKind: i0.UpdateKind.delete,
),
result: [
i0.TableUpdate('local_asset_upload_entity', kind: i0.UpdateKind.delete),
],
),
i0.WritePropagation( i0.WritePropagation(
on: i0.TableUpdateQuery.onTableName( on: i0.TableUpdateQuery.onTableName(
'remote_asset_entity', 'remote_asset_entity',
@ -327,44 +315,44 @@ class $DriftManager {
i1.$$UserEntityTableTableManager(_db, _db.userEntity); i1.$$UserEntityTableTableManager(_db, _db.userEntity);
i2.$$RemoteAssetEntityTableTableManager get remoteAssetEntity => i2.$$RemoteAssetEntityTableTableManager get remoteAssetEntity =>
i2.$$RemoteAssetEntityTableTableManager(_db, _db.remoteAssetEntity); i2.$$RemoteAssetEntityTableTableManager(_db, _db.remoteAssetEntity);
i3.$$LocalAssetEntityTableTableManager get localAssetEntity => i3.$$StackEntityTableTableManager get stackEntity =>
i3.$$LocalAssetEntityTableTableManager(_db, _db.localAssetEntity); i3.$$StackEntityTableTableManager(_db, _db.stackEntity);
i4.$$LocalAssetUploadEntityTableTableManager get localAssetUploadEntity => i4.$$LocalAssetEntityTableTableManager get localAssetEntity =>
i4.$$LocalAssetUploadEntityTableTableManager( i4.$$LocalAssetEntityTableTableManager(_db, _db.localAssetEntity);
i5.$$RemoteAlbumEntityTableTableManager get remoteAlbumEntity =>
i5.$$RemoteAlbumEntityTableTableManager(_db, _db.remoteAlbumEntity);
i6.$$LocalAlbumEntityTableTableManager get localAlbumEntity =>
i6.$$LocalAlbumEntityTableTableManager(_db, _db.localAlbumEntity);
i7.$$LocalAlbumAssetEntityTableTableManager get localAlbumAssetEntity => i7
.$$LocalAlbumAssetEntityTableTableManager(_db, _db.localAlbumAssetEntity);
i8.$$AuthUserEntityTableTableManager get authUserEntity =>
i8.$$AuthUserEntityTableTableManager(_db, _db.authUserEntity);
i9.$$UserMetadataEntityTableTableManager get userMetadataEntity =>
i9.$$UserMetadataEntityTableTableManager(_db, _db.userMetadataEntity);
i10.$$PartnerEntityTableTableManager get partnerEntity =>
i10.$$PartnerEntityTableTableManager(_db, _db.partnerEntity);
i11.$$LocalAssetUploadEntityTableTableManager get localAssetUploadEntity =>
i11.$$LocalAssetUploadEntityTableTableManager(
_db, _db,
_db.localAssetUploadEntity, _db.localAssetUploadEntity,
); );
i6.$$StackEntityTableTableManager get stackEntity => i12.$$RemoteExifEntityTableTableManager get remoteExifEntity =>
i6.$$StackEntityTableTableManager(_db, _db.stackEntity); i12.$$RemoteExifEntityTableTableManager(_db, _db.remoteExifEntity);
i7.$$RemoteAlbumEntityTableTableManager get remoteAlbumEntity => i13.$$RemoteAlbumAssetEntityTableTableManager get remoteAlbumAssetEntity =>
i7.$$RemoteAlbumEntityTableTableManager(_db, _db.remoteAlbumEntity); i13.$$RemoteAlbumAssetEntityTableTableManager(
i8.$$LocalAlbumEntityTableTableManager get localAlbumEntity =>
i8.$$LocalAlbumEntityTableTableManager(_db, _db.localAlbumEntity);
i9.$$LocalAlbumAssetEntityTableTableManager get localAlbumAssetEntity => i9
.$$LocalAlbumAssetEntityTableTableManager(_db, _db.localAlbumAssetEntity);
i10.$$AuthUserEntityTableTableManager get authUserEntity =>
i10.$$AuthUserEntityTableTableManager(_db, _db.authUserEntity);
i11.$$UserMetadataEntityTableTableManager get userMetadataEntity =>
i11.$$UserMetadataEntityTableTableManager(_db, _db.userMetadataEntity);
i12.$$PartnerEntityTableTableManager get partnerEntity =>
i12.$$PartnerEntityTableTableManager(_db, _db.partnerEntity);
i13.$$RemoteExifEntityTableTableManager get remoteExifEntity =>
i13.$$RemoteExifEntityTableTableManager(_db, _db.remoteExifEntity);
i14.$$RemoteAlbumAssetEntityTableTableManager get remoteAlbumAssetEntity =>
i14.$$RemoteAlbumAssetEntityTableTableManager(
_db, _db,
_db.remoteAlbumAssetEntity, _db.remoteAlbumAssetEntity,
); );
i15.$$RemoteAlbumUserEntityTableTableManager get remoteAlbumUserEntity => i15 i14.$$RemoteAlbumUserEntityTableTableManager get remoteAlbumUserEntity => i14
.$$RemoteAlbumUserEntityTableTableManager(_db, _db.remoteAlbumUserEntity); .$$RemoteAlbumUserEntityTableTableManager(_db, _db.remoteAlbumUserEntity);
i16.$$MemoryEntityTableTableManager get memoryEntity => i15.$$MemoryEntityTableTableManager get memoryEntity =>
i16.$$MemoryEntityTableTableManager(_db, _db.memoryEntity); i15.$$MemoryEntityTableTableManager(_db, _db.memoryEntity);
i17.$$MemoryAssetEntityTableTableManager get memoryAssetEntity => i16.$$MemoryAssetEntityTableTableManager get memoryAssetEntity =>
i17.$$MemoryAssetEntityTableTableManager(_db, _db.memoryAssetEntity); i16.$$MemoryAssetEntityTableTableManager(_db, _db.memoryAssetEntity);
i18.$$PersonEntityTableTableManager get personEntity => i17.$$PersonEntityTableTableManager get personEntity =>
i18.$$PersonEntityTableTableManager(_db, _db.personEntity); i17.$$PersonEntityTableTableManager(_db, _db.personEntity);
i19.$$AssetFaceEntityTableTableManager get assetFaceEntity => i18.$$AssetFaceEntityTableTableManager get assetFaceEntity =>
i19.$$AssetFaceEntityTableTableManager(_db, _db.assetFaceEntity); i18.$$AssetFaceEntityTableTableManager(_db, _db.assetFaceEntity);
i20.$$StoreEntityTableTableManager get storeEntity => i19.$$StoreEntityTableTableManager get storeEntity =>
i20.$$StoreEntityTableTableManager(_db, _db.storeEntity); i19.$$StoreEntityTableTableManager(_db, _db.storeEntity);
} }

View File

@ -5043,21 +5043,20 @@ final class Schema13 extends i0.VersionedSchema {
late final List<i1.DatabaseSchemaEntity> entities = [ late final List<i1.DatabaseSchemaEntity> entities = [
userEntity, userEntity,
remoteAssetEntity, remoteAssetEntity,
stackEntity,
localAssetEntity, localAssetEntity,
localAssetUploadEntity, remoteAlbumEntity,
deleteUploadErrorOnRemoteInsert, localAlbumEntity,
localAlbumAssetEntity,
idxLocalAssetChecksum, idxLocalAssetChecksum,
idxRemoteAssetOwnerChecksum, idxRemoteAssetOwnerChecksum,
uQRemoteAssetsOwnerChecksum, uQRemoteAssetsOwnerChecksum,
uQRemoteAssetsOwnerLibraryChecksum, uQRemoteAssetsOwnerLibraryChecksum,
idxRemoteAssetChecksum, idxRemoteAssetChecksum,
stackEntity,
remoteAlbumEntity,
localAlbumEntity,
localAlbumAssetEntity,
authUserEntity, authUserEntity,
userMetadataEntity, userMetadataEntity,
partnerEntity, partnerEntity,
localAssetUploadEntity,
remoteExifEntity, remoteExifEntity,
remoteAlbumAssetEntity, remoteAlbumAssetEntity,
remoteAlbumUserEntity, remoteAlbumUserEntity,
@ -5116,6 +5115,17 @@ final class Schema13 extends i0.VersionedSchema {
), ),
alias: null, alias: null,
); );
late final Shape3 stackEntity = Shape3(
source: i0.VersionedTable(
entityName: 'stack_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(id)'],
columns: [_column_0, _column_9, _column_5, _column_15, _column_75],
attachedDatabase: database,
),
alias: null,
);
late final Shape2 localAssetEntity = Shape2( late final Shape2 localAssetEntity = Shape2(
source: i0.VersionedTable( source: i0.VersionedTable(
entityName: 'local_asset_entity', entityName: 'local_asset_entity',
@ -5139,52 +5149,6 @@ final class Schema13 extends i0.VersionedSchema {
), ),
alias: null, alias: null,
); );
late final Shape23 localAssetUploadEntity = Shape23(
source: i0.VersionedTable(
entityName: 'local_asset_upload_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(asset_id)'],
columns: [_column_34, _column_95, _column_96, _column_97, _column_98],
attachedDatabase: database,
),
alias: null,
);
final i1.Trigger deleteUploadErrorOnRemoteInsert = i1.Trigger(
'CREATE TRIGGER delete_upload_error_on_remote_insert AFTER INSERT ON remote_asset_entity BEGIN DELETE FROM local_asset_upload_entity WHERE asset_id IN (SELECT lae.id FROM local_asset_entity AS lae WHERE lae.checksum = NEW.checksum);END',
'delete_upload_error_on_remote_insert',
);
final i1.Index idxLocalAssetChecksum = i1.Index(
'idx_local_asset_checksum',
'CREATE INDEX IF NOT EXISTS idx_local_asset_checksum ON local_asset_entity (checksum)',
);
final i1.Index idxRemoteAssetOwnerChecksum = i1.Index(
'idx_remote_asset_owner_checksum',
'CREATE INDEX IF NOT EXISTS idx_remote_asset_owner_checksum ON remote_asset_entity (owner_id, checksum)',
);
final i1.Index uQRemoteAssetsOwnerChecksum = i1.Index(
'UQ_remote_assets_owner_checksum',
'CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum ON remote_asset_entity (owner_id, checksum) WHERE(library_id IS NULL)',
);
final i1.Index uQRemoteAssetsOwnerLibraryChecksum = i1.Index(
'UQ_remote_assets_owner_library_checksum',
'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)',
);
final i1.Index idxRemoteAssetChecksum = i1.Index(
'idx_remote_asset_checksum',
'CREATE INDEX IF NOT EXISTS idx_remote_asset_checksum ON remote_asset_entity (checksum)',
);
late final Shape3 stackEntity = Shape3(
source: i0.VersionedTable(
entityName: 'stack_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(id)'],
columns: [_column_0, _column_9, _column_5, _column_15, _column_75],
attachedDatabase: database,
),
alias: null,
);
late final Shape9 remoteAlbumEntity = Shape9( late final Shape9 remoteAlbumEntity = Shape9(
source: i0.VersionedTable( source: i0.VersionedTable(
entityName: 'remote_album_entity', entityName: 'remote_album_entity',
@ -5236,6 +5200,26 @@ final class Schema13 extends i0.VersionedSchema {
), ),
alias: null, alias: null,
); );
final i1.Index idxLocalAssetChecksum = i1.Index(
'idx_local_asset_checksum',
'CREATE INDEX IF NOT EXISTS idx_local_asset_checksum ON local_asset_entity (checksum)',
);
final i1.Index idxRemoteAssetOwnerChecksum = i1.Index(
'idx_remote_asset_owner_checksum',
'CREATE INDEX IF NOT EXISTS idx_remote_asset_owner_checksum ON remote_asset_entity (owner_id, checksum)',
);
final i1.Index uQRemoteAssetsOwnerChecksum = i1.Index(
'UQ_remote_assets_owner_checksum',
'CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum ON remote_asset_entity (owner_id, checksum) WHERE(library_id IS NULL)',
);
final i1.Index uQRemoteAssetsOwnerLibraryChecksum = i1.Index(
'UQ_remote_assets_owner_library_checksum',
'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)',
);
final i1.Index idxRemoteAssetChecksum = i1.Index(
'idx_remote_asset_checksum',
'CREATE INDEX IF NOT EXISTS idx_remote_asset_checksum ON remote_asset_entity (checksum)',
);
late final Shape21 authUserEntity = Shape21( late final Shape21 authUserEntity = Shape21(
source: i0.VersionedTable( source: i0.VersionedTable(
entityName: 'auth_user_entity', entityName: 'auth_user_entity',
@ -5280,6 +5264,17 @@ final class Schema13 extends i0.VersionedSchema {
), ),
alias: null, alias: null,
); );
late final Shape23 localAssetUploadEntity = Shape23(
source: i0.VersionedTable(
entityName: 'local_asset_upload_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(asset_id)'],
columns: [_column_34, _column_95, _column_96, _column_97, _column_98],
attachedDatabase: database,
),
alias: null,
);
late final Shape8 remoteExifEntity = Shape8( late final Shape8 remoteExifEntity = Shape8(
source: i0.VersionedTable( source: i0.VersionedTable(
entityName: 'remote_exif_entity', entityName: 'remote_exif_entity',

View File

@ -8,7 +8,7 @@ class DriftLocalAssetUploadRepository extends DriftDatabaseRepository {
final Drift _db; final Drift _db;
const DriftLocalAssetUploadRepository(this._db) : super(_db); const DriftLocalAssetUploadRepository(this._db) : super(_db);
Future<List<DriftUploadStatus>> getAll() async { Stream<List<DriftUploadStatus>> watchAll() {
final query = _db.localAssetUploadEntity.select().addColumns([_db.localAssetEntity.name]).join([ final query = _db.localAssetUploadEntity.select().addColumns([_db.localAssetEntity.name]).join([
leftOuterJoin( leftOuterJoin(
_db.localAssetEntity, _db.localAssetEntity,
@ -16,12 +16,11 @@ class DriftLocalAssetUploadRepository extends DriftDatabaseRepository {
useColumns: false, useColumns: false,
), ),
]); ]);
final results = await query.get(); return query.map((row) {
return results.map((row) {
final upload = row.readTable(_db.localAssetUploadEntity); final upload = row.readTable(_db.localAssetUploadEntity);
final assetName = row.read(_db.localAssetEntity.name)!; final assetName = row.read(_db.localAssetEntity.name)!;
return DriftUploadStatus(taskId: upload.assetId, filename: assetName, error: upload.errorMessage, isFailed: true); return DriftUploadStatus(taskId: upload.assetId, filename: assetName, error: upload.errorMessage, isFailed: true);
}).toList(); }).watch();
} }
Future<void> upsert(String assetId, UploadErrorType errorType, String error) { Future<void> upsert(String assetId, UploadErrorType errorType, String error) {
@ -49,4 +48,23 @@ class DriftLocalAssetUploadRepository extends DriftDatabaseRepository {
Future<void> delete(String assetId) async { Future<void> delete(String assetId) async {
await _db.managers.localAssetUploadEntity.filter((row) => row.assetId.id.equals(assetId)).delete(); await _db.managers.localAssetUploadEntity.filter((row) => row.assetId.id.equals(assetId)).delete();
} }
Future<void> prune() async {
final query =
_db.localAssetUploadEntity.selectOnly().join([
leftOuterJoin(
_db.localAssetEntity,
_db.localAssetUploadEntity.assetId.equalsExp(_db.localAssetEntity.id),
useColumns: false,
),
leftOuterJoin(
_db.remoteAssetEntity,
_db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum),
useColumns: false,
),
])
..where(_db.remoteAssetEntity.checksum.isNotNull())
..addColumns([_db.localAssetUploadEntity.assetId]);
await _db.localAssetUploadEntity.deleteWhere((row) => row.assetId.isInQuery(query));
}
} }

View File

@ -9,6 +9,7 @@ import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.dart'
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart'; import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart'; import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
import 'package:immich_mobile/providers/infrastructure/upload.provider.dart'; import 'package:immich_mobile/providers/infrastructure/upload.provider.dart';
import 'package:immich_mobile/services/upload.service.dart';
import 'package:immich_mobile/utils/bytes_units.dart'; import 'package:immich_mobile/utils/bytes_units.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
@ -113,7 +114,9 @@ class DriftUploadDetailPage extends ConsumerWidget {
], ],
), ),
), ),
if (progress != null) if (item.isFailed == true)
_buildRetryButton(item)
else if (progress != null)
_buildProgressIndicator( _buildProgressIndicator(
context, context,
progress, progress,
@ -177,6 +180,26 @@ class DriftUploadDetailPage extends ConsumerWidget {
); );
} }
Widget _buildRetryButton(DriftUploadStatus item) {
return Consumer(
builder: (context, ref, child) {
return IconButton(
onPressed: () => _retryFailedUpload(ref, item),
icon: const Icon(Icons.refresh_rounded),
iconSize: 24,
color: context.colorScheme.onErrorContainer,
tooltip: "retry_upload".t(context: context),
);
},
);
}
Future<void> _retryFailedUpload(WidgetRef ref, DriftUploadStatus item) async {
await ref.read(uploadServiceProvider).clearError(item.taskId);
ref.invalidate(failedUploadStatusProvider);
await ref.read(uploadServiceProvider).manualBackupId(item.taskId);
}
Future<void> _showFileDetailDialog(BuildContext context, DriftUploadStatus item) { Future<void> _showFileDetailDialog(BuildContext context, DriftUploadStatus item) {
return showDialog( return showDialog(
context: context, context: context,

View File

@ -81,10 +81,11 @@ final assetUploadRepositoryProvider = Provider<DriftLocalAssetUploadRepository>(
(ref) => DriftLocalAssetUploadRepository(ref.watch(driftProvider)), (ref) => DriftLocalAssetUploadRepository(ref.watch(driftProvider)),
); );
final failedUploadStatusProvider = FutureProvider.autoDispose<Map<String, DriftUploadStatus>>((ref) async { final failedUploadStatusProvider = StreamProvider.autoDispose<Map<String, DriftUploadStatus>>((ref) {
final allUploads = await ref.watch(assetUploadRepositoryProvider).getAll(); return ref.watch(assetUploadRepositoryProvider).watchAll().map((uploads) {
return allUploads.fold<Map<String, DriftUploadStatus>>({}, (acc, upload) { return uploads.fold<Map<String, DriftUploadStatus>>({}, (acc, upload) {
acc[upload.taskId] = upload; acc[upload.taskId] = upload;
return acc; return acc;
}); });
});
}); });

View File

@ -113,6 +113,15 @@ class UploadService {
return _backupRepository.getAllCounts(userId); return _backupRepository.getAllCounts(userId);
} }
Future<void> manualBackupId(String localId) async {
final localAsset = await _localAssetRepository.get(localId);
if (localAsset == null) {
_logger.warning('Local asset with id $localId not found for manual backup');
return;
}
await manualBackup([localAsset]);
}
Future<void> manualBackup(List<LocalAsset> localAssets) async { Future<void> manualBackup(List<LocalAsset> localAssets) async {
await _storageRepository.clearCache(); await _storageRepository.clearCache();
List<UploadTask> tasks = []; List<UploadTask> tasks = [];
@ -141,6 +150,7 @@ class UploadService {
bool ignoreFailed = false, bool ignoreFailed = false,
}) async { }) async {
await _storageRepository.clearCache(); await _storageRepository.clearCache();
await _assetUploadRepository.prune();
shouldAbortQueuingTasks = false; shouldAbortQueuingTasks = false;
@ -164,6 +174,7 @@ class UploadService {
Future<void> startBackupWithHttpClient(String userId, bool hasWifi, CancellationToken token) async { Future<void> startBackupWithHttpClient(String userId, bool hasWifi, CancellationToken token) async {
await _storageRepository.clearCache(); await _storageRepository.clearCache();
await _assetUploadRepository.prune();
shouldAbortQueuingTasks = false; shouldAbortQueuingTasks = false;
@ -206,6 +217,7 @@ class UploadService {
shouldAbortQueuingTasks = true; shouldAbortQueuingTasks = true;
await _storageRepository.clearCache(); await _storageRepository.clearCache();
await _assetUploadRepository.prune();
await _uploadRepository.reset(kBackupGroup); await _uploadRepository.reset(kBackupGroup);
await _uploadRepository.deleteDatabaseRecords(kBackupGroup); await _uploadRepository.deleteDatabaseRecords(kBackupGroup);

File diff suppressed because it is too large Load Diff