From 14d785cec9897efa74c5db4d6c33adaba4dff9e8 Mon Sep 17 00:00:00 2001 From: xCJPECKOVERx Date: Mon, 9 Jun 2025 11:11:43 -0400 Subject: [PATCH] feat(server): Add album filter to search (#18985) * - updated dtos - added inAlbums to search builder - only check isNotInAlbum if albumIds is blank/empty * - consider inAlbums as OR * - make open-api-dart * - lint & format * - remove inAlbums groupBy clause * - merge main open-api * - make open-api * - inAlbums filter AND instead of OR --- .../lib/model/metadata_search_dto.dart | Bin 29009 -> 29363 bytes .../openapi/lib/model/random_search_dto.dart | Bin 21559 -> 21913 bytes .../openapi/lib/model/smart_search_dto.dart | Bin 21645 -> 21999 bytes .../lib/model/statistics_search_dto.dart | Bin 18875 -> 19229 bytes open-api/immich-openapi-specs.json | 28 ++++++++++++++++++ open-api/typescript-sdk/src/fetch-client.ts | 4 +++ server/src/dtos/search.dto.ts | 3 ++ server/src/repositories/search.repository.ts | 7 ++++- server/src/utils/database.ts | 17 ++++++++++- 9 files changed, 57 insertions(+), 2 deletions(-) diff --git a/mobile/openapi/lib/model/metadata_search_dto.dart b/mobile/openapi/lib/model/metadata_search_dto.dart index 7f1184467b1d6c8c9c5ded2832fc6ebf2199aca6..520777a45de3aa412f5c1e2de0c47bbd7b98fdf1 100644 GIT binary patch delta 212 zcmcckh;j2%#tl7;tcf{ErMZ(YGD~jmVJv4B^~o$Qu?a3I%FIi*Qvl0(rW9|UD3-*y zIf2d0U~-F6^!*PqPF3JO`p x`FYVr>M#lQSOr^!l8nq^J($SmVoxz~F&NJZMZ@GZ=^9YCXQV}K?o2o#006KzPLKcq delta 53 zcmV-50LuTf+CI3kb8I1}-qO1UF{}vxPl_2(uhU`2({) LN)Q*b>tV)rxRVc~GEY^dGY(8z$D<}rzS)pi{yw6huYS|mlsLc^>_jv({flS~4 delta 44 zcmV+{0Mq}Os{yyD0kDPvv!nri0<${=+9I<{C&L7@C@ew-vwkw~0<)GihY_>7N8b&R Cv=Qe3 diff --git a/mobile/openapi/lib/model/smart_search_dto.dart b/mobile/openapi/lib/model/smart_search_dto.dart index a915d97b319af940626a3be2d2aef171bded918e..c221340553f9f21fc81ce2927a1764b485fa40da 100644 GIT binary patch delta 215 zcmeBO$@qRXS;pu!ld^(B zR&jn_bdfqtLOoW&R-q&#vse!%vYFAeLr@IHvqI4@`GB_u)cLQyqc(TCvG4%^NuEr) delta 44 zcmV+{0Mq~Ps{xIv0kDGsv!MZv0<%a2`69D-C(Q)2UMxliv$!(r0<+9Df)TUpM+6S6 C;}UoP diff --git a/mobile/openapi/lib/model/statistics_search_dto.dart b/mobile/openapi/lib/model/statistics_search_dto.dart index 0fe0770b6dc2f4acc5523194d141e7c3d27c1070..55de23ba3225d653cbd33dbb01dd4341d53c38af 100644 GIT binary patch delta 215 zcmdlznQ`tk#toAgSrc=TN^>XgXOi4JiP3;b)F-pJ#3s0;C^IkJP5~_EnNqxYFY_0f z$)?KE!Y~mXxSZzZl?sk5A}|TPjKty$=lqmZO$F`EPgI&%;WD-=Ff}>~o71%BGAS!4 zWEJPA!_q18%16KmWNFw delta 44 zcmV+{0Mq}SmI1qy0kDz*v#(qb: SelectQueryBuilder, personIds: ); } +export function inAlbums(qb: SelectQueryBuilder, albumIds: string[]) { + return qb.innerJoin( + (eb) => + eb + .selectFrom('albums_assets_assets') + .select('assetsId') + .where('albumsId', '=', anyUuid(albumIds!)) + .groupBy('assetsId') + .having((eb) => eb.fn.count('albumsId').distinct(), '=', albumIds.length) + .as('has_album'), + (join) => join.onRef('has_album.assetsId', '=', 'assets.id'), + ); +} + export function hasTags(qb: SelectQueryBuilder, tagIds: string[]) { return qb.innerJoin( (eb) => @@ -292,6 +306,7 @@ export function searchAssetBuilder(kysely: Kysely, options: AssetSearchBuild .withPlugin(joinDeduplicationPlugin) .selectFrom('assets') .where('assets.visibility', '=', visibility) + .$if(!!options.albumIds && options.albumIds.length > 0, (qb) => inAlbums(qb, options.albumIds!)) .$if(!!options.tagIds && options.tagIds.length > 0, (qb) => hasTags(qb, options.tagIds!)) .$if(!!options.personIds && options.personIds.length > 0, (qb) => hasPeople(qb, options.personIds!)) .$if(!!options.createdBefore, (qb) => qb.where('assets.createdAt', '<=', options.createdBefore!)) @@ -368,7 +383,7 @@ export function searchAssetBuilder(kysely: Kysely, options: AssetSearchBuild .$if(options.isMotion !== undefined, (qb) => qb.where('assets.livePhotoVideoId', options.isMotion ? 'is not' : 'is', null), ) - .$if(!!options.isNotInAlbum, (qb) => + .$if(!!options.isNotInAlbum && (!options.albumIds || options.albumIds.length === 0), (qb) => qb.where((eb) => eb.not(eb.exists((eb) => eb.selectFrom('albums_assets_assets').whereRef('assetsId', '=', 'assets.id'))), ),