mirror of
https://github.com/immich-app/immich.git
synced 2026-03-01 18:19:10 +03:00
refactor: new asset-job repository (#17622)
* refactor: new asset-job repository * fix: broken medium tests on main
This commit is contained in:
95
server/src/repositories/asset-job.repository.ts
Normal file
95
server/src/repositories/asset-job.repository.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Kysely } from 'kysely';
|
||||
import { jsonArrayFrom } from 'kysely/helpers/postgres';
|
||||
import { InjectKysely } from 'nestjs-kysely';
|
||||
import { DB } from 'src/db';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { withFiles } from 'src/entities/asset.entity';
|
||||
import { AssetFileType } from 'src/enum';
|
||||
import { StorageAsset } from 'src/types';
|
||||
import { asUuid } from 'src/utils/database';
|
||||
|
||||
@Injectable()
|
||||
export class AssetJobRepository {
|
||||
constructor(@InjectKysely() private db: Kysely<DB>) {}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID] })
|
||||
getForSearchDuplicatesJob(id: string) {
|
||||
return this.db
|
||||
.selectFrom('assets')
|
||||
.where('assets.id', '=', asUuid(id))
|
||||
.leftJoin('smart_search', 'assets.id', 'smart_search.assetId')
|
||||
.select((eb) => [
|
||||
'id',
|
||||
'type',
|
||||
'ownerId',
|
||||
'duplicateId',
|
||||
'stackId',
|
||||
'isVisible',
|
||||
'smart_search.embedding',
|
||||
withFiles(eb, AssetFileType.PREVIEW),
|
||||
])
|
||||
.limit(1)
|
||||
.executeTakeFirst();
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID] })
|
||||
getForSidecarWriteJob(id: string) {
|
||||
return this.db
|
||||
.selectFrom('assets')
|
||||
.where('assets.id', '=', asUuid(id))
|
||||
.select((eb) => [
|
||||
'id',
|
||||
'sidecarPath',
|
||||
'originalPath',
|
||||
jsonArrayFrom(
|
||||
eb
|
||||
.selectFrom('tags')
|
||||
.select(['tags.value'])
|
||||
.innerJoin('tag_asset', 'tags.id', 'tag_asset.tagsId')
|
||||
.whereRef('assets.id', '=', 'tag_asset.assetsId'),
|
||||
).as('tags'),
|
||||
])
|
||||
.limit(1)
|
||||
.executeTakeFirst();
|
||||
}
|
||||
|
||||
private storageTemplateAssetQuery() {
|
||||
return this.db
|
||||
.selectFrom('assets')
|
||||
.innerJoin('exif', 'assets.id', 'exif.assetId')
|
||||
.select([
|
||||
'assets.id',
|
||||
'assets.ownerId',
|
||||
'assets.type',
|
||||
'assets.checksum',
|
||||
'assets.originalPath',
|
||||
'assets.isExternal',
|
||||
'assets.sidecarPath',
|
||||
'assets.originalFileName',
|
||||
'assets.livePhotoVideoId',
|
||||
'assets.fileCreatedAt',
|
||||
'exif.timeZone',
|
||||
'exif.fileSizeInByte',
|
||||
])
|
||||
.where('assets.deletedAt', 'is', null);
|
||||
}
|
||||
|
||||
getForStorageTemplateJob(id: string): Promise<StorageAsset | undefined> {
|
||||
return this.storageTemplateAssetQuery().where('assets.id', '=', id).executeTakeFirst() as Promise<
|
||||
StorageAsset | undefined
|
||||
>;
|
||||
}
|
||||
|
||||
streamForStorageTemplateJob() {
|
||||
return this.storageTemplateAssetQuery().stream() as AsyncIterableIterator<StorageAsset>;
|
||||
}
|
||||
|
||||
streamForDeletedJob(trashedBefore: Date) {
|
||||
return this.db
|
||||
.selectFrom('assets')
|
||||
.select(['id', 'isOffline'])
|
||||
.where('assets.deletedAt', '<=', trashedBefore)
|
||||
.stream();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Insertable, Kysely, Selectable, UpdateResult, Updateable, sql } from 'kysely';
|
||||
import { jsonArrayFrom } from 'kysely/helpers/postgres';
|
||||
import { isEmpty, isUndefined, omitBy } from 'lodash';
|
||||
import { InjectKysely } from 'nestjs-kysely';
|
||||
import { AssetFiles, AssetJobStatus, Assets, DB, Exif } from 'src/db';
|
||||
@@ -24,7 +23,6 @@ import {
|
||||
} from 'src/entities/asset.entity';
|
||||
import { AssetFileType, AssetOrder, AssetStatus, AssetType } from 'src/enum';
|
||||
import { AssetSearchOptions, SearchExploreItem, SearchExploreItemSet } from 'src/repositories/search.repository';
|
||||
import { StorageAsset } from 'src/types';
|
||||
import { anyUuid, asUuid, removeUndefinedKeys, unnest } from 'src/utils/database';
|
||||
import { globToSqlPattern } from 'src/utils/misc';
|
||||
import { Paginated, PaginationOptions, paginationHelper } from 'src/utils/pagination';
|
||||
@@ -473,47 +471,6 @@ export class AssetRepository {
|
||||
return count;
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID] })
|
||||
getAssetForSearchDuplicatesJob(id: string) {
|
||||
return this.db
|
||||
.selectFrom('assets')
|
||||
.where('assets.id', '=', asUuid(id))
|
||||
.leftJoin('smart_search', 'assets.id', 'smart_search.assetId')
|
||||
.select((eb) => [
|
||||
'id',
|
||||
'type',
|
||||
'ownerId',
|
||||
'duplicateId',
|
||||
'stackId',
|
||||
'isVisible',
|
||||
'smart_search.embedding',
|
||||
withFiles(eb, AssetFileType.PREVIEW),
|
||||
])
|
||||
.limit(1)
|
||||
.executeTakeFirst();
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID] })
|
||||
getAssetForSidecarWriteJob(id: string) {
|
||||
return this.db
|
||||
.selectFrom('assets')
|
||||
.where('assets.id', '=', asUuid(id))
|
||||
.select((eb) => [
|
||||
'id',
|
||||
'sidecarPath',
|
||||
'originalPath',
|
||||
jsonArrayFrom(
|
||||
eb
|
||||
.selectFrom('tags')
|
||||
.select(['tags.value'])
|
||||
.innerJoin('tag_asset', 'tags.id', 'tag_asset.tagsId')
|
||||
.whereRef('assets.id', '=', 'tag_asset.assetsId'),
|
||||
).as('tags'),
|
||||
])
|
||||
.limit(1)
|
||||
.executeTakeFirst();
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID] })
|
||||
getById(
|
||||
id: string,
|
||||
@@ -653,45 +610,6 @@ export class AssetRepository {
|
||||
.executeTakeFirst() as Promise<AssetEntity | undefined>;
|
||||
}
|
||||
|
||||
private storageTemplateAssetQuery() {
|
||||
return this.db
|
||||
.selectFrom('assets')
|
||||
.innerJoin('exif', 'assets.id', 'exif.assetId')
|
||||
.select([
|
||||
'assets.id',
|
||||
'assets.ownerId',
|
||||
'assets.type',
|
||||
'assets.checksum',
|
||||
'assets.originalPath',
|
||||
'assets.isExternal',
|
||||
'assets.sidecarPath',
|
||||
'assets.originalFileName',
|
||||
'assets.livePhotoVideoId',
|
||||
'assets.fileCreatedAt',
|
||||
'exif.timeZone',
|
||||
'exif.fileSizeInByte',
|
||||
])
|
||||
.where('assets.deletedAt', 'is', null);
|
||||
}
|
||||
|
||||
getStorageTemplateAsset(id: string): Promise<StorageAsset | undefined> {
|
||||
return this.storageTemplateAssetQuery().where('assets.id', '=', id).executeTakeFirst() as Promise<
|
||||
StorageAsset | undefined
|
||||
>;
|
||||
}
|
||||
|
||||
streamStorageTemplateAssets() {
|
||||
return this.storageTemplateAssetQuery().stream() as AsyncIterableIterator<StorageAsset>;
|
||||
}
|
||||
|
||||
streamDeletedAssets(trashedBefore: Date) {
|
||||
return this.db
|
||||
.selectFrom('assets')
|
||||
.select(['id', 'isOffline'])
|
||||
.where('assets.deletedAt', '<=', trashedBefore)
|
||||
.stream();
|
||||
}
|
||||
|
||||
@GenerateSql(
|
||||
...Object.values(WithProperty).map((property) => ({
|
||||
name: property,
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ActivityRepository } from 'src/repositories/activity.repository';
|
||||
import { AlbumUserRepository } from 'src/repositories/album-user.repository';
|
||||
import { AlbumRepository } from 'src/repositories/album.repository';
|
||||
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
||||
import { AssetJobRepository } from 'src/repositories/asset-job.repository';
|
||||
import { AssetRepository } from 'src/repositories/asset.repository';
|
||||
import { AuditRepository } from 'src/repositories/audit.repository';
|
||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||
@@ -48,6 +49,7 @@ export const repositories = [
|
||||
AuditRepository,
|
||||
ApiKeyRepository,
|
||||
AssetRepository,
|
||||
AssetJobRepository,
|
||||
ConfigRepository,
|
||||
CronRepository,
|
||||
CryptoRepository,
|
||||
|
||||
Reference in New Issue
Block a user