mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-07 21:04:34 -05:00
Add mutations to update multiple metas (#1874)
This commit is contained in:
@@ -4,9 +4,14 @@ import graphql.execution.DataFetcherResult
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.exposed.dao.id.EntityID
|
||||
import org.jetbrains.exposed.sql.LikePattern
|
||||
import org.jetbrains.exposed.sql.Op
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.like
|
||||
import org.jetbrains.exposed.sql.and
|
||||
import org.jetbrains.exposed.sql.deleteWhere
|
||||
import org.jetbrains.exposed.sql.or
|
||||
import org.jetbrains.exposed.sql.selectAll
|
||||
import org.jetbrains.exposed.sql.statements.BatchUpdateStatement
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
@@ -15,6 +20,7 @@ import suwayomi.tachidesk.graphql.asDataFetcherResult
|
||||
import suwayomi.tachidesk.graphql.directives.RequireAuth
|
||||
import suwayomi.tachidesk.graphql.types.ChapterMetaType
|
||||
import suwayomi.tachidesk.graphql.types.ChapterType
|
||||
import suwayomi.tachidesk.graphql.types.MetaInput
|
||||
import suwayomi.tachidesk.graphql.types.SyncConflictInfoType
|
||||
import suwayomi.tachidesk.manga.impl.Chapter
|
||||
import suwayomi.tachidesk.manga.impl.chapter.getChapterDownloadReadyById
|
||||
@@ -246,6 +252,138 @@ class ChapterMutation {
|
||||
DeleteChapterMetaPayload(clientMutationId, meta, chapter)
|
||||
}
|
||||
|
||||
data class SetChapterMetasItem(
|
||||
val chapterIds: List<Int>,
|
||||
val metas: List<MetaInput>,
|
||||
)
|
||||
|
||||
data class SetChapterMetasInput(
|
||||
val clientMutationId: String? = null,
|
||||
val items: List<SetChapterMetasItem>,
|
||||
)
|
||||
|
||||
data class SetChapterMetasPayload(
|
||||
val clientMutationId: String?,
|
||||
val metas: List<ChapterMetaType>,
|
||||
val chapters: List<ChapterType>,
|
||||
)
|
||||
|
||||
@RequireAuth
|
||||
fun setChapterMetas(input: SetChapterMetasInput): DataFetcherResult<SetChapterMetasPayload?> =
|
||||
asDataFetcherResult {
|
||||
val (clientMutationId, items) = input
|
||||
|
||||
val metaByChapterId =
|
||||
items
|
||||
.flatMap { item ->
|
||||
val metaMap = item.metas.associate { it.key to it.value }
|
||||
item.chapterIds.map { chapterId -> chapterId to metaMap }
|
||||
}.groupBy({ it.first }, { it.second })
|
||||
.mapValues { (_, maps) -> maps.reduce { acc, map -> acc + map } }
|
||||
|
||||
Chapter.modifyChaptersMetas(metaByChapterId)
|
||||
|
||||
val allChapterIds = metaByChapterId.keys
|
||||
val allMetaKeys = metaByChapterId.values.flatMap { it.keys }.distinct()
|
||||
|
||||
val (updatedMetas, chapters) =
|
||||
transaction {
|
||||
val updatedMetas =
|
||||
ChapterMetaTable
|
||||
.selectAll()
|
||||
.where { (ChapterMetaTable.ref inList allChapterIds) and (ChapterMetaTable.key inList allMetaKeys) }
|
||||
.map { ChapterMetaType(it) }
|
||||
|
||||
val chapters =
|
||||
ChapterTable
|
||||
.selectAll()
|
||||
.where { ChapterTable.id inList allChapterIds }
|
||||
.map { ChapterType(it) }
|
||||
.distinctBy { it.id }
|
||||
|
||||
updatedMetas to chapters
|
||||
}
|
||||
|
||||
SetChapterMetasPayload(clientMutationId, updatedMetas, chapters)
|
||||
}
|
||||
|
||||
data class DeleteChapterMetasItem(
|
||||
val chapterIds: List<Int>,
|
||||
val keys: List<String>? = null,
|
||||
val prefixes: List<String>? = null,
|
||||
)
|
||||
|
||||
data class DeleteChapterMetasInput(
|
||||
val clientMutationId: String? = null,
|
||||
val items: List<DeleteChapterMetasItem>,
|
||||
)
|
||||
|
||||
data class DeleteChapterMetasPayload(
|
||||
val clientMutationId: String?,
|
||||
val metas: List<ChapterMetaType>,
|
||||
val chapters: List<ChapterType>,
|
||||
)
|
||||
|
||||
@RequireAuth
|
||||
fun deleteChapterMetas(input: DeleteChapterMetasInput): DataFetcherResult<DeleteChapterMetasPayload?> =
|
||||
asDataFetcherResult {
|
||||
val (clientMutationId, items) = input
|
||||
|
||||
items.forEach { item ->
|
||||
require(!item.keys.isNullOrEmpty() || !item.prefixes.isNullOrEmpty()) {
|
||||
"Either 'keys' or 'prefixes' must be provided for each item"
|
||||
}
|
||||
}
|
||||
|
||||
val (allDeletedMetas, allChapterIds) =
|
||||
transaction {
|
||||
val deletedMetas = mutableListOf<ChapterMetaType>()
|
||||
val chapterIds = mutableSetOf<Int>()
|
||||
|
||||
items.forEach { item ->
|
||||
val keyCondition: Op<Boolean>? =
|
||||
item.keys?.takeIf { it.isNotEmpty() }?.let { ChapterMetaTable.key inList it }
|
||||
|
||||
val prefixCondition: Op<Boolean>? =
|
||||
item.prefixes
|
||||
?.filter { it.isNotEmpty() }
|
||||
?.map { (ChapterMetaTable.key like LikePattern("$it%")) as Op<Boolean> }
|
||||
?.reduceOrNull { acc, op -> acc or op }
|
||||
|
||||
val metaKeyCondition =
|
||||
if (keyCondition != null && prefixCondition != null) {
|
||||
keyCondition or prefixCondition
|
||||
} else {
|
||||
keyCondition ?: prefixCondition!!
|
||||
}
|
||||
|
||||
val condition = (ChapterMetaTable.ref inList item.chapterIds) and metaKeyCondition
|
||||
|
||||
deletedMetas +=
|
||||
ChapterMetaTable
|
||||
.selectAll()
|
||||
.where { condition }
|
||||
.map { ChapterMetaType(it) }
|
||||
|
||||
ChapterMetaTable.deleteWhere { condition }
|
||||
chapterIds += item.chapterIds
|
||||
}
|
||||
|
||||
deletedMetas to chapterIds
|
||||
}
|
||||
|
||||
val chapters =
|
||||
transaction {
|
||||
ChapterTable
|
||||
.selectAll()
|
||||
.where { ChapterTable.id inList allChapterIds }
|
||||
.map { ChapterType(it) }
|
||||
.distinctBy { it.id }
|
||||
}
|
||||
|
||||
DeleteChapterMetasPayload(clientMutationId, allDeletedMetas, chapters)
|
||||
}
|
||||
|
||||
data class FetchChapterPagesInput(
|
||||
val clientMutationId: String? = null,
|
||||
val chapterId: Int,
|
||||
|
||||
Reference in New Issue
Block a user