add pagination to recentChapters (#246)

* add pagination to recentChapters

* Use kotlin native library

Co-authored-by: Mitchell Syer <Mitchellptbo@gmail.com>

Co-authored-by: Mitchell Syer <Mitchellptbo@gmail.com>
This commit is contained in:
Aria Moradi
2021-11-08 18:45:52 +03:30
committed by GitHub
parent 420d14fc37
commit 30f7cdc1ba
5 changed files with 164 additions and 13 deletions

View File

@@ -112,7 +112,7 @@ object MangaAPI {
}
path("update") {
get("recentChapters", UpdateController::recentChapters)
get("recentChapters/{pageNum}", UpdateController::recentChapters)
}
}
}

View File

@@ -14,9 +14,11 @@ import suwayomi.tachidesk.server.JavalinSetup.future
object UpdateController {
/** get recently updated manga chapters */
fun recentChapters(ctx: Context) {
val pageNum = ctx.pathParam("pageNum").toInt()
ctx.future(
future {
Chapter.getRecentChapters()
Chapter.getRecentChapters(pageNum)
}
)
}

View File

@@ -27,6 +27,8 @@ import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogue
import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse
import suwayomi.tachidesk.manga.model.dataclass.ChapterDataClass
import suwayomi.tachidesk.manga.model.dataclass.MangaChapterDataClass
import suwayomi.tachidesk.manga.model.dataclass.PaginatedList
import suwayomi.tachidesk.manga.model.dataclass.paginatedFrom
import suwayomi.tachidesk.manga.model.table.ChapterMetaTable
import suwayomi.tachidesk.manga.model.table.ChapterTable
import suwayomi.tachidesk.manga.model.table.MangaTable
@@ -321,17 +323,19 @@ object Chapter {
}
}
fun getRecentChapters(): List<MangaChapterDataClass> {
return transaction {
(ChapterTable innerJoin MangaTable)
.select { (MangaTable.inLibrary eq true) and (ChapterTable.fetchedAt greater MangaTable.inLibraryAt) }
.orderBy(ChapterTable.fetchedAt to SortOrder.DESC)
.map {
MangaChapterDataClass(
MangaTable.toDataClass(it),
ChapterTable.toDataClass(it)
)
}
fun getRecentChapters(pageNum: Int): PaginatedList<MangaChapterDataClass> {
return paginatedFrom(pageNum) {
transaction {
(ChapterTable innerJoin MangaTable)
.select { (MangaTable.inLibrary eq true) and (ChapterTable.fetchedAt greater MangaTable.inLibraryAt) }
.orderBy(ChapterTable.fetchedAt to SortOrder.DESC)
.map {
MangaChapterDataClass(
MangaTable.toDataClass(it),
ChapterTable.toDataClass(it)
)
}
}
}
}
}

View File

@@ -0,0 +1,40 @@
package suwayomi.tachidesk.manga.model.dataclass
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import kotlin.math.min
data class PaginatedList<T>(
val page: List<T>,
val hasNextPage: Boolean,
)
const val PaginationFactor = 50
fun <T> paginatedFrom(
pageNum: Int,
paginationFactor: Int = PaginationFactor,
lister: () -> List<T>
): PaginatedList<T> {
val list = lister()
val lastIndex = list.size - 1
val lowerIndex = pageNum * paginationFactor
val higherIndex = (pageNum + 1) * paginationFactor - 1
if (lowerIndex > lastIndex) {
return PaginatedList(emptyList(), false)
}
val sliced = list.slice(lowerIndex..min(lastIndex, higherIndex))
return PaginatedList(
sliced,
higherIndex < lastIndex
)
}

View File

@@ -0,0 +1,105 @@
package suwayomi.tachidesk.manga.model
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import suwayomi.tachidesk.manga.model.dataclass.PaginatedList
import suwayomi.tachidesk.manga.model.dataclass.PaginationFactor
import suwayomi.tachidesk.manga.model.dataclass.paginatedFrom
import suwayomi.tachidesk.test.ApplicationTest
class PaginatedListTest : ApplicationTest() {
@Test
fun `empty list`() {
val paginated = paginatedFrom(0) { listIndicesOf(0, 0) }
assertEquals(
PaginatedList(emptyList<Int>(), false),
paginated
)
}
@Test
fun `size smaller than PaginationFactor`() {
val paginated = paginatedFrom(0) { listIndicesOf(0, PaginationFactor - 1) }
assertEquals(
PaginatedList(listIndicesOf(0, PaginationFactor - 1), false),
paginated,
)
}
@Test
fun `one less than two times PaginationFactor`() {
val masterLister = { listIndicesOf(0, PaginationFactor * 2 - 1) }
val firstPage = paginatedFrom(0, lister = masterLister)
assertEquals(
PaginatedList(listIndicesOf(0, PaginationFactor), true),
firstPage,
)
val secondPage = paginatedFrom(1, lister = masterLister)
assertEquals(
PaginatedList(listIndicesOf(PaginationFactor, PaginationFactor * 2 - 1), false),
secondPage,
)
}
@Test
fun `two times PaginationFactor`() {
val masterLister = { listIndicesOf(0, PaginationFactor * 2) }
val firstPage = paginatedFrom(0, lister = masterLister)
assertEquals(
PaginatedList(listIndicesOf(0, PaginationFactor), true),
firstPage,
)
val secondPage = paginatedFrom(1, lister = masterLister)
assertEquals(
PaginatedList(listIndicesOf(PaginationFactor, PaginationFactor * 2), false),
secondPage,
)
}
@Test
fun `one more than two times PaginationFactor`() {
val masterLister = { listIndicesOf(0, PaginationFactor * 2 + 1) }
val firstPage = paginatedFrom(0, lister = masterLister)
assertEquals(
PaginatedList(listIndicesOf(0, PaginationFactor), true),
firstPage,
)
val secondPage = paginatedFrom(1, lister = masterLister)
assertEquals(
PaginatedList(listIndicesOf(PaginationFactor, PaginationFactor * 2), true),
secondPage,
)
val thirdPage = paginatedFrom(2, lister = masterLister)
assertEquals(
PaginatedList(listIndicesOf(PaginationFactor * 2, PaginationFactor * 2 + 1), false),
thirdPage,
)
}
private fun listIndicesOf(first: Int, last: Int): List<Int> {
return (first until last).toList()
}
}