feat(api): count series by first letter

This commit is contained in:
Gauthier Roebroeck 2021-07-21 11:06:25 +08:00
parent 1fe55809a1
commit 199c6190a3
4 changed files with 86 additions and 0 deletions

View file

@ -6,6 +6,7 @@ import org.gotson.komga.domain.model.SeriesSearchWithReadProgress
import org.gotson.komga.infrastructure.web.toFilePath import org.gotson.komga.infrastructure.web.toFilePath
import org.gotson.komga.interfaces.rest.dto.AuthorDto import org.gotson.komga.interfaces.rest.dto.AuthorDto
import org.gotson.komga.interfaces.rest.dto.BookMetadataAggregationDto import org.gotson.komga.interfaces.rest.dto.BookMetadataAggregationDto
import org.gotson.komga.interfaces.rest.dto.GroupCountDto
import org.gotson.komga.interfaces.rest.dto.SeriesDto import org.gotson.komga.interfaces.rest.dto.SeriesDto
import org.gotson.komga.interfaces.rest.dto.SeriesMetadataDto import org.gotson.komga.interfaces.rest.dto.SeriesMetadataDto
import org.gotson.komga.interfaces.rest.persistence.SeriesDtoRepository import org.gotson.komga.interfaces.rest.persistence.SeriesDtoRepository
@ -20,7 +21,9 @@ import org.jooq.Record
import org.jooq.ResultQuery import org.jooq.ResultQuery
import org.jooq.SelectOnConditionStep import org.jooq.SelectOnConditionStep
import org.jooq.impl.DSL import org.jooq.impl.DSL
import org.jooq.impl.DSL.count
import org.jooq.impl.DSL.lower import org.jooq.impl.DSL.lower
import org.jooq.impl.DSL.substring
import org.springframework.data.domain.Page import org.springframework.data.domain.Page
import org.springframework.data.domain.PageImpl import org.springframework.data.domain.PageImpl
import org.springframework.data.domain.PageRequest import org.springframework.data.domain.PageRequest
@ -103,6 +106,27 @@ class SeriesDtoDao(
return findAll(conditions, userId, pageable, search.toJoinConditions()) return findAll(conditions, userId, pageable, search.toJoinConditions())
} }
override fun countByFirstCharacter(search: SeriesSearchWithReadProgress, userId: String): List<GroupCountDto> {
val conditions = search.toCondition()
val joinConditions = search.toJoinConditions()
val firstChar = lower(substring(d.TITLE_SORT, 1, 1))
return dsl.select(firstChar, count())
.from(s)
.leftJoin(d).on(s.ID.eq(d.SERIES_ID))
.leftJoin(bma).on(s.ID.eq(bma.SERIES_ID))
.leftJoin(rs).on(s.ID.eq(rs.SERIES_ID)).and(readProgressConditionSeries(userId))
.apply { if (joinConditions.genre) leftJoin(g).on(s.ID.eq(g.SERIES_ID)) }
.apply { if (joinConditions.tag) leftJoin(st).on(s.ID.eq(st.SERIES_ID)) }
.apply { if (joinConditions.collection) leftJoin(cs).on(s.ID.eq(cs.SERIES_ID)) }
.apply { if (joinConditions.aggregationAuthor) leftJoin(bmaa).on(s.ID.eq(bmaa.SERIES_ID)) }
.where(conditions)
.groupBy(firstChar)
.map {
GroupCountDto(it.value1(), it.value2())
}
}
override fun findByIdOrNull(seriesId: String, userId: String): SeriesDto? = override fun findByIdOrNull(seriesId: String, userId: String): SeriesDto? =
selectBase(userId) selectBase(userId)
.where(s.ID.eq(seriesId)) .where(s.ID.eq(seriesId))

View file

