Add categories to graphql

This commit is contained in:
Valter Martinek
2022-11-11 01:27:11 +01:00
committed by Syer10
parent 623172af6d
commit bf7f1a04b3
9 changed files with 169 additions and 6 deletions
@@ -0,0 +1,49 @@
/*
* 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/. */
package suwayomi.tachidesk.graphql.dataLoaders
import com.expediagroup.graphql.dataloader.KotlinDataLoader
import org.dataloader.DataLoader
import org.dataloader.DataLoaderFactory
import org.jetbrains.exposed.sql.StdOutSqlLogger
import org.jetbrains.exposed.sql.addLogger
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.types.CategoryType
import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
import suwayomi.tachidesk.manga.model.table.CategoryTable
import java.util.concurrent.CompletableFuture
class CategoryDataLoader : KotlinDataLoader<Int, CategoryType> {
override val dataLoaderName = "CategoryDataLoader"
override fun getDataLoader(): DataLoader<Int, CategoryType> = DataLoaderFactory.newDataLoader<Int, CategoryType> { ids ->
CompletableFuture.supplyAsync {
transaction {
addLogger(StdOutSqlLogger)
CategoryTable.select { CategoryTable.id inList ids }
.map { CategoryType(it) }
}
}
}
}
class CategoriesForMangaDataLoader : KotlinDataLoader<Int, List<CategoryType>> {
override val dataLoaderName = "CategoriesForMangaDataLoader"
override fun getDataLoader(): DataLoader<Int, List<CategoryType>> = DataLoaderFactory.newDataLoader<Int, List<CategoryType>> { ids ->
CompletableFuture.supplyAsync {
transaction {
addLogger(StdOutSqlLogger)
val itemsByRef = CategoryMangaTable.innerJoin(CategoryTable).select { CategoryMangaTable.manga inList ids }
.map { Pair(it[CategoryMangaTable.manga].value, CategoryType(it)) }
.groupBy { it.first }
.mapValues { it.value.map { pair -> pair.second } }
ids.map { itemsByRef[it] ?: emptyList() }
}
}
}
}
@@ -10,11 +10,13 @@ package suwayomi.tachidesk.graphql.dataLoaders
import com.expediagroup.graphql.dataloader.KotlinDataLoader
import org.dataloader.DataLoader
import org.dataloader.DataLoaderFactory
import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList
import org.jetbrains.exposed.sql.StdOutSqlLogger
import org.jetbrains.exposed.sql.addLogger
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.types.MangaType
import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
import suwayomi.tachidesk.manga.model.table.MangaTable
import java.util.concurrent.CompletableFuture
@@ -30,3 +32,19 @@ class MangaDataLoader : KotlinDataLoader<Int, MangaType> {
}
}
}
class MangaForCategoryDataLoader : KotlinDataLoader<Int, List<MangaType>> {
override val dataLoaderName = "MangaForCategoryDataLoader"
override fun getDataLoader(): DataLoader<Int, List<MangaType>> = DataLoaderFactory.newDataLoader<Int, List<MangaType>> { ids ->
CompletableFuture.supplyAsync {
transaction {
addLogger(StdOutSqlLogger)
val itemsByRef = CategoryMangaTable.innerJoin(MangaTable).select { CategoryMangaTable.category inList ids }
.map { Pair(it[CategoryMangaTable.category].value, MangaType(it)) }
.groupBy { it.first }
.mapValues { it.value.map { pair -> pair.second } }
ids.map { itemsByRef[it] ?: emptyList() }
}
}
}
}
@@ -7,6 +7,7 @@ import org.jetbrains.exposed.sql.StdOutSqlLogger
import org.jetbrains.exposed.sql.addLogger
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.types.CategoryMetaItem
import suwayomi.tachidesk.graphql.types.ChapterMetaItem
import suwayomi.tachidesk.graphql.types.MangaMetaItem
import suwayomi.tachidesk.graphql.types.MetaType
@@ -20,10 +21,10 @@ class ChapterMetaDataLoader : KotlinDataLoader<Int, MetaType> {
CompletableFuture.supplyAsync {
transaction {
addLogger(StdOutSqlLogger)
val metasByChapterId = ChapterMetaTable.select { ChapterMetaTable.ref inList ids }
val metasByRefId = ChapterMetaTable.select { ChapterMetaTable.ref inList ids }
.map { ChapterMetaItem(it) }
.groupBy { it.ref }
ids.map { metasByChapterId[it] ?: emptyList() }
ids.map { metasByRefId[it] ?: emptyList() }
}
}
}
@@ -35,10 +36,25 @@ class MangaMetaDataLoader : KotlinDataLoader<Int, MetaType> {
CompletableFuture.supplyAsync {
transaction {
addLogger(StdOutSqlLogger)
val metasByChapterId = MangaMetaTable.select { MangaMetaTable.ref inList ids }
val metasByRefId = MangaMetaTable.select { MangaMetaTable.ref inList ids }
.map { MangaMetaItem(it) }
.groupBy { it.ref }
ids.map { metasByChapterId[it] ?: emptyList() }
ids.map { metasByRefId[it] ?: emptyList() }
}
}
}
}
class CategoryMetaDataLoader : KotlinDataLoader<Int, MetaType> {
override val dataLoaderName = "CategoryMetaDataLoader"
override fun getDataLoader(): DataLoader<Int, MetaType> = DataLoaderFactory.newDataLoader<Int, MetaType> { ids ->
CompletableFuture.supplyAsync {
transaction {
addLogger(StdOutSqlLogger)
val metasByRefId = MangaMetaTable.select { MangaMetaTable.ref inList ids }
.map { CategoryMetaItem(it) }
.groupBy { it.ref }
ids.map { metasByRefId[it] ?: emptyList() }
}
}
}
@@ -14,5 +14,8 @@ val tachideskDataLoaderRegistryFactory = KotlinDataLoaderRegistryFactory(
ChapterDataLoader(),
ChaptersForMangaDataLoader(),
ChapterMetaDataLoader(),
MangaMetaDataLoader()
MangaMetaDataLoader(),
MangaForCategoryDataLoader(),
CategoryMetaDataLoader(),
CategoriesForMangaDataLoader()
)
@@ -16,6 +16,7 @@ import graphql.GraphQL
import graphql.scalars.ExtendedScalars
import graphql.schema.GraphQLType
import suwayomi.tachidesk.graphql.mutations.ChapterMutation
import suwayomi.tachidesk.graphql.queries.CategoryQuery
import suwayomi.tachidesk.graphql.queries.ChapterQuery
import suwayomi.tachidesk.graphql.queries.MangaQuery
import kotlin.reflect.KClass
@@ -36,7 +37,8 @@ val schema = toSchema(
),
queries = listOf(
TopLevelObject(MangaQuery()),
TopLevelObject(ChapterQuery())
TopLevelObject(ChapterQuery()),
TopLevelObject(CategoryQuery())
),
mutations = listOf(
TopLevelObject(ChapterMutation())
@@ -0,0 +1,30 @@
/*
* 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/. */
package suwayomi.tachidesk.graphql.queries
import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.types.CategoryType
import suwayomi.tachidesk.manga.model.table.CategoryTable
import java.util.concurrent.CompletableFuture
class CategoryQuery {
fun category(dataFetchingEnvironment: DataFetchingEnvironment, id: Int): CompletableFuture<CategoryType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, CategoryType>("CategoryDataLoader", id)
}
fun categories(): List<CategoryType> {
val results = transaction {
CategoryTable.selectAll().toList()
}
return results.map { CategoryType(it) }
}
}
@@ -0,0 +1,36 @@
/*
* 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/. */
package suwayomi.tachidesk.graphql.types
import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.ResultRow
import suwayomi.tachidesk.manga.model.table.CategoryTable
import java.util.concurrent.CompletableFuture
class CategoryType(
val id: Int,
val order: Int,
val name: String,
val default: Boolean
) {
constructor(row: ResultRow) : this(
row[CategoryTable.id].value,
row[CategoryTable.order],
row[CategoryTable.name],
row[CategoryTable.isDefault]
)
fun manga(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<MangaType>> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, List<MangaType>>("MangaForCategoryDataLoader", id)
}
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MetaType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MetaType>("CategoryMetaDataLoader", id)
}
}
@@ -71,4 +71,8 @@ class MangaType(
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MetaType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MetaType>("MangaMetaDataLoader", id)
}
fun categories(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<CategoryType>> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, List<CategoryType>>("CategoriesForMangaDataLoader", id)
}
}
@@ -2,6 +2,7 @@ package suwayomi.tachidesk.graphql.types
import com.expediagroup.graphql.generator.annotations.GraphQLIgnore
import org.jetbrains.exposed.sql.ResultRow
import suwayomi.tachidesk.manga.model.table.CategoryMetaTable
import suwayomi.tachidesk.manga.model.table.ChapterMetaTable
import suwayomi.tachidesk.manga.model.table.MangaMetaTable
@@ -21,3 +22,7 @@ class ChapterMetaItem(
class MangaMetaItem(
private val row: ResultRow
) : MetaItem(row[MangaMetaTable.key], row[MangaMetaTable.value], row[MangaMetaTable.ref].value)
class CategoryMetaItem(
private val row: ResultRow
) : MetaItem(row[CategoryMetaTable.key], row[CategoryMetaTable.value], row[CategoryMetaTable.ref].value)