Skip to content

Commit

Permalink
refactor: Back to actual types
Browse files Browse the repository at this point in the history
This partly reverts #119, mainly for the following reasons:

- I think I now have a bit more understanding of how KGraphQL works
  and/or was intended, and the `__` types seem to represent definition
  types, i.e. do not (and should not) have any execution details;
  similarly, the classes without `__` represent types that are used
  during execution to hold execution-specific extensions
- Further implementation for schema stitching shows that it is anyway
  necessary to create dedicated types for execution

To make that distinction more explicit, I even started to convert `__`
types to execution types.
  • Loading branch information
stuebingerb committed Jan 9, 2025
1 parent 7851dc0 commit 3e60ae9
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import com.apurebase.kgraphql.request.Variables
import com.apurebase.kgraphql.request.VariablesJson
import com.apurebase.kgraphql.schema.DefaultSchema
import com.apurebase.kgraphql.schema.introspection.TypeKind
import com.apurebase.kgraphql.schema.introspection.__Field
import com.apurebase.kgraphql.schema.introspection.__Type
import com.apurebase.kgraphql.schema.model.FunctionWrapper
import com.apurebase.kgraphql.schema.model.ast.ArgumentNodes
import com.apurebase.kgraphql.schema.scalar.serializeScalar
Expand Down Expand Up @@ -78,7 +76,7 @@ class DataLoaderPreparedRequestExecutor(val schema: DefaultSchema) : RequestExec
applyKeyToElement(ctx, result, node, node.field.returnType, 1)
}

