From a589049cc7f5357cb41ead6eb79186c6ad00cec0 Mon Sep 17 00:00:00 2001 From: Syer10 Date: Tue, 4 Apr 2023 21:01:43 -0400 Subject: [PATCH] Move things around and introduce Cursor type --- .../graphql/queries/filter/Filter.kt | 1 + .../graphql/server/TachideskGraphQLSchema.kt | 4 + .../graphql/server/primitives/Cursor.kt | 119 ++++++++++++++++++ .../LongAsString.kt} | 2 +- .../{types => server/primitives}/NodeList.kt | 6 +- .../tachidesk/graphql/types/CategoryType.kt | 15 ++- .../tachidesk/graphql/types/ChapterType.kt | 15 ++- .../tachidesk/graphql/types/DownloadType.kt | 15 ++- .../tachidesk/graphql/types/ExtensionType.kt | 15 ++- .../tachidesk/graphql/types/MangaType.kt | 15 ++- .../tachidesk/graphql/types/MetaType.kt | 15 ++- .../tachidesk/graphql/types/SourceType.kt | 15 ++- .../tachidesk/graphql/types/UpdatesType.kt | 15 ++- 13 files changed, 207 insertions(+), 45 deletions(-) create mode 100644 server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/Cursor.kt rename server/src/main/kotlin/suwayomi/tachidesk/graphql/server/{TachideskGraphQLLongAsString.kt => primitives/LongAsString.kt} (98%) rename server/src/main/kotlin/suwayomi/tachidesk/graphql/{types => server/primitives}/NodeList.kt (92%) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/filter/Filter.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/filter/Filter.kt index 995377a6..87283a23 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/filter/Filter.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/filter/Filter.kt @@ -173,6 +173,7 @@ data class StringFilter( val greaterThanOrEqualToInsensitive: String? = null ) : ComparableScalarFilter +@Suppress("UNCHECKED_CAST") fun andFilterWithCompareString( column: Column, filter: StringFilter? diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLSchema.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLSchema.kt index 5725a029..292aa016 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLSchema.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLSchema.kt @@ -20,6 +20,9 @@ import suwayomi.tachidesk.graphql.queries.MangaQuery import suwayomi.tachidesk.graphql.queries.MetaQuery import suwayomi.tachidesk.graphql.queries.SourceQuery import suwayomi.tachidesk.graphql.queries.UpdatesQuery +import suwayomi.tachidesk.graphql.server.primitives.Cursor +import suwayomi.tachidesk.graphql.server.primitives.GraphQLCursor +import suwayomi.tachidesk.graphql.server.primitives.GraphQLLongAsString import suwayomi.tachidesk.graphql.subscriptions.DownloadSubscription import kotlin.reflect.KClass import kotlin.reflect.KType @@ -27,6 +30,7 @@ import kotlin.reflect.KType class CustomSchemaGeneratorHooks : FlowSubscriptionSchemaGeneratorHooks() { override fun willGenerateGraphQLType(type: KType): GraphQLType? = when (type.classifier as? KClass<*>) { Long::class -> GraphQLLongAsString // encode to string for JS + Cursor::class -> GraphQLCursor else -> super.willGenerateGraphQLType(type) } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/Cursor.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/Cursor.kt new file mode 100644 index 00000000..eb07e470 --- /dev/null +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/Cursor.kt @@ -0,0 +1,119 @@ +package suwayomi.tachidesk.graphql.server.primitives + +import graphql.GraphQLContext +import graphql.execution.CoercedVariables +import graphql.language.StringValue +import graphql.language.Value +import graphql.scalar.CoercingUtil +import graphql.schema.Coercing +import graphql.schema.CoercingParseLiteralException +import graphql.schema.CoercingParseValueException +import graphql.schema.CoercingSerializeException +import graphql.schema.GraphQLScalarType +import java.util.Locale + +data class Cursor(val value: String) + +val GraphQLCursor: GraphQLScalarType = GraphQLScalarType.newScalar() + .name("Cursor").description("A location in a connection that can be used for resuming pagination.").coercing(GraphqlCursorCoercing()).build() + +private class GraphqlCursorCoercing : Coercing { + private fun toStringImpl(input: Any): String? { + return (input as? Cursor)?.value + } + + private fun parseValueImpl(input: Any, locale: Locale): Cursor { + if (input !is String) { + throw CoercingParseValueException( + CoercingUtil.i18nMsg( + locale, + "String.unexpectedRawValueType", + CoercingUtil.typeName(input) + ) + ) + } + return Cursor(input) + } + + private fun parseLiteralImpl(input: Any, locale: Locale): Cursor { + if (input !is StringValue) { + throw CoercingParseLiteralException( + CoercingUtil.i18nMsg( + locale, + "Scalar.unexpectedAstType", + "StringValue", + CoercingUtil.typeName(input) + ) + ) + } + return Cursor(input.value) + } + + private fun valueToLiteralImpl(input: Any): StringValue { + return StringValue.newStringValue(input.toString()).build() + } + + @Deprecated("") + override fun serialize(dataFetcherResult: Any): String { + return toStringImpl(dataFetcherResult) ?: throw CoercingSerializeException( + CoercingUtil.i18nMsg( + Locale.getDefault(), + "String.unexpectedRawValueType", + CoercingUtil.typeName(dataFetcherResult) + ) + ) + } + + @Throws(CoercingSerializeException::class) + override fun serialize( + dataFetcherResult: Any, + graphQLContext: GraphQLContext, + locale: Locale + ): String { + return toStringImpl(dataFetcherResult) ?: throw CoercingSerializeException( + CoercingUtil.i18nMsg( + locale, + "String.unexpectedRawValueType", + CoercingUtil.typeName(dataFetcherResult) + ) + ) + } + + @Deprecated("") + override fun parseValue(input: Any): Cursor { + return parseValueImpl(input, Locale.getDefault()) + } + + @Throws(CoercingParseValueException::class) + override fun parseValue(input: Any, graphQLContext: GraphQLContext, locale: Locale): Cursor { + return parseValueImpl(input, locale) + } + + @Deprecated("") + override fun parseLiteral(input: Any): Cursor { + return parseLiteralImpl(input, Locale.getDefault()) + } + + @Throws(CoercingParseLiteralException::class) + override fun parseLiteral( + input: Value<*>, + variables: CoercedVariables, + graphQLContext: GraphQLContext, + locale: Locale + ): Cursor { + return parseLiteralImpl(input, locale) + } + + @Deprecated("") + override fun valueToLiteral(input: Any): Value<*> { + return valueToLiteralImpl(input) + } + + override fun valueToLiteral( + input: Any, + graphQLContext: GraphQLContext, + locale: Locale + ): Value<*> { + return valueToLiteralImpl(input) + } +} diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLLongAsString.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/LongAsString.kt similarity index 98% rename from server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLLongAsString.kt rename to server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/LongAsString.kt index a5841ab7..e5157ee6 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLLongAsString.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/LongAsString.kt @@ -1,4 +1,4 @@ -package suwayomi.tachidesk.graphql.server +package suwayomi.tachidesk.graphql.server.primitives import graphql.GraphQLContext import graphql.execution.CoercedVariables diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/NodeList.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/NodeList.kt similarity index 92% rename from server/src/main/kotlin/suwayomi/tachidesk/graphql/types/NodeList.kt rename to server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/NodeList.kt index 0d0ced8f..9a886f9f 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/NodeList.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/NodeList.kt @@ -1,11 +1,9 @@ -package suwayomi.tachidesk.graphql.types +package suwayomi.tachidesk.graphql.server.primitives import com.expediagroup.graphql.generator.annotations.GraphQLDescription interface Node -typealias Cursor = Int - abstract class NodeList { @GraphQLDescription("A list of [T] objects.") abstract val nodes: List @@ -36,5 +34,5 @@ abstract class Edges { abstract val cursor: Cursor @GraphQLDescription("The [T] at the end of the edge.") - abstract val node: Node? + abstract val node: Node } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/CategoryType.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/CategoryType.kt index 727c475a..16d2a83b 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/CategoryType.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/CategoryType.kt @@ -10,6 +10,11 @@ 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.graphql.server.primitives.Cursor +import suwayomi.tachidesk.graphql.server.primitives.Edges +import suwayomi.tachidesk.graphql.server.primitives.Node +import suwayomi.tachidesk.graphql.server.primitives.NodeList +import suwayomi.tachidesk.graphql.server.primitives.PageInfo import suwayomi.tachidesk.manga.model.table.CategoryTable import java.util.concurrent.CompletableFuture @@ -43,7 +48,7 @@ data class CategoryNodeList( ) : NodeList() { data class CategoryEdges( override val cursor: Cursor, - override val node: CategoryType? + override val node: CategoryType ) : Edges() companion object { @@ -51,14 +56,14 @@ data class CategoryNodeList( return CategoryNodeList( nodes = this, edges = CategoryEdges( - cursor = lastIndex, - node = lastOrNull() + cursor = Cursor(lastIndex.toString()), + node = last() ), pageInfo = PageInfo( hasNextPage = false, hasPreviousPage = false, - startCursor = 0, - endCursor = lastIndex + startCursor = Cursor(0.toString()), + endCursor = Cursor(lastIndex.toString()) ), totalCount = size ) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/ChapterType.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/ChapterType.kt index 01276a44..8d87d8f8 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/ChapterType.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/ChapterType.kt @@ -10,6 +10,11 @@ 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.graphql.server.primitives.Cursor +import suwayomi.tachidesk.graphql.server.primitives.Edges +import suwayomi.tachidesk.graphql.server.primitives.Node +import suwayomi.tachidesk.graphql.server.primitives.NodeList +import suwayomi.tachidesk.graphql.server.primitives.PageInfo import suwayomi.tachidesk.manga.model.dataclass.ChapterDataClass import suwayomi.tachidesk.manga.model.table.ChapterTable import java.util.concurrent.CompletableFuture @@ -86,7 +91,7 @@ data class ChapterNodeList( ) : NodeList() { data class ChapterEdges( override val cursor: Cursor, - override val node: ChapterType? + override val node: ChapterType ) : Edges() companion object { @@ -94,14 +99,14 @@ data class ChapterNodeList( return ChapterNodeList( nodes = this, edges = ChapterEdges( - cursor = lastIndex, - node = lastOrNull() + cursor = Cursor(lastIndex.toString()), + node = last() ), pageInfo = PageInfo( hasNextPage = false, hasPreviousPage = false, - startCursor = 0, - endCursor = lastIndex + startCursor = Cursor(0.toString()), + endCursor = Cursor(lastIndex.toString()) ), totalCount = size ) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/DownloadType.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/DownloadType.kt index e65adfc6..fc6565b8 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/DownloadType.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/DownloadType.kt @@ -8,6 +8,11 @@ package suwayomi.tachidesk.graphql.types import com.expediagroup.graphql.generator.annotations.GraphQLIgnore +import suwayomi.tachidesk.graphql.server.primitives.Cursor +import suwayomi.tachidesk.graphql.server.primitives.Edges +import suwayomi.tachidesk.graphql.server.primitives.Node +import suwayomi.tachidesk.graphql.server.primitives.NodeList +import suwayomi.tachidesk.graphql.server.primitives.PageInfo import suwayomi.tachidesk.manga.impl.download.model.DownloadChapter import suwayomi.tachidesk.manga.impl.download.model.DownloadState import suwayomi.tachidesk.manga.model.dataclass.ChapterDataClass @@ -53,7 +58,7 @@ data class DownloadNodeList( ) : NodeList() { data class DownloadEdges( override val cursor: Cursor, - override val node: DownloadType? + override val node: DownloadType ) : Edges() companion object { @@ -61,14 +66,14 @@ data class DownloadNodeList( return DownloadNodeList( nodes = this, edges = DownloadEdges( - cursor = lastIndex, - node = lastOrNull() + cursor = Cursor(lastIndex.toString()), + node = last() ), pageInfo = PageInfo( hasNextPage = false, hasPreviousPage = false, - startCursor = 0, - endCursor = lastIndex + startCursor = Cursor(0.toString()), + endCursor = Cursor(lastIndex.toString()) ), totalCount = size ) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/ExtensionType.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/ExtensionType.kt index c725687d..adee3407 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/ExtensionType.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/ExtensionType.kt @@ -10,6 +10,11 @@ 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.graphql.server.primitives.Cursor +import suwayomi.tachidesk.graphql.server.primitives.Edges +import suwayomi.tachidesk.graphql.server.primitives.Node +import suwayomi.tachidesk.graphql.server.primitives.NodeList +import suwayomi.tachidesk.graphql.server.primitives.PageInfo import suwayomi.tachidesk.manga.model.table.ExtensionTable import java.util.concurrent.CompletableFuture @@ -55,7 +60,7 @@ data class ExtensionNodeList( ) : NodeList() { data class ExtensionEdges( override val cursor: Cursor, - override val node: ExtensionType? + override val node: ExtensionType ) : Edges() companion object { @@ -63,14 +68,14 @@ data class ExtensionNodeList( return ExtensionNodeList( nodes = this, edges = ExtensionEdges( - cursor = lastIndex, - node = lastOrNull() + cursor = Cursor(lastIndex.toString()), + node = last() ), pageInfo = PageInfo( hasNextPage = false, hasPreviousPage = false, - startCursor = 0, - endCursor = lastIndex + startCursor = Cursor(0.toString()), + endCursor = Cursor(lastIndex.toString()) ), totalCount = size ) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/MangaType.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/MangaType.kt index 2b20a301..816b793a 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/MangaType.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/MangaType.kt @@ -10,6 +10,11 @@ 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.graphql.server.primitives.Cursor +import suwayomi.tachidesk.graphql.server.primitives.Edges +import suwayomi.tachidesk.graphql.server.primitives.Node +import suwayomi.tachidesk.graphql.server.primitives.NodeList +import suwayomi.tachidesk.graphql.server.primitives.PageInfo import suwayomi.tachidesk.manga.model.dataclass.MangaDataClass import suwayomi.tachidesk.manga.model.dataclass.toGenreList import suwayomi.tachidesk.manga.model.table.MangaStatus @@ -109,7 +114,7 @@ data class MangaNodeList( ) : NodeList() { data class MangaEdges( override val cursor: Cursor, - override val node: MangaType? + override val node: MangaType ) : Edges() companion object { @@ -117,14 +122,14 @@ data class MangaNodeList( return MangaNodeList( nodes = this, edges = MangaEdges( - cursor = lastIndex, - node = lastOrNull() + cursor = Cursor(lastIndex.toString()), + node = last() ), pageInfo = PageInfo( hasNextPage = false, hasPreviousPage = false, - startCursor = 0, - endCursor = lastIndex + startCursor = Cursor(0.toString()), + endCursor = Cursor(lastIndex.toString()) ), totalCount = size ) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/MetaType.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/MetaType.kt index fe85a61a..288170b6 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/MetaType.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/MetaType.kt @@ -3,6 +3,11 @@ package suwayomi.tachidesk.graphql.types import com.expediagroup.graphql.generator.annotations.GraphQLIgnore import org.jetbrains.exposed.sql.ResultRow import suwayomi.tachidesk.global.model.table.GlobalMetaTable +import suwayomi.tachidesk.graphql.server.primitives.Cursor +import suwayomi.tachidesk.graphql.server.primitives.Edges +import suwayomi.tachidesk.graphql.server.primitives.Node +import suwayomi.tachidesk.graphql.server.primitives.NodeList +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 @@ -38,7 +43,7 @@ data class MetaNodeList( ) : NodeList() { data class MetaEdges( override val cursor: Cursor, - override val node: MetaItem? + override val node: MetaItem ) : Edges() companion object { @@ -46,14 +51,14 @@ data class MetaNodeList( return MetaNodeList( nodes = this, edges = MetaEdges( - cursor = lastIndex, - node = lastOrNull() + cursor = Cursor(lastIndex.toString()), + node = last() ), pageInfo = PageInfo( hasNextPage = false, hasPreviousPage = false, - startCursor = 0, - endCursor = lastIndex + startCursor = Cursor(0.toString()), + endCursor = Cursor(lastIndex.toString()) ), totalCount = size ) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/SourceType.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/SourceType.kt index 2c9e19aa..bb0b9496 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/SourceType.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/SourceType.kt @@ -13,6 +13,11 @@ import eu.kanade.tachiyomi.source.ConfigurableSource import graphql.schema.DataFetchingEnvironment import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.select +import suwayomi.tachidesk.graphql.server.primitives.Cursor +import suwayomi.tachidesk.graphql.server.primitives.Edges +import suwayomi.tachidesk.graphql.server.primitives.Node +import suwayomi.tachidesk.graphql.server.primitives.NodeList +import suwayomi.tachidesk.graphql.server.primitives.PageInfo import suwayomi.tachidesk.manga.impl.extension.Extension import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource import suwayomi.tachidesk.manga.model.dataclass.SourceDataClass @@ -84,7 +89,7 @@ data class SourceNodeList( ) : NodeList() { data class SourceEdges( override val cursor: Cursor, - override val node: SourceType? + override val node: SourceType ) : Edges() companion object { @@ -92,14 +97,14 @@ data class SourceNodeList( return SourceNodeList( nodes = this, edges = SourceEdges( - cursor = lastIndex, - node = lastOrNull() + cursor = Cursor(lastIndex.toString()), + node = last() ), pageInfo = PageInfo( hasNextPage = false, hasPreviousPage = false, - startCursor = 0, - endCursor = lastIndex + startCursor = Cursor(0.toString()), + endCursor = Cursor(lastIndex.toString()) ), totalCount = size ) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/UpdatesType.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/UpdatesType.kt index bacfd014..e32ecb1a 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/UpdatesType.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/UpdatesType.kt @@ -8,6 +8,11 @@ package suwayomi.tachidesk.graphql.types import org.jetbrains.exposed.sql.ResultRow +import suwayomi.tachidesk.graphql.server.primitives.Cursor +import suwayomi.tachidesk.graphql.server.primitives.Edges +import suwayomi.tachidesk.graphql.server.primitives.Node +import suwayomi.tachidesk.graphql.server.primitives.NodeList +import suwayomi.tachidesk.graphql.server.primitives.PageInfo class UpdatesType( val manga: MangaType, @@ -27,7 +32,7 @@ data class UpdatesNodeList( ) : NodeList() { data class UpdatesEdges( override val cursor: Cursor, - override val node: UpdatesType? + override val node: UpdatesType ) : Edges() companion object { @@ -35,14 +40,14 @@ data class UpdatesNodeList( return UpdatesNodeList( nodes = this, edges = UpdatesEdges( - cursor = lastIndex, - node = lastOrNull() + cursor = Cursor(lastIndex.toString()), + node = last() ), pageInfo = PageInfo( hasNextPage = false, hasPreviousPage = false, - startCursor = 0, - endCursor = lastIndex + startCursor = Cursor(0.toString()), + endCursor = Cursor(lastIndex.toString()) ), totalCount = size )