![JAR search and dependency download from the Maven repository](/logo.png)
commonMain.com.apollographql.execution.internal.coerceVariablesValues.kt Maven / Gradle / Ivy
package com.apollographql.execution.internal
import com.apollographql.apollo.ast.GQLEnumTypeDefinition
import com.apollographql.apollo.ast.GQLEnumValue
import com.apollographql.apollo.ast.GQLInputObjectTypeDefinition
import com.apollographql.apollo.ast.GQLInterfaceTypeDefinition
import com.apollographql.apollo.ast.GQLListType
import com.apollographql.apollo.ast.GQLNamedType
import com.apollographql.apollo.ast.GQLNonNullType
import com.apollographql.apollo.ast.GQLObjectTypeDefinition
import com.apollographql.apollo.ast.GQLScalarTypeDefinition
import com.apollographql.apollo.ast.GQLType
import com.apollographql.apollo.ast.GQLUnionTypeDefinition
import com.apollographql.apollo.ast.GQLValue
import com.apollographql.apollo.ast.GQLVariableDefinition
import com.apollographql.apollo.ast.Schema
import com.apollographql.execution.Coercing
import com.apollographql.execution.scalarCoercingDeserialize
internal fun coerceVariablesValues(
schema: Schema,
variableDefinitions: List,
variables: Map,
coercings: Map>,
): Map {
val coercedValues = mutableMapOf()
variableDefinitions.forEach { variableDefinition ->
val hasValue = variables.containsKey(variableDefinition.name)
if (!hasValue && variableDefinition.defaultValue != null) {
/**
* Sadly defaultValues are not coerced 😞
* This is conceptually wrong but also what the spec is saying so this is what we want I guess
* See https://github.com/graphql/graphql-spec/pull/793
*/
coercedValues.put(variableDefinition.name, variableDefinition.defaultValue!!.toInternalValue())
return@forEach
}
val value = variables.get(variableDefinition.name)
if (variableDefinition.type is GQLNonNullType) {
if (!hasValue) {
error("No variable found for '${variableDefinition.name}'")
}
if (value == null) {
error("'null' is not accepted for '${variableDefinition.name}'")
}
}
if (hasValue) {
if (value == null) {
coercedValues.put(variableDefinition.name, null)
} else {
coercedValues.put(variableDefinition.name, coerceExternalToInternal(schema, value, variableDefinition.type, coercings))
}
}
}
return coercedValues
}
/**
*
*/
private fun coerceExternalToInternal(schema: Schema, value: ExternalValue, type: GQLType, coercings: Map>): InternalValue {
if (value == null) {
check(type !is GQLNonNullType) {
error("'null' found in non-null position")
}
return null
}
return when (type) {
is GQLNonNullType -> {
coerceExternalToInternal(schema, value, type.type, coercings)
}
is GQLListType -> {
if (value is List<*>) {
value.map { coerceExternalToInternal(schema, it, type.type, coercings) }
} else {
// Single items are mapped to a list of 1
listOf(coerceExternalToInternal(schema, value, type.type, coercings))
}
}
is GQLNamedType -> {
val definition = schema.typeDefinition(type.name)
when (definition) {
is GQLEnumTypeDefinition -> {
coerceEnumExternalToInternal(value = value, coercings = coercings, definition = definition)
}
is GQLInputObjectTypeDefinition -> {
coerceInputObject(schema, definition, value, coercings)
}
is GQLInterfaceTypeDefinition,
is GQLObjectTypeDefinition,
is GQLUnionTypeDefinition,
-> {
error("Output type '${definition.name}' cannot be used in input position")
}
is GQLScalarTypeDefinition -> {
scalarCoercingDeserialize(value, coercings, definition.name)
}
}
}
}
}
internal fun coerceEnumExternalToInternal(value: ExternalValue, coercings: Map>, definition: GQLEnumTypeDefinition): InternalValue {
check(value is String) {
error("Don't know how to coerce '$value' to a '${definition.name}' enum value")
}
val coercing = coercings.get(definition.name)
return if (coercing == null) {
check(definition.enumValues.any { it.name == value }) {
val possibleValues = definition.enumValues.map { it.name }.toSet()
"'$value' cannot be coerced to a '${definition.name}' enum value. Possible values are: '$possibleValues'"
}
value
} else {
coercing.deserialize(value)
}
}
private fun coerceInputObject(schema: Schema, definition: GQLInputObjectTypeDefinition, externalValue: ExternalValue, coercings: Map>): InternalValue {
if (externalValue !is Map<*, *>) {
error("Don't know how to coerce '$externalValue' to a '${definition.name}' input object")
}
val map = definition.inputFields.mapNotNull { inputValueDefinition ->
val inputFieldType = inputValueDefinition.type
if (!externalValue.containsKey(inputValueDefinition.name)) {
if (inputValueDefinition.defaultValue != null) {
inputValueDefinition.name to inputValueDefinition.defaultValue!!.toInternalValue()
} else {
if (inputFieldType is GQLNonNullType) {
error("Missing input field '${inputValueDefinition.name}")
}
// Skip this field
null
}
} else {
val inputFieldValue = externalValue.get(inputValueDefinition.name)
inputValueDefinition.name to coerceExternalToInternal(schema, inputFieldValue, inputFieldType, coercings)
}
}.toMap()
val coercing = coercings.get(definition.name)
return if (coercing != null) {
coercing.deserialize(map)
} else {
map
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy