Skip to content

Commit 496ed16

Browse files
authored
Merge pull request #119 from guy120494/fix-connection
Fix connection
2 parents 4663688 + 55fb330 commit 496ed16

File tree

247 files changed

+772
-85
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

247 files changed

+772
-85
lines changed

README.md

+14-1

build.gradle

+3-4
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ idea {
4444
vcs = 'Git'
4545
}
4646
}
47-
4847
release {
4948
tagTemplate = 'v${version}'
5049
failOnPublishNeeded = false
@@ -152,12 +151,12 @@ bintray {
152151
vcsUrl = 'https://github.com/graphql-java/graphql-java-annotations'
153152
version {
154153
name = project.version
155-
released = new Date()
154+
released = new Date()
156155
}
157156
}
158157
}
159158

160159
task bundle(type: Bundle) {
161-
from sourceSets.main.output
162-
bndfile = file('bundle.bnd')
160+
from sourceSets.main.output
161+
bndfile = file('bundle.bnd')
163162
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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 java.util.Iterator;
18+
19+
public abstract class AbstractPaginatedData<T> implements PaginatedData<T> {
20+
21+
boolean hasPreviousPage;
22+
boolean hasNextPage;
23+
Iterable<T> data;
24+
25+
public AbstractPaginatedData(boolean hasPreviousPage, boolean hasNextPage, Iterable<T> data) {
26+
this.hasNextPage = hasNextPage;
27+
this.hasPreviousPage = hasPreviousPage;
28+
this.data = data;
29+
}
30+
31+
@Override
32+
public boolean hasNextPage() {
33+
return hasNextPage;
34+
}
35+
36+
@Override
37+
public boolean hasPreviousPage() {
38+
return hasPreviousPage;
39+
}
40+
41+
@Override
42+
public Iterator<T> iterator() {
43+
return data.iterator();
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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.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+
28+
public class ConnectionDataFetcher<T> implements DataFetcher<Connection<T>> {
29+
private final DataFetcher<?> actualDataFetcher;
30+
private final Constructor<ConnectionFetcher<T>> constructor;
31+
32+
@SuppressWarnings("unchecked")
33+
public ConnectionDataFetcher(Class<? extends ConnectionFetcher<T>> connection, DataFetcher<?> actualDataFetcher) {
34+
this.actualDataFetcher = actualDataFetcher;
35+
Optional<Constructor<ConnectionFetcher<T>>> constructor =
36+
Arrays.stream(connection.getConstructors()).
37+
filter(c -> c.getParameterCount() == 1).
38+
map(c -> (Constructor<ConnectionFetcher<T>>) c).
39+
findFirst();
40+
if (constructor.isPresent()) {
41+
this.constructor = constructor.get();
42+
} else {
43+
throw new IllegalArgumentException(connection.getSimpleName() + " doesn't have a single argument constructor");
44+
}
45+
}
46+
47+
@Override
48+
public Connection<T> get(DataFetchingEnvironment environment) {
49+
ConnectionFetcher<T> conn = constructNewInstance(constructor, actualDataFetcher);
50+
return conn.get(environment);
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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.Connection;
18+
import graphql.schema.DataFetcher;
19+
20+
public interface ConnectionFetcher<T> extends DataFetcher<Connection<T>> {
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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 java.lang.reflect.AccessibleObject;
18+
19+
public interface ConnectionValidator {
20+
21+
void validate(AccessibleObject field);
22+
}

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

+14-7
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,8 @@
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.annotationTypes;
15+
package graphql.annotations.connection;
1616

17-
import graphql.annotations.dataFetchers.connection.Connection;
18-
import graphql.annotations.dataFetchers.connection.DispatchingConnection;
1917

2018
import java.lang.annotation.ElementType;
2119
import java.lang.annotation.Retention;
@@ -24,7 +22,7 @@
2422

2523
/**
2624
* Specifies that the annotated field or method (given it is also
27-
* annotated with {@link GraphQLField}) is a collection that will
25+
* annotated with {@link graphql.annotations.annotationTypes.GraphQLField}) is a collection that will
2826
* be adhering <a href="https://facebook.github.io/relay/graphql/connections.htm">Relay Connection specification</a>
2927
*
3028
* At the moment, the only allowed type for such field is <code>List&lt;?&gt;</code>
@@ -33,16 +31,25 @@
3331
@Retention(RetentionPolicy.RUNTIME)
3432
public @interface GraphQLConnection {
3533
/**
36-
* By default, a simple List connection is specified, but can be overridden using
37-
* this property to allow for more efficient fetching procedures (limiting database queries, etc.)
34+
* By default, a paginated data connection is specified.
35+
* this property allows for more efficient fetching procedures (limiting database queries, etc.)
36+
* NOTE: if you override this, you should also override the validator field, and specify
37+
* your own connection validator
3838
* @return a connection class
3939
*/
40-
Class<? extends Connection> connection() default DispatchingConnection.class;
40+
Class<? extends ConnectionFetcher> connection() default PaginatedDataConnectionFetcher.class;
4141

4242
/**
4343
* By default, wrapped type's name is used for naming TypeConnection, but can be overridden
4444
* using this property
4545
* @return the wrapped type's name
4646
*/
4747
String name() default "";
48+
49+
/**
50+
* By default, the the validator validates a paginated data connection.
51+
* Can be overridden (and should be) if you are using a custom connection
52+
* @return a connection validator
53+
*/
54+
Class <? extends ConnectionValidator> validator() default PaginatedDataConnectionTypeValidator.class;
4855
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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+
class GraphQLConnectionException extends RuntimeException {
18+
19+
GraphQLConnectionException(String error) {
20+
super(error);
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
/**
18+
* This class is the result of a connection. Every Graphql connection field must return this interface
19+
* <p>
20+
* NOTE: this interface extends Iterable. The data is retrieved from the "iterator" function.
21+
* Please implement the iterator with data structure that has order
22+
*
23+
* @param <T> the data of which we paginated over
24+
*/
25+
public interface PaginatedData<T> extends Iterable<T> {
26+
27+
/**
28+
* Whether or not this is the last page
29+
*
30+
* @return true if there is a next page, false otherwise
31+
*/
32+
boolean hasNextPage();
33+
34+
/**
35+
* Whether or not this is the first page
36+
*
37+
* @return true if there is a previous page, false otherwise
38+
*/
39+
boolean hasPreviousPage();
40+
41+
/**
42+
* get the encoded cursor of the entity
43+
*
44+
* @param entity the entity
45+
* @return String representation of the cursor of the entity
46+
*/
47+
String getCursor(T entity);
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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.*;
18+
import graphql.schema.DataFetcher;
19+
import graphql.schema.DataFetchingEnvironment;
20+
21+
import java.util.ArrayList;
22+
import java.util.Collections;
23+
import java.util.Iterator;
24+
import java.util.List;
25+
26+
/**
27+
* Use this class in {@link GraphQLConnection} to do a real pagination,
28+
* i.e you fetch each time the relevant data, you make the cursors and
29+
* you decide if there are previous or next pages
30+
* <p>
31+
* Note: If you are using the connection, the return type of the associated dataFetcher must implement {@link PaginatedData}
32+
*
33+
* @param <T> the entity type that is paginated
34+
*/
35+
public class PaginatedDataConnectionFetcher<T> implements ConnectionFetcher<T> {
36+
37+
private DataFetcher<PaginatedData<T>> paginationDataFetcher;
38+
39+
public PaginatedDataConnectionFetcher(DataFetcher<PaginatedData<T>> paginationDataFetcher) {
40+
this.paginationDataFetcher = paginationDataFetcher;
41+
}
42+
43+
@Override
44+
public Connection<T> get(DataFetchingEnvironment environment) {
45+
PaginatedData<T> paginatedData = paginationDataFetcher.get(environment);
46+
if (paginatedData == null) {
47+
return new DefaultConnection<>(Collections.emptyList(), new DefaultPageInfo(null,null,false,false));
48+
}
49+
List<Edge<T>> edges = buildEdges(paginatedData);
50+
PageInfo pageInfo = getPageInfo(edges, paginatedData);
51+
return new DefaultConnection<>(edges, pageInfo);
52+
}
53+
54+
private PageInfo getPageInfo(List<Edge<T>> edges, PaginatedData<T> paginatedData) {
55+
ConnectionCursor firstCursor = edges.get(0).getCursor();
56+
ConnectionCursor lastCursor = edges.get(edges.size() - 1).getCursor();
57+
return new DefaultPageInfo(
58+
firstCursor,
59+
lastCursor,
60+
paginatedData.hasPreviousPage(),
61+
paginatedData.hasNextPage()
62+
);
63+
}
64+
65+
private List<Edge<T>> buildEdges(PaginatedData<T> paginatedData) {
66+
Iterator<T> data = paginatedData.iterator();
67+
List<Edge<T>> edges = new ArrayList<>();
68+
for (; data.hasNext(); ) {
69+
T entity = data.next();
70+
edges.add(new DefaultEdge<>(entity, new DefaultConnectionCursor(paginatedData.getCursor(entity))));
71+
}
72+
return edges;
73+
}
74+
}

0 commit comments

Comments
 (0)