refactor: use JPA joins instead of subqueries

This commit is contained in:
Gauthier Roebroeck 2020-01-16 18:17:51 +08:00
parent 07905018e5
commit 759d60f468
3 changed files with 16 additions and 15 deletions

View file

@ -19,9 +19,6 @@ interface SeriesRepository : JpaRepository<Series, Long>, JpaSpecificationExecut
@QueryHints(QueryHint(name = CACHEABLE, value = "true"))
override fun findAll(pageable: Pageable): Page<Series>
@QueryHints(QueryHint(name = CACHEABLE, value = "true"))
fun findByLibraryIn(libraries: Collection<Library>): List<Series>
@QueryHints(QueryHint(name = CACHEABLE, value = "true"))
fun findByLibraryIn(libraries: Collection<Library>, sort: Sort): List<Series>
@ -31,9 +28,6 @@ interface SeriesRepository : JpaRepository<Series, Long>, JpaSpecificationExecut
@QueryHints(QueryHint(name = CACHEABLE, value = "true"))
fun findByLibraryId(libraryId: Long, sort: Sort): List<Series>
@QueryHints(QueryHint(name = CACHEABLE, value = "true"))
fun findByLibraryIdIn(libraryIDs: Collection<Long>): List<Series>
@Query("select s from Series s where s.createdDate <> s.lastModifiedDate")
@QueryHints(QueryHint(name = CACHEABLE, value = "true"))
fun findRecentlyUpdated(pageable: Pageable): Page<Series>

View file

@ -8,10 +8,11 @@ import org.gotson.komga.application.service.AsyncOrchestrator
import org.gotson.komga.application.service.BookLifecycle
import org.gotson.komga.domain.model.Book
import org.gotson.komga.domain.model.ImageConversionException
import org.gotson.komga.domain.model.Library
import org.gotson.komga.domain.model.Media
import org.gotson.komga.domain.model.MediaNotReadyException
import org.gotson.komga.domain.model.Series
import org.gotson.komga.domain.persistence.BookRepository
import org.gotson.komga.domain.persistence.SeriesRepository
import org.gotson.komga.infrastructure.image.ImageType
import org.gotson.komga.infrastructure.security.KomgaPrincipal
import org.gotson.komga.interfaces.rest.dto.BookDto
@ -46,13 +47,13 @@ import java.nio.file.NoSuchFileException
import java.time.ZoneOffset
import java.util.concurrent.RejectedExecutionException
import java.util.concurrent.TimeUnit
import javax.persistence.criteria.JoinType
private val logger = KotlinLogging.logger {}
@RestController
@RequestMapping(produces = [MediaType.APPLICATION_JSON_VALUE])
class BookController(
private val seriesRepository: SeriesRepository,
private val bookRepository: BookRepository,
private val bookLifecycle: BookLifecycle,
private val asyncOrchestrator: AsyncOrchestrator
@ -75,16 +76,19 @@ class BookController(
return mutableListOf<Specification<Book>>().let { specs ->
when {
// limited user & libraryIds are specified: filter on provided libraries intersecting user's authorized libraries
!principal.user.sharedAllLibraries && !libraryIds.isNullOrEmpty() -> {
val authorizedLibraryIDs = libraryIds.intersect(principal.user.sharedLibraries.map { it.id })
if (authorizedLibraryIDs.isEmpty()) return@let Page.empty<Book>(pageRequest)
else specs.add(Book::series.`in`(seriesRepository.findByLibraryIdIn(authorizedLibraryIDs)))
else specs.add(Book::series.toJoin().join(Series::library, JoinType.INNER).where(Library::id).`in`(authorizedLibraryIDs))
}
!principal.user.sharedAllLibraries -> specs.add(Book::series.`in`(seriesRepository.findByLibraryIn(principal.user.sharedLibraries)))
// limited user: filter on user's authorized libraries
!principal.user.sharedAllLibraries -> specs.add(Book::series.toJoin().where(Series::library).`in`(principal.user.sharedLibraries))
// non-limited user: filter on provided libraries
!libraryIds.isNullOrEmpty() -> {
specs.add(Book::series.`in`(seriesRepository.findByLibraryIdIn(libraryIds)))
specs.add(Book::series.toJoin().join(Series::library, JoinType.INNER).where(Library::id).`in`(libraryIds))
}
}

View file

@ -2,12 +2,13 @@ package org.gotson.komga.interfaces.rest
import com.github.klinq.jpaspec.`in`
import com.github.klinq.jpaspec.likeLower
import com.github.klinq.jpaspec.toJoin
import mu.KotlinLogging
import org.gotson.komga.application.service.AsyncOrchestrator
import org.gotson.komga.domain.model.Library
import org.gotson.komga.domain.model.Media
import org.gotson.komga.domain.model.Series
import org.gotson.komga.domain.persistence.BookRepository
import org.gotson.komga.domain.persistence.LibraryRepository
import org.gotson.komga.domain.persistence.SeriesRepository
import org.gotson.komga.infrastructure.security.KomgaPrincipal
import org.gotson.komga.interfaces.rest.dto.BookDto
@ -41,7 +42,6 @@ private val logger = KotlinLogging.logger {}
@RequestMapping("api/v1/series", produces = [MediaType.APPLICATION_JSON_VALUE])
class SeriesController(
private val seriesRepository: SeriesRepository,
private val libraryRepository: LibraryRepository,
private val bookRepository: BookRepository,
private val bookController: BookController,
private val asyncOrchestrator: AsyncOrchestrator
@ -63,16 +63,19 @@ class SeriesController(
return mutableListOf<Specification<Series>>().let { specs ->
when {
// limited user & libraryIds are specified: filter on provided libraries intersecting user's authorized libraries
!principal.user.sharedAllLibraries && !libraryIds.isNullOrEmpty() -> {
val authorizedLibraryIDs = libraryIds.intersect(principal.user.sharedLibraries.map { it.id })
if (authorizedLibraryIDs.isEmpty()) return@let Page.empty<Series>(pageRequest)
else specs.add(Series::library.`in`(libraryRepository.findAllById(authorizedLibraryIDs)))
else specs.add(Series::library.toJoin().where(Library::id).`in`(authorizedLibraryIDs))
}
// limited user: filter on user's authorized libraries
!principal.user.sharedAllLibraries -> specs.add(Series::library.`in`(principal.user.sharedLibraries))
// non-limited user: filter on provided libraries
!libraryIds.isNullOrEmpty() -> {
specs.add(Series::library.`in`(libraryRepository.findAllById(libraryIds)))
specs.add(Series::library.toJoin().where(Library::id).`in`(libraryIds))
}
}