@ -39,6 +39,7 @@ import org.gotson.komga.infrastructure.web.Authors
import org.gotson.komga.infrastructure.web.DelimitedPair import org.gotson.komga.infrastructure.web.DelimitedPair
import org.gotson.komga.interfaces.rest.dto.BookDto import org.gotson.komga.interfaces.rest.dto.BookDto
import org.gotson.komga.interfaces.rest.dto.CollectionDto import org.gotson.komga.interfaces.rest.dto.CollectionDto
import org.gotson.komga.interfaces.rest.dto.GroupCountDto
import org.gotson.komga.interfaces.rest.dto.SeriesDto import org.gotson.komga.interfaces.rest.dto.SeriesDto
import org.gotson.komga.interfaces.rest.dto.SeriesMetadataUpdateDto import org.gotson.komga.interfaces.rest.dto.SeriesMetadataUpdateDto
import org.gotson.komga.interfaces.rest.dto.TachiyomiReadProgressDto import org.gotson.komga.interfaces.rest.dto.TachiyomiReadProgressDto
@ -162,6 +163,58 @@ class SeriesController(
.map { it.restrictUrl(!principal.user.roleAdmin) } .map { it.restrictUrl(!principal.user.roleAdmin) }
} }
@AuthorsAsQueryParam
@Parameters(
Parameter(
description = "Search by regex criteria, in the form: regex,field. Supported fields are TITLE and TITLE_SORT.",
`in` = ParameterIn.QUERY, name = "search_regex", schema = Schema(type = "string")
)
)
@GetMapping("alphabetical-groups")
fun getAlphabeticalGroups(
@AuthenticationPrincipal principal: KomgaPrincipal,
@RequestParam(name = "search", required = false) searchTerm: String?,
@Parameter(hidden = true) @DelimitedPair("search_regex") searchRegex: Pair<String, String>?,
@RequestParam(name = "library_id", required = false) libraryIds: List<String>?,
@RequestParam(name = "collection_id", required = false) collectionIds: List<String>?,
@RequestParam(name = "status", required = false) metadataStatus: List<SeriesMetadata.Status>?,
@RequestParam(name = "read_status", required = false) readStatus: List<ReadStatus>?,
@RequestParam(name = "publisher", required = false) publishers: List<String>?,
@RequestParam(name = "language", required = false) languages: List<String>?,
@RequestParam(name = "genre", required = false) genres: List<String>?,
@RequestParam(name = "tag", required = false) tags: List<String>?,
@RequestParam(name = "age_rating", required = false) ageRatings: List<String>?,
@RequestParam(name = "release_year", required = false) release_years: List<String>?,
@RequestParam(name = "deleted", required = false) deleted: Boolean?,
@Parameter(hidden = true) @Authors authors: List<Author>?,
@Parameter(hidden = true) page: Pageable
): List<GroupCountDto> {
val seriesSearch = SeriesSearchWithReadProgress(
libraryIds = principal.user.getAuthorizedLibraryIds(libraryIds),
collectionIds = collectionIds,
searchTerm = searchTerm,
searchRegex = searchRegex?.let {
when (it.second.lowercase()) {
"title" -> Pair(it.first, SeriesSearch.SearchField.TITLE)
"title_sort" -> Pair(it.first, SeriesSearch.SearchField.TITLE_SORT)
else -> null
}
},
metadataStatus = metadataStatus,
readStatus = readStatus,
publishers = publishers,
deleted = deleted,
languages = languages,
genres = genres,
tags = tags,
ageRatings = ageRatings?.map { it.toIntOrNull() },
releaseYears = release_years,
authors = authors
)
return seriesDtoRepository.countByFirstCharacter(seriesSearch, principal.user.id)
}
@Operation(description = "Return recently added or updated series.") @Operation(description = "Return recently added or updated series.")
@PageableWithoutSortAsQueryParam @PageableWithoutSortAsQueryParam
@GetMapping("/latest") @GetMapping("/latest")

View file

@ -0,0 +1,6 @@
package org.gotson.komga.interfaces.rest.dto
data class GroupCountDto(
val group: String,
val count: Int,
)

View file

@ -1,6 +1,7 @@
package org.gotson.komga.interfaces.rest.persistence package org.gotson.komga.interfaces.rest.persistence
import org.gotson.komga.domain.model.SeriesSearchWithReadProgress import org.gotson.komga.domain.model.SeriesSearchWithReadProgress
import org.gotson.komga.interfaces.rest.dto.GroupCountDto
import org.gotson.komga.interfaces.rest.dto.SeriesDto import org.gotson.komga.interfaces.rest.dto.SeriesDto
import org.springframework.data.domain.Page import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable import org.springframework.data.domain.Pageable
@ -11,4 +12,6 @@ interface SeriesDtoRepository {
fun findAll(search: SeriesSearchWithReadProgress, userId: String, pageable: Pageable): Page<SeriesDto> fun findAll(search: SeriesSearchWithReadProgress, userId: String, pageable: Pageable): Page<SeriesDto>
fun findAllByCollectionId(collectionId: String, search: SeriesSearchWithReadProgress, userId: String, pageable: Pageable): Page<SeriesDto> fun findAllByCollectionId(collectionId: String, search: SeriesSearchWithReadProgress, userId: String, pageable: Pageable): Page<SeriesDto>
fun findAllRecentlyUpdated(search: SeriesSearchWithReadProgress, userId: String, pageable: Pageable): Page<SeriesDto> fun findAllRecentlyUpdated(search: SeriesSearchWithReadProgress, userId: String, pageable: Pageable): Page<SeriesDto>
fun countByFirstCharacter(search: SeriesSearchWithReadProgress, userId: String): List<GroupCountDto>
} }