mirror of
https://github.com/gotson/komga.git
synced 2025-12-26 10:24:04 +01:00
parent
ffc397f119
commit
70bcb8f417
4 changed files with 173 additions and 0 deletions
|
|
@ -162,4 +162,21 @@ class SearchCondition {
|
|||
val name: String? = null,
|
||||
val role: String? = null,
|
||||
)
|
||||
|
||||
data class Poster(
|
||||
@JsonProperty("poster")
|
||||
val operator: SearchOperator.Equality<PosterMatch>,
|
||||
) : Book
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
data class PosterMatch(
|
||||
val type: Type? = null,
|
||||
val selected: Boolean? = null,
|
||||
) {
|
||||
enum class Type {
|
||||
GENERATED,
|
||||
SIDECAR,
|
||||
USER_UPLOADED,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ class BookSearchHelper(
|
|||
rlbAlias(searchCondition.operator.value)
|
||||
.READLIST_ID
|
||||
.eq(searchCondition.operator.value) to setOf(RequiredJoin.ReadList(searchCondition.operator.value))
|
||||
|
||||
is SearchOperator.IsNot -> {
|
||||
val inner = { readListId: String ->
|
||||
DSL
|
||||
|
|
@ -198,6 +199,38 @@ class BookSearchHelper(
|
|||
} to emptySet()
|
||||
}
|
||||
|
||||
is SearchCondition.Poster ->
|
||||
Tables.BOOK.ID.let { field ->
|
||||
val inner = { type: SearchCondition.PosterMatch.Type?, selected: Boolean? ->
|
||||
DSL
|
||||
.select(Tables.THUMBNAIL_BOOK.BOOK_ID)
|
||||
.from(Tables.THUMBNAIL_BOOK)
|
||||
.where(DSL.noCondition())
|
||||
.apply {
|
||||
if (type != null)
|
||||
and(Tables.THUMBNAIL_BOOK.TYPE.equalIgnoreCase(type.name))
|
||||
if (selected != null && selected)
|
||||
and(Tables.THUMBNAIL_BOOK.SELECTED.isTrue)
|
||||
if (selected != null && !selected)
|
||||
and(Tables.THUMBNAIL_BOOK.SELECTED.isFalse)
|
||||
}
|
||||
}
|
||||
when (searchCondition.operator) {
|
||||
is SearchOperator.Is -> {
|
||||
if (searchCondition.operator.value.type == null && searchCondition.operator.value.selected == null)
|
||||
DSL.noCondition()
|
||||
else
|
||||
field.`in`(inner(searchCondition.operator.value.type, searchCondition.operator.value.selected))
|
||||
}
|
||||
|
||||
is SearchOperator.IsNot ->
|
||||
if (searchCondition.operator.value.type == null && searchCondition.operator.value.selected == null)
|
||||
DSL.noCondition()
|
||||
else
|
||||
field.notIn(inner(searchCondition.operator.value.type, searchCondition.operator.value.selected))
|
||||
} to emptySet()
|
||||
}
|
||||
|
||||
is SearchCondition.OneShot -> searchCondition.operator.toCondition(Tables.BOOK.ONESHOT) to emptySet()
|
||||
|
||||
null -> DSL.noCondition() to emptySet()
|
||||
|
|
|
|||
|
|
@ -63,6 +63,10 @@ class BookSearchTest(
|
|||
SearchCondition.Author(SearchOperator.IsNot(AuthorMatch())),
|
||||
SearchCondition.OneShot(SearchOperator.IsFalse),
|
||||
SearchCondition.OneShot(SearchOperator.IsTrue),
|
||||
SearchCondition.Poster(SearchOperator.Is(SearchCondition.PosterMatch(type = SearchCondition.PosterMatch.Type.GENERATED, selected = false))),
|
||||
SearchCondition.Poster(SearchOperator.Is(SearchCondition.PosterMatch(selected = true))),
|
||||
SearchCondition.Poster(SearchOperator.IsNot(SearchCondition.PosterMatch(type = SearchCondition.PosterMatch.Type.SIDECAR))),
|
||||
SearchCondition.Poster(SearchOperator.IsNot(SearchCondition.PosterMatch())),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ import org.assertj.core.api.Assertions.assertThat
|
|||
import org.assertj.core.api.Assertions.catchThrowable
|
||||
import org.gotson.komga.domain.model.Author
|
||||
import org.gotson.komga.domain.model.BookSearch
|
||||
import org.gotson.komga.domain.model.Dimension
|
||||
import org.gotson.komga.domain.model.KomgaUser
|
||||
import org.gotson.komga.domain.model.MarkSelectedPreference
|
||||
import org.gotson.komga.domain.model.Media
|
||||
import org.gotson.komga.domain.model.MediaProfile
|
||||
import org.gotson.komga.domain.model.MediaType
|
||||
|
|
@ -19,6 +21,7 @@ import org.gotson.komga.domain.model.SearchCondition
|
|||
import org.gotson.komga.domain.model.SearchCondition.AuthorMatch
|
||||
import org.gotson.komga.domain.model.SearchContext
|
||||
import org.gotson.komga.domain.model.SearchOperator
|
||||
import org.gotson.komga.domain.model.ThumbnailBook
|
||||
import org.gotson.komga.domain.model.makeBook
|
||||
import org.gotson.komga.domain.model.makeLibrary
|
||||
import org.gotson.komga.domain.model.makeSeries
|
||||
|
|
@ -970,4 +973,120 @@ class BookSearchTest(
|
|||
assertThat(foundDto.map { it.name }).containsExactlyInAnyOrder("2")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given some books when searching by poster then results are accurate`() {
|
||||
// book with GENERATED selected
|
||||
makeBook("1", libraryId = library1.id, seriesId = series1.id).let { book ->
|
||||
seriesLifecycle.addBooks(series1, listOf(book))
|
||||
bookLifecycle.addThumbnailForBook(ThumbnailBook(bookId = book.id, type = ThumbnailBook.Type.GENERATED, mediaType = "image/jpeg", fileSize = 0L, dimension = Dimension(0, 0)), MarkSelectedPreference.YES)
|
||||
}
|
||||
// book with GENERATED not selected, SIDECAR selected
|
||||
makeBook("2", libraryId = library2.id, seriesId = series2.id).let { book ->
|
||||
seriesLifecycle.addBooks(series2, listOf(book))
|
||||
bookLifecycle.addThumbnailForBook(ThumbnailBook(bookId = book.id, type = ThumbnailBook.Type.GENERATED, mediaType = "image/jpeg", fileSize = 0L, dimension = Dimension(0, 0)), MarkSelectedPreference.YES)
|
||||
bookLifecycle.addThumbnailForBook(ThumbnailBook(bookId = book.id, type = ThumbnailBook.Type.SIDECAR, mediaType = "image/jpeg", fileSize = 0L, dimension = Dimension(0, 0)), MarkSelectedPreference.YES)
|
||||
}
|
||||
// book with GENERATED not selected, USER_UPLOADED selected
|
||||
makeBook("3", libraryId = library2.id, seriesId = series2.id).let { book ->
|
||||
seriesLifecycle.addBooks(series2, listOf(book))
|
||||
bookLifecycle.addThumbnailForBook(ThumbnailBook(bookId = book.id, type = ThumbnailBook.Type.GENERATED, mediaType = "image/jpeg", fileSize = 0L, dimension = Dimension(0, 0)), MarkSelectedPreference.YES)
|
||||
bookLifecycle.addThumbnailForBook(ThumbnailBook(bookId = book.id, type = ThumbnailBook.Type.USER_UPLOADED, mediaType = "image/jpeg", fileSize = 0L, dimension = Dimension(0, 0)), MarkSelectedPreference.YES)
|
||||
}
|
||||
// book without poster
|
||||
makeBook("4", libraryId = library2.id, seriesId = series2.id).let { book ->
|
||||
seriesLifecycle.addBooks(series2, listOf(book))
|
||||
}
|
||||
|
||||
// books with a poster of type GENERATED
|
||||
run {
|
||||
val search =
|
||||
BookSearch(
|
||||
SearchCondition.Poster(SearchOperator.Is(SearchCondition.PosterMatch(SearchCondition.PosterMatch.Type.GENERATED))),
|
||||
)
|
||||
val found = bookDao.findAll(search.condition, SearchContext(user1), Pageable.unpaged()).content
|
||||
val foundDto = bookDtoDao.findAll(search, SearchContext(user1), Pageable.unpaged()).content
|
||||
|
||||
assertThat(found.map { it.name }).containsExactlyInAnyOrder("1", "2", "3")
|
||||
assertThat(foundDto.map { it.name }).containsExactlyInAnyOrder("1", "2", "3")
|
||||
}
|
||||
|
||||
// books with a poster of type GENERATED, selected
|
||||
run {
|
||||
val search =
|
||||
BookSearch(
|
||||
SearchCondition.Poster(SearchOperator.Is(SearchCondition.PosterMatch(SearchCondition.PosterMatch.Type.GENERATED, true))),
|
||||
)
|
||||
val found = bookDao.findAll(search.condition, SearchContext(user1), Pageable.unpaged()).content
|
||||
val foundDto = bookDtoDao.findAll(search, SearchContext(user1), Pageable.unpaged()).content
|
||||
|
||||
assertThat(found.map { it.name }).containsExactlyInAnyOrder("1")
|
||||
assertThat(foundDto.map { it.name }).containsExactlyInAnyOrder("1")
|
||||
}
|
||||
|
||||
// books with any poster not selected
|
||||
run {
|
||||
val search =
|
||||
BookSearch(
|
||||
SearchCondition.Poster(SearchOperator.Is(SearchCondition.PosterMatch(selected = false))),
|
||||
)
|
||||
val found = bookDao.findAll(search.condition, SearchContext(user1), Pageable.unpaged()).content
|
||||
val foundDto = bookDtoDao.findAll(search, SearchContext(user1), Pageable.unpaged()).content
|
||||
|
||||
assertThat(found.map { it.name }).containsExactlyInAnyOrder("2", "3")
|
||||
assertThat(foundDto.map { it.name }).containsExactlyInAnyOrder("2", "3")
|
||||
}
|
||||
|
||||
// books without a poster of type SIDECAR
|
||||
run {
|
||||
val search =
|
||||
BookSearch(
|
||||
SearchCondition.Poster(SearchOperator.IsNot(SearchCondition.PosterMatch(SearchCondition.PosterMatch.Type.SIDECAR))),
|
||||
)
|
||||
val found = bookDao.findAll(search.condition, SearchContext(user1), Pageable.unpaged()).content
|
||||
val foundDto = bookDtoDao.findAll(search, SearchContext(user1), Pageable.unpaged()).content
|
||||
|
||||
assertThat(found.map { it.name }).containsExactlyInAnyOrder("1", "3", "4")
|
||||
assertThat(foundDto.map { it.name }).containsExactlyInAnyOrder("1", "3", "4")
|
||||
}
|
||||
|
||||
// books without a poster of type GENERATED
|
||||
run {
|
||||
val search =
|
||||
BookSearch(
|
||||
SearchCondition.Poster(SearchOperator.IsNot(SearchCondition.PosterMatch(SearchCondition.PosterMatch.Type.GENERATED))),
|
||||
)
|
||||
val found = bookDao.findAll(search.condition, SearchContext(user1), Pageable.unpaged()).content
|
||||
val foundDto = bookDtoDao.findAll(search, SearchContext(user1), Pageable.unpaged()).content
|
||||
|
||||
assertThat(found.map { it.name }).containsExactlyInAnyOrder("4")
|
||||
assertThat(foundDto.map { it.name }).containsExactlyInAnyOrder("4")
|
||||
}
|
||||
|
||||
// books without selected poster
|
||||
run {
|
||||
val search =
|
||||
BookSearch(
|
||||
SearchCondition.Poster(SearchOperator.IsNot(SearchCondition.PosterMatch(selected = true))),
|
||||
)
|
||||
val found = bookDao.findAll(search.condition, SearchContext(user1), Pageable.unpaged()).content
|
||||
val foundDto = bookDtoDao.findAll(search, SearchContext(user1), Pageable.unpaged()).content
|
||||
|
||||
assertThat(found.map { it.name }).containsExactlyInAnyOrder("4")
|
||||
assertThat(foundDto.map { it.name }).containsExactlyInAnyOrder("4")
|
||||
}
|
||||
|
||||
// empty PosterMatch does not apply any condition
|
||||
run {
|
||||
val search =
|
||||
BookSearch(
|
||||
SearchCondition.Poster(SearchOperator.Is(SearchCondition.PosterMatch())),
|
||||
)
|
||||
val found = bookDao.findAll(search.condition, SearchContext(user1), Pageable.unpaged()).content
|
||||
val foundDto = bookDtoDao.findAll(search, SearchContext(user1), Pageable.unpaged()).content
|
||||
|
||||
assertThat(found.map { it.name }).containsExactlyInAnyOrder("1", "2", "3", "4")
|
||||
assertThat(foundDto.map { it.name }).containsExactlyInAnyOrder("1", "2", "3", "4")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue