0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-04-08 03:01:32 -05:00

refactor(server): bulk update exif (#17109)

* bulk update exif

* update sql

* update tests

* check job queeuing in test
This commit is contained in:
Mert 2025-03-25 17:24:24 -04:00 committed by GitHub
parent 4cf7c55680
commit 75df8fc10e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 51 additions and 2 deletions

View file

@ -1,5 +1,12 @@
-- NOTE: This file is auto generated by ./sql-generator
-- AssetRepository.updateAllExif
update "exif"
set
"model" = $1
where
"assetId" in ($2)
-- AssetRepository.getByDayOfYear
with
"res" as (

View file

@ -201,6 +201,16 @@ export class AssetRepository {
.execute();
}
@GenerateSql({ params: [[DummyValue.UUID], { model: DummyValue.STRING }] })
@Chunked()
async updateAllExif(ids: string[], options: Updateable<Exif>): Promise<void> {
if (ids.length === 0) {
return;
}
await this.db.updateTable('exif').set(options).where('assetId', 'in', ids).execute();
}
async upsertJobStatus(...jobStatus: Insertable<AssetJobStatus>[]): Promise<void> {
if (jobStatus.length === 0) {
return;

View file

@ -460,6 +460,34 @@ describe(AssetService.name, () => {
rating: undefined,
});
expect(mocks.asset.updateAll).toHaveBeenCalled();
expect(mocks.asset.updateAllExif).toHaveBeenCalledWith(['asset-1'], { latitude: 0, longitude: 0 });
expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ name: JobName.SIDECAR_WRITE, data: { id: 'asset-1', latitude: 0, longitude: 0 } },
]);
});
it('should update exif table if latitude field is provided', async () => {
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1']));
const dateTimeOriginal = new Date().toISOString();
await sut.updateAll(authStub.admin, {
ids: ['asset-1'],
latitude: 30,
longitude: 50,
dateTimeOriginal,
isArchived: undefined,
isFavorite: false,
duplicateId: undefined,
rating: undefined,
});
expect(mocks.asset.updateAll).toHaveBeenCalled();
expect(mocks.asset.updateAllExif).toHaveBeenCalledWith(['asset-1'], {
dateTimeOriginal,
latitude: 30,
longitude: 50,
});
expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ name: JobName.SIDECAR_WRITE, data: { id: 'asset-1', dateTimeOriginal, latitude: 30, longitude: 50 } },
]);
});
});

View file

@ -134,8 +134,11 @@ export class AssetService extends BaseService {
const { ids, dateTimeOriginal, latitude, longitude, ...options } = dto;
await this.requireAccess({ auth, permission: Permission.ASSET_UPDATE, ids });
for (const id of ids) {
await this.updateMetadata({ id, dateTimeOriginal, latitude, longitude });
if (dateTimeOriginal !== undefined || latitude !== undefined || longitude !== undefined) {
await this.assetRepository.updateAllExif(ids, { dateTimeOriginal, latitude, longitude });
await this.jobRepository.queueAll(
ids.map((id) => ({ name: JobName.SIDECAR_WRITE, data: { id, dateTimeOriginal, latitude, longitude } })),
);
}
if (

View file

@ -7,6 +7,7 @@ export const newAssetRepositoryMock = (): Mocked<RepositoryInterface<AssetReposi
create: vitest.fn(),
createAll: vitest.fn(),
upsertExif: vitest.fn(),
updateAllExif: vitest.fn(),
upsertJobStatus: vitest.fn(),
getByDayOfYear: vitest.fn(),
getByIds: vitest.fn().mockResolvedValue([]),