graphql.execution.ValuesResolver Maven / Gradle / Ivy
package graphql.execution;
import graphql.Internal;
import graphql.language.Argument;
import graphql.language.ArrayValue;
import graphql.language.NullValue;
import graphql.language.ObjectField;
import graphql.language.ObjectValue;
import graphql.language.Value;
import graphql.language.VariableDefinition;
import graphql.language.VariableReference;
import graphql.schema.CoercingParseValueException;
import graphql.schema.GraphQLArgument;
import graphql.schema.GraphQLEnumType;
import graphql.schema.GraphQLInputObjectField;
import graphql.schema.GraphQLInputObjectType;
import graphql.schema.GraphQLList;
import graphql.schema.GraphQLNonNull;
import graphql.schema.GraphQLScalarType;
import graphql.schema.GraphQLSchema;
import graphql.schema.GraphQLType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static graphql.Assert.assertShouldNeverHappen;
@Internal
public class ValuesResolver {
/**
* The http://facebook.github.io/graphql/#sec-Coercing-Variable-Values says :
*
*
* 1. Let coercedValues be an empty unordered Map.
* 2. Let variableDefinitions be the variables defined by operation.
* 3. For each variableDefinition in variableDefinitions:
* a. Let variableName be the name of variableDefinition.
* b. Let variableType be the expected type of variableDefinition.
* c. Let defaultValue be the default value for variableDefinition.
* d. Let value be the value provided in variableValues for the name variableName.
* e. If value does not exist (was not provided in variableValues):
* i. If defaultValue exists (including null):
* 1. Add an entry to coercedValues named variableName with the value defaultValue.
* ii. Otherwise if variableType is a Non‐Nullable type, throw a query error.
* iii. Otherwise, continue to the next variable definition.
* f. Otherwise, if value cannot be coerced according to the input coercion rules of variableType, throw a query error.
* g. Let coercedValue be the result of coercing value according to the input coercion rules of variableType.
* h. Add an entry to coercedValues named variableName with the value coercedValue.
* 4. Return coercedValues.
*
*
* @param schema the schema
* @param variableDefinitions the variable definitions
* @param variableValues the supplied variables
*
* @return coerced variable values as a map
*/
public Map coerceArgumentValues(GraphQLSchema schema, List variableDefinitions, Map variableValues) {
Map coercedValues = new LinkedHashMap<>();
for (VariableDefinition variableDefinition : variableDefinitions) {
String variableName = variableDefinition.getName();
GraphQLType variableType = TypeFromAST.getTypeFromAST(schema, variableDefinition.getType());
// 3.e
if (!variableValues.containsKey(variableName)) {
Value defaultValue = variableDefinition.getDefaultValue();
if (defaultValue != null) {
// 3.e.i
Object coercedValue = coerceValueAst(variableType, variableDefinition.getDefaultValue(), null);
coercedValues.put(variableName, coercedValue);
} else if (isNonNullType(variableType)) {
// 3.e.ii
throw new NonNullableValueCoercedAsNullException(variableDefinition, variableType);
}
} else {
Object value = variableValues.get(variableName);
// 3.f
Object coercedValue = getVariableValue(variableDefinition, variableType, value);
// 3.g
coercedValues.put(variableName, coercedValue);
}
}
return coercedValues;
}
private Object getVariableValue(VariableDefinition variableDefinition, GraphQLType variableType, Object value) {
if (value == null && variableDefinition.getDefaultValue() != null) {
return coerceValueAst(variableType, variableDefinition.getDefaultValue(), null);
}
return coerceValue(variableDefinition, variableType, value);
}
private boolean isNonNullType(GraphQLType variableType) {
return variableType instanceof GraphQLNonNull;
}
public Map getArgumentValues(List argumentTypes, List arguments, Map variables) {
if (argumentTypes.isEmpty()) {
return Collections.emptyMap();
}
Map result = new LinkedHashMap<>();
Map argumentMap = argumentMap(arguments);
for (GraphQLArgument fieldArgument : argumentTypes) {
String argName = fieldArgument.getName();
Argument argument = argumentMap.get(argName);
Object value;
if (argument != null) {
value = coerceValueAst(fieldArgument.getType(), argument.getValue(), variables);
} else {
value = fieldArgument.getDefaultValue();
}
// only put an arg into the result IF they specified a variable at all or
// the default value ended up being something non null
if (argumentMap.containsKey(argName) || value != null) {
result.put(argName, value);
}
}
return result;
}
private Map argumentMap(List arguments) {
Map result = new LinkedHashMap<>();
for (Argument argument : arguments) {
result.put(argument.getName(), argument);
}
return result;
}
@SuppressWarnings("unchecked")
private Object coerceValue(VariableDefinition variableDefinition, GraphQLType graphQLType, Object value) {
if (graphQLType instanceof GraphQLNonNull) {
Object returnValue = coerceValue(variableDefinition, ((GraphQLNonNull) graphQLType).getWrappedType(), value);
if (returnValue == null) {
throw new NonNullableValueCoercedAsNullException(variableDefinition, graphQLType);
}
return returnValue;
}
if (value == null) {
return null;
}
if (graphQLType instanceof GraphQLScalarType) {
return coerceValueForScalar((GraphQLScalarType) graphQLType, value);
} else if (graphQLType instanceof GraphQLEnumType) {
return coerceValueForEnum((GraphQLEnumType) graphQLType, value);
} else if (graphQLType instanceof GraphQLList) {
return coerceValueForList(variableDefinition, (GraphQLList) graphQLType, value);
} else if (graphQLType instanceof GraphQLInputObjectType) {
if (value instanceof Map) {
return coerceValueForInputObjectType(variableDefinition, (GraphQLInputObjectType) graphQLType, (Map) value);
} else {
throw new CoercingParseValueException("Variables for GraphQLInputObjectType must be an instance of a Map according to the graphql specification. The offending object was a " + value.getClass().getName());
}
} else {
return assertShouldNeverHappen("unhandled type " + graphQLType);
}
}
private Object coerceValueForInputObjectType(VariableDefinition variableDefinition, GraphQLInputObjectType inputObjectType, Map input) {
Map result = new LinkedHashMap<>();
List fields = inputObjectType.getFields();
List fieldNames = fields.stream().map(GraphQLInputObjectField::getName).collect(Collectors.toList());
for (String inputFieldName : input.keySet()) {
if (!fieldNames.contains(inputFieldName)) {
throw new InputMapDefinesTooManyFieldsException(inputObjectType, inputFieldName);
}
}
for (GraphQLInputObjectField inputField : fields) {
if (input.containsKey(inputField.getName()) || alwaysHasValue(inputField)) {
Object value = coerceValue(variableDefinition, inputField.getType(), input.get(inputField.getName()));
result.put(inputField.getName(), value == null ? inputField.getDefaultValue() : value);
}
}
return result;
}
private boolean alwaysHasValue(GraphQLInputObjectField inputField) {
return inputField.getDefaultValue() != null
|| inputField.getType() instanceof GraphQLNonNull;
}
private Object coerceValueForScalar(GraphQLScalarType graphQLScalarType, Object value) {
return graphQLScalarType.getCoercing().parseValue(value);
}
private Object coerceValueForEnum(GraphQLEnumType graphQLEnumType, Object value) {
return graphQLEnumType.getCoercing().parseValue(value);
}
private List coerceValueForList(VariableDefinition variableDefinition, GraphQLList graphQLList, Object value) {
if (value instanceof Iterable) {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy