X Tutup
Skip to content
Merged
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
44 changes: 28 additions & 16 deletions src/main/java/graphql/TypeResolutionEnvironment.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package graphql;

import graphql.collect.ImmutableMapWithNullValues;
import graphql.execution.DataFetcherResult;
import graphql.execution.MergedField;
import graphql.execution.TypeResolutionParameters;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.DataFetchingFieldSelectionSet;
import graphql.schema.GraphQLSchema;
import graphql.schema.GraphQLType;
Expand All @@ -24,24 +27,20 @@ public class TypeResolutionEnvironment {
private final GraphQLSchema schema;
private final Object context;
private final GraphQLContext graphQLContext;
private final Object localContext;
private final DataFetchingFieldSelectionSet fieldSelectionSet;

public TypeResolutionEnvironment(Object object,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this is breaking API - but this should not have been made public - a builder pattern (which we started AFTER this class was invented) would have not made this a breaking change.

We really dont want consumers making these

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could got the whole hog and merge the two classes and put the builder int this class. I chose not to do this - progress over perfection

Map<String, Object> arguments,
MergedField field,
GraphQLType fieldType,
GraphQLSchema schema,
Object context,
GraphQLContext graphQLContext,
DataFetchingFieldSelectionSet fieldSelectionSet) {
this.object = object;
this.arguments = ImmutableMapWithNullValues.copyOf(arguments);
this.field = field;
this.fieldType = fieldType;
this.schema = schema;
this.context = context;
this.graphQLContext = graphQLContext;
this.fieldSelectionSet = fieldSelectionSet;
@Internal
public TypeResolutionEnvironment(TypeResolutionParameters parameters) {
this.object = parameters.getValue();
this.arguments = ImmutableMapWithNullValues.copyOf(parameters.getArgumentValues());
this.field = parameters.getField();
this.fieldType = parameters.getFieldType();
this.schema = parameters.getSchema();
this.context = parameters.getContext();
this.graphQLContext = parameters.getGraphQLContext();
this.localContext = parameters.getLocalContext();
this.fieldSelectionSet = parameters.getSelectionSet();
}


Expand Down Expand Up @@ -97,6 +96,7 @@ public GraphQLSchema getSchema() {
*/
@Deprecated
public <T> T getContext() {
//noinspection unchecked
return (T) context;
}

Expand All @@ -107,6 +107,18 @@ public GraphQLContext getGraphQLContext() {
return graphQLContext;
}

/**
* Returns the local context object set in via {@link DataFetcherResult#getLocalContext()}
*
* @param <T> to two
*
* @return the local context object
*/
<T> T getLocalContext() {
//noinspection unchecked
return (T) localContext;
}

/**
* @return the {@link DataFetchingFieldSelectionSet} for the current field fetch that needs type resolution
*/
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/graphql/execution/ExecutionStrategy.java
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ protected Iterable<Object> toIterable(Object result) {
}

protected GraphQLObjectType resolveType(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLType fieldType) {
return resolvedType.resolveType(executionContext, parameters.getField(), parameters.getSource(), parameters.getExecutionStepInfo(), fieldType);
return resolvedType.resolveType(executionContext, parameters.getField(), parameters.getSource(), parameters.getExecutionStepInfo(), fieldType, parameters.getLocalContext());
}


Expand Down
60 changes: 23 additions & 37 deletions src/main/java/graphql/execution/ResolveType.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,24 @@
public class ResolveType {


public GraphQLObjectType resolveType(ExecutionContext executionContext, MergedField field, Object source, ExecutionStepInfo executionStepInfo, GraphQLType fieldType) {
public GraphQLObjectType resolveType(ExecutionContext executionContext, MergedField field, Object source, ExecutionStepInfo executionStepInfo, GraphQLType fieldType, Object localContext) {
GraphQLObjectType resolvedType;
DataFetchingFieldSelectionSet fieldSelectionSet = buildSelectionSet(executionContext, field, (GraphQLOutputType) fieldType, executionStepInfo);
TypeResolutionEnvironment env = TypeResolutionParameters.newParameters()
.field(field)
.fieldType(fieldType)
.value(source)
.argumentValues(executionStepInfo.getArguments())
.selectionSet(fieldSelectionSet)
.context(executionContext.getContext())
.graphQLContext(executionContext.getGraphQLContext())
.localContext(localContext)
.schema(executionContext.getGraphQLSchema())
.build();
if (fieldType instanceof GraphQLInterfaceType) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified - there was never a need for the union vs interface type - there are never treated special outside this spot and again only for resolver lookup

DataFetchingFieldSelectionSet fieldSelectionSet = buildSelectionSet(executionContext, field, (GraphQLOutputType) fieldType, executionStepInfo);
TypeResolutionParameters resolutionParams = TypeResolutionParameters.newParameters()
.graphQLInterfaceType((GraphQLInterfaceType) fieldType)
.field(field)
.value(source)
.argumentValues(executionStepInfo.getArguments())
.selectionSet(fieldSelectionSet)
.context(executionContext.getContext())
.graphQLContext(executionContext.getGraphQLContext())
.schema(executionContext.getGraphQLSchema()).build();
resolvedType = resolveTypeForInterface(resolutionParams);

resolvedType = resolveTypeForInterface(env, (GraphQLInterfaceType) fieldType);
} else if (fieldType instanceof GraphQLUnionType) {
DataFetchingFieldSelectionSet selectionSet = buildSelectionSet(executionContext, field, (GraphQLOutputType) fieldType, executionStepInfo);
TypeResolutionParameters resolutionParams = TypeResolutionParameters.newParameters()
.graphQLUnionType((GraphQLUnionType) fieldType)
.field(field)
.value(source)
.argumentValues(executionStepInfo.getArguments())
.selectionSet(selectionSet)
.context(executionContext.getContext())
.graphQLContext(executionContext.getGraphQLContext())
.schema(executionContext.getGraphQLSchema()).build();
resolvedType = resolveTypeForUnion(resolutionParams);
resolvedType = resolveTypeForUnion(env, (GraphQLUnionType) fieldType);
} else {
resolvedType = (GraphQLObjectType) fieldType;
}
Expand All @@ -59,28 +50,23 @@ private DataFetchingFieldSelectionSet buildSelectionSet(ExecutionContext executi
return DataFetchingFieldSelectionSetImpl.newCollector(executionContext.getGraphQLSchema(), fieldType, normalizedFieldSupplier);
}

public GraphQLObjectType resolveTypeForInterface(TypeResolutionParameters params) {
TypeResolutionEnvironment env = new TypeResolutionEnvironment(params.getValue(), params.getArgumentValues(), params.getField(), params.getGraphQLInterfaceType(), params.getSchema(), params.getContext(), params.getGraphQLContext(), params.getSelectionSet());
GraphQLInterfaceType abstractType = params.getGraphQLInterfaceType();
TypeResolver typeResolver = params.getSchema().getCodeRegistry().getTypeResolver(abstractType);
return resolveAbstractType(params, env, typeResolver, abstractType);
public GraphQLObjectType resolveTypeForInterface(TypeResolutionEnvironment env, GraphQLInterfaceType abstractType) {
TypeResolver typeResolver = env.getSchema().getCodeRegistry().getTypeResolver(abstractType);
return resolveAbstractType(env, typeResolver, abstractType);
}

public GraphQLObjectType resolveTypeForUnion(TypeResolutionParameters params) {
TypeResolutionEnvironment env = new TypeResolutionEnvironment(params.getValue(), params.getArgumentValues(), params.getField(), params.getGraphQLUnionType(), params.getSchema(), params.getContext(), params.getGraphQLContext(), params.getSelectionSet());
GraphQLUnionType abstractType = params.getGraphQLUnionType();
TypeResolver typeResolver = params.getSchema().getCodeRegistry().getTypeResolver(abstractType);
return resolveAbstractType(params, env, typeResolver, abstractType);
public GraphQLObjectType resolveTypeForUnion(TypeResolutionEnvironment env, GraphQLUnionType abstractType) {
TypeResolver typeResolver = env.getSchema().getCodeRegistry().getTypeResolver(abstractType);
return resolveAbstractType(env, typeResolver, abstractType);
}

private GraphQLObjectType resolveAbstractType(TypeResolutionParameters params, TypeResolutionEnvironment env, TypeResolver typeResolver, GraphQLNamedOutputType abstractType) {
private GraphQLObjectType resolveAbstractType(TypeResolutionEnvironment env, TypeResolver typeResolver, GraphQLNamedOutputType abstractType) {
GraphQLObjectType result = typeResolver.getType(env);

if (result == null) {
throw new UnresolvedTypeException(abstractType);
}

if (!params.getSchema().isPossibleType(abstractType, result)) {
if (!env.getSchema().isPossibleType(abstractType, result)) {
throw new UnresolvedTypeException(abstractType, result);
}

Expand Down
56 changes: 31 additions & 25 deletions src/main/java/graphql/execution/TypeResolutionParameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,51 @@

import graphql.GraphQLContext;
import graphql.Internal;
import graphql.TypeResolutionEnvironment;
import graphql.collect.ImmutableMapWithNullValues;
import graphql.schema.DataFetchingFieldSelectionSet;
import graphql.schema.GraphQLInterfaceType;
import graphql.schema.GraphQLSchema;
import graphql.schema.GraphQLUnionType;
import graphql.schema.GraphQLType;

import java.util.Map;

/**
* This class is a classic builder style one that SHOULD have been on have been on {@link TypeResolutionEnvironment}
* but for legacy reasons was not. So it acts as the builder of {@link TypeResolutionEnvironment} objects
*/
@Internal
public class TypeResolutionParameters {

private final GraphQLInterfaceType graphQLInterfaceType;
private final GraphQLUnionType graphQLUnionType;
private final MergedField field;
private final GraphQLType fieldType;
private final Object value;
private final ImmutableMapWithNullValues<String, Object> argumentValues;
private final GraphQLSchema schema;
private final Object context;
private final Object localContext;
private final GraphQLContext graphQLContext;
private final DataFetchingFieldSelectionSet selectionSet;

private TypeResolutionParameters(Builder builder) {
this.graphQLInterfaceType = builder.graphQLInterfaceType;
this.graphQLUnionType = builder.graphQLUnionType;
this.field = builder.field;
this.fieldType = builder.fieldType;
this.value = builder.value;
this.argumentValues = builder.argumentValues;
this.schema = builder.schema;
this.context = builder.context;
this.graphQLContext = builder.graphQLContext;
this.localContext = builder.localContext;
this.selectionSet = builder.selectionSet;
}

public GraphQLInterfaceType getGraphQLInterfaceType() {
return graphQLInterfaceType;
}

public GraphQLUnionType getGraphQLUnionType() {
return graphQLUnionType;
}

public MergedField getField() {
return field;
}

public GraphQLType getFieldType() {
return fieldType;
}

public Object getValue() {
return value;
}
Expand Down Expand Up @@ -81,30 +81,29 @@ public GraphQLContext getGraphQLContext() {
return graphQLContext;
}

public Object getLocalContext() {
return localContext;
}

public static class Builder {

private MergedField field;
private GraphQLInterfaceType graphQLInterfaceType;
private GraphQLUnionType graphQLUnionType;
private GraphQLType fieldType;
private Object value;
private ImmutableMapWithNullValues<String, Object> argumentValues;
private GraphQLSchema schema;
private Object context;
private GraphQLContext graphQLContext;
private Object localContext;
private DataFetchingFieldSelectionSet selectionSet;

public Builder field(MergedField field) {
this.field = field;
return this;
}

public Builder graphQLInterfaceType(GraphQLInterfaceType graphQLInterfaceType) {
this.graphQLInterfaceType = graphQLInterfaceType;
return this;
}

public Builder graphQLUnionType(GraphQLUnionType graphQLUnionType) {
this.graphQLUnionType = graphQLUnionType;
public Builder fieldType(GraphQLType fieldType) {
this.fieldType = fieldType;
return this;
}

Expand Down Expand Up @@ -134,13 +133,20 @@ public Builder graphQLContext(GraphQLContext context) {
return this;
}

public Builder localContext(Object localContext) {
this.localContext = localContext;
return this;
}

public Builder selectionSet(DataFetchingFieldSelectionSet selectionSet) {
this.selectionSet = selectionSet;
return this;
}

public TypeResolutionParameters build() {
return new TypeResolutionParameters(this);
public TypeResolutionEnvironment build() {
// this build should have always been in TypeResolutionEnvironment but this little workaround improves it a smidge,
// and we can fix it up later so this class is redundant
return new TypeResolutionEnvironment(new TypeResolutionParameters(this));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public FieldSubSelection createFieldSubSelection(ExecutionContext executionConte
Object localContext = resolvedValue.getLocalContext();

GraphQLOutputType sourceType = executionInfo.getUnwrappedNonNullType();
GraphQLObjectType resolvedObjectType = resolveType.resolveType(executionContext, field, source, executionInfo, sourceType);
GraphQLObjectType resolvedObjectType = resolveType.resolveType(executionContext, field, source, executionInfo, sourceType, localContext);
FieldCollectorParameters collectorParameters = newParameters()
.schema(executionContext.getGraphQLSchema())
.objectType(resolvedObjectType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ private FetchedValueAnalysis analyzeFetchedValueImpl(ExecutionContext executionC
.build();
}
try {
GraphQLObjectType resolvedObjectType = resolveType.resolveType(executionContext, field, toAnalyze, executionInfo, fieldType);
GraphQLObjectType resolvedObjectType = resolveType.resolveType(executionContext, field, toAnalyze, executionInfo, fieldType, fetchedValue.getLocalContext());
return newFetchedValueAnalysis(OBJECT)
.fetchedValue(fetchedValue)
.executionStepInfo(executionInfo)
Expand Down
43 changes: 40 additions & 3 deletions src/test/groovy/graphql/TypeResolutionEnvironmentTest.groovy
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package graphql


import graphql.execution.TypeResolutionParameters
import graphql.language.Field
import graphql.schema.GraphQLObjectType
import graphql.schema.TypeResolver
Expand Down Expand Up @@ -36,12 +38,23 @@ class TypeResolutionEnvironmentTest extends Specification {

def schema = TestUtil.schema(idl)

def interfaceType = schema.getType("Foo")

def graphqlContext = GraphQLContext.newContext().of("a", "b").build()

def "basic operations"() {
given:

def environment = new TypeResolutionEnvironment("source", [:], mergedField(new Field("field")), Scalars.GraphQLString, schema, "FooBar", graphqlContext, null)
def environment = TypeResolutionParameters.newParameters()
.value("source")
.argumentValues([a: "b"])
.field(mergedField(new Field("field")))
.fieldType(interfaceType)
.schema(schema)
.context("FooBar")
.graphQLContext(graphqlContext)
.localContext("LocalContext")
.build()

when:

Expand All @@ -50,6 +63,12 @@ class TypeResolutionEnvironmentTest extends Specification {
GraphQLObjectType getType(TypeResolutionEnvironment env) {
String source = env.getObject()
assert source == "source"
assert env.getField().getName() == "field"
assert env.getFieldType() == interfaceType
assert env.getContext() == "FooBar"
assert env.getLocalContext() == "LocalContext"
assert env.getGraphQLContext() == graphqlContext
assert env.getArguments() == [a: "b"]
return schema.getObjectType("FooBar")
}
}
Expand Down Expand Up @@ -96,14 +115,32 @@ class TypeResolutionEnvironmentTest extends Specification {
}

when:
def environmentFooBar = new TypeResolutionEnvironment("source", [:], mergedField(new Field("field")), Scalars.GraphQLString, schema, "FooBar", graphqlContext, null)
def environmentFooBar = TypeResolutionParameters.newParameters()
.value("source")
.argumentValues([:])
.field(mergedField(new Field("field")))
.fieldType(interfaceType)
.schema(schema)
.context("FooBar")
.graphQLContext(graphqlContext)
.build()

def objTypeFooBar = resolverWithContext.getType(environmentFooBar)

then:
objTypeFooBar.name == "FooBar"

when:
def environmentFooImpl = new TypeResolutionEnvironment("source", [:], mergedField(new Field("field")), Scalars.GraphQLString, schema, "Foo", graphqlContext, null)
def environmentFooImpl = TypeResolutionParameters.newParameters()
.value("source")
.argumentValues([:])
.field(mergedField(new Field("field")))
.fieldType(interfaceType)
.schema(schema)
.context("Foo")
.graphQLContext(graphqlContext)
.build()

def objTypeFooImpl = resolverWithContext.getType(environmentFooImpl)

then:
Expand Down
Loading
X Tutup