mirror of
https://github.com/immich-app/immich.git
synced 2025-05-30 19:54:52 -04:00
refactor(server): filter assets by people using a subquery instead of a cte (#15768)
This commit is contained in:
parent
098bab7c9b
commit
1b141d5ca9
@ -238,24 +238,20 @@ export function withFacesAndPeople(eb: ExpressionBuilder<DB, 'assets'>) {
|
|||||||
.as('faces');
|
.as('faces');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Adds a `has_people` CTE that can be inner joined on to filter out assets */
|
export function hasPeople<O>(qb: SelectQueryBuilder<DB, 'assets', O>, personIds: string[]) {
|
||||||
export function hasPeopleCte(db: Kysely<DB>, personIds: string[]) {
|
return qb.innerJoin(
|
||||||
return db.with('has_people', (qb) =>
|
(eb) =>
|
||||||
qb
|
eb
|
||||||
.selectFrom('asset_faces')
|
.selectFrom('asset_faces')
|
||||||
.select('assetId')
|
.select('assetId')
|
||||||
.where('personId', '=', anyUuid(personIds!))
|
.where('personId', '=', anyUuid(personIds!))
|
||||||
.groupBy('assetId')
|
.groupBy('assetId')
|
||||||
.having((eb) => eb.fn.count('personId').distinct(), '=', personIds.length),
|
.having((eb) => eb.fn.count('personId').distinct(), '=', personIds.length)
|
||||||
|
.as('has_people'),
|
||||||
|
(join) => join.onRef('has_people.assetId', '=', 'assets.id'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasPeople(db: Kysely<DB>, personIds?: string[]) {
|
|
||||||
return personIds && personIds.length > 0
|
|
||||||
? hasPeopleCte(db, personIds).selectFrom('assets').innerJoin('has_people', 'has_people.assetId', 'assets.id')
|
|
||||||
: db.selectFrom('assets');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function withOwner(eb: ExpressionBuilder<DB, 'assets'>) {
|
export function withOwner(eb: ExpressionBuilder<DB, 'assets'>) {
|
||||||
return jsonObjectFrom(eb.selectFrom('users').selectAll().whereRef('users.id', '=', 'assets.ownerId')).as('owner');
|
return jsonObjectFrom(eb.selectFrom('users').selectAll().whereRef('users.id', '=', 'assets.ownerId')).as('owner');
|
||||||
}
|
}
|
||||||
@ -326,8 +322,11 @@ const joinDeduplicationPlugin = new DeduplicateJoinsPlugin();
|
|||||||
export function searchAssetBuilder(kysely: Kysely<DB>, options: AssetSearchBuilderOptions) {
|
export function searchAssetBuilder(kysely: Kysely<DB>, options: AssetSearchBuilderOptions) {
|
||||||
options.isArchived ??= options.withArchived ? undefined : false;
|
options.isArchived ??= options.withArchived ? undefined : false;
|
||||||
options.withDeleted ||= !!(options.trashedAfter || options.trashedBefore);
|
options.withDeleted ||= !!(options.trashedAfter || options.trashedBefore);
|
||||||
return hasPeople(kysely.withPlugin(joinDeduplicationPlugin), options.personIds)
|
return kysely
|
||||||
|
.withPlugin(joinDeduplicationPlugin)
|
||||||
|
.selectFrom('assets')
|
||||||
.selectAll('assets')
|
.selectAll('assets')
|
||||||
|
.$if(!!options.personIds && options.personIds.length > 0, (qb) => hasPeople(qb, options.personIds!))
|
||||||
.$if(!!options.createdBefore, (qb) => qb.where('assets.createdAt', '<=', options.createdBefore!))
|
.$if(!!options.createdBefore, (qb) => qb.where('assets.createdAt', '<=', options.createdBefore!))
|
||||||
.$if(!!options.createdAfter, (qb) => qb.where('assets.createdAt', '>=', options.createdAfter!))
|
.$if(!!options.createdAfter, (qb) => qb.where('assets.createdAt', '>=', options.createdAfter!))
|
||||||
.$if(!!options.updatedBefore, (qb) => qb.where('assets.updatedAt', '<=', options.updatedBefore!))
|
.$if(!!options.updatedBefore, (qb) => qb.where('assets.updatedAt', '<=', options.updatedBefore!))
|
||||||
|
@ -8,7 +8,6 @@ import { Chunked, ChunkedArray, DummyValue, GenerateSql } from 'src/decorators';
|
|||||||
import {
|
import {
|
||||||
AssetEntity,
|
AssetEntity,
|
||||||
hasPeople,
|
hasPeople,
|
||||||
hasPeopleCte,
|
|
||||||
searchAssetBuilder,
|
searchAssetBuilder,
|
||||||
truncatedDate,
|
truncatedDate,
|
||||||
withAlbums,
|
withAlbums,
|
||||||
@ -576,7 +575,7 @@ export class AssetRepository implements IAssetRepository {
|
|||||||
@GenerateSql({ params: [{ size: TimeBucketSize.MONTH }] })
|
@GenerateSql({ params: [{ size: TimeBucketSize.MONTH }] })
|
||||||
async getTimeBuckets(options: TimeBucketOptions): Promise<TimeBucketItem[]> {
|
async getTimeBuckets(options: TimeBucketOptions): Promise<TimeBucketItem[]> {
|
||||||
return (
|
return (
|
||||||
((options.personId ? hasPeopleCte(this.db, [options.personId]) : this.db) as Kysely<DB>)
|
this.db
|
||||||
.with('assets', (qb) =>
|
.with('assets', (qb) =>
|
||||||
qb
|
qb
|
||||||
.selectFrom('assets')
|
.selectFrom('assets')
|
||||||
@ -589,11 +588,7 @@ export class AssetRepository implements IAssetRepository {
|
|||||||
.innerJoin('albums_assets_assets', 'assets.id', 'albums_assets_assets.assetsId')
|
.innerJoin('albums_assets_assets', 'assets.id', 'albums_assets_assets.assetsId')
|
||||||
.where('albums_assets_assets.albumsId', '=', asUuid(options.albumId!)),
|
.where('albums_assets_assets.albumsId', '=', asUuid(options.albumId!)),
|
||||||
)
|
)
|
||||||
.$if(!!options.personId, (qb) =>
|
.$if(!!options.personId, (qb) => hasPeople(qb, [options.personId!]))
|
||||||
qb.innerJoin(sql.table('has_people').as('has_people'), (join) =>
|
|
||||||
join.onRef(sql`has_people."assetId"`, '=', 'assets.id'),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.$if(!!options.withStacked, (qb) =>
|
.$if(!!options.withStacked, (qb) =>
|
||||||
qb
|
qb
|
||||||
.leftJoin('asset_stack', (join) =>
|
.leftJoin('asset_stack', (join) =>
|
||||||
@ -628,10 +623,12 @@ export class AssetRepository implements IAssetRepository {
|
|||||||
|
|
||||||
@GenerateSql({ params: [DummyValue.TIME_BUCKET, { size: TimeBucketSize.MONTH, withStacked: true }] })
|
@GenerateSql({ params: [DummyValue.TIME_BUCKET, { size: TimeBucketSize.MONTH, withStacked: true }] })
|
||||||
async getTimeBucket(timeBucket: string, options: TimeBucketOptions): Promise<AssetEntity[]> {
|
async getTimeBucket(timeBucket: string, options: TimeBucketOptions): Promise<AssetEntity[]> {
|
||||||
return hasPeople(this.db, options.personId ? [options.personId] : undefined)
|
return this.db
|
||||||
|
.selectFrom('assets')
|
||||||
.selectAll('assets')
|
.selectAll('assets')
|
||||||
.$call(withExif)
|
.$call(withExif)
|
||||||
.$if(!!options.albumId, (qb) => withAlbums(qb, { albumId: options.albumId }))
|
.$if(!!options.albumId, (qb) => withAlbums(qb, { albumId: options.albumId }))
|
||||||
|
.$if(!!options.personId, (qb) => hasPeople(qb, [options.personId!]))
|
||||||
.$if(!!options.userIds, (qb) => qb.where('assets.ownerId', '=', anyUuid(options.userIds!)))
|
.$if(!!options.userIds, (qb) => qb.where('assets.ownerId', '=', anyUuid(options.userIds!)))
|
||||||
.$if(options.isArchived !== undefined, (qb) => qb.where('assets.isArchived', '=', options.isArchived!))
|
.$if(options.isArchived !== undefined, (qb) => qb.where('assets.isArchived', '=', options.isArchived!))
|
||||||
.$if(options.isFavorite !== undefined, (qb) => qb.where('assets.isFavorite', '=', options.isFavorite!))
|
.$if(options.isFavorite !== undefined, (qb) => qb.where('assets.isFavorite', '=', options.isFavorite!))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user