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.Coercing;
import graphql.schema.CoercingParseValueException;
import graphql.schema.GraphQLArgument;
import graphql.schema.GraphQLCodeRegistry;
import graphql.schema.GraphQLEnumType;
import graphql.schema.GraphQLInputObjectField;
import graphql.schema.GraphQLInputObjectType;
import graphql.schema.GraphQLList;
import graphql.schema.GraphQLScalarType;
import graphql.schema.GraphQLSchema;
import graphql.schema.GraphQLType;
import graphql.schema.visibility.GraphqlFieldVisibility;
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;
import static graphql.schema.GraphQLTypeUtil.isList;
import static graphql.schema.GraphQLTypeUtil.isNonNull;
import static graphql.schema.GraphQLTypeUtil.unwrapOne;
import static graphql.schema.visibility.DefaultGraphqlFieldVisibility.DEFAULT_FIELD_VISIBILITY;
@Internal
public class ValuesResolver {
/**
* This method coerces the "raw" variables values provided to the engine. The coerced values will be used to
* provide arguments to {@link graphql.schema.DataFetchingEnvironment}
* The coercing is ultimately done via {@link Coercing}.
*
* @param schema the schema
* @param variableDefinitions the variable definitions
* @param variableValues the supplied variables
*
* @return coerced variable values as a map
*/
public Map coerceVariableValues(GraphQLSchema schema, List variableDefinitions, Map variableValues) {
GraphqlFieldVisibility fieldVisibility = schema.getFieldVisibility();
Map coercedValues = new LinkedHashMap<>();
for (VariableDefinition variableDefinition : variableDefinitions) {
String variableName = variableDefinition.getName();
GraphQLType variableType = TypeFromAST.getTypeFromAST(schema, variableDefinition.getType());
if (!variableValues.containsKey(variableName)) {
Value defaultValue = variableDefinition.getDefaultValue();
if (defaultValue != null) {
Object coercedValue = coerceValueAst(fieldVisibility, variableType, variableDefinition.getDefaultValue(), null);
coercedValues.put(variableName, coercedValue);
} else if (isNonNull(variableType)) {
throw new NonNullableValueCoercedAsNullException(variableDefinition, variableType);
}
} else {
Object value = variableValues.get(variableName);
Object coercedValue = getVariableValue(fieldVisibility, variableDefinition, variableType, value);
coercedValues.put(variableName, coercedValue);
}
}
return coercedValues;
}
private Object getVariableValue(GraphqlFieldVisibility fieldVisibility, VariableDefinition variableDefinition, GraphQLType variableType, Object value) {
if (value == null && variableDefinition.getDefaultValue() != null) {
return coerceValueAst(fieldVisibility, variableType, variableDefinition.getDefaultValue(), null);
}
return coerceValue(fieldVisibility, variableDefinition, variableDefinition.getName(), variableType, value);
}
public Map getArgumentValues(List argumentTypes, List arguments, Map variables) {
GraphQLCodeRegistry codeRegistry = GraphQLCodeRegistry.newCodeRegistry().fieldVisibility(DEFAULT_FIELD_VISIBILITY).build();
return getArgumentValuesImpl(codeRegistry, argumentTypes, arguments, variables);
}
public Map getArgumentValues(GraphQLCodeRegistry codeRegistry, List argumentTypes, List arguments, Map variables) {
return getArgumentValuesImpl(codeRegistry, argumentTypes, arguments, variables);
}
private Map getArgumentValuesImpl(GraphQLCodeRegistry codeRegistry, 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(codeRegistry.getFieldVisibility(), 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(GraphqlFieldVisibility fieldVisibility, VariableDefinition variableDefinition, String inputName, GraphQLType graphQLType, Object value) {
try {
if (isNonNull(graphQLType)) {
Object returnValue =
coerceValue(fieldVisibility, variableDefinition, inputName, unwrapOne(graphQLType), value);
if (returnValue == null) {
throw new NonNullableValueCoercedAsNullException(variableDefinition, inputName, 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(fieldVisibility, variableDefinition, inputName, (GraphQLList) graphQLType, value);
} else if (graphQLType instanceof GraphQLInputObjectType) {
if (value instanceof Map) {
return coerceValueForInputObjectType(fieldVisibility, variableDefinition, (GraphQLInputObjectType) graphQLType, (Map) value);
} else {
throw new CoercingParseValueException(
"Expected type 'Map' but was '" + value.getClass().getSimpleName() +
"'. Variables for input objects must be an instance of type 'Map'."
);
}
} else {
return assertShouldNeverHappen("unhandled type %s", graphQLType);
}
} catch (CoercingParseValueException e) {
if (e.getLocations() != null) {
throw e;
}
throw new CoercingParseValueException(
"Variable '" + inputName + "' has an invalid value. " + e.getMessage(),
e.getCause(),
variableDefinition.getSourceLocation()
);
}
}
private Object coerceValueForInputObjectType(GraphqlFieldVisibility fieldVisibility, VariableDefinition variableDefinition, GraphQLInputObjectType inputObjectType, Map input) {
Map result = new LinkedHashMap<>();
List fields = fieldVisibility.getFieldDefinitions(inputObjectType);
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(fieldVisibility, variableDefinition,
inputField.getName(),
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
|| isNonNull(inputField.getType());
}
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(GraphqlFieldVisibility fieldVisibility, VariableDefinition variableDefinition, String inputName, GraphQLList graphQLList, Object value) {
if (value instanceof Iterable) {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy