Skip to content

Commit d8381e6

Browse files
James Bodkinbclozel
James Bodkin
authored andcommitted
Allow non-nullable types in GraphQL Relay
Closes gh-1173 Signed-off-by: James Bodkin <[email protected]> [[email protected]: remove unrelated test] Signed-off-by: Brian Clozel <[email protected]>
1 parent a6c69eb commit d8381e6

File tree

2 files changed

+51
-7
lines changed

2 files changed

+51
-7
lines changed

Diff for: spring-graphql/src/main/java/org/springframework/graphql/data/pagination/ConnectionFieldTypeVisitor.java

+13-5
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
import graphql.schema.GraphQLList;
4040
import graphql.schema.GraphQLNonNull;
4141
import graphql.schema.GraphQLObjectType;
42-
import graphql.schema.GraphQLOutputType;
4342
import graphql.schema.GraphQLSchemaElement;
4443
import graphql.schema.GraphQLType;
4544
import graphql.schema.GraphQLTypeVisitorStub;
@@ -153,7 +152,7 @@ private static GraphQLObjectType getAsObjectType(@Nullable GraphQLFieldDefinitio
153152
@Nullable
154153
private static GraphQLObjectType getEdgeType(@Nullable GraphQLFieldDefinition field) {
155154
if (getType(field) instanceof GraphQLList listType) {
156-
if (listType.getWrappedType() instanceof GraphQLObjectType type) {
155+
if (unwrapNonNullType(listType.getWrappedType()) instanceof GraphQLObjectType type) {
157156
return type;
158157
}
159158
}
@@ -165,7 +164,14 @@ private static GraphQLType getType(@Nullable GraphQLFieldDefinition field) {
165164
if (field == null) {
166165
return null;
167166
}
168-
GraphQLOutputType type = field.getType();
167+
return unwrapNonNullType(field.getType());
168+
}
169+
170+
@Nullable
171+
private static GraphQLType unwrapNonNullType(@Nullable GraphQLType type) {
172+
if (type == null) {
173+
return null;
174+
}
169175
return (type instanceof GraphQLNonNull nonNullType) ? nonNullType.getWrappedType() : type;
170176
}
171177

@@ -184,14 +190,16 @@ public static ConnectionFieldTypeVisitor create(List<ConnectionAdapter> adapters
184190

185191
/**
186192
* {@code DataFetcher} decorator that adapts return values with an adapter.
193+
* @param delegate the datafetcher delegate
194+
* @param adapter the connection adapter to use
187195
*/
188-
private record ConnectionDataFetcher(DataFetcher<?> delegate, ConnectionAdapter adapter) implements DataFetcher<Object> {
196+
record ConnectionDataFetcher(DataFetcher<?> delegate, ConnectionAdapter adapter) implements DataFetcher<Object> {
189197

190198
private static final Connection<?> EMPTY_CONNECTION =
191199
new DefaultConnection<>(Collections.emptyList(), new DefaultPageInfo(null, null, false, false));
192200

193201

194-
private ConnectionDataFetcher {
202+
ConnectionDataFetcher {
195203
Assert.notNull(delegate, "DataFetcher delegate is required");
196204
Assert.notNull(adapter, "ConnectionAdapter is required");
197205
}

Diff for: spring-graphql/src/test/java/org/springframework/graphql/data/pagination/ConnectionFieldTypeVisitorTests.java

+38-2
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,44 @@ void connectionTypeWithoutEdgesIsNotDecorated() throws Exception {
205205
assertThat(actual).isSameAs(dataFetcher);
206206
}
207207

208+
@Test
209+
void connectionTypeWithNonNullEdgesIsDecorated() throws Exception {
210+
String schemaContent = """
211+
type Query {
212+
libraries(first: Int, after: String, last: Int, before: String): LibraryConnection!
213+
}
214+
215+
type LibraryConnection {
216+
edges: [LibraryEdge!]!
217+
pageInfo: PageInfo!
218+
}
219+
220+
type LibraryEdge {
221+
node: Library!
222+
cursor: String!
223+
}
224+
225+
type Library {
226+
name: String
227+
}
228+
229+
type PageInfo {
230+
hasPreviousPage: Boolean!
231+
hasNextPage: Boolean!
232+
startCursor: String
233+
endCursor: String
234+
}
235+
""";
236+
237+
FieldCoordinates coordinates = FieldCoordinates.coordinates("Query", "libraries");
238+
DataFetcher<?> dataFetcher = env -> null;
239+
240+
DataFetcher<?> actual =
241+
applyConnectionFieldTypeVisitor(schemaContent, coordinates, dataFetcher);
242+
243+
assertThat(actual).isInstanceOf(ConnectionFieldTypeVisitor.ConnectionDataFetcher.class);
244+
}
245+
208246
private static DataFetcher<?> applyConnectionFieldTypeVisitor(
209247
Object schemaSource, FieldCoordinates coordinates, DataFetcher<?> fetcher) throws Exception {
210248

@@ -291,8 +329,6 @@ public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node,
291329
}
292330
}
293331

294-
295-
296332
private static class ListConnectionAdapter implements ConnectionAdapter {
297333

298334
private int initialOffset = 0;

0 commit comments

Comments
 (0)