Skip to content

Commit a3d2fde

Browse files
author
Thomas Draier
committed
Handle GraphQLConnection on fields/method with GraphQLNonNull. Allows to return null on a connection field if not set to non-null.
1 parent c20332f commit a3d2fde

File tree

2 files changed

+86
-25
lines changed

2 files changed

+86
-25
lines changed

src/main/java/graphql/annotations/GraphQLAnnotations.java

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -470,12 +470,13 @@ protected GraphQLFieldDefinition getField(Field field) throws GraphQLAnnotations
470470
typeFunction = newInstance(annotation.value());
471471
}
472472

473-
GraphQLOutputType type = (GraphQLOutputType) typeFunction.buildType(field.getType(), field.getAnnotatedType());
473+
GraphQLOutputType outputType = (GraphQLOutputType) typeFunction.buildType(field.getType(), field.getAnnotatedType());
474+
outputType = field.getAnnotation(NotNull.class) == null ? outputType : new GraphQLNonNull(outputType);
474475

475-
GraphQLOutputType outputType = field.getAnnotation(NotNull.class) == null ? type : new GraphQLNonNull(type);
476-
477-
boolean isConnection = isConnection(field, field.getType(), type);
478-
outputType = getGraphQLConnection(isConnection, field, type, outputType, builder);
476+
boolean isConnection = isConnection(field, outputType);
477+
if (isConnection) {
478+
outputType = getGraphQLConnection(field, outputType, builder);
479+
}
479480

480481
builder.type(outputType);
481482

@@ -575,24 +576,35 @@ private boolean checkIfPrefixGetterExists(Class c, String prefix, String propert
575576
return true;
576577
}
577578

578-
private GraphQLOutputType getGraphQLConnection(boolean isConnection, AccessibleObject field, GraphQLOutputType type, GraphQLOutputType outputType, GraphQLFieldDefinition.Builder builder) {
579-
if (isConnection) {
580-
if (type instanceof GraphQLList) {
581-
graphql.schema.GraphQLType wrappedType = ((GraphQLList) type).getWrappedType();
582-
assert wrappedType instanceof GraphQLObjectType;
583-
String annValue = field.getAnnotation(GraphQLConnection.class).name();
584-
String connectionName = annValue.isEmpty() ? wrappedType.getName() : annValue;
585-
GraphQLObjectType edgeType = relay.edgeType(connectionName, (GraphQLOutputType) wrappedType, null, Collections.<GraphQLFieldDefinition>emptyList());
586-
outputType = relay.connectionType(connectionName, edgeType, Collections.emptyList());
587-
builder.argument(relay.getConnectionFieldArguments());
588-
}
579+
private GraphQLOutputType getGraphQLConnection(AccessibleObject field, GraphQLOutputType type, GraphQLFieldDefinition.Builder builder) {
580+
boolean isNonNull = (type instanceof GraphQLNonNull);
581+
if (isNonNull) {
582+
type = (GraphQLOutputType) ((GraphQLNonNull) type).getWrappedType();
583+
}
584+
585+
if (type instanceof GraphQLList) {
586+
graphql.schema.GraphQLType wrappedType = ((GraphQLList) type).getWrappedType();
587+
assert wrappedType instanceof GraphQLObjectType;
588+
String annValue = field.getAnnotation(GraphQLConnection.class).name();
589+
String connectionName = annValue.isEmpty() ? wrappedType.getName() : annValue;
590+
GraphQLObjectType edgeType = relay.edgeType(connectionName, (GraphQLOutputType) wrappedType, null, Collections.<GraphQLFieldDefinition>emptyList());
591+
type = relay.connectionType(connectionName, edgeType, Collections.emptyList());
592+
builder.argument(relay.getConnectionFieldArguments());
589593
}
590-
return outputType;
594+
595+
if (isNonNull) {
596+
type = new GraphQLNonNull(type);
597+
}
598+
return type;
591599
}
592600

593-
private boolean isConnection(AccessibleObject obj, Class<?> klass, GraphQLOutputType type) {
601+
private boolean isConnection(AccessibleObject obj, GraphQLOutputType type) {
602+
if (type instanceof GraphQLNonNull) {
603+
type = (GraphQLOutputType) ((GraphQLNonNull) type).getWrappedType();
604+
}
605+
final GraphQLOutputType wrappedType = type;
594606
return obj.isAnnotationPresent(GraphQLConnection.class) &&
595-
type instanceof GraphQLList && TYPES_FOR_CONNECTION.stream().anyMatch(aClass -> aClass.isInstance(((GraphQLList) type).getWrappedType()));
607+
wrappedType instanceof GraphQLList && TYPES_FOR_CONNECTION.stream().anyMatch(aClass -> aClass.isInstance(((GraphQLList) wrappedType).getWrappedType()));
596608
}
597609

598610
protected GraphQLFieldDefinition getField(Method method) throws GraphQLAnnotationsException {
@@ -618,11 +630,13 @@ protected GraphQLFieldDefinition getField(Method method) throws GraphQLAnnotatio
618630
outputTypeFunction = typeFunction;
619631
}
620632

621-
GraphQLOutputType type = (GraphQLOutputType) outputTypeFunction.buildType(method.getReturnType(), annotatedReturnType);
622-
GraphQLOutputType outputType = method.getAnnotation(NotNull.class) == null ? type : new GraphQLNonNull(type);
633+
GraphQLOutputType outputType = (GraphQLOutputType) outputTypeFunction.buildType(method.getReturnType(), annotatedReturnType);
634+
outputType = method.getAnnotation(NotNull.class) == null ? outputType : new GraphQLNonNull(outputType);
623635

624-
boolean isConnection = isConnection(method, method.getReturnType(), type);
625-
outputType = getGraphQLConnection(isConnection, method, type, outputType, builder);
636+
boolean isConnection = isConnection(method, outputType);
637+
if (isConnection) {
638+
outputType = getGraphQLConnection(method, outputType, builder);
639+
}
626640

627641
builder.type(outputType);
628642

@@ -837,8 +851,12 @@ public Object get(DataFetchingEnvironment environment) {
837851
DataFetchingEnvironment env = new DataFetchingEnvironmentImpl(environment.getSource(), arguments, environment.getContext(),
838852
environment.getFields(), environment.getFieldType(), environment.getParentType(), environment.getGraphQLSchema(),
839853
environment.getFragmentsByName(), environment.getExecutionId(), environment.getSelectionSet());
840-
Connection conn = constructNewInstance(constructor, actualDataFetcher.get(env));
841-
return conn.get(environment);
854+
Object data = actualDataFetcher.get(env);
855+
if (data != null) {
856+
Connection conn = constructNewInstance(constructor, data);
857+
return conn.get(environment);
858+
}
859+
return null;
842860
}
843861
}
844862

src/test/java/graphql/annotations/GraphQLConnectionTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,19 @@ public Stream<Obj> getObjStreamWithParam(@GraphQLName("filter") String filter) {
104104
return this.objs.stream().filter( obj -> obj.val.startsWith(filter));
105105
}
106106

107+
@GraphQLField
108+
@GraphQLConnection(name = "nonNullObjs")
109+
@GraphQLNonNull
110+
public List<Obj> getNonNullObjs() {
111+
return this.objs;
112+
}
113+
114+
@GraphQLField
115+
@GraphQLConnection(name = "null")
116+
public List<Obj> getNull() {
117+
return null;
118+
}
119+
107120

108121
}
109122

@@ -164,6 +177,36 @@ public void methodStream() {
164177
testResult("objStream", result);
165178
}
166179

180+
@Test
181+
public void methodNonNull() {
182+
GraphQLObjectType object = GraphQLAnnotations.object(TestConnections.class);
183+
GraphQLSchema schema = newSchema().query(object).build();
184+
185+
GraphQL graphQL = GraphQL.newGraphQL(schema).build();
186+
ExecutionResult result = graphQL.execute("{ nonNullObjs(first: 1) { edges { cursor node { id, val } } } }",
187+
new TestConnections(Arrays.asList(new Obj("1", "test"), new Obj("2", "hello"), new Obj("3", "world"))));
188+
189+
assertTrue(result.getErrors().isEmpty());
190+
191+
testResult("nonNullObjs", result);
192+
}
193+
194+
@Test
195+
public void methodNull() {
196+
GraphQLObjectType object = GraphQLAnnotations.object(TestConnections.class);
197+
GraphQLSchema schema = newSchema().query(object).build();
198+
199+
GraphQL graphQL = GraphQL.newGraphQL(schema).build();
200+
ExecutionResult result = graphQL.execute("{ null(first: 1) { edges { cursor node { id, val } } } }",
201+
new TestConnections(Arrays.asList(new Obj("1", "test"), new Obj("2", "hello"), new Obj("3", "world"))));
202+
203+
assertTrue(result.getErrors().isEmpty());
204+
205+
Map<String, Map<String, List<Map<String, Map<String, Object>>>>> data = result.getData();
206+
207+
assertEquals(data.get("null"), null);
208+
}
209+
167210
@Test
168211
public void methodListWithParam() {
169212
GraphQLObjectType object = GraphQLAnnotations.object(TestConnections.class);

0 commit comments

Comments
 (0)