Skip to content

Commit 4e6dc63

Browse files
authored
Merge pull request #144 from vinayknl/connection-async
Add option to use Asynchronous loading of connection data.
2 parents 4b1da8a + 200e88c commit 4e6dc63

File tree

6 files changed

+83
-7
lines changed

6 files changed

+83
-7
lines changed

src/main/java/graphql/annotations/connection/GraphQLConnection.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,11 @@
5252
* @return a connection validator
5353
*/
5454
Class <? extends ConnectionValidator> validator() default PaginatedDataConnectionTypeValidator.class;
55+
56+
/**
57+
* By default, the paginated data is fetched synchronously. If explicitly specified, asynchronous data fetching
58+
* will be used.
59+
* @return if async fetching to be used.
60+
*/
61+
boolean async() default false;
5562
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Copyright 2016 Yurii Rashkovskii
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
*/
15+
package graphql.annotations.dataFetchers.connection;
16+
17+
import graphql.schema.DataFetcher;
18+
import graphql.schema.DataFetchingEnvironment;
19+
20+
import java.util.concurrent.CompletableFuture;
21+
22+
import static java.util.concurrent.CompletableFuture.supplyAsync;
23+
24+
public class AsyncConnectionDataFetcher<T> implements DataFetcher<CompletableFuture<graphql.relay.Connection<T>>> {
25+
private final ConnectionDataFetcher connectionDataFetcher;
26+
27+
@SuppressWarnings("unchecked")
28+
public AsyncConnectionDataFetcher(ConnectionDataFetcher connectionFetcher) {
29+
this.connectionDataFetcher = connectionFetcher;
30+
}
31+
32+
@Override
33+
public CompletableFuture<graphql.relay.Connection<T>> get(DataFetchingEnvironment environment) {
34+
return supplyAsync(() -> connectionDataFetcher.get(environment));
35+
}
36+
}

src/main/java/graphql/annotations/processor/retrievers/fieldBuilders/field/FieldDataFetcherBuilder.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,20 @@
1919
import graphql.annotations.connection.GraphQLConnection;
2020
import graphql.annotations.dataFetchers.ExtensionDataFetcherWrapper;
2121
import graphql.annotations.dataFetchers.MethodDataFetcher;
22-
import graphql.annotations.dataFetchers.connection.ConnectionDataFetcher;
2322
import graphql.annotations.processor.ProcessingElementsContainer;
2423
import graphql.annotations.processor.retrievers.fieldBuilders.Builder;
2524
import graphql.annotations.processor.typeFunctions.TypeFunction;
2625
import graphql.annotations.processor.util.DataFetcherConstructor;
27-
import graphql.schema.*;
26+
import graphql.schema.DataFetcher;
27+
import graphql.schema.GraphQLNonNull;
28+
import graphql.schema.GraphQLType;
29+
import graphql.schema.PropertyDataFetcher;
2830

2931
import java.lang.reflect.Field;
3032
import java.lang.reflect.Method;
3133

3234
import static graphql.Scalars.GraphQLBoolean;
35+
import static graphql.annotations.processor.util.ConnectionUtil.getConnectionDataFetcher;
3336
import static java.util.Objects.nonNull;
3437

3538
public class FieldDataFetcherBuilder implements Builder<DataFetcher> {
@@ -61,9 +64,8 @@ public DataFetcher build() {
6164
actualDataFetcher = handleNullCase(actualDataFetcher);
6265
}
6366

64-
6567
if (isConnection) {
66-
actualDataFetcher = new ConnectionDataFetcher(field.getAnnotation(GraphQLConnection.class).connection(), actualDataFetcher);
68+
actualDataFetcher = getConnectionDataFetcher(field.getAnnotation(GraphQLConnection.class), actualDataFetcher);
6769
}
6870
return actualDataFetcher;
6971
}
@@ -75,7 +77,7 @@ private DataFetcher handleNullCase(DataFetcher actualDataFetcher) {
7577
actualDataFetcher = getBooleanDataFetcher(actualDataFetcher);
7678
} else if (checkIfPrefixGetterExists(field.getDeclaringClass(), "get", field.getName())) {
7779
actualDataFetcher = wrapExtension(new PropertyDataFetcher(field.getName()), field);
78-
} else{
80+
} else {
7981
actualDataFetcher = getDataFetcherWithFluentGetter(actualDataFetcher);
8082
}
8183

src/main/java/graphql/annotations/processor/retrievers/fieldBuilders/method/MethodDataFetcherBuilder.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import graphql.annotations.dataFetchers.BatchedMethodDataFetcher;
2222
import graphql.annotations.dataFetchers.MethodDataFetcher;
2323
import graphql.annotations.dataFetchers.RelayMutationMethodDataFetcher;
24-
import graphql.annotations.dataFetchers.connection.ConnectionDataFetcher;
2524
import graphql.annotations.processor.ProcessingElementsContainer;
2625
import graphql.annotations.processor.retrievers.fieldBuilders.Builder;
2726
import graphql.annotations.processor.typeFunctions.TypeFunction;
@@ -34,6 +33,8 @@
3433
import java.lang.reflect.Method;
3534
import java.util.List;
3635

36+
import static graphql.annotations.processor.util.ConnectionUtil.getConnectionDataFetcher;
37+
3738
public class MethodDataFetcherBuilder implements Builder<DataFetcher> {
3839
private Method method;
3940
private GraphQLOutputType outputType;
@@ -74,7 +75,7 @@ public DataFetcher build() {
7475
}
7576

7677
if (isConnection){
77-
actualDataFetcher = new ConnectionDataFetcher(method.getAnnotation(GraphQLConnection.class).connection(), actualDataFetcher);
78+
actualDataFetcher = getConnectionDataFetcher(method.getAnnotation(GraphQLConnection.class), actualDataFetcher);
7879
}
7980
return actualDataFetcher;
8081
}

src/main/java/graphql/annotations/processor/util/ConnectionUtil.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
import graphql.annotations.connection.ConnectionValidator;
1818
import graphql.annotations.connection.GraphQLConnection;
19+
import graphql.annotations.dataFetchers.connection.AsyncConnectionDataFetcher;
20+
import graphql.annotations.dataFetchers.connection.ConnectionDataFetcher;
1921
import graphql.schema.*;
2022

2123
import java.lang.reflect.AccessibleObject;
@@ -45,4 +47,12 @@ public static boolean isConnection(AccessibleObject obj, GraphQLType type) {
4547
}
4648
}
4749

50+
public static DataFetcher getConnectionDataFetcher(GraphQLConnection connectionAnnotation, DataFetcher actualDataFetcher) {
51+
actualDataFetcher = new ConnectionDataFetcher(connectionAnnotation.connection(), actualDataFetcher);
52+
if (connectionAnnotation.async()) {
53+
actualDataFetcher = new AsyncConnectionDataFetcher((ConnectionDataFetcher) actualDataFetcher);
54+
}
55+
return actualDataFetcher;
56+
}
57+
4858
}

src/test/java/graphql/annotations/connection/GraphQLEnhancedConnectionTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ public static class TestListField {
8181
@GraphQLDataFetcher(GoodConnectionDataFetcher.class)
8282
public PaginatedData<Obj> objs;
8383

84+
@GraphQLField
85+
@GraphQLConnection(connection = PaginatedDataConnectionFetcher.class, async = true)
86+
@GraphQLDataFetcher(GoodConnectionDataFetcher.class)
87+
public PaginatedData<Obj> objsAsync;
88+
8489
public TestListField(PaginatedData<Obj> objs) {
8590
this.objs = objs;
8691
}
@@ -148,6 +153,21 @@ public void validDatafetcher_queryForCursors_getValidCursors() throws Exception
148153
assertEquals(edges.get(1).get("cursor"), "2");
149154
}
150155

156+
@Test
157+
public void fetchConnectionAsync() throws Exception {
158+
//Arrange
159+
ExecutionInput executionInput = new ExecutionInput("{ objsAsync(first:2) { edges { cursor } } }",
160+
null, "CONTEXT", null, null);
161+
//Act
162+
ExecutionResult result = graphQL.execute(executionInput);
163+
Map<String, Map<String, List<Map<String, Map<String, Object>>>>> data = result.getData();
164+
List<Map<String, Map<String, Object>>> edges = data.get("objsAsync").get("edges");
165+
166+
//Assert
167+
assertEquals(edges.get(0).get("cursor"), "1");
168+
assertEquals(edges.get(1).get("cursor"), "2");
169+
}
170+
151171
@Test
152172
public void validDatafetcher_queryForValues_returnsValidValues() throws Exception {
153173
//Arrange

0 commit comments

Comments
 (0)