package graphql.execution; import graphql.GraphQLException; import graphql.language.*; import graphql.schema.*; import java.util.*; public class ValuesResolver { public Map<String, Object> getVariableValues(GraphQLSchema schema, List<VariableDefinition> variableDefinitions, Map<String, Object> inputs) { Map<String, Object> result = new LinkedHashMap<>(); for (VariableDefinition variableDefinition : variableDefinitions) { result.put(variableDefinition.getName(), getVariableValue(schema, variableDefinition, inputs.get(variableDefinition.getName()))); } return result; } public Map<String, Object> getArgumentValues(List<GraphQLArgument> argumentTypes, List<Argument> arguments, Map<String, Object> variables) { Map<String, Object> result = new LinkedHashMap<>(); Map<String, Argument> argumentMap = argumentMap(arguments); for (GraphQLArgument fieldArgument : argumentTypes) { Argument argument = argumentMap.get(fieldArgument.getName()); Object value; if (argument != null) { value = coerceValueAst(fieldArgument.getType(), argument.getValue(), variables); } else { value = fieldArgument.getDefaultValue(); } result.put(fieldArgument.getName(), value); } return result; } private Map<String, Argument> argumentMap(List<Argument> arguments) { Map<String, Argument> result = new LinkedHashMap<>(); for (Argument argument : arguments) { result.put(argument.getName(), argument); } return result; } private Object getVariableValue(GraphQLSchema schema, VariableDefinition variableDefinition, Object inputValue) { GraphQLType type = TypeFromAST.getTypeFromAST(schema, variableDefinition.getType()); if (!isValid(type, inputValue)) { throw new GraphQLException("Invalid value for type"); } if (inputValue == null && variableDefinition.getDefaultValue() != null) { return coerceValueAst(type, variableDefinition.getDefaultValue(), null); } return coerceValue(type, inputValue); } private boolean isValid(GraphQLType type, Object inputValue) { return true; } private Object coerceValue(GraphQLType graphQLType, Object value) { if (graphQLType instanceof GraphQLNonNull) { Object returnValue = coerceValue(((GraphQLNonNull) graphQLType).getWrappedType(), value); if (returnValue == null) { throw new GraphQLException("Null value for NonNull type " + 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((GraphQLList) graphQLType, value); } else if (graphQLType instanceof GraphQLInputObjectType && value instanceof Map) { return coerceValueForInputObjectType((GraphQLInputObjectType) graphQLType, (Map<String, Object>) value); } else if (graphQLType instanceof GraphQLInputObjectType) { return value; } else { throw new GraphQLException("unknown type " + graphQLType); } } private Object coerceValueForInputObjectType(GraphQLInputObjectType inputObjectType, Map<String, Object> input) { Map<String, Object> result = new LinkedHashMap<>(); for (GraphQLInputObjectField inputField : inputObjectType.getFields()) { if (input.containsKey(inputField.getName()) || alwaysHasValue(inputField)) { Object value = coerceValue(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(GraphQLList graphQLList, Object value) { if (value instanceof Iterable) { List<Object> result = new ArrayList<>(); for (Object val : (Iterable) value) { result.add(coerceValue(graphQLList.getWrappedType(), val)); } return result; } else { return Collections.singletonList(coerceValue(graphQLList.getWrappedType(), value)); } } private Object coerceValueAst(GraphQLType type, Value inputValue, Map<String, Object> variables) { if (inputValue instanceof VariableReference) { return variables.get(((VariableReference) inputValue).getName()); } if (type instanceof GraphQLScalarType) { return ((GraphQLScalarType) type).getCoercing().parseLiteral(inputValue); } if (type instanceof GraphQLNonNull) { return coerceValueAst(((GraphQLNonNull) type).getWrappedType(), inputValue, variables); } if (type instanceof GraphQLInputObjectType) { return coerceValueAstForInputObject((GraphQLInputObjectType) type, (ObjectValue) inputValue, variables); } if (type instanceof GraphQLEnumType) { return ((GraphQLEnumType) type).getCoercing().parseLiteral(inputValue); } if (type instanceof GraphQLList) { return coerceValueAstForList((GraphQLList) type, inputValue, variables); } return null; } private Object coerceValueAstForList(GraphQLList graphQLList, Value value, Map<String, Object> variables) { if (value instanceof ArrayValue) { ArrayValue arrayValue = (ArrayValue) value; List<Object> result = new ArrayList<>(); for (Value singleValue : arrayValue.getValues()) { result.add(coerceValueAst(graphQLList.getWrappedType(), singleValue, variables)); } return result; } else { return Collections.singletonList(coerceValueAst(graphQLList.getWrappedType(), value, variables)); } } private Object coerceValueAstForInputObject(GraphQLInputObjectType type, ObjectValue inputValue, Map<String, Object> variables) { Map<String, Object> result = new LinkedHashMap<>(); Map<String, ObjectField> inputValueFieldsByName = mapObjectValueFieldsByName(inputValue); for (GraphQLInputObjectField inputTypeField : type.getFields()) { if (inputValueFieldsByName.containsKey(inputTypeField.getName())) { ObjectField field = inputValueFieldsByName.get(inputTypeField.getName()); Object fieldValue = coerceValueAst(inputTypeField.getType(), field.getValue(), variables); if (fieldValue == null) { fieldValue = inputTypeField.getDefaultValue(); } result.put(field.getName(), fieldValue); } else if (inputTypeField.getDefaultValue() != null) { result.put(inputTypeField.getName(), inputTypeField.getDefaultValue()); } else if (inputTypeField.getType() instanceof GraphQLNonNull) { // Possibly overkill; an object literal with a missing non null field shouldn't pass validation throw new GraphQLException("Null value for NonNull type " + inputTypeField.getType()); } } return result; } private Map<String, ObjectField> mapObjectValueFieldsByName(ObjectValue inputValue) { Map<String, ObjectField> inputValueFieldsByName = new LinkedHashMap<>(); for (ObjectField objectField : inputValue.getObjectFields()) { inputValueFieldsByName.put(objectField.getName(), objectField); } return inputValueFieldsByName; } }