Skip to content

Commit 3db0e51

Browse files
authored
fix(GH-224): HHH000104: firstResult/maxResults specified with collection fetch; applying in memory (#229)
* feat: Added initial support for streaming result list from query stream * refactor: Wrapped result stream with Java proxy instance * feat: Added initial query results stream support * fix: Added text/event-stream HTTP content negotiation for /graphql endpoint * feat: Added support for SSE id,event,data spec * chore: cleanup * feat(test): Added test `@defer` streaming * fix: Added SseEventBuilder wrapper * refactor(web): Use Spring `@Transactional` annotation with read only * fix(autoconfigure): Added support for merging additional types * fix: firstResult/maxResults specified with collection fetch; applying in memory! * fix: Added support for idClass attributes in keys query * fix: Corrected keys query predicates for id class attributes * refactor: Added hasIdAttribute and hasIdClassAttribute conditional check * chore: polish * refactor: Replaced constructors with builders for data fetchers * fix: Revert paginationArgument to static final field * refactor: Let's use Logical enum names for GraphQL input types
1 parent 09dd88c commit 3db0e51

File tree

19 files changed

+1963
-452
lines changed

19 files changed

+1963
-452
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ target/
2121
.project
2222
.springBeans
2323
.classpath
24-
2524
.externalToolBuilders
25+
.sts4-cache
2626

27+
# Scala
28+
.cache-main
29+
.cache-tests

graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLSchemaFactoryBean.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@
44
import static graphql.schema.FieldCoordinates.coordinates;
55
import static graphql.util.TraversalControl.CONTINUE;
66

7+
import java.util.Arrays;
78
import java.util.Collection;
89
import java.util.List;
10+
import java.util.Map;
911
import java.util.Objects;
1012
import java.util.Optional;
13+
import java.util.Set;
14+
import java.util.concurrent.ConcurrentHashMap;
15+
import java.util.function.Function;
16+
import java.util.function.Predicate;
1117
import java.util.stream.Collectors;
1218
import java.util.stream.Stream;
1319

@@ -17,6 +23,7 @@
1723
import graphql.schema.DataFetcher;
1824
import graphql.schema.FieldCoordinates;
1925
import graphql.schema.GraphQLCodeRegistry;
26+
import graphql.schema.GraphQLDirective;
2027
import graphql.schema.GraphQLFieldDefinition;
2128
import graphql.schema.GraphQLFieldsContainer;
2229
import graphql.schema.GraphQLInterfaceType;
@@ -116,6 +123,26 @@ protected GraphQLSchema createInstance() throws Exception {
116123
.flatMap(Collection::stream)
117124
.collect(Collectors.toList());
118125

126+
Set<GraphQLDirective> directives = Stream.of(managedGraphQLSchemas)
127+
.map(GraphQLSchema::getDirectives)
128+
.flatMap(Collection::stream)
129+
.filter(distinctByKeys(GraphQLDirective::getName))
130+
.collect(Collectors.toSet());
131+
132+
if(!directives.isEmpty()) {
133+
schemaBuilder.additionalDirectives(directives);
134+
}
135+
136+
Set<GraphQLType> types = Stream.of(managedGraphQLSchemas)
137+
.map(GraphQLSchema::getAdditionalTypes)
138+
.flatMap(Collection::stream)
139+
.filter(distinctByKeys(GraphQLType::getName))
140+
.distinct()
141+
.collect(Collectors.toSet());
142+
if (!types.isEmpty()) {
143+
schemaBuilder.additionalTypes(types);
144+
}
145+
119146
if(!mutations.isEmpty())
120147
schemaBuilder.mutation(GraphQLObjectType.newObject()
121148
.name(this.mutationName)
@@ -137,6 +164,19 @@ protected GraphQLSchema createInstance() throws Exception {
137164
return schemaBuilder.codeRegistry(codeRegistryBuilder.build())
138165
.build();
139166
}
167+
168+
@SafeVarargs
169+
private static <T> Predicate<T> distinctByKeys(Function<? super T, ?>... keyExtractors) {
170+
final Map<List<?>, Boolean> seen = new ConcurrentHashMap<>();
171+
172+
return t -> {
173+
final List<?> keys = Arrays.stream(keyExtractors)
174+
.map(ke -> ke.apply(t))
175+
.collect(Collectors.toList());
176+
177+
return seen.putIfAbsent(keys, Boolean.TRUE) == null;
178+
};
179+
}
140180

141181
@Override
142182
public Class<?> getObjectType() {

graphql-jpa-query-autoconfigure/src/test/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLSchemaAutoConfigurationTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.introproventures.graphql.jpa.query.autoconfigure.support.QueryRoot;
2828
import com.introproventures.graphql.jpa.query.autoconfigure.support.SubscriptionRoot;
2929

30+
import graphql.Directives;
3031
import graphql.GraphQL;
3132
import graphql.Scalars;
3233
import graphql.annotations.AnnotationsSchemaCreator;
@@ -36,6 +37,7 @@
3637
import graphql.annotations.annotationTypes.directives.definition.GraphQLDirectiveDefinition;
3738
import graphql.schema.FieldCoordinates;
3839
import graphql.schema.GraphQLCodeRegistry;
40+
import graphql.schema.GraphQLDirective;
3941
import graphql.schema.GraphQLFieldDefinition;
4042
import graphql.schema.GraphQLObjectType;
4143
import graphql.schema.GraphQLSchema;
@@ -201,6 +203,7 @@ public void configure(GraphQLShemaRegistration registry) {
201203
GraphQLSchema graphQLSchema = GraphQLSchema.newSchema()
202204
.query(query)
203205
.codeRegistry(codeRegistry)
206+
.additionalDirective(Directives.DeferDirective)
204207
.build();
205208

206209
registry.register(graphQLSchema);
@@ -216,6 +219,14 @@ public void contextLoads() {
216219

217220
}
218221

222+
@Test
223+
public void directivesSupport() {
224+
assertThat(graphQLSchema.getDirectives())
225+
.extracting(GraphQLDirective::getName)
226+
.containsExactly("include", "skip", "defer");
227+
228+
}
229+
219230
@Test
220231
public void querySchemaConfigurer() {
221232
// given

graphql-jpa-query-schema/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@
2727
<groupId>org.atteo</groupId>
2828
<artifactId>evo-inflector</artifactId>
2929
</dependency>
30+
31+
<dependency>
32+
<groupId>io.projectreactor</groupId>
33+
<artifactId>reactor-core</artifactId>
34+
</dependency>
3035

3136
<dependency>
3237
<groupId>org.slf4j</groupId>

graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/EntityIntrospector.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.slf4j.Logger;
2828
import org.slf4j.LoggerFactory;
2929

30+
import com.introproventures.graphql.jpa.query.annotation.GraphQLDefaultOrderBy;
3031
import com.introproventures.graphql.jpa.query.annotation.GraphQLDescription;
3132
import com.introproventures.graphql.jpa.query.annotation.GraphQLIgnore;
3233
import com.introproventures.graphql.jpa.query.introspection.ClassDescriptor;
@@ -284,6 +285,14 @@ public Optional<String> getSchemaDescription() {
284285
public boolean hasSchemaDescription() {
285286
return getSchemaDescription().isPresent();
286287
}
288+
289+
public boolean hasDefaultOrderBy() {
290+
return getDefaultOrderBy().isPresent();
291+
}
292+
293+
public Optional<GraphQLDefaultOrderBy> getDefaultOrderBy() {
294+
return getAnnotation(GraphQLDefaultOrderBy.class);
295+
}
287296

288297
public boolean isTransient() {
289298
return !attribute.isPresent();

0 commit comments

Comments
 (0)