private fun Any?.toPrimitive(node: Execution.Node, returnType: __Type): JsonElement = when {
private fun Any?.toPrimitive(node: Execution.Node, returnType: Type): JsonElement = when {
this == null -> createNullNode(node, returnType.unwrapList())
this is Collection<*> || this is Array<*> -> when (this) {
is Array<*> -> toList()
Expand All @@ -99,7 +97,7 @@ class DataLoaderPreparedRequestExecutor(val schema: DefaultSchema) : RequestExec
ctx: ExecutionContext,
value: T?,
node: Execution.Node,
returnType: __Type,
returnType: Type,
parentCount: Long
) {
return when {
Expand Down Expand Up @@ -164,7 +162,7 @@ class DataLoaderPreparedRequestExecutor(val schema: DefaultSchema) : RequestExec
}
}

private fun <T> createSimpleValueNode(returnType: __Type, value: T, node: Execution.Node): JsonElement {
private fun <T> createSimpleValueNode(returnType: Type, value: T, node: Execution.Node): JsonElement {
return when (val unwrapped = returnType.unwrapped()) {
is Type.Scalar<*> -> {
serializeScalar(unwrapped, value, node)
Expand All @@ -179,7 +177,7 @@ class DataLoaderPreparedRequestExecutor(val schema: DefaultSchema) : RequestExec
ctx: ExecutionContext,
value: T,
node: Execution.Node,
type: __Type,
type: Type,
parentCount: Long
) {
node.children.map { child ->
Expand Down Expand Up @@ -228,7 +226,7 @@ class DataLoaderPreparedRequestExecutor(val schema: DefaultSchema) : RequestExec
ctx: ExecutionContext,
value: T,
child: Execution,
type: __Type,
type: Type,
parentCount: Long
) {
when (child) {
Expand Down Expand Up @@ -291,7 +289,7 @@ class DataLoaderPreparedRequestExecutor(val schema: DefaultSchema) : RequestExec
ctx: ExecutionContext,
parentValue: T,
node: Execution.Node,
field: __Field,
field: Field,
parentCount: Long
) {
node.field.checkAccess(parentValue, ctx.requestContext)
Expand Down Expand Up @@ -396,7 +394,7 @@ class DataLoaderPreparedRequestExecutor(val schema: DefaultSchema) : RequestExec
result.await().toString()
}

private fun createNullNode(node: Execution.Node, returnType: __Type): JsonNull =
private fun createNullNode(node: Execution.Node, returnType: Type): JsonNull =
if (returnType.kind != TypeKind.NON_NULL) {
JsonNull
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ package com.apurebase.kgraphql.schema.execution

import com.apurebase.kgraphql.schema.directive.Directive
import com.apurebase.kgraphql.schema.introspection.NotIntrospected
import com.apurebase.kgraphql.schema.introspection.__Type
import com.apurebase.kgraphql.schema.structure.Field
import com.apurebase.kgraphql.schema.model.ast.ArgumentNodes
import com.apurebase.kgraphql.schema.model.ast.SelectionNode
import com.apurebase.kgraphql.schema.model.ast.VariableDefinitionNode
import com.apurebase.kgraphql.schema.structure.Field
import com.apurebase.kgraphql.schema.structure.Type

sealed class Execution {
abstract val selectionNode: SelectionNode
Expand Down Expand Up @@ -36,7 +36,7 @@ sealed class Execution {
class Union(
node: SelectionNode,
val unionField: Field.Union<*>,
val memberChildren: Map<__Type, Collection<Execution>>,
val memberChildren: Map<Type, Collection<Execution>>,
key: String,
alias: String?,
directives: Map<Directive, ArgumentNodes?>?
Expand All @@ -48,7 +48,7 @@ sealed class Execution {
alias = alias,
directives = directives
) {
fun memberExecution(type: __Type): Node {
fun memberExecution(type: Type): Node {
return Node(
selectionNode = selectionNode,
field = field,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import com.apurebase.kgraphql.request.Variables
import com.apurebase.kgraphql.request.VariablesJson
import com.apurebase.kgraphql.schema.DefaultSchema
import com.apurebase.kgraphql.schema.introspection.TypeKind
import com.apurebase.kgraphql.schema.introspection.__Field
import com.apurebase.kgraphql.schema.introspection.__Type
import com.apurebase.kgraphql.schema.model.FunctionWrapper
import com.apurebase.kgraphql.schema.model.ast.ArgumentNodes
import com.apurebase.kgraphql.schema.scalar.serializeScalar
Expand Down Expand Up @@ -131,7 +129,7 @@ class ParallelRequestExecutor(val schema: DefaultSchema) : RequestExecutor {
ctx: ExecutionContext,
value: T?,
node: Execution.Node,
returnType: __Type
returnType: Type
): JsonNode {
if (value == null) {
return createNullNode(node, returnType)
Expand Down Expand Up @@ -180,7 +178,7 @@ class ParallelRequestExecutor(val schema: DefaultSchema) : RequestExecutor {
}
}

private fun <T> createSimpleValueNode(returnType: __Type, value: T, node: Execution.Node): JsonNode =
private fun <T> createSimpleValueNode(returnType: Type, value: T, node: Execution.Node): JsonNode =
when (val unwrapped = returnType.unwrapped()) {
is Type.Scalar<*> -> {
serializeScalar(jsonNodeFactory, unwrapped, value, node)
Expand All @@ -193,7 +191,7 @@ class ParallelRequestExecutor(val schema: DefaultSchema) : RequestExecutor {
else -> throw ExecutionException("Invalid Type: ${unwrapped.name}", node)
}

private fun createNullNode(node: Execution.Node, returnType: __Type): NullNode {
private fun createNullNode(node: Execution.Node, returnType: Type): NullNode {
if (returnType.kind != TypeKind.NON_NULL) {
return jsonNodeFactory.nullNode()
} else {
Expand All @@ -205,7 +203,7 @@ class ParallelRequestExecutor(val schema: DefaultSchema) : RequestExecutor {
ctx: ExecutionContext,
value: T,
node: Execution.Node,
type: __Type
type: Type
): ObjectNode {
val objectNode = jsonNodeFactory.objectNode()
for (child in node.children) {
Expand All @@ -224,7 +222,7 @@ class ParallelRequestExecutor(val schema: DefaultSchema) : RequestExecutor {
ctx: ExecutionContext,
value: T,
child: Execution,
type: __Type
type: Type
): Pair<String, JsonNode?>? {
when (child) {
// Union is subclass of Node so check it first
Expand Down Expand Up @@ -290,7 +288,7 @@ class ParallelRequestExecutor(val schema: DefaultSchema) : RequestExecutor {
ctx: ExecutionContext,
parentValue: T,
node: Execution.Node,
field: __Field
field: Field
): JsonNode? {
val include = shouldInclude(ctx, node)
node.field.checkAccess(parentValue, ctx.requestContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,9 @@ interface __Type {
// NON_NULL and LIST only
val ofType: __Type?

operator fun get(name: String): __Field? = null

fun isList(): Boolean = when {
kind == TypeKind.LIST -> true
ofType == null -> false
else -> (ofType as __Type).isList()
}

fun typeReference(): String = when (kind) {
TypeKind.NON_NULL -> "${ofType?.typeReference()}!"
TypeKind.LIST -> "[${ofType?.typeReference()}]"
else -> name ?: ""
}

fun unwrapped(): __Type = when (kind) {
TypeKind.NON_NULL, TypeKind.LIST -> ofType!!.unwrapped()
else -> this
}

fun unwrapList(): __Type = when (kind) {
TypeKind.LIST -> ofType as __Type
else -> ofType?.unwrapList() ?: throw NoSuchElementException("this type does not wrap list element")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ sealed class Field : __Field {
override val args: List<__InputValue>
get() = arguments.filterNot { it.type.kClass?.findAnnotation<NotIntrospected>() != null }

abstract val returnType: __Type
abstract val returnType: Type

override val type: __Type
get() = returnType
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.apurebase.kgraphql.schema.structure
import com.apurebase.kgraphql.isIterable
import com.apurebase.kgraphql.request.TypeReference
import com.apurebase.kgraphql.schema.Schema
import com.apurebase.kgraphql.schema.introspection.__Type
import kotlin.reflect.KClass
import kotlin.reflect.KType
import kotlin.reflect.jvm.jvmErasure
Expand Down Expand Up @@ -36,5 +35,5 @@ interface LookupSchema : Schema {
}
}

fun findTypeByName(name: String): __Type?
fun findTypeByName(name: String): Type?
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import com.apurebase.kgraphql.schema.execution.Execution
import com.apurebase.kgraphql.schema.execution.ExecutionOptions
import com.apurebase.kgraphql.schema.execution.ExecutionPlan
import com.apurebase.kgraphql.schema.execution.TypeCondition
import com.apurebase.kgraphql.schema.introspection.__Type
import com.apurebase.kgraphql.schema.model.ast.DefinitionNode.ExecutableDefinitionNode
import com.apurebase.kgraphql.schema.model.ast.DefinitionNode.ExecutableDefinitionNode.FragmentDefinitionNode
import com.apurebase.kgraphql.schema.model.ast.DefinitionNode.ExecutableDefinitionNode.OperationDefinitionNode
Expand All @@ -32,7 +31,7 @@ class RequestInterpreter(private val schemaModel: SchemaModel) {
private val directivesByName = schemaModel.directives.associateBy { it.name }

inner class InterpreterContext(
val fragments: Map<String, Pair<__Type, SelectionSetNode>>
val fragments: Map<String, Pair<Type, SelectionSetNode>>
) {
// prevent stack overflow
private val fragmentsStack = Stack<String>()
Expand Down Expand Up @@ -95,12 +94,12 @@ class RequestInterpreter(private val schemaModel: SchemaModel) {
}
}

private fun handleReturnType(ctx: InterpreterContext, type: __Type, requestNode: FieldNode) =
private fun handleReturnType(ctx: InterpreterContext, type: Type, requestNode: FieldNode) =
handleReturnType(ctx, type, requestNode.selectionSet, requestNode.name)

private fun handleReturnType(
ctx: InterpreterContext,
type: __Type,
type: Type,
selectionSet: SelectionSetNode?,
propertyName: NameNode? = null
): List<Execution> = if (!selectionSet?.selections.isNullOrEmpty()) {
Expand All @@ -116,13 +115,13 @@ class RequestInterpreter(private val schemaModel: SchemaModel) {
emptyList()
}

private fun handleReturnTypeChildOrFragment(node: SelectionNode, returnType: __Type, ctx: InterpreterContext) =
private fun handleReturnTypeChildOrFragment(node: SelectionNode, returnType: Type, ctx: InterpreterContext) =
returnType.unwrapped().handleSelectionFieldOrFragment(node, ctx)

private fun findFragmentType(
fragment: FragmentNode,
ctx: InterpreterContext,
enclosingType: __Type
enclosingType: Type
): Execution.Fragment = when (fragment) {
is FragmentSpreadNode -> {
ctx.get(fragment) ?: throw unknownFragmentTypeException(fragment)
Expand All @@ -145,13 +144,13 @@ class RequestInterpreter(private val schemaModel: SchemaModel) {
}
}

private fun __Type.handleSelectionFieldOrFragment(node: SelectionNode, ctx: InterpreterContext): Execution =
private fun Type.handleSelectionFieldOrFragment(node: SelectionNode, ctx: InterpreterContext): Execution =
when (node) {
is FragmentNode -> findFragmentType(node, ctx, this)
is FieldNode -> handleSelection(node, ctx)
}

private fun __Type.handleSelection(
private fun Type.handleSelection(
node: FieldNode,
ctx: InterpreterContext,
variables: List<VariableDefinitionNode>? = null
Expand All @@ -164,7 +163,7 @@ class RequestInterpreter(private val schemaModel: SchemaModel) {

is Field.Union<*> -> handleUnion(field, node, ctx)

is Field -> {
else -> {
validatePropertyArguments(this, field, node)

return Execution.Node(
Expand All @@ -179,9 +178,6 @@ class RequestInterpreter(private val schemaModel: SchemaModel) {
)
}

else -> {
error("unhandled field $field")
}
}
}

Expand All @@ -197,7 +193,7 @@ class RequestInterpreter(private val schemaModel: SchemaModel) {
// other fields on an interface, typed fragments must be used. This is the same as for unions, but unions
// do not define any fields, so *no* fields may be queried on this type without the use of type refining
// fragments or inline fragments (with the exception of the meta-field `__typename`)."
val unionMembersChildren: Map<__Type, List<Execution>> =
val unionMembersChildren: Map<Type, List<Execution>> =
(field.returnType.unwrapped() as Type.Union).possibleTypes.associateWith { possibleType ->
val mergedSelectionsForType = selectionNode.selectionSet?.selections?.flatMap {
when {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ package com.apurebase.kgraphql.schema.structure
import com.apurebase.kgraphql.schema.directive.Directive
import com.apurebase.kgraphql.schema.introspection.NotIntrospected
import com.apurebase.kgraphql.schema.introspection.__Schema
import com.apurebase.kgraphql.schema.introspection.__Type
import kotlin.reflect.KClass
import kotlin.reflect.full.findAnnotation

data class SchemaModel(
val query: Type,
val mutation: Type?,
val subscription: Type?,
private val query: Type,
private val mutation: Type?,
private val subscription: Type?,
val allTypes: List<Type>,
val queryTypes: Map<KClass<*>, Type>,
val inputTypes: Map<KClass<*>, Type>,
Expand All @@ -21,9 +20,9 @@ data class SchemaModel(

val queryTypesByName = queryTypes.values.associateBy { it.name }

override val types: List<__Type> = toTypeList()
override val types: List<Type> = toTypeList()

private fun toTypeList(): List<__Type> {
private fun toTypeList(): List<Type> {
val list = allTypes
// workaround on the fact that Double and Float are treated as GraphQL Float
.filterNot { it is Type.Scalar<*> && it.kClass == Float::class }
Expand All @@ -40,10 +39,10 @@ data class SchemaModel(
return list.toList()
}

override val queryType: __Type = query
override val queryType: Type = query

override val mutationType: __Type? = mutation
override val mutationType: Type? = mutation

override val subscriptionType: __Type? = subscription
override val subscriptionType: Type? = subscription
}

Loading

0 comments on commit 3e60ae9

Please sign in to comment.