From 4de763a7bf7c4ad9a3e24c735d6d83b2699fb495 Mon Sep 17 00:00:00 2001 From: Gauthier Roebroeck Date: Wed, 19 Feb 2025 15:46:12 +0800 Subject: [PATCH] feat(api): referential APIs accept multiple library_id for filtering --- .../persistence/ReferentialRepository.kt | 32 ++++----- .../jooq/main/ReferentialDao.kt | 70 +++++++++---------- .../api/rest/ReferentialController.kt | 34 ++++----- 3 files changed, 69 insertions(+), 67 deletions(-) diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/persistence/ReferentialRepository.kt b/komga/src/main/kotlin/org/gotson/komga/domain/persistence/ReferentialRepository.kt index de32548e..89829128 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/persistence/ReferentialRepository.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/persistence/ReferentialRepository.kt @@ -43,10 +43,10 @@ interface ReferentialRepository { pageable: Pageable, ): Page - fun findAllAuthorsByNameAndLibrary( + fun findAllAuthorsByNameAndLibraries( search: String?, role: String?, - libraryId: String, + libraryIds: Set, filterOnLibraryIds: Collection?, pageable: Pageable, ): Page @@ -77,8 +77,8 @@ interface ReferentialRepository { fun findAllGenres(filterOnLibraryIds: Collection?): Set - fun findAllGenresByLibrary( - libraryId: String, + fun findAllGenresByLibraries( + libraryIds: Set, filterOnLibraryIds: Collection?, ): Set @@ -89,8 +89,8 @@ interface ReferentialRepository { fun findAllSeriesAndBookTags(filterOnLibraryIds: Collection?): Set - fun findAllSeriesAndBookTagsByLibrary( - libraryId: String, + fun findAllSeriesAndBookTagsByLibraries( + libraryIds: Set, filterOnLibraryIds: Collection?, ): Set @@ -125,8 +125,8 @@ interface ReferentialRepository { fun findAllLanguages(filterOnLibraryIds: Collection?): Set - fun findAllLanguagesByLibrary( - libraryId: String, + fun findAllLanguagesByLibraries( + libraryIds: Set, filterOnLibraryIds: Collection?, ): Set @@ -142,8 +142,8 @@ interface ReferentialRepository { pageable: Pageable, ): Page - fun findAllPublishersByLibrary( - libraryId: String, + fun findAllPublishersByLibraries( + libraryIds: Set, filterOnLibraryIds: Collection?, ): Set @@ -154,8 +154,8 @@ interface ReferentialRepository { fun findAllAgeRatings(filterOnLibraryIds: Collection?): Set - fun findAllAgeRatingsByLibrary( - libraryId: String, + fun findAllAgeRatingsByLibraries( + libraryIds: Set, filterOnLibraryIds: Collection?, ): Set @@ -166,8 +166,8 @@ interface ReferentialRepository { fun findAllSeriesReleaseDates(filterOnLibraryIds: Collection?): Set - fun findAllSeriesReleaseDatesByLibrary( - libraryId: String, + fun findAllSeriesReleaseDatesByLibraries( + libraryIds: Set, filterOnLibraryIds: Collection?, ): Set @@ -178,8 +178,8 @@ interface ReferentialRepository { fun findAllSharingLabels(filterOnLibraryIds: Collection?): Set - fun findAllSharingLabelsByLibrary( - libraryId: String, + fun findAllSharingLabelsByLibraries( + libraryIds: Set, filterOnLibraryIds: Collection?, ): Set diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReferentialDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReferentialDao.kt index b1306b19..34593420 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReferentialDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReferentialDao.kt @@ -109,13 +109,13 @@ class ReferentialDao( pageable: Pageable, ): Page = findAuthorsByName(search, role, filterOnLibraryIds, pageable, null) - override fun findAllAuthorsByNameAndLibrary( + override fun findAllAuthorsByNameAndLibraries( search: String?, role: String?, - libraryId: String, + libraryIds: Set, filterOnLibraryIds: Collection?, pageable: Pageable, - ): Page = findAuthorsByName(search, role, filterOnLibraryIds, pageable, FilterBy(FilterByType.LIBRARY, libraryId)) + ): Page = findAuthorsByName(search, role, filterOnLibraryIds, pageable, FilterBy(FilterByType.LIBRARY, libraryIds)) override fun findAllAuthorsByNameAndCollection( search: String?, @@ -123,7 +123,7 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, pageable: Pageable, - ): Page = findAuthorsByName(search, role, filterOnLibraryIds, pageable, FilterBy(FilterByType.COLLECTION, collectionId)) + ): Page = findAuthorsByName(search, role, filterOnLibraryIds, pageable, FilterBy(FilterByType.COLLECTION, setOf(collectionId))) override fun findAllAuthorsByNameAndSeries( search: String?, @@ -131,7 +131,7 @@ class ReferentialDao( seriesId: String, filterOnLibraryIds: Collection?, pageable: Pageable, - ): Page = findAuthorsByName(search, role, filterOnLibraryIds, pageable, FilterBy(FilterByType.SERIES, seriesId)) + ): Page = findAuthorsByName(search, role, filterOnLibraryIds, pageable, FilterBy(FilterByType.SERIES, setOf(seriesId))) override fun findAllAuthorsByNameAndReadList( search: String?, @@ -139,7 +139,7 @@ class ReferentialDao( readListId: String, filterOnLibraryIds: Collection?, pageable: Pageable, - ): Page = findAuthorsByName(search, role, filterOnLibraryIds, pageable, FilterBy(FilterByType.READLIST, readListId)) + ): Page = findAuthorsByName(search, role, filterOnLibraryIds, pageable, FilterBy(FilterByType.READLIST, setOf(readListId))) private enum class FilterByType { LIBRARY, @@ -150,7 +150,7 @@ class ReferentialDao( private data class FilterBy( val type: FilterByType, - val id: String, + val ids: Set, ) private fun findAuthorsByName( @@ -179,10 +179,10 @@ class ReferentialDao( .apply { filterBy?.let { when (it.type) { - FilterByType.LIBRARY -> and(s.LIBRARY_ID.eq(it.id)) - FilterByType.COLLECTION -> and(cs.COLLECTION_ID.eq(it.id)) - FilterByType.SERIES -> and(bmaa.SERIES_ID.eq(it.id)) - FilterByType.READLIST -> and(rb.READLIST_ID.eq(it.id)) + FilterByType.LIBRARY -> and(s.LIBRARY_ID.`in`(it.ids)) + FilterByType.COLLECTION -> and(cs.COLLECTION_ID.`in`(it.ids)) + FilterByType.SERIES -> and(bmaa.SERIES_ID.`in`(it.ids)) + FilterByType.READLIST -> and(rb.READLIST_ID.`in`(it.ids)) } } } @@ -247,8 +247,8 @@ class ReferentialDao( }.orderBy(g.GENRE.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) .fetchSet(g.GENRE) - override fun findAllGenresByLibrary( - libraryId: String, + override fun findAllGenresByLibraries( + libraryIds: Set, filterOnLibraryIds: Collection?, ): Set = dsl @@ -256,7 +256,7 @@ class ReferentialDao( .from(g) .leftJoin(s) .on(g.SERIES_ID.eq(s.ID)) - .where(s.LIBRARY_ID.eq(libraryId)) + .where(s.LIBRARY_ID.`in`(libraryIds)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } .orderBy(g.GENRE.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) .fetchSet(g.GENRE) @@ -289,8 +289,8 @@ class ReferentialDao( .sortedBy { it.stripAccents().lowercase() } .toSet() - override fun findAllSeriesAndBookTagsByLibrary( - libraryId: String, + override fun findAllSeriesAndBookTagsByLibraries( + libraryIds: Set, filterOnLibraryIds: Collection?, ): Set = dsl @@ -298,14 +298,14 @@ class ReferentialDao( .from(bt) .leftJoin(b) .on(bt.BOOK_ID.eq(b.ID)) - .where(b.LIBRARY_ID.eq(libraryId)) + .where(b.LIBRARY_ID.`in`(libraryIds)) .apply { filterOnLibraryIds?.let { and(b.LIBRARY_ID.`in`(it)) } } .union( select(st.TAG.`as`("tag")) .from(st) .leftJoin(s) .on(st.SERIES_ID.eq(s.ID)) - .where(s.LIBRARY_ID.eq(libraryId)) + .where(s.LIBRARY_ID.`in`(libraryIds)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } }, ).fetchSet(0, String::class.java) .sortedBy { it.stripAccents().lowercase() } @@ -419,8 +419,8 @@ class ReferentialDao( .on(bt.BOOK_ID.eq(b.ID)) .where(b.LIBRARY_ID.`in`(it)) } - }.orderBy(st.TAG.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) - .fetchSet(st.TAG) + }.orderBy(bt.TAG.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) + .fetchSet(bt.TAG) override fun findAllLanguages(filterOnLibraryIds: Collection?): Set = dsl @@ -432,8 +432,8 @@ class ReferentialDao( .orderBy(sd.LANGUAGE) .fetchSet(sd.LANGUAGE) - override fun findAllLanguagesByLibrary( - libraryId: String, + override fun findAllLanguagesByLibraries( + libraryIds: Set, filterOnLibraryIds: Collection?, ): Set = dsl @@ -442,7 +442,7 @@ class ReferentialDao( .leftJoin(s) .on(sd.SERIES_ID.eq(s.ID)) .where(sd.LANGUAGE.ne("")) - .and(s.LIBRARY_ID.eq(libraryId)) + .and(s.LIBRARY_ID.`in`(libraryIds)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } .orderBy(sd.LANGUAGE) .fetchSet(sd.LANGUAGE) @@ -505,8 +505,8 @@ class ReferentialDao( ) } - override fun findAllPublishersByLibrary( - libraryId: String, + override fun findAllPublishersByLibraries( + libraryIds: Set, filterOnLibraryIds: Collection?, ): Set = dsl @@ -515,7 +515,7 @@ class ReferentialDao( .leftJoin(s) .on(sd.SERIES_ID.eq(s.ID)) .where(sd.PUBLISHER.ne("")) - .and(s.LIBRARY_ID.eq(libraryId)) + .and(s.LIBRARY_ID.`in`(libraryIds)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } .orderBy(sd.PUBLISHER.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) .fetchSet(sd.PUBLISHER) @@ -549,8 +549,8 @@ class ReferentialDao( }.orderBy(sd.AGE_RATING) .fetchSet(sd.AGE_RATING) - override fun findAllAgeRatingsByLibrary( - libraryId: String, + override fun findAllAgeRatingsByLibraries( + libraryIds: Set, filterOnLibraryIds: Collection?, ): Set = dsl @@ -558,7 +558,7 @@ class ReferentialDao( .from(sd) .leftJoin(s) .on(sd.SERIES_ID.eq(s.ID)) - .where(s.LIBRARY_ID.eq(libraryId)) + .where(s.LIBRARY_ID.`in`(libraryIds)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } .orderBy(sd.AGE_RATING) .fetchSet(sd.AGE_RATING) @@ -588,8 +588,8 @@ class ReferentialDao( .orderBy(bma.RELEASE_DATE.desc()) .fetchSet(bma.RELEASE_DATE) - override fun findAllSeriesReleaseDatesByLibrary( - libraryId: String, + override fun findAllSeriesReleaseDatesByLibraries( + libraryIds: Set, filterOnLibraryIds: Collection?, ): Set = dsl @@ -597,7 +597,7 @@ class ReferentialDao( .from(bma) .leftJoin(s) .on(bma.SERIES_ID.eq(s.ID)) - .where(s.LIBRARY_ID.eq(libraryId)) + .where(s.LIBRARY_ID.`in`(libraryIds)) .and(bma.RELEASE_DATE.isNotNull) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } .orderBy(bma.RELEASE_DATE.desc()) @@ -632,8 +632,8 @@ class ReferentialDao( }.orderBy(sl.LABEL.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) .fetchSet(sl.LABEL) - override fun findAllSharingLabelsByLibrary( - libraryId: String, + override fun findAllSharingLabelsByLibraries( + libraryIds: Set, filterOnLibraryIds: Collection?, ): Set = dsl @@ -641,7 +641,7 @@ class ReferentialDao( .from(sl) .leftJoin(s) .on(sl.SERIES_ID.eq(s.ID)) - .where(s.LIBRARY_ID.eq(libraryId)) + .where(s.LIBRARY_ID.`in`(libraryIds)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } .orderBy(sl.LABEL.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) .fetchSet(sl.LABEL) diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReferentialController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReferentialController.kt index d3ceaef4..104ec681 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReferentialController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReferentialController.kt @@ -50,7 +50,7 @@ class ReferentialController( @AuthenticationPrincipal principal: KomgaPrincipal, @RequestParam(name = "search", required = false) search: String?, @RequestParam(name = "role", required = false) role: String?, - @RequestParam(name = "library_id", required = false) libraryId: String?, + @RequestParam(name = "library_id", required = false) libraryIds: Set = emptySet(), @RequestParam(name = "collection_id", required = false) collectionId: String?, @RequestParam(name = "series_id", required = false) seriesId: String?, @RequestParam(name = "readlist_id", required = false) readListId: String?, @@ -67,7 +67,7 @@ class ReferentialController( ) return when { - libraryId != null -> referentialRepository.findAllAuthorsByNameAndLibrary(search, role, libraryId, principal.user.getAuthorizedLibraryIds(null), pageRequest) + libraryIds.isNotEmpty() -> referentialRepository.findAllAuthorsByNameAndLibraries(search, role, libraryIds, principal.user.getAuthorizedLibraryIds(null), pageRequest) collectionId != null -> referentialRepository.findAllAuthorsByNameAndCollection(search, role, collectionId, principal.user.getAuthorizedLibraryIds(null), pageRequest) seriesId != null -> referentialRepository.findAllAuthorsByNameAndSeries(search, role, seriesId, principal.user.getAuthorizedLibraryIds(null), pageRequest) readListId != null -> referentialRepository.findAllAuthorsByNameAndReadList(search, role, readListId, principal.user.getAuthorizedLibraryIds(null), pageRequest) @@ -92,11 +92,11 @@ class ReferentialController( @Operation(summary = "List genres", description = "Can be filtered by various criteria") fun getGenres( @AuthenticationPrincipal principal: KomgaPrincipal, - @RequestParam(name = "library_id", required = false) libraryId: String?, + @RequestParam(name = "library_id", required = false) libraryIds: Set = emptySet(), @RequestParam(name = "collection_id", required = false) collectionId: String?, ): Set = when { - libraryId != null -> referentialRepository.findAllGenresByLibrary(libraryId, principal.user.getAuthorizedLibraryIds(null)) + libraryIds.isNotEmpty() -> referentialRepository.findAllGenresByLibraries(libraryIds, principal.user.getAuthorizedLibraryIds(null)) collectionId != null -> referentialRepository.findAllGenresByCollection(collectionId, principal.user.getAuthorizedLibraryIds(null)) else -> referentialRepository.findAllGenres(principal.user.getAuthorizedLibraryIds(null)) } @@ -105,11 +105,11 @@ class ReferentialController( @Operation(summary = "List sharing labels", description = "Can be filtered by various criteria") fun getSharingLabels( @AuthenticationPrincipal principal: KomgaPrincipal, - @RequestParam(name = "library_id", required = false) libraryId: String?, + @RequestParam(name = "library_id", required = false) libraryIds: Set = emptySet(), @RequestParam(name = "collection_id", required = false) collectionId: String?, ): Set = when { - libraryId != null -> referentialRepository.findAllSharingLabelsByLibrary(libraryId, principal.user.getAuthorizedLibraryIds(null)) + libraryIds.isNotEmpty() -> referentialRepository.findAllSharingLabelsByLibraries(libraryIds, principal.user.getAuthorizedLibraryIds(null)) collectionId != null -> referentialRepository.findAllSharingLabelsByCollection(collectionId, principal.user.getAuthorizedLibraryIds(null)) else -> referentialRepository.findAllSharingLabels(principal.user.getAuthorizedLibraryIds(null)) } @@ -118,11 +118,11 @@ class ReferentialController( @Operation(summary = "List tags", description = "Can be filtered by various criteria") fun getTags( @AuthenticationPrincipal principal: KomgaPrincipal, - @RequestParam(name = "library_id", required = false) libraryId: String?, + @RequestParam(name = "library_id", required = false) libraryIds: Set = emptySet(), @RequestParam(name = "collection_id", required = false) collectionId: String?, ): Set = when { - libraryId != null -> referentialRepository.findAllSeriesAndBookTagsByLibrary(libraryId, principal.user.getAuthorizedLibraryIds(null)) + libraryIds.isNotEmpty() -> referentialRepository.findAllSeriesAndBookTagsByLibraries(libraryIds, principal.user.getAuthorizedLibraryIds(null)) collectionId != null -> referentialRepository.findAllSeriesAndBookTagsByCollection(collectionId, principal.user.getAuthorizedLibraryIds(null)) else -> referentialRepository.findAllSeriesAndBookTags(principal.user.getAuthorizedLibraryIds(null)) } @@ -133,10 +133,12 @@ class ReferentialController( @AuthenticationPrincipal principal: KomgaPrincipal, @RequestParam(name = "series_id", required = false) seriesId: String?, @RequestParam(name = "readlist_id", required = false) readListId: String?, + @RequestParam(name = "library_id", required = false) libraryIds: Set = emptySet(), ): Set = when { seriesId != null -> referentialRepository.findAllBookTagsBySeries(seriesId, principal.user.getAuthorizedLibraryIds(null)) readListId != null -> referentialRepository.findAllBookTagsByReadList(readListId, principal.user.getAuthorizedLibraryIds(null)) + libraryIds.isNotEmpty() -> referentialRepository.findAllBookTags(principal.user.getAuthorizedLibraryIds(libraryIds)) else -> referentialRepository.findAllBookTags(principal.user.getAuthorizedLibraryIds(null)) } @@ -157,11 +159,11 @@ class ReferentialController( @Operation(summary = "List languages", description = "Can be filtered by various criteria") fun getLanguages( @AuthenticationPrincipal principal: KomgaPrincipal, - @RequestParam(name = "library_id", required = false) libraryId: String?, + @RequestParam(name = "library_id", required = false) libraryIds: Set = emptySet(), @RequestParam(name = "collection_id", required = false) collectionId: String?, ): Set = when { - libraryId != null -> referentialRepository.findAllLanguagesByLibrary(libraryId, principal.user.getAuthorizedLibraryIds(null)) + libraryIds.isNotEmpty() -> referentialRepository.findAllLanguagesByLibraries(libraryIds, principal.user.getAuthorizedLibraryIds(null)) collectionId != null -> referentialRepository.findAllLanguagesByCollection(collectionId, principal.user.getAuthorizedLibraryIds(null)) else -> referentialRepository.findAllLanguages(principal.user.getAuthorizedLibraryIds(null)) } @@ -170,11 +172,11 @@ class ReferentialController( @Operation(summary = "List publishers", description = "Can be filtered by various criteria") fun getPublishers( @AuthenticationPrincipal principal: KomgaPrincipal, - @RequestParam(name = "library_id", required = false) libraryId: String?, + @RequestParam(name = "library_id", required = false) libraryIds: Set = emptySet(), @RequestParam(name = "collection_id", required = false) collectionId: String?, ): Set = when { - libraryId != null -> referentialRepository.findAllPublishersByLibrary(libraryId, principal.user.getAuthorizedLibraryIds(null)) + libraryIds.isNotEmpty() -> referentialRepository.findAllPublishersByLibraries(libraryIds, principal.user.getAuthorizedLibraryIds(null)) collectionId != null -> referentialRepository.findAllPublishersByCollection(collectionId, principal.user.getAuthorizedLibraryIds(null)) else -> referentialRepository.findAllPublishers(principal.user.getAuthorizedLibraryIds(null)) } @@ -183,11 +185,11 @@ class ReferentialController( @Operation(summary = "List age ratings", description = "Can be filtered by various criteria") fun getAgeRatings( @AuthenticationPrincipal principal: KomgaPrincipal, - @RequestParam(name = "library_id", required = false) libraryId: String?, + @RequestParam(name = "library_id", required = false) libraryIds: Set = emptySet(), @RequestParam(name = "collection_id", required = false) collectionId: String?, ): Set = when { - libraryId != null -> referentialRepository.findAllAgeRatingsByLibrary(libraryId, principal.user.getAuthorizedLibraryIds(null)) + libraryIds.isNotEmpty() -> referentialRepository.findAllAgeRatingsByLibraries(libraryIds, principal.user.getAuthorizedLibraryIds(null)) collectionId != null -> referentialRepository.findAllAgeRatingsByCollection(collectionId, principal.user.getAuthorizedLibraryIds(null)) else -> referentialRepository.findAllAgeRatings(principal.user.getAuthorizedLibraryIds(null)) }.map { it?.toString() ?: "None" }.toSet() @@ -196,11 +198,11 @@ class ReferentialController( @Operation(summary = "List series release dates", description = "Can be filtered by various criteria") fun getSeriesReleaseDates( @AuthenticationPrincipal principal: KomgaPrincipal, - @RequestParam(name = "library_id", required = false) libraryId: String?, + @RequestParam(name = "library_id", required = false) libraryIds: Set = emptySet(), @RequestParam(name = "collection_id", required = false) collectionId: String?, ): Set = when { - libraryId != null -> referentialRepository.findAllSeriesReleaseDatesByLibrary(libraryId, principal.user.getAuthorizedLibraryIds(null)) + libraryIds.isNotEmpty() -> referentialRepository.findAllSeriesReleaseDatesByLibraries(libraryIds, principal.user.getAuthorizedLibraryIds(null)) collectionId != null -> referentialRepository.findAllSeriesReleaseDatesByCollection(collectionId, principal.user.getAuthorizedLibraryIds(null)) else -> referentialRepository.findAllSeriesReleaseDates(principal.user.getAuthorizedLibraryIds(null)) }.map { it.year.toString() }.toSet()