mirror of
https://github.com/gotson/komga.git
synced 2026-05-08 12:35:30 +02:00
fix(api): prevent SQLITE_TOOBIG book search returns many matches
Closes: #940
This commit is contained in:
parent
a3929e2e1f
commit
f8cc3cd4ca
1 changed files with 48 additions and 24 deletions
|
|
@ -25,6 +25,7 @@ import org.jooq.DSLContext
|
||||||
import org.jooq.Record
|
import org.jooq.Record
|
||||||
import org.jooq.ResultQuery
|
import org.jooq.ResultQuery
|
||||||
import org.jooq.impl.DSL
|
import org.jooq.impl.DSL
|
||||||
|
import org.jooq.impl.DSL.falseCondition
|
||||||
import org.jooq.impl.DSL.inline
|
import org.jooq.impl.DSL.inline
|
||||||
import org.jooq.impl.DSL.noCondition
|
import org.jooq.impl.DSL.noCondition
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
|
|
@ -109,7 +110,30 @@ class BookDtoDao(
|
||||||
searchTerm: String?,
|
searchTerm: String?,
|
||||||
): Page<BookDto> {
|
): Page<BookDto> {
|
||||||
val bookIds = luceneHelper.searchEntitiesIds(searchTerm, LuceneEntity.Book)
|
val bookIds = luceneHelper.searchEntitiesIds(searchTerm, LuceneEntity.Book)
|
||||||
val searchCondition = b.ID.inOrNoCondition(bookIds)
|
|
||||||
|
val searchCondition = when {
|
||||||
|
bookIds == null -> noCondition()
|
||||||
|
bookIds.isEmpty() -> falseCondition()
|
||||||
|
// use temp table in case there are many search results
|
||||||
|
else -> b.ID.`in`(dsl.selectTempStrings())
|
||||||
|
}
|
||||||
|
|
||||||
|
// we can handle paging from the search results directly to reduce the sql query complexity
|
||||||
|
val (bookIdsPaged, pagingBySearch) = when {
|
||||||
|
bookIds.isNullOrEmpty() -> emptyList<String>() to false
|
||||||
|
pageable.isPaged -> bookIds.drop(pageable.pageSize * pageable.pageNumber).take(pageable.pageSize) to true
|
||||||
|
else -> bookIds to false
|
||||||
|
}
|
||||||
|
|
||||||
|
val orderBy =
|
||||||
|
pageable.sort.mapNotNull {
|
||||||
|
if (it.property == "relevance" && !bookIds.isNullOrEmpty()) b.ID.sortByValues(bookIdsPaged, it.isAscending)
|
||||||
|
else it.toSortField(sorts)
|
||||||
|
}
|
||||||
|
|
||||||
|
val (count, dtos) = transactionTemplate.execute {
|
||||||
|
// only insert if we know we are going to select on that condition
|
||||||
|
if (!bookIds.isNullOrEmpty()) dsl.insertTempStrings(batchSize, bookIds)
|
||||||
|
|
||||||
val count = dsl.fetchCount(
|
val count = dsl.fetchCount(
|
||||||
dsl.select(b.ID)
|
dsl.select(b.ID)
|
||||||
|
|
@ -127,20 +151,20 @@ class BookDtoDao(
|
||||||
.groupBy(b.ID),
|
.groupBy(b.ID),
|
||||||
)
|
)
|
||||||
|
|
||||||
val orderBy =
|
// adjust temp table if we are paging by search results
|
||||||
pageable.sort.mapNotNull {
|
if (pagingBySearch) dsl.insertTempStrings(batchSize, bookIdsPaged)
|
||||||
if (it.property == "relevance" && !bookIds.isNullOrEmpty()) b.ID.sortByValues(bookIds, it.isAscending)
|
|
||||||
else it.toSortField(sorts)
|
|
||||||
}
|
|
||||||
|
|
||||||
val dtos = selectBase(userId, joinConditions)
|
val dtos = selectBase(userId, joinConditions)
|
||||||
.where(conditions)
|
.where(conditions)
|
||||||
.and(searchCondition)
|
.and(searchCondition)
|
||||||
.apply { filterOnLibraryIds?.let { and(b.LIBRARY_ID.`in`(it)) } }
|
.apply { filterOnLibraryIds?.let { and(b.LIBRARY_ID.`in`(it)) } }
|
||||||
.orderBy(orderBy)
|
.orderBy(orderBy)
|
||||||
.apply { if (pageable.isPaged) limit(pageable.pageSize).offset(pageable.offset) }
|
.apply { if (!pagingBySearch && pageable.isPaged) limit(pageable.pageSize).offset(pageable.offset) }
|
||||||
.fetchAndMap()
|
.fetchAndMap()
|
||||||
|
|
||||||
|
count to dtos
|
||||||
|
}!!
|
||||||
|
|
||||||
val pageSort = if (orderBy.isNotEmpty()) pageable.sort else Sort.unsorted()
|
val pageSort = if (orderBy.isNotEmpty()) pageable.sort else Sort.unsorted()
|
||||||
return PageImpl(
|
return PageImpl(
|
||||||
dtos,
|
dtos,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue