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

View File

@@ -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() }
}
}
}
}

View File

@@ -10,11 +10,13 @@ package suwayomi.tachidesk.graphql.dataLoaders
import com.expediagroup.graphql.dataloader.KotlinDataLoader import com.expediagroup.graphql.dataloader.KotlinDataLoader
import org.dataloader.DataLoader import org.dataloader.DataLoader
import org.dataloader.DataLoaderFactory import org.dataloader.DataLoaderFactory
import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList
import org.jetbrains.exposed.sql.StdOutSqlLogger import org.jetbrains.exposed.sql.StdOutSqlLogger
import org.jetbrains.exposed.sql.addLogger import org.jetbrains.exposed.sql.addLogger
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 suwayomi.tachidesk.graphql.types.MangaType import suwayomi.tachidesk.graphql.types.MangaType
import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
import suwayomi.tachidesk.manga.model.table.MangaTable import suwayomi.tachidesk.manga.model.table.MangaTable
import java.util.concurrent.CompletableFuture 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() }
}
}
}
}

View File

@@ -7,6 +7,7 @@ import org.jetbrains.exposed.sql.StdOutSqlLogger
import org.jetbrains.exposed.sql.addLogger import org.jetbrains.exposed.sql.addLogger
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 suwayomi.tachidesk.graphql.types.CategoryMetaItem
import suwayomi.tachidesk.graphql.types.ChapterMetaItem import suwayomi.tachidesk.graphql.types.ChapterMetaItem
import suwayomi.tachidesk.graphql.types.MangaMetaItem import suwayomi.tachidesk.graphql.types.MangaMetaItem
import suwayomi.tachidesk.graphql.types.MetaType import suwayomi.tachidesk.graphql.types.MetaType
@@ -20,10 +21,10 @@ class ChapterMetaDataLoader : KotlinDataLoader<Int, MetaType> {
CompletableFuture.supplyAsync { CompletableFuture.supplyAsync {
transaction { transaction {
addLogger(StdOutSqlLogger) addLogger(StdOutSqlLogger)
val metasByChapterId = ChapterMetaTable.select { ChapterMetaTable.ref inList ids } val metasByRefId = ChapterMetaTable.select { ChapterMetaTable.ref inList ids }
.map { ChapterMetaItem(it) } .map { ChapterMetaItem(it) }
.groupBy { it.ref } .groupBy { it.ref }
ids.map { metasByChapterId[it] ?: emptyList() } ids.map { metasByRefId[it] ?: emptyList() }
} }
} }
} }
@@ -35,10 +36,25 @@ class MangaMetaDataLoader : KotlinDataLoader<Int, MetaType> {
CompletableFuture.supplyAsync { CompletableFuture.supplyAsync {
transaction { transaction {
addLogger(StdOutSqlLogger) addLogger(StdOutSqlLogger)
val metasByChapterId = MangaMetaTable.select { MangaMetaTable.ref inList ids } val metasByRefId = MangaMetaTable.select { MangaMetaTable.ref inList ids }
.map { MangaMetaItem(it) } .map { MangaMetaItem(it) }
.groupBy { it.ref } .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() }
} }
} }
} }

View File

@@ -14,5 +14,8 @@ val tachideskDataLoaderRegistryFactory = KotlinDataLoaderRegistryFactory(
ChapterDataLoader(), ChapterDataLoader(),
ChaptersForMangaDataLoader(), ChaptersForMangaDataLoader(),
ChapterMetaDataLoader(), ChapterMetaDataLoader(),
MangaMetaDataLoader() MangaMetaDataLoader(),
MangaForCategoryDataLoader(),
CategoryMetaDataLoader(),
CategoriesForMangaDataLoader()
) )

View File

@@ -16,6 +16,7 @@ import graphql.GraphQL
import graphql.scalars.ExtendedScalars import graphql.scalars.ExtendedScalars
import graphql.schema.GraphQLType import graphql.schema.GraphQLType
import suwayomi.tachidesk.graphql.mutations.ChapterMutation import suwayomi.tachidesk.graphql.mutations.ChapterMutation
import suwayomi.tachidesk.graphql.queries.CategoryQuery
import suwayomi.tachidesk.graphql.queries.ChapterQuery import suwayomi.tachidesk.graphql.queries.ChapterQuery
import suwayomi.tachidesk.graphql.queries.MangaQuery import suwayomi.tachidesk.graphql.queries.MangaQuery
import kotlin.reflect.KClass import kotlin.reflect.KClass
@@ -36,7 +37,8 @@ val schema = toSchema(
), ),
queries = listOf( queries = listOf(
TopLevelObject(MangaQuery()), TopLevelObject(MangaQuery()),
TopLevelObject(ChapterQuery()) TopLevelObject(ChapterQuery()),
TopLevelObject(CategoryQuery())
), ),
mutations = listOf( mutations = listOf(
TopLevelObject(ChapterMutation()) TopLevelObject(ChapterMutation())

View File

@@ -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) }
}
}

View File

@@ -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)
}
}

View File

@@ -71,4 +71,8 @@ class MangaType(
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MetaType> { fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MetaType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MetaType>("MangaMetaDataLoader", id) return dataFetchingEnvironment.getValueFromDataLoader<Int, MetaType>("MangaMetaDataLoader", id)
} }
fun categories(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<CategoryType>> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, List<CategoryType>>("CategoriesForMangaDataLoader", id)
}
} }

View File

@@ -2,6 +2,7 @@ package suwayomi.tachidesk.graphql.types
import com.expediagroup.graphql.generator.annotations.GraphQLIgnore import com.expediagroup.graphql.generator.annotations.GraphQLIgnore
import org.jetbrains.exposed.sql.ResultRow 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.ChapterMetaTable
import suwayomi.tachidesk.manga.model.table.MangaMetaTable import suwayomi.tachidesk.manga.model.table.MangaMetaTable
@@ -21,3 +22,7 @@ class ChapterMetaItem(
class MangaMetaItem( class MangaMetaItem(
private val row: ResultRow private val row: ResultRow
) : MetaItem(row[MangaMetaTable.key], row[MangaMetaTable.value], row[MangaMetaTable.ref].value) ) : 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)