Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/main/java/graphql/execution/ValueTransformer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package graphql.execution;

/**
* Overrideable class that allows transformation of values pre-coercion
*
*/
public abstract class ValueTransformer {

public abstract Object transformValue(Object value);
}
22 changes: 15 additions & 7 deletions src/main/java/graphql/execution/ValuesResolverConversion.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ static Object externalValueToLiteral(GraphqlFieldVisibility fieldVisibility,
if (value == null) {
return newNullValue().build();
}

if (GraphQLTypeUtil.isNonNull(type)) {
return externalValueToLiteral(fieldVisibility, value, (GraphQLInputType) unwrapNonNull(type), valueMode, graphqlContext, locale);
}
Expand Down Expand Up @@ -250,13 +251,15 @@ static CoercedVariables externalValueToInternalValueForVariables(GraphQLSchema s
// can be NullValue
Value defaultValue = variableDefinition.getDefaultValue();
boolean hasValue = rawVariables.containsKey(variableName);
Object value = rawVariables.get(variableName);
Object originalValue = rawVariables.get(variableName);
if (!hasValue && defaultValue != null) {
Object coercedDefaultValue = literalToInternalValue(fieldVisibility, variableType, defaultValue, CoercedVariables.emptyVariables(), graphqlContext, locale);
coercedValues.put(variableName, coercedDefaultValue);
} else if (isNonNull(variableType) && (!hasValue || value == null)) {
} else if (isNonNull(variableType) && (!hasValue || originalValue == null)) {
throw new NonNullableValueCoercedAsNullException(variableDefinition, variableType);
} else if (hasValue) {
ValueTransformer transformer = graphqlContext.get(ValueTransformer.class);
Object value = (transformer != null) ? transformer.transformValue(originalValue) : originalValue;
if (value == null) {
coercedValues.put(variableName, null);
} else {
Expand Down Expand Up @@ -285,22 +288,25 @@ static CoercedVariables externalValueToInternalValueForVariables(GraphQLSchema s
@SuppressWarnings("unchecked")
static Object externalValueToInternalValueImpl(GraphqlFieldVisibility fieldVisibility,
GraphQLType graphQLType,
Object value,
Object originalValue,
GraphQLContext graphqlContext,
Locale locale) throws NonNullableValueCoercedAsNullException, CoercingParseValueException {
if (isNonNull(graphQLType)) {
Object returnValue =
externalValueToInternalValueImpl(fieldVisibility, unwrapOne(graphQLType), value, graphqlContext, locale);
externalValueToInternalValueImpl(fieldVisibility, unwrapOne(graphQLType), originalValue, graphqlContext, locale);
if (returnValue == null) {
throw new NonNullableValueCoercedAsNullException(graphQLType);
}
return returnValue;
}

if (value == null) {
if (originalValue == null) {
return null;
}

ValueTransformer transformer = graphqlContext.get(ValueTransformer.class);
Object value = (transformer != null) ? transformer.transformValue(originalValue) : originalValue;

if (graphQLType instanceof GraphQLScalarType) {
return externalValueToInternalValueForScalar((GraphQLScalarType) graphQLType, value, graphqlContext, locale);
} else if (graphQLType instanceof GraphQLEnumType) {
Expand Down Expand Up @@ -344,15 +350,17 @@ private static Object externalValueToInternalValueForObject(GraphqlFieldVisibili
String fieldName = inputFieldDefinition.getName();
InputValueWithState defaultValue = inputFieldDefinition.getInputFieldDefaultValue();
boolean hasValue = inputMap.containsKey(fieldName);
Object value = inputMap.getOrDefault(fieldName, null);
Object originalValue = inputMap.getOrDefault(fieldName, null);
if (!hasValue && inputFieldDefinition.hasSetDefaultValue()) {
Object coercedDefaultValue = defaultValueToInternalValue(fieldVisibility,
defaultValue,
fieldType, graphqlContext, locale);
coercedValues.put(fieldName, coercedDefaultValue);
} else if (isNonNull(fieldType) && (!hasValue || value == null)) {
} else if (isNonNull(fieldType) && (!hasValue || originalValue == null)) {
throw new NonNullableValueCoercedAsNullException(fieldName, emptyList(), fieldType);
} else if (hasValue) {
ValueTransformer transformer = graphqlContext.get(ValueTransformer.class);
Object value = (transformer != null) ? transformer.transformValue(originalValue) : originalValue;
if (value == null) {
coercedValues.put(fieldName, null);
} else {
Expand Down
41 changes: 41 additions & 0 deletions src/test/groovy/graphql/execution/ValuesResolverTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import graphql.schema.CoercingParseValueException
import spock.lang.Specification
import spock.lang.Unroll

import java.util.function.Function

import static graphql.Scalars.GraphQLBoolean
import static graphql.Scalars.GraphQLFloat
import static graphql.Scalars.GraphQLInt
Expand Down Expand Up @@ -122,6 +124,39 @@ class ValuesResolverTest extends Specification {
thrown(CoercingParseValueException)
}

def "getVariableValues: object as variable input with custom value transform"() {

given:
def nameField = newInputObjectField()
.name("name")
.type(GraphQLString)
def idField = newInputObjectField()
.name("id")
.type(GraphQLInt)
def inputType = newInputObject()
.name("Person")
.field(nameField)
.field(idField)
.build()
def schema = TestUtil.schemaWithInputType(inputType)
VariableDefinition variableDefinition = new VariableDefinition("variable", new TypeName("Person"))

when:
graphQLContext.put(ValueTransformer.class, new CustomValueTransformer())
def obj = new Person('a', 123)
def resolvedValues = ValuesResolver.coerceVariableValues(schema, [variableDefinition], RawVariables.of([variable: inputValue]), graphQLContext, locale)

then:
resolvedValues.get('variable') == outputValue

where:
inputValue || outputValue
[name: "null", id: 123] || [name: null, id: 123]
[id: 123] || [id: 123]
[name: "null"] || [name: null]
}


def "getVariableValues: simple value gets resolved to a list when the type is a List"() {
given:
def schema = TestUtil.schemaWithInputType(list(GraphQLString))
Expand Down Expand Up @@ -682,4 +717,10 @@ class ValuesResolverTest extends Specification {
executionResult.errors[0].message == "Variable 'input' has an invalid value: Expected a Number input, but it was a 'String'"
executionResult.errors[0].locations == [new SourceLocation(2, 35)]
}

class CustomValueTransformer extends ValueTransformer {
public Object transformValue(Object value) {
return value.equals("null") ? null : value;
}
}
}