Skip to content

Commit 0d3016d

Browse files
authored
Merge pull request #163 from guy120494/custom-paging
Custom paging
2 parents ea31cb2 + 297844c commit 0d3016d

23 files changed

+736
-142
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,3 +307,17 @@ NOTE: because `PropertyDataFetcher` and `FieldDataFetcher` can't handle connecti
307307
By default, GraphQLAnnotations will use the `graphql.relay.Relay` class to create the Relay specific schema types (Mutations, Connections, Edges, PageInfo, ...).
308308
It is possible to set a custom implementation of the Relay class with `GraphQLAnnotations.setRelay` method. The class should inherit from `graphql.relay.Relay` and
309309
can redefine methods that create Relay types.
310+
311+
It is also possible to specify for every connection which relay do you want to use, by giving a value to the annotation:
312+
`@GraphQLConnection(connectionType = customRelay.class)`. If you do that, please also give values to `connectionFetcher`
313+
and `validator`.
314+
315+
There is also a support for simple paging, without "Nodes" and "Edges". To use it, annotate you connection like that:
316+
`@GraphQLConnection(connectionFetcher = SimplePaginatedDataConnectionFetcher.class, connectionType = SimpleRelay.class, validator = SimplePaginatedDataConnectionTypeValidator.class)`
317+
and the return type must be of type `SimplePaginatedData`.
318+
It has 2 methods:
319+
1. `getTotalCount` - how many elements are there in total
320+
2. `getData` - get the data
321+
322+
For you convenience, there are two classes that you can use: `AbstractSimplePaginatedData` and `SimplePaginatedDataImpl`
323+
For examples, look at the tests

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ buildscript {
1111
}
1212
}
1313
plugins {
14-
id "com.github.hierynomus.license" version "0.12.1"
1514
id "com.jfrog.bintray" version "1.7"
1615
id 'net.researchgate.release' version '2.3.4'
16+
id "com.github.hierynomus.license" version "0.14.0"
1717
}
1818

1919
apply plugin: 'java'
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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.connection;
16+
17+
import graphql.relay.Relay;
18+
19+
/**
20+
* This class is just for the library to know whether to use the relay in the container or not
21+
*/
22+
public final class FakeRelay extends Relay {
23+
}

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
package graphql.annotations.connection;
1616

1717

18+
import graphql.relay.Relay;
19+
1820
import java.lang.annotation.ElementType;
1921
import java.lang.annotation.Retention;
2022
import java.lang.annotation.RetentionPolicy;
@@ -27,7 +29,7 @@
2729
*
2830
* At the moment, the only allowed type for such field is <code>List&lt;?&gt;</code>
2931
*/
30-
@Target({ElementType.FIELD, ElementType.METHOD})
32+
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
3133
@Retention(RetentionPolicy.RUNTIME)
3234
public @interface GraphQLConnection {
3335
/**
@@ -37,7 +39,7 @@
3739
* your own connection validator
3840
* @return a connection class
3941
*/
40-
Class<? extends ConnectionFetcher> connection() default PaginatedDataConnectionFetcher.class;
42+
Class<? extends ConnectionFetcher> connectionFetcher() default PaginatedDataConnectionFetcher.class;
4143

4244
/**
4345
* By default, wrapped type's name is used for naming TypeConnection, but can be overridden
@@ -59,4 +61,12 @@
5961
* @return if async fetching to be used.
6062
*/
6163
boolean async() default false;
64+
65+
/**
66+
* By default, the relay connection that the container has is used. If you want to change the way connection works
67+
* (For example, you don't want edges and nodes), override the {@link Relay} class and specify it.
68+
*
69+
* @return a class that represents the connection type
70+
*/
71+
Class<? extends Relay> connectionType() default FakeRelay.class;
6272
}

src/main/java/graphql/annotations/connection/SimplePaginatedData.java renamed to src/main/java/graphql/annotations/connection/NaivePaginatedData.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@
1919

2020
import static java.util.Base64.getEncoder;
2121

