mirror of
https://github.com/immich-app/immich.git
synced 2025-05-24 01:12:58 -04:00
refactor: more job query stuff (#17658)
This commit is contained in:
parent
85c2d36d99
commit
1bbfacfc09
@ -183,7 +183,7 @@ from
|
||||
where
|
||||
"assets"."id" = $1
|
||||
|
||||
-- AssetJobRepository.getAlbumThumbnailFile
|
||||
-- AssetJobRepository.getAlbumThumbnailFiles
|
||||
select
|
||||
"asset_files"."id",
|
||||
"asset_files"."path",
|
||||
@ -192,6 +192,32 @@ from
|
||||
"asset_files"
|
||||
where
|
||||
"asset_files"."assetId" = $1
|
||||
and "asset_files"."type" = $2
|
||||
|
||||
-- AssetJobRepository.getForClipEncoding
|
||||
select
|
||||
"assets"."id",
|
||||
"assets"."isVisible",
|
||||
(
|
||||
select
|
||||
coalesce(json_agg(agg), '[]')
|
||||
from
|
||||
(
|
||||
select
|
||||
"asset_files"."id",
|
||||
"asset_files"."path",
|
||||
"asset_files"."type"
|
||||
from
|
||||
"asset_files"
|
||||
where
|
||||
"asset_files"."assetId" = "assets"."id"
|
||||
and "asset_files"."type" = $1
|
||||
) as agg
|
||||
) as "files"
|
||||
from
|
||||
"assets"
|
||||
where
|
||||
"assets"."id" = $2
|
||||
|
||||
-- AssetJobRepository.getForStorageTemplateJob
|
||||
select
|
||||
|
@ -117,9 +117,24 @@ export class AssetJobRepository {
|
||||
.executeTakeFirst();
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID, AssetFileType.THUMBNAIL] })
|
||||
getAlbumThumbnailFiles(id: string, fileType?: AssetFileType) {
|
||||
return this.db
|
||||
.selectFrom('asset_files')
|
||||
.select(columns.assetFiles)
|
||||
.where('asset_files.assetId', '=', id)
|
||||
.$if(!!fileType, (qb) => qb.where('asset_files.type', '=', fileType!))
|
||||
.execute();
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID] })
|
||||
getAlbumThumbnailFile(id: string) {
|
||||
return this.db.selectFrom('asset_files').select(columns.assetFiles).where('asset_files.assetId', '=', id).execute();
|
||||
getForClipEncoding(id: string) {
|
||||
return this.db
|
||||
.selectFrom('assets')
|
||||
.select(['assets.id', 'assets.isVisible'])
|
||||
.select((eb) => withFiles(eb, AssetFileType.PREVIEW))
|
||||
.where('assets.id', '=', id)
|
||||
.executeTakeFirst();
|
||||
}
|
||||
|
||||
private storageTemplateAssetQuery() {
|
||||
|
@ -412,11 +412,12 @@ describe(NotificationService.name, () => {
|
||||
});
|
||||
mocks.systemMetadata.get.mockResolvedValue({ server: {} });
|
||||
mocks.notification.renderEmail.mockResolvedValue({ html: '', text: '' });
|
||||
mocks.assetJob.getAlbumThumbnailFile.mockResolvedValue([]);
|
||||
mocks.assetJob.getAlbumThumbnailFiles.mockResolvedValue([]);
|
||||
|
||||
await expect(sut.handleAlbumInvite({ id: '', recipientId: '' })).resolves.toBe(JobStatus.SUCCESS);
|
||||
expect(mocks.assetJob.getAlbumThumbnailFile).toHaveBeenCalledWith(
|
||||
expect(mocks.assetJob.getAlbumThumbnailFiles).toHaveBeenCalledWith(
|
||||
albumStub.emptyWithValidThumbnail.albumThumbnailAssetId,
|
||||
AssetFileType.THUMBNAIL,
|
||||
);
|
||||
expect(mocks.job.queue).toHaveBeenCalledWith({
|
||||
name: JobName.SEND_EMAIL,
|
||||
@ -440,13 +441,14 @@ describe(NotificationService.name, () => {
|
||||
});
|
||||
mocks.systemMetadata.get.mockResolvedValue({ server: {} });
|
||||
mocks.notification.renderEmail.mockResolvedValue({ html: '', text: '' });
|
||||
mocks.assetJob.getAlbumThumbnailFile.mockResolvedValue([
|
||||
mocks.assetJob.getAlbumThumbnailFiles.mockResolvedValue([
|
||||
{ id: '1', type: AssetFileType.THUMBNAIL, path: 'path-to-thumb.jpg' },
|
||||
]);
|
||||
|
||||
await expect(sut.handleAlbumInvite({ id: '', recipientId: '' })).resolves.toBe(JobStatus.SUCCESS);
|
||||
expect(mocks.assetJob.getAlbumThumbnailFile).toHaveBeenCalledWith(
|
||||
expect(mocks.assetJob.getAlbumThumbnailFiles).toHaveBeenCalledWith(
|
||||
albumStub.emptyWithValidThumbnail.albumThumbnailAssetId,
|
||||
AssetFileType.THUMBNAIL,
|
||||
);
|
||||
expect(mocks.job.queue).toHaveBeenCalledWith({
|
||||
name: JobName.SEND_EMAIL,
|
||||
@ -470,11 +472,12 @@ describe(NotificationService.name, () => {
|
||||
});
|
||||
mocks.systemMetadata.get.mockResolvedValue({ server: {} });
|
||||
mocks.notification.renderEmail.mockResolvedValue({ html: '', text: '' });
|
||||
mocks.assetJob.getAlbumThumbnailFile.mockResolvedValue(assetStub.image.files);
|
||||
mocks.assetJob.getAlbumThumbnailFiles.mockResolvedValue([assetStub.image.files[2]]);
|
||||
|
||||
await expect(sut.handleAlbumInvite({ id: '', recipientId: '' })).resolves.toBe(JobStatus.SUCCESS);
|
||||
expect(mocks.assetJob.getAlbumThumbnailFile).toHaveBeenCalledWith(
|
||||
expect(mocks.assetJob.getAlbumThumbnailFiles).toHaveBeenCalledWith(
|
||||
albumStub.emptyWithValidThumbnail.albumThumbnailAssetId,
|
||||
AssetFileType.THUMBNAIL,
|
||||
);
|
||||
expect(mocks.job.queue).toHaveBeenCalledWith({
|
||||
name: JobName.SEND_EMAIL,
|
||||
@ -506,7 +509,7 @@ describe(NotificationService.name, () => {
|
||||
});
|
||||
mocks.user.get.mockResolvedValueOnce(userStub.user1);
|
||||
mocks.notification.renderEmail.mockResolvedValue({ html: '', text: '' });
|
||||
mocks.assetJob.getAlbumThumbnailFile.mockResolvedValue([]);
|
||||
mocks.assetJob.getAlbumThumbnailFiles.mockResolvedValue([]);
|
||||
|
||||
await sut.handleAlbumUpdate({ id: '', recipientIds: [userStub.user1.id] });
|
||||
expect(mocks.user.get).toHaveBeenCalledWith(userStub.user1.id, { withDeleted: false });
|
||||
@ -528,7 +531,7 @@ describe(NotificationService.name, () => {
|
||||
],
|
||||
});
|
||||
mocks.notification.renderEmail.mockResolvedValue({ html: '', text: '' });
|
||||
mocks.assetJob.getAlbumThumbnailFile.mockResolvedValue([]);
|
||||
mocks.assetJob.getAlbumThumbnailFiles.mockResolvedValue([]);
|
||||
|
||||
await sut.handleAlbumUpdate({ id: '', recipientIds: [userStub.user1.id] });
|
||||
expect(mocks.user.get).toHaveBeenCalledWith(userStub.user1.id, { withDeleted: false });
|
||||
@ -550,7 +553,7 @@ describe(NotificationService.name, () => {
|
||||
],
|
||||
});
|
||||
mocks.notification.renderEmail.mockResolvedValue({ html: '', text: '' });
|
||||
mocks.assetJob.getAlbumThumbnailFile.mockResolvedValue([]);
|
||||
mocks.assetJob.getAlbumThumbnailFiles.mockResolvedValue([]);
|
||||
|
||||
await sut.handleAlbumUpdate({ id: '', recipientIds: [userStub.user1.id] });
|
||||
expect(mocks.user.get).toHaveBeenCalledWith(userStub.user1.id, { withDeleted: false });
|
||||
@ -564,7 +567,7 @@ describe(NotificationService.name, () => {
|
||||
});
|
||||
mocks.user.get.mockResolvedValue(userStub.user1);
|
||||
mocks.notification.renderEmail.mockResolvedValue({ html: '', text: '' });
|
||||
mocks.assetJob.getAlbumThumbnailFile.mockResolvedValue([]);
|
||||
mocks.assetJob.getAlbumThumbnailFiles.mockResolvedValue([]);
|
||||
|
||||
await sut.handleAlbumUpdate({ id: '', recipientIds: [userStub.user1.id] });
|
||||
expect(mocks.user.get).toHaveBeenCalledWith(userStub.user1.id, { withDeleted: false });
|
||||
|
@ -6,7 +6,6 @@ import { ArgOf } from 'src/repositories/event.repository';
|
||||
import { EmailTemplate } from 'src/repositories/notification.repository';
|
||||
import { BaseService } from 'src/services/base.service';
|
||||
import { EmailImageAttachment, IEntityJob, INotifyAlbumUpdateJob, JobItem, JobOf } from 'src/types';
|
||||
import { getAssetFile } from 'src/utils/asset.util';
|
||||
import { getFilenameExtension } from 'src/utils/file';
|
||||
import { getExternalDomain } from 'src/utils/misc';
|
||||
import { isEqualObject } from 'src/utils/object';
|
||||
@ -398,19 +397,18 @@ export class NotificationService extends BaseService {
|
||||
return;
|
||||
}
|
||||
|
||||
const albumThumbnailFiles = await this.assetJobRepository.getAlbumThumbnailFile(album.albumThumbnailAssetId);
|
||||
if (albumThumbnailFiles.length === 0) {
|
||||
return;
|
||||
}
|
||||
const albumThumbnailFiles = await this.assetJobRepository.getAlbumThumbnailFiles(
|
||||
album.albumThumbnailAssetId,
|
||||
AssetFileType.THUMBNAIL,
|
||||
);
|
||||
|
||||
const thumbnailFile = getAssetFile(albumThumbnailFiles, AssetFileType.THUMBNAIL);
|
||||
if (!thumbnailFile) {
|
||||
if (albumThumbnailFiles.length !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
filename: `album-thumbnail${getFilenameExtension(thumbnailFile.path)}`,
|
||||
path: thumbnailFile.path,
|
||||
filename: `album-thumbnail${getFilenameExtension(albumThumbnailFiles[0].path)}`,
|
||||
path: albumThumbnailFiles[0].path,
|
||||
cid: 'album-thumbnail',
|
||||
};
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ describe(SmartInfoService.name, () => {
|
||||
});
|
||||
|
||||
it('should skip assets without a resize path', async () => {
|
||||
mocks.asset.getByIds.mockResolvedValue([assetStub.noResizePath]);
|
||||
mocks.assetJob.getForClipEncoding.mockResolvedValue({ ...assetStub.noResizePath, files: [] });
|
||||
|
||||
expect(await sut.handleEncodeClip({ id: assetStub.noResizePath.id })).toEqual(JobStatus.FAILED);
|
||||
|
||||
@ -274,6 +274,7 @@ describe(SmartInfoService.name, () => {
|
||||
|
||||
it('should save the returned objects', async () => {
|
||||
mocks.machineLearning.encodeImage.mockResolvedValue('[0.01, 0.02, 0.03]');
|
||||
mocks.assetJob.getForClipEncoding.mockResolvedValue({ ...assetStub.image, files: [assetStub.image.files[1]] });
|
||||
|
||||
expect(await sut.handleEncodeClip({ id: assetStub.image.id })).toEqual(JobStatus.SUCCESS);
|
||||
|
||||
@ -286,7 +287,10 @@ describe(SmartInfoService.name, () => {
|
||||
});
|
||||
|
||||
it('should skip invisible assets', async () => {
|
||||
mocks.asset.getByIds.mockResolvedValue([assetStub.livePhotoMotionAsset]);
|
||||
mocks.assetJob.getForClipEncoding.mockResolvedValue({
|
||||
...assetStub.livePhotoMotionAsset,
|
||||
files: [assetStub.image.files[1]],
|
||||
});
|
||||
|
||||
expect(await sut.handleEncodeClip({ id: assetStub.livePhotoMotionAsset.id })).toEqual(JobStatus.SKIPPED);
|
||||
|
||||
@ -295,7 +299,7 @@ describe(SmartInfoService.name, () => {
|
||||
});
|
||||
|
||||
it('should fail if asset could not be found', async () => {
|
||||
mocks.asset.getByIds.mockResolvedValue([]);
|
||||
mocks.assetJob.getForClipEncoding.mockResolvedValue(void 0);
|
||||
|
||||
expect(await sut.handleEncodeClip({ id: assetStub.image.id })).toEqual(JobStatus.FAILED);
|
||||
|
||||
@ -306,6 +310,7 @@ describe(SmartInfoService.name, () => {
|
||||
it('should wait for database', async () => {
|
||||
mocks.machineLearning.encodeImage.mockResolvedValue('[0.01, 0.02, 0.03]');
|
||||
mocks.database.isBusy.mockReturnValue(true);
|
||||
mocks.assetJob.getForClipEncoding.mockResolvedValue({ ...assetStub.image, files: [assetStub.image.files[1]] });
|
||||
|
||||
expect(await sut.handleEncodeClip({ id: assetStub.image.id })).toEqual(JobStatus.SUCCESS);
|
||||
|
||||
|
@ -2,12 +2,11 @@ import { Injectable } from '@nestjs/common';
|
||||
import { SystemConfig } from 'src/config';
|
||||
import { JOBS_ASSET_PAGINATION_SIZE } from 'src/constants';
|
||||
import { OnEvent, OnJob } from 'src/decorators';
|
||||
import { AssetFileType, DatabaseLock, ImmichWorker, JobName, JobStatus, QueueName } from 'src/enum';
|
||||
import { DatabaseLock, ImmichWorker, JobName, JobStatus, QueueName } from 'src/enum';
|
||||
import { WithoutProperty } from 'src/repositories/asset.repository';
|
||||
import { ArgOf } from 'src/repositories/event.repository';
|
||||
import { BaseService } from 'src/services/base.service';
|
||||
import { JobOf } from 'src/types';
|
||||
import { getAssetFile } from 'src/utils/asset.util';
|
||||
import { getCLIPModelInfo, isSmartSearchEnabled } from 'src/utils/misc';
|
||||
import { usePagination } from 'src/utils/pagination';
|
||||
|
||||
@ -107,8 +106,8 @@ export class SmartInfoService extends BaseService {
|
||||
return JobStatus.SKIPPED;
|
||||
}
|
||||
|
||||
const [asset] = await this.assetRepository.getByIds([id], { files: true });
|
||||
if (!asset) {
|
||||
const asset = await this.assetJobRepository.getForClipEncoding(id);
|
||||
if (!asset || asset.files.length !== 1) {
|
||||
return JobStatus.FAILED;
|
||||
}
|
||||
|
||||
@ -116,14 +115,9 @@ export class SmartInfoService extends BaseService {
|
||||
return JobStatus.SKIPPED;
|
||||
}
|
||||
|
||||
const previewFile = getAssetFile(asset.files, AssetFileType.PREVIEW);
|
||||
if (!previewFile) {
|
||||
return JobStatus.FAILED;
|
||||
}
|
||||
|
||||
const embedding = await this.machineLearningRepository.encodeImage(
|
||||
machineLearning.urls,
|
||||
previewFile.path,
|
||||
asset.files[0].path,
|
||||
machineLearning.clip,
|
||||
);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user