![JAR search and dependency download from the Maven repository](/logo.png)
commonMain.com.apollographql.execution.Resolver.kt Maven / Gradle / Ivy
package com.apollographql.execution
import com.apollographql.apollo.api.ExecutionContext
import com.apollographql.apollo.api.Optional
import com.apollographql.apollo.ast.GQLField
import com.apollographql.apollo.ast.GQLFieldDefinition
import com.apollographql.apollo.ast.Schema
import com.apollographql.apollo.ast.definitionFromScope
import com.apollographql.execution.internal.InternalValue
fun interface Resolver {
/**
* Resolves a field. A typical implementation is to use [ResolveInfo.parentObject]:
*
* ```kotlin
* fun resolve(resolveInfo: ResolveInfo): Any? {
* val parent = resolveInfo.parentObject as Map
* return parent[resolveInfo.fieldName]
* }
* ```
*
* @return the resolved result:
* - If the field type is a non-nullable type and [resolve] returns null, a field error is raised.
* - For leaf types (scalars and enums), the resolved result must be coercible according to the type of the field.
* - For composite types, the resolved result is an opaque type that is passed down to child resolvers.
* - For list types, the resolved result must be a kotlin List.
*/
fun resolve(resolveInfo: ResolveInfo): Any?
}
internal interface Roots {
fun query(): Any
fun mutation(): Any
fun subscription(): Any
companion object {
fun create(queryRoot: (() -> Any)?, mutationRoot: (() -> Any)?, subscriptionRoot: (() -> Any)?): Roots {
return object : Roots {
override fun query(): Any {
return queryRoot?.invoke() ?: DefaultQueryRoot
}
override fun mutation(): Any {
return mutationRoot?.invoke() ?: DefaultMutationRoot
}
override fun subscription(): Any {
return subscriptionRoot?.invoke() ?: DefaultSubscriptionRoot
}
}
}
}
}
/**
* A resolver that always throws
*/
internal object ThrowingResolver : Resolver {
override fun resolve(resolveInfo: ResolveInfo): Any? {
error("No resolver found for '${resolveInfo.coordinates()}' and no defaultResolver set.")
}
}
interface Instrumentation {
/**
* For subscriptions, this is called only once on the root field and then for every data in the nested fields
*/
fun beforeResolve(resolveInfo: ResolveInfo)
}
class ResolveTypeInfo(
val type: String,
val schema: Schema
)
class ResolveInfo internal constructor(
/**
* The parent object
*
* @see [ExecutableSchema.Builder.queryRoot]
* @see [ExecutableSchema.Builder.mutationRoot]
* @see [ExecutableSchema.Builder.subscriptionRoot]
*/
val parentObject: Any?,
val executionContext: ExecutionContext,
val fields: List,
val schema: Schema,
/**
* Coerced variables
*/
val variables: Map,
/**
* Coerced arguments
*/
private val arguments: Map,
val parentType: String,
) {
val field: GQLField
get() = fields.first()
val fieldName: String
get() = fields.first().name
fun fieldDefinition(): GQLFieldDefinition {
return field.definitionFromScope(schema, parentType)
?: error("Cannot find fieldDefinition $parentType.${field.name}")
}
/**
* Returns the argument for field [name]
*
* The argument is coerced according to the configured [Coercing] so it is safe to force cast the result to the matching type.
*
*/
fun getArgument(
name: String,
): Optional {
return if(!arguments.containsKey(name)) {
Optional.absent()
} else {
Optional.present(arguments.get(name))
}
}
fun getRequiredArgument(name: String): InternalValue {
return getArgument(name).getOrThrow()
}
fun coordinates(): String {
return "$parentType.$fieldName"
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy