mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-04 03:14:40 -05:00
Send last read chapter in Mangas in Category API (#507)
* Send last read chapter with manga * optimize query * introduce new field for better performance
This commit is contained in:
@@ -10,14 +10,16 @@ package suwayomi.tachidesk.manga.impl
|
|||||||
import org.jetbrains.exposed.sql.ResultRow
|
import org.jetbrains.exposed.sql.ResultRow
|
||||||
import org.jetbrains.exposed.sql.SortOrder
|
import org.jetbrains.exposed.sql.SortOrder
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
|
import org.jetbrains.exposed.sql.alias
|
||||||
import org.jetbrains.exposed.sql.and
|
import org.jetbrains.exposed.sql.and
|
||||||
import org.jetbrains.exposed.sql.count
|
import org.jetbrains.exposed.sql.count
|
||||||
import org.jetbrains.exposed.sql.deleteWhere
|
import org.jetbrains.exposed.sql.deleteWhere
|
||||||
import org.jetbrains.exposed.sql.insert
|
import org.jetbrains.exposed.sql.insert
|
||||||
|
import org.jetbrains.exposed.sql.leftJoin
|
||||||
|
import org.jetbrains.exposed.sql.max
|
||||||
import org.jetbrains.exposed.sql.select
|
import org.jetbrains.exposed.sql.select
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import org.jetbrains.exposed.sql.update
|
import org.jetbrains.exposed.sql.update
|
||||||
import org.jetbrains.exposed.sql.wrapAsExpression
|
|
||||||
import suwayomi.tachidesk.manga.impl.Category.DEFAULT_CATEGORY_ID
|
import suwayomi.tachidesk.manga.impl.Category.DEFAULT_CATEGORY_ID
|
||||||
import suwayomi.tachidesk.manga.impl.util.lang.isEmpty
|
import suwayomi.tachidesk.manga.impl.util.lang.isEmpty
|
||||||
import suwayomi.tachidesk.manga.model.dataclass.CategoryDataClass
|
import suwayomi.tachidesk.manga.model.dataclass.CategoryDataClass
|
||||||
@@ -61,46 +63,40 @@ object CategoryManga {
|
|||||||
* list of mangas that belong to a category
|
* list of mangas that belong to a category
|
||||||
*/
|
*/
|
||||||
fun getCategoryMangaList(categoryId: Int): List<MangaDataClass> {
|
fun getCategoryMangaList(categoryId: Int): List<MangaDataClass> {
|
||||||
val unreadExpression = wrapAsExpression<Long>(
|
// Select the required columns from the MangaTable and add the aggregate functions to compute unread, download, and chapter counts
|
||||||
ChapterTable
|
val unreadCountEx = ChapterTable.isRead.count().alias("unread_count")
|
||||||
.slice(ChapterTable.id.count())
|
val downloadedCount = ChapterTable.isDownloaded.count().alias("download_count")
|
||||||
.select { (MangaTable.id eq ChapterTable.manga) and (ChapterTable.isRead eq false) }
|
val chapterCount = ChapterTable.id.count().alias("chapter_count")
|
||||||
)
|
val lastReadAt = ChapterTable.lastReadAt.max().alias("last_read_at")
|
||||||
val downloadExpression = wrapAsExpression<Long>(
|
val selectedColumns = MangaTable.columns + unreadCountEx + downloadedCount + chapterCount + lastReadAt
|
||||||
ChapterTable
|
|
||||||
.slice(ChapterTable.id.count())
|
|
||||||
.select { (MangaTable.id eq ChapterTable.manga) and (ChapterTable.isDownloaded eq true) }
|
|
||||||
)
|
|
||||||
val chapterCountExpression = wrapAsExpression<Long>(
|
|
||||||
ChapterTable
|
|
||||||
.slice(ChapterTable.id.count())
|
|
||||||
.select { (MangaTable.id eq ChapterTable.manga) }
|
|
||||||
)
|
|
||||||
|
|
||||||
val selectedColumns = MangaTable.columns + unreadExpression + downloadExpression + chapterCountExpression
|
|
||||||
|
|
||||||
val transform: (ResultRow) -> MangaDataClass = {
|
val transform: (ResultRow) -> MangaDataClass = {
|
||||||
|
// Map the data from the result row to the MangaDataClass
|
||||||
val dataClass = MangaTable.toDataClass(it)
|
val dataClass = MangaTable.toDataClass(it)
|
||||||
dataClass.unreadCount = it[unreadExpression]
|
dataClass.lastReadAt = it[lastReadAt]
|
||||||
dataClass.downloadCount = it[downloadExpression]
|
dataClass.unreadCount = it[unreadCountEx]
|
||||||
dataClass.chapterCount = it[chapterCountExpression]
|
dataClass.downloadCount = it[downloadedCount]
|
||||||
|
dataClass.chapterCount = it[chapterCount]
|
||||||
dataClass
|
dataClass
|
||||||
}
|
}
|
||||||
|
|
||||||
if (categoryId == DEFAULT_CATEGORY_ID) {
|
|
||||||
return transaction {
|
|
||||||
MangaTable
|
|
||||||
.slice(selectedColumns)
|
|
||||||
.select { (MangaTable.inLibrary eq true) and (MangaTable.defaultCategory eq true) }
|
|
||||||
.map(transform)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return transaction {
|
return transaction {
|
||||||
CategoryMangaTable.innerJoin(MangaTable)
|
// Fetch data from the MangaTable and join with the CategoryMangaTable, if a category is specified
|
||||||
.slice(selectedColumns)
|
val query = if (categoryId == DEFAULT_CATEGORY_ID) {
|
||||||
.select { (MangaTable.inLibrary eq true) and (CategoryMangaTable.category eq categoryId) }
|
MangaTable
|
||||||
.map(transform)
|
.leftJoin(ChapterTable, { MangaTable.id }, { ChapterTable.manga })
|
||||||
|
.slice(columns = selectedColumns)
|
||||||
|
.select { (MangaTable.inLibrary eq true) and (MangaTable.defaultCategory eq true) }
|
||||||
|
} else {
|
||||||
|
MangaTable
|
||||||
|
.innerJoin(CategoryMangaTable)
|
||||||
|
.leftJoin(ChapterTable, { MangaTable.id }, { ChapterTable.manga })
|
||||||
|
.slice(columns = selectedColumns)
|
||||||
|
.select { (MangaTable.inLibrary eq true) and (CategoryMangaTable.category eq categoryId) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join with the ChapterTable to fetch the last read chapter for each manga
|
||||||
|
query.groupBy(*MangaTable.columns.toTypedArray()).map(transform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ data class MangaDataClass(
|
|||||||
var unreadCount: Long? = null,
|
var unreadCount: Long? = null,
|
||||||
var downloadCount: Long? = null,
|
var downloadCount: Long? = null,
|
||||||
var chapterCount: Long? = null,
|
var chapterCount: Long? = null,
|
||||||
|
var lastReadAt: Long? = null,
|
||||||
var lastChapterRead: ChapterDataClass? = null,
|
var lastChapterRead: ChapterDataClass? = null,
|
||||||
|
|
||||||
val age: Long? = if (lastFetchedAt == null) 0 else Instant.now().epochSecond.minus(lastFetchedAt),
|
val age: Long? = if (lastFetchedAt == null) 0 else Instant.now().epochSecond.minus(lastFetchedAt),
|
||||||
|
|||||||
Reference in New Issue
Block a user