22-
public class SimplePaginatedData<T> extends AbstractPaginatedData<T> {
22+
public class NaivePaginatedData<T> extends AbstractPaginatedData<T> {
2323
private static final String DUMMY_CURSOR_PREFIX = "simple-cursor";
2424
private final String prefix;
2525

26-
public SimplePaginatedData(boolean hasPreviousPage, boolean hasNextPage, Iterable<T> data) {
26+
public NaivePaginatedData(boolean hasPreviousPage, boolean hasNextPage, Iterable<T> data) {
2727
this(hasPreviousPage, hasNextPage, data, DUMMY_CURSOR_PREFIX);
2828
}
2929

30-
public SimplePaginatedData(boolean hasPreviousPage, boolean hasNextPage, Iterable<T> data, String prefix) {
30+
public NaivePaginatedData(boolean hasPreviousPage, boolean hasNextPage, Iterable<T> data, String prefix) {
3131
super(hasPreviousPage, hasNextPage, data);
3232
this.prefix = prefix;
3333
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717

1818
import graphql.annotations.annotationTypes.GraphQLDataFetcher;
19+
import graphql.annotations.connection.exceptions.GraphQLConnectionException;
1920

2021
import java.lang.reflect.AccessibleObject;
2122
import java.lang.reflect.Field;

src/main/java/graphql/annotations/connection/GraphQLConnectionException.java renamed to src/main/java/graphql/annotations/connection/exceptions/GraphQLConnectionException.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
* See the License for the specific language governing permissions and
1414
*/
15-
package graphql.annotations.connection;
15+
package graphql.annotations.connection.exceptions;
1616

17-
class GraphQLConnectionException extends RuntimeException {
17+
public class GraphQLConnectionException extends RuntimeException {
1818

19-
GraphQLConnectionException(String error) {
19+
public GraphQLConnectionException(String error) {
2020
super(error);
2121
}
2222
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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.connection.simple;
16+
17+
import java.util.ArrayList;
18+
import java.util.Iterator;
19+
import java.util.List;
20+
21+
public abstract class AbstractSimplePaginatedData<T> implements SimplePaginatedData<T> {
22+
private Iterable<T> data;
23+
24+
public AbstractSimplePaginatedData(Iterable<T> data) {
25+
this.data = data;
26+
}
27+
28+
@Override
29+
public Iterator<T> iterator() {
30+
return data.iterator();
31+
}
32+
33+
@Override
34+
public List<T> getData() {
35+
List<T> dataList = new ArrayList<>();
36+
data.forEach(dataList::add);
37+
return dataList;
38+
}
39+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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.connection.simple;
16+
17+
18+
import graphql.relay.Connection;
19+
import graphql.relay.Edge;
20+
import graphql.relay.PageInfo;
21+
22+
import java.util.List;
23+
24+
/**
25+
* This is a more intuitive implementation for paging. You send back only the data that is requested,
26+
* along with "overall" - the amount of all the entities
27+
*
28+
* @param <T> The type of the entities
29+
*/
30+
public interface SimpleConnection<T> extends Connection<T> {
31+
32+
/**
33+
* Get the list of the entities
34+
*
35+
* @return List of entities
36+
*/
37+
List<T> getData();
38+
39+
/**
40+
* The amount of entities
41+
*
42+
* @return The amount of entities
43+
*/
44+
long getTotalCount();
45+
46+
@Override
47+
default List<Edge<T>> getEdges() {
48+
throw new UnsupportedOperationException("Simple paging doesn't have edges");
49+
}
50+
51+
@Override
52+
default PageInfo getPageInfo() {
53+
throw new UnsupportedOperationException("Simple paging doesn't have page info");
54+
}
55+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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.connection.simple;
16+
17+
import graphql.relay.Connection;
18+
import graphql.schema.DataFetcher;
19+
import graphql.schema.DataFetchingEnvironment;
20+
21+
import java.lang.reflect.Constructor;
22+
import java.util.Arrays;
23+
import java.util.Optional;
24+
25+
import static graphql.annotations.processor.util.ReflectionKit.constructNewInstance;
26+
27+
public class SimpleConnectionDataFetcher<T> implements SimpleConnectionFetcher<T> {
28+
private final DataFetcher<?> actualDataFetcher;
29+
private final Constructor<SimpleConnectionFetcher<T>> constructor;
30+
31+
@SuppressWarnings("unchecked")
32+
public SimpleConnectionDataFetcher(Class<? extends SimpleConnectionFetcher<T>> connection, DataFetcher<?> actualDataFetcher) {
33+
this.actualDataFetcher = actualDataFetcher;
34+
Optional<Constructor<SimpleConnectionFetcher<T>>> constructor =
35+
Arrays.stream(connection.getConstructors()).
36+
filter(c -> c.getParameterCount() == 1).
37+
map(c -> (Constructor<SimpleConnectionFetcher<T>>) c).
38+
findFirst();
39+
if (constructor.isPresent()) {
40+
this.constructor = constructor.get();
41+
} else {
42+
throw new IllegalArgumentException(connection.getSimpleName() + " doesn't have a single argument constructor");
43+
}
44+
}
45+
46+
@Override
47+
public Connection<T> get(DataFetchingEnvironment environment) {
48+
SimpleConnectionFetcher<T> conn = constructNewInstance(constructor, actualDataFetcher);
49+
return conn.get(environment);
50+
}
51+
}

0 commit comments

Comments
 (0)