Rewrite meta and add meta mutations (#556)

This commit is contained in:
Mitchell Syer
2023-05-26 06:15:16 -04:00
committed by GitHub
parent 04a671382a
commit 3f91663ecf
20 changed files with 384 additions and 122 deletions
@@ -21,9 +21,9 @@ import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
import suwayomi.tachidesk.manga.model.table.CategoryTable
import suwayomi.tachidesk.server.JavalinSetup.future
class CategoryDataLoader : KotlinDataLoader<Int, CategoryType?> {
class CategoryDataLoader : KotlinDataLoader<Int, CategoryType> {
override val dataLoaderName = "CategoryDataLoader"
override fun getDataLoader(): DataLoader<Int, CategoryType?> = DataLoaderFactory.newDataLoader { ids ->
override fun getDataLoader(): DataLoader<Int, CategoryType> = DataLoaderFactory.newDataLoader { ids ->
future {
transaction {
addLogger(Slf4jSqlDebugLogger)
@@ -8,25 +8,23 @@ import org.jetbrains.exposed.sql.addLogger
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.global.model.table.GlobalMetaTable
import suwayomi.tachidesk.graphql.types.CategoryMetaItem
import suwayomi.tachidesk.graphql.types.ChapterMetaItem
import suwayomi.tachidesk.graphql.types.GlobalMetaItem
import suwayomi.tachidesk.graphql.types.MangaMetaItem
import suwayomi.tachidesk.graphql.types.MetaItem
import suwayomi.tachidesk.graphql.types.MetaNodeList
import suwayomi.tachidesk.graphql.types.MetaNodeList.Companion.toNodeList
import suwayomi.tachidesk.graphql.types.CategoryMetaType
import suwayomi.tachidesk.graphql.types.ChapterMetaType
import suwayomi.tachidesk.graphql.types.GlobalMetaType
import suwayomi.tachidesk.graphql.types.MangaMetaType
import suwayomi.tachidesk.manga.model.table.CategoryMetaTable
import suwayomi.tachidesk.manga.model.table.ChapterMetaTable
import suwayomi.tachidesk.manga.model.table.MangaMetaTable
import suwayomi.tachidesk.server.JavalinSetup.future
class GlobalMetaDataLoader : KotlinDataLoader<String, MetaItem?> {
class GlobalMetaDataLoader : KotlinDataLoader<String, GlobalMetaType?> {
override val dataLoaderName = "GlobalMetaDataLoader"
override fun getDataLoader(): DataLoader<String, MetaItem?> = DataLoaderFactory.newDataLoader<String, MetaItem?> { ids ->
override fun getDataLoader(): DataLoader<String, GlobalMetaType?> = DataLoaderFactory.newDataLoader<String, GlobalMetaType?> { ids ->
future {
transaction {
addLogger(Slf4jSqlDebugLogger)
val metasByRefId = GlobalMetaTable.select { GlobalMetaTable.key inList ids }
.map { GlobalMetaItem(it) }
.map { GlobalMetaType(it) }
.associateBy { it.key }
ids.map { metasByRefId[it] }
}
@@ -34,46 +32,46 @@ class GlobalMetaDataLoader : KotlinDataLoader<String, MetaItem?> {
}
}
class ChapterMetaDataLoader : KotlinDataLoader<Int, MetaNodeList> {
class ChapterMetaDataLoader : KotlinDataLoader<Int, List<ChapterMetaType>> {
override val dataLoaderName = "ChapterMetaDataLoader"
override fun getDataLoader(): DataLoader<Int, MetaNodeList> = DataLoaderFactory.newDataLoader<Int, MetaNodeList> { ids ->
override fun getDataLoader(): DataLoader<Int, List<ChapterMetaType>> = DataLoaderFactory.newDataLoader<Int, List<ChapterMetaType>> { ids ->
future {
transaction {
addLogger(Slf4jSqlDebugLogger)
val metasByRefId = ChapterMetaTable.select { ChapterMetaTable.ref inList ids }
.map { ChapterMetaItem(it) }
.groupBy { it.ref }
ids.map { (metasByRefId[it] ?: emptyList()).toNodeList() }
.map { ChapterMetaType(it) }
.groupBy { it.chapterId }
ids.map { metasByRefId[it].orEmpty() }
}
}
}
}
class MangaMetaDataLoader : KotlinDataLoader<Int, MetaNodeList> {
class MangaMetaDataLoader : KotlinDataLoader<Int, List<MangaMetaType>> {
override val dataLoaderName = "MangaMetaDataLoader"
override fun getDataLoader(): DataLoader<Int, MetaNodeList> = DataLoaderFactory.newDataLoader<Int, MetaNodeList> { ids ->
override fun getDataLoader(): DataLoader<Int, List<MangaMetaType>> = DataLoaderFactory.newDataLoader<Int, List<MangaMetaType>> { ids ->
future {
transaction {
addLogger(Slf4jSqlDebugLogger)
val metasByRefId = MangaMetaTable.select { MangaMetaTable.ref inList ids }
.map { MangaMetaItem(it) }
.groupBy { it.ref }
ids.map { (metasByRefId[it] ?: emptyList()).toNodeList() }
.map { MangaMetaType(it) }
.groupBy { it.mangaId }
ids.map { metasByRefId[it].orEmpty() }
}
}
}
}
class CategoryMetaDataLoader : KotlinDataLoader<Int, MetaNodeList> {
class CategoryMetaDataLoader : KotlinDataLoader<Int, List<CategoryMetaType>> {
override val dataLoaderName = "CategoryMetaDataLoader"
override fun getDataLoader(): DataLoader<Int, MetaNodeList> = DataLoaderFactory.newDataLoader<Int, MetaNodeList> { ids ->
override fun getDataLoader(): DataLoader<Int, List<CategoryMetaType>> = DataLoaderFactory.newDataLoader<Int, List<CategoryMetaType>> { ids ->
future {
transaction {
addLogger(Slf4jSqlDebugLogger)
val metasByRefId = MangaMetaTable.select { MangaMetaTable.ref inList ids }
.map { CategoryMetaItem(it) }
.groupBy { it.ref }
ids.map { (metasByRefId[it] ?: emptyList()).toNodeList() }
val metasByRefId = CategoryMetaTable.select { CategoryMetaTable.ref inList ids }
.map { CategoryMetaType(it) }
.groupBy { it.categoryId }
ids.map { metasByRefId[it].orEmpty() }
}
}
}
@@ -0,0 +1,68 @@
package suwayomi.tachidesk.graphql.mutations
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.types.CategoryMetaType
import suwayomi.tachidesk.manga.impl.Category
import suwayomi.tachidesk.manga.model.table.CategoryMetaTable
/**
* TODO Mutations
* - Name
* - Order
* - Default
* - Create
* - Delete
*/
class CategoryMutation {
data class SetCategoryMetaInput(
val clientMutationId: String? = null,
val meta: CategoryMetaType
)
data class SetCategoryMetaPayload(
val clientMutationId: String?,
val meta: CategoryMetaType
)
fun setCategoryMeta(
input: SetCategoryMetaInput
): SetCategoryMetaPayload {
val (clientMutationId, meta) = input
Category.modifyMeta(meta.categoryId, meta.key, meta.value)
return SetCategoryMetaPayload(clientMutationId, meta)
}
data class DeleteCategoryMetaInput(
val clientMutationId: String? = null,
val categoryId: Int,
val key: String
)
data class DeleteCategoryMetaPayload(
val clientMutationId: String?,
val meta: CategoryMetaType?
)
fun deleteCategoryMeta(
input: DeleteCategoryMetaInput
): DeleteCategoryMetaPayload {
val (clientMutationId, categoryId, key) = input
val meta = transaction {
val meta = CategoryMetaTable.select { (CategoryMetaTable.ref eq categoryId) and (CategoryMetaTable.key eq key) }
.firstOrNull()
CategoryMetaTable.deleteWhere { (CategoryMetaTable.ref eq categoryId) and (CategoryMetaTable.key eq key) }
if (meta != null) {
CategoryMetaType(meta)
} else {
null
}
}
return DeleteCategoryMetaPayload(clientMutationId, meta)
}
}
@@ -3,11 +3,16 @@ package suwayomi.tachidesk.graphql.mutations
import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
import com.expediagroup.graphql.server.extensions.getValuesFromDataLoader
import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
import suwayomi.tachidesk.graphql.types.ChapterMetaType
import suwayomi.tachidesk.graphql.types.ChapterType
import suwayomi.tachidesk.manga.impl.Chapter
import suwayomi.tachidesk.manga.model.table.ChapterMetaTable
import suwayomi.tachidesk.manga.model.table.ChapterTable
import suwayomi.tachidesk.server.JavalinSetup.future
import java.time.Instant
@@ -15,7 +20,6 @@ import java.util.concurrent.CompletableFuture
/**
* TODO Mutations
* - Check for updates?
* - Download
* - Delete download
*/
@@ -124,4 +128,52 @@ class ChapterMutation {
)
}
}
data class SetChapterMetaInput(
val clientMutationId: String? = null,
val meta: ChapterMetaType
)
data class SetChapterMetaPayload(
val clientMutationId: String?,
val meta: ChapterMetaType
)
fun setChapterMeta(
input: SetChapterMetaInput
): SetChapterMetaPayload {
val (clientMutationId, meta) = input
Chapter.modifyChapterMeta(meta.chapterId, meta.key, meta.value)
return SetChapterMetaPayload(clientMutationId, meta)
}
data class DeleteChapterMetaInput(
val clientMutationId: String? = null,
val chapterId: Int,
val key: String
)
data class DeleteChapterMetaPayload(
val clientMutationId: String?,
val meta: ChapterMetaType?
)
fun deleteChapterMeta(
input: DeleteChapterMetaInput
): DeleteChapterMetaPayload {
val (clientMutationId, chapterId, key) = input
val meta = transaction {
val meta = ChapterMetaTable.select { (ChapterMetaTable.ref eq chapterId) and (ChapterMetaTable.key eq key) }
.firstOrNull()
ChapterMetaTable.deleteWhere { (ChapterMetaTable.ref eq chapterId) and (ChapterMetaTable.key eq key) }
if (meta != null) {
ChapterMetaType(meta)
} else {
null
}
}
return DeleteChapterMetaPayload(clientMutationId, meta)
}
}
@@ -0,0 +1,10 @@
package suwayomi.tachidesk.graphql.mutations
/**
* TODO Mutations
* - Install
* - Update
* - Uninstall
* - Check for updates (global mutation?)
*/
class ExtensionMutation
@@ -3,12 +3,16 @@ package suwayomi.tachidesk.graphql.mutations
import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
import com.expediagroup.graphql.server.extensions.getValuesFromDataLoader
import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
import suwayomi.tachidesk.graphql.queries.MangaQuery
import suwayomi.tachidesk.graphql.types.MangaMetaType
import suwayomi.tachidesk.graphql.types.MangaType
import suwayomi.tachidesk.manga.impl.Manga
import suwayomi.tachidesk.manga.model.table.MangaMetaTable
import suwayomi.tachidesk.manga.model.table.MangaTable
import suwayomi.tachidesk.server.JavalinSetup.future
import java.util.concurrent.CompletableFuture
@@ -17,11 +21,8 @@ import java.util.concurrent.CompletableFuture
* TODO Mutations
* - Add to category
* - Remove from category
* - Check for updates
* - Download x(all = -1) chapters
* - Delete read/all downloaded chapters
* - Add/update meta
* - Delete meta
*/
class MangaMutation {
data class UpdateMangaPatch(
@@ -112,4 +113,52 @@ class MangaMutation {
)
}
}
data class SetMangaMetaInput(
val clientMutationId: String? = null,
val meta: MangaMetaType
)
data class SetMangaMetaPayload(
val clientMutationId: String?,
val meta: MangaMetaType
)
fun setMangaMeta(
input: SetMangaMetaInput
): SetMangaMetaPayload {
val (clientMutationId, meta) = input
Manga.modifyMangaMeta(meta.mangaId, meta.key, meta.value)
return SetMangaMetaPayload(clientMutationId, meta)
}
data class DeleteMangaMetaInput(
val clientMutationId: String? = null,
val mangaId: Int,
val key: String
)
data class DeleteMangaMetaPayload(
val clientMutationId: String?,
val meta: MangaMetaType?
)
fun deleteMangaMeta(
input: DeleteMangaMetaInput
): DeleteMangaMetaPayload {
val (clientMutationId, mangaId, key) = input
val meta = transaction {
val meta = MangaMetaTable.select { (MangaMetaTable.ref eq mangaId) and (MangaMetaTable.key eq key) }
.firstOrNull()
MangaMetaTable.deleteWhere { (MangaMetaTable.ref eq mangaId) and (MangaMetaTable.key eq key) }
if (meta != null) {
MangaMetaType(meta)
} else {
null
}
}
return DeleteMangaMetaPayload(clientMutationId, meta)
}
}
@@ -0,0 +1,60 @@
package suwayomi.tachidesk.graphql.mutations
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.global.impl.GlobalMeta
import suwayomi.tachidesk.global.model.table.GlobalMetaTable
import suwayomi.tachidesk.graphql.types.GlobalMetaType
import suwayomi.tachidesk.manga.model.table.MangaMetaTable
class MetaMutation {
data class SetGlobalMetaInput(
val clientMutationId: String? = null,
val meta: GlobalMetaType
)
data class SetGlobalMetaPayload(
val clientMutationId: String?,
val meta: GlobalMetaType
)
fun setGlobalMeta(
input: SetGlobalMetaInput
): SetGlobalMetaPayload {
val (clientMutationId, meta) = input
GlobalMeta.modifyMeta(meta.key, meta.value)
return SetGlobalMetaPayload(clientMutationId, meta)
}
data class DeleteGlobalMetaInput(
val clientMutationId: String? = null,
val key: String
)
data class DeleteGlobalMetaPayload(
val clientMutationId: String?,
val meta: GlobalMetaType?
)
fun deleteGlobalMeta(
input: DeleteGlobalMetaInput
): DeleteGlobalMetaPayload {
val (clientMutationId, key) = input
val meta = transaction {
val meta = GlobalMetaTable.select { MangaMetaTable.key eq key }
.firstOrNull()
GlobalMetaTable.deleteWhere { GlobalMetaTable.key eq key }
if (meta != null) {
GlobalMetaType(meta)
} else {
null
}
}
return DeleteGlobalMetaPayload(clientMutationId, meta)
}
}
@@ -0,0 +1,8 @@
package suwayomi.tachidesk.graphql.mutations
/**
* TODO Mutations
* - Browse with filters
* - Configure settings
*/
class SourceMutation
@@ -39,18 +39,6 @@ import suwayomi.tachidesk.graphql.types.CategoryType
import suwayomi.tachidesk.manga.model.table.CategoryTable
import java.util.concurrent.CompletableFuture
/**
* TODO Queries
*
* TODO Mutations
* - Name
* - Order
* - Default
* - Create
* - Delete
* - Add/update meta
* - Delete meta
*/
class CategoryQuery {
fun category(dataFetchingEnvironment: DataFetchingEnvironment, id: Int): CompletableFuture<CategoryType?> {
return dataFetchingEnvironment.getValueFromDataLoader("CategoryDataLoader", id)
@@ -38,15 +38,6 @@ import suwayomi.tachidesk.graphql.types.ExtensionType
import suwayomi.tachidesk.manga.model.table.ExtensionTable
import java.util.concurrent.CompletableFuture
/**
* TODO Queries
*
* TODO Mutations
* - Install
* - Update
* - Uninstall
* - Check for updates (global mutation?)
*/
class ExtensionQuery {
fun extension(dataFetchingEnvironment: DataFetchingEnvironment, pkgName: String): CompletableFuture<ExtensionType?> {
return dataFetchingEnvironment.getValueFromDataLoader("ExtensionDataLoader", pkgName)
@@ -42,9 +42,6 @@ import suwayomi.tachidesk.manga.model.table.MangaStatus
import suwayomi.tachidesk.manga.model.table.MangaTable
import java.util.concurrent.CompletableFuture
/**
* TODO Queries
*/
class MangaQuery {
fun manga(dataFetchingEnvironment: DataFetchingEnvironment, id: Int): CompletableFuture<MangaType?> {
return dataFetchingEnvironment.getValueFromDataLoader("MangaDataLoader", id)
@@ -31,25 +31,16 @@ import suwayomi.tachidesk.graphql.server.primitives.QueryResults
import suwayomi.tachidesk.graphql.server.primitives.greaterNotUnique
import suwayomi.tachidesk.graphql.server.primitives.lessNotUnique
import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
import suwayomi.tachidesk.graphql.types.GlobalMetaItem
import suwayomi.tachidesk.graphql.types.MetaItem
import suwayomi.tachidesk.graphql.types.MetaNodeList
import suwayomi.tachidesk.graphql.types.GlobalMetaNodeList
import suwayomi.tachidesk.graphql.types.GlobalMetaType
import java.util.concurrent.CompletableFuture
/**
* TODO Queries
*
* TODO Mutations
* - Add/update meta
* - Delete meta
*
*/
class MetaQuery {
fun meta(dataFetchingEnvironment: DataFetchingEnvironment, key: String): CompletableFuture<MetaItem?> {
return dataFetchingEnvironment.getValueFromDataLoader<String, MetaItem?>("GlobalMetaDataLoader", key)
fun meta(dataFetchingEnvironment: DataFetchingEnvironment, key: String): CompletableFuture<GlobalMetaType?> {
return dataFetchingEnvironment.getValueFromDataLoader<String, GlobalMetaType?>("GlobalMetaDataLoader", key)
}
enum class MetaOrderBy(override val column: Column<out Comparable<*>>) : OrderBy<MetaItem> {
enum class MetaOrderBy(override val column: Column<out Comparable<*>>) : OrderBy<GlobalMetaType> {
KEY(GlobalMetaTable.key),
VALUE(GlobalMetaTable.value);
@@ -67,7 +58,7 @@ class MetaQuery {
}
}
override fun asCursor(type: MetaItem): Cursor {
override fun asCursor(type: GlobalMetaType): Cursor {
val value = when (this) {
KEY -> type.key
VALUE -> type.key + "\\-" + type.value
@@ -114,7 +105,7 @@ class MetaQuery {
first: Int? = null,
last: Int? = null,
offset: Int? = null
): MetaNodeList {
): GlobalMetaNodeList {
val queryResults = transaction {
val res = GlobalMetaTable.selectAll()
@@ -157,24 +148,24 @@ class MetaQuery {
QueryResults(total, firstResult, lastResult, res.toList())
}
val getAsCursor: (MetaItem) -> Cursor = (orderBy ?: MetaOrderBy.KEY)::asCursor
val getAsCursor: (GlobalMetaType) -> Cursor = (orderBy ?: MetaOrderBy.KEY)::asCursor
val resultsAsType = queryResults.results.map { GlobalMetaItem(it) }
val resultsAsType = queryResults.results.map { GlobalMetaType(it) }
return MetaNodeList(
return GlobalMetaNodeList(
resultsAsType,
if (resultsAsType.isEmpty()) {
emptyList()
} else {
listOfNotNull(
resultsAsType.firstOrNull()?.let {
MetaNodeList.MetaEdge(
GlobalMetaNodeList.MetaEdge(
getAsCursor(it),
it
)
},
resultsAsType.lastOrNull()?.let {
MetaNodeList.MetaEdge(
GlobalMetaNodeList.MetaEdge(
getAsCursor(it),
it
)
@@ -39,14 +39,6 @@ import suwayomi.tachidesk.graphql.types.SourceType
import suwayomi.tachidesk.manga.model.table.SourceTable
import java.util.concurrent.CompletableFuture
/**
* TODO Queries
*
* TODO Mutations
* - Browse with filters
* - Configure settings
*
*/
class SourceQuery {
fun source(dataFetchingEnvironment: DataFetchingEnvironment, id: Long): CompletableFuture<SourceType?> {
return dataFetchingEnvironment.getValueFromDataLoader<Long, SourceType?>("SourceDataLoader", id)
@@ -9,6 +9,7 @@ package suwayomi.tachidesk.graphql.server
import com.expediagroup.graphql.dataloader.KotlinDataLoaderRegistryFactory
import suwayomi.tachidesk.graphql.dataLoaders.CategoriesForMangaDataLoader
import suwayomi.tachidesk.graphql.dataLoaders.CategoryDataLoader
import suwayomi.tachidesk.graphql.dataLoaders.CategoryMetaDataLoader
import suwayomi.tachidesk.graphql.dataLoaders.ChapterDataLoader
import suwayomi.tachidesk.graphql.dataLoaders.ChapterMetaDataLoader
@@ -33,6 +34,7 @@ class TachideskDataLoaderRegistryFactory {
ChapterMetaDataLoader(),
MangaMetaDataLoader(),
MangaForCategoryDataLoader(),
CategoryDataLoader(),
CategoryMetaDataLoader(),
CategoriesForMangaDataLoader(),
SourceDataLoader(),
@@ -12,8 +12,12 @@ import com.expediagroup.graphql.generator.TopLevelObject
import com.expediagroup.graphql.generator.hooks.FlowSubscriptionSchemaGeneratorHooks
import com.expediagroup.graphql.generator.toSchema
import graphql.schema.GraphQLType
import suwayomi.tachidesk.graphql.mutations.CategoryMutation
import suwayomi.tachidesk.graphql.mutations.ChapterMutation
import suwayomi.tachidesk.graphql.mutations.ExtensionMutation
import suwayomi.tachidesk.graphql.mutations.MangaMutation
import suwayomi.tachidesk.graphql.mutations.MetaMutation
import suwayomi.tachidesk.graphql.mutations.SourceMutation
import suwayomi.tachidesk.graphql.queries.CategoryQuery
import suwayomi.tachidesk.graphql.queries.ChapterQuery
import suwayomi.tachidesk.graphql.queries.ExtensionQuery
@@ -42,16 +46,20 @@ val schema = toSchema(
hooks = CustomSchemaGeneratorHooks()
),
queries = listOf(
TopLevelObject(MangaQuery()),
TopLevelObject(ChapterQuery()),
TopLevelObject(CategoryQuery()),
TopLevelObject(SourceQuery()),
TopLevelObject(ChapterQuery()),
TopLevelObject(ExtensionQuery()),
TopLevelObject(MetaQuery())
TopLevelObject(MangaQuery()),
TopLevelObject(MetaQuery()),
TopLevelObject(SourceQuery())
),
mutations = listOf(
TopLevelObject(CategoryMutation()),
TopLevelObject(ChapterMutation()),
TopLevelObject(MangaMutation())
TopLevelObject(ExtensionMutation()),
TopLevelObject(MangaMutation()),
TopLevelObject(MetaMutation()),
TopLevelObject(SourceMutation())
),
subscriptions = listOf(
TopLevelObject(DownloadSubscription())
@@ -35,8 +35,8 @@ class CategoryType(
return dataFetchingEnvironment.getValueFromDataLoader<Int, MangaNodeList>("MangaForCategoryDataLoader", id)
}
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MetaNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MetaNodeList>("CategoryMetaDataLoader", id)
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<CategoryMetaType>> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, List<CategoryMetaType>>("CategoryMetaDataLoader", id)
}
}
@@ -81,8 +81,8 @@ class ChapterType(
return dataFetchingEnvironment.getValueFromDataLoader<Int, MangaType>("MangaDataLoader", mangaId)
}
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MetaNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MetaNodeList>("ChapterMetaDataLoader", id)
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<ChapterMetaType>> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, List<ChapterMetaType>>("ChapterMetaDataLoader", id)
}
}
@@ -93,8 +93,8 @@ class MangaType(
return Instant.now().epochSecond.minus(chaptersLastFetchedAt!!)
}
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MetaNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MetaNodeList>("MangaMetaDataLoader", id)
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<MangaMetaType>> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, List<MangaMetaType>>("MangaMetaDataLoader", id)
}
fun categories(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<CategoryNodeList> {
@@ -1,6 +1,7 @@
package suwayomi.tachidesk.graphql.types
import com.expediagroup.graphql.generator.annotations.GraphQLIgnore
import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.ResultRow
import suwayomi.tachidesk.global.model.table.GlobalMetaTable
import suwayomi.tachidesk.graphql.server.primitives.Cursor
@@ -11,44 +12,85 @@ import suwayomi.tachidesk.graphql.server.primitives.PageInfo
import suwayomi.tachidesk.manga.model.table.CategoryMetaTable
import suwayomi.tachidesk.manga.model.table.ChapterMetaTable
import suwayomi.tachidesk.manga.model.table.MangaMetaTable
import java.util.concurrent.CompletableFuture
open class MetaItem(
val key: String,
val value: String,
@GraphQLIgnore
val ref: Int?
) : Node
interface MetaType : Node {
val key: String
val value: String
}
class ChapterMetaItem(
private val row: ResultRow
) : MetaItem(row[ChapterMetaTable.key], row[ChapterMetaTable.value], row[ChapterMetaTable.ref].value)
class ChapterMetaType(
override val key: String,
override val value: String,
val chapterId: Int
) : MetaType {
constructor(row: ResultRow) : this(
key = row[ChapterMetaTable.key],
value = row[ChapterMetaTable.value],
chapterId = row[ChapterMetaTable.ref].value
)
class MangaMetaItem(
private val row: ResultRow
) : MetaItem(row[MangaMetaTable.key], row[MangaMetaTable.value], row[MangaMetaTable.ref].value)
fun chapter(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ChapterType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, ChapterType>("ChapterDataLoader", chapterId)
}
}
class CategoryMetaItem(
private val row: ResultRow
) : MetaItem(row[CategoryMetaTable.key], row[CategoryMetaTable.value], row[CategoryMetaTable.ref].value)
class MangaMetaType(
override val key: String,
override val value: String,
val mangaId: Int
) : MetaType {
constructor(row: ResultRow) : this(
key = row[MangaMetaTable.key],
value = row[MangaMetaTable.value],
mangaId = row[MangaMetaTable.ref].value
)
class GlobalMetaItem(
private val row: ResultRow
) : MetaItem(row[GlobalMetaTable.key], row[GlobalMetaTable.value], null)
fun manga(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MangaType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MangaType>("MangaDataLoader", mangaId)
}
}
data class MetaNodeList(
override val nodes: List<MetaItem>,
class CategoryMetaType(
override val key: String,
override val value: String,
val categoryId: Int
) : MetaType {
constructor(row: ResultRow) : this(
key = row[CategoryMetaTable.key],
value = row[CategoryMetaTable.value],
categoryId = row[CategoryMetaTable.ref].value
)
fun category(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<CategoryType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, CategoryType>("CategoryDataLoader", categoryId)
}
}
class GlobalMetaType(
override val key: String,
override val value: String
) : MetaType {
constructor(row: ResultRow) : this(
key = row[GlobalMetaTable.key],
value = row[GlobalMetaTable.value]
)
}
data class GlobalMetaNodeList(
override val nodes: List<GlobalMetaType>,
override val edges: List<MetaEdge>,
override val pageInfo: PageInfo,
override val totalCount: Int
) : NodeList() {
data class MetaEdge(
override val cursor: Cursor,
override val node: MetaItem
override val node: GlobalMetaType
) : Edge()
companion object {
fun List<MetaItem>.toNodeList(): MetaNodeList {
return MetaNodeList(
fun List<GlobalMetaType>.toNodeList(): GlobalMetaNodeList {
return GlobalMetaNodeList(
nodes = this,
edges = getEdges(),
pageInfo = PageInfo(
@@ -61,7 +103,7 @@ data class MetaNodeList(
)
}
private fun List<MetaItem>.getEdges(): List<MetaEdge> {
private fun List<GlobalMetaType>.getEdges(): List<MetaEdge> {
if (isEmpty()) return emptyList()
return listOf(
MetaEdge(
@@ -307,6 +307,12 @@ object Chapter {
val chapterId =
ChapterTable.select { (ChapterTable.manga eq mangaId) and (ChapterTable.sourceOrder eq chapterIndex) }
.first()[ChapterTable.id].value
modifyChapterMeta(chapterId, key, value)
}
}
fun modifyChapterMeta(chapterId: Int, key: String, value: String) {
transaction {
val meta =
ChapterMetaTable.select { (ChapterMetaTable.ref eq chapterId) and (ChapterMetaTable.key eq key) }
.firstOrNull()