Skip to content

Commit 7315720

Browse files
authored
fix: add enable result stream feature for JPA queries (#317)
1 parent bed8bba commit 7315720

19 files changed

+2562
-2425
lines changed

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

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,6 @@
1515
*/
1616
package com.introproventures.graphql.jpa.query.schema.impl;
1717

18-
import static com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder.SELECT_DISTINCT_PARAM_NAME;
19-
import static com.introproventures.graphql.jpa.query.support.GraphQLSupport.getObjectField;
20-
import static com.introproventures.graphql.jpa.query.support.GraphQLSupport.isAfterArgument;
21-
import static com.introproventures.graphql.jpa.query.support.GraphQLSupport.isDistinctArgument;
22-
import static com.introproventures.graphql.jpa.query.support.GraphQLSupport.isFirstArgument;
23-
import static com.introproventures.graphql.jpa.query.support.GraphQLSupport.isLogicalArgument;
24-
import static com.introproventures.graphql.jpa.query.support.GraphQLSupport.isPageArgument;
25-
import static com.introproventures.graphql.jpa.query.support.GraphQLSupport.isWhereArgument;
26-
import static graphql.introspection.Introspection.SchemaMetaFieldDef;
27-
import static graphql.introspection.Introspection.TypeMetaFieldDef;
28-
import static graphql.introspection.Introspection.TypeNameMetaFieldDef;
29-
import static java.util.stream.Collectors.groupingBy;
30-
3118
import java.beans.BeanInfo;
3219
import java.beans.Introspector;
3320
import java.beans.PropertyDescriptor;
@@ -52,7 +39,6 @@
5239
import java.util.stream.Collectors;
5340
import java.util.stream.IntStream;
5441
import java.util.stream.Stream;
55-
5642
import javax.persistence.EntityManager;
5743
import javax.persistence.TypedQuery;
5844
import javax.persistence.criteria.AbstractQuery;
@@ -74,11 +60,6 @@
7460
import javax.persistence.metamodel.PluralAttribute;
7561
import javax.persistence.metamodel.SingularAttribute;
7662
import javax.persistence.metamodel.Type;
77-
78-
import graphql.execution.CoercedVariables;
79-
import org.slf4j.Logger;
80-
import org.slf4j.LoggerFactory;
81-
8263
import com.introproventures.graphql.jpa.query.annotation.GraphQLDefaultOrderBy;
8364
import com.introproventures.graphql.jpa.query.introspection.ReflectionUtil;
8465
import com.introproventures.graphql.jpa.query.schema.JavaScalars;
@@ -87,8 +68,8 @@
8768
import com.introproventures.graphql.jpa.query.schema.impl.EntityIntrospector.EntityIntrospectionResult.AttributePropertyDescriptor;
8869
import com.introproventures.graphql.jpa.query.schema.impl.PredicateFilter.Criteria;
8970
import com.introproventures.graphql.jpa.query.support.GraphQLSupport;
90-
9171
import graphql.GraphQLException;
72+
import graphql.execution.CoercedVariables;
9273
import graphql.execution.MergedField;
9374
import graphql.execution.ValuesResolver;
9475
import graphql.language.Argument;
@@ -113,6 +94,21 @@
11394
import graphql.schema.GraphQLScalarType;
11495
import graphql.schema.GraphQLSchema;
11596
import graphql.schema.GraphQLType;
97+
import org.slf4j.Logger;
98+
import org.slf4j.LoggerFactory;
99+
100+
import static com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder.SELECT_DISTINCT_PARAM_NAME;
101+
import static com.introproventures.graphql.jpa.query.support.GraphQLSupport.getObjectField;
102+
import static com.introproventures.graphql.jpa.query.support.GraphQLSupport.isAfterArgument;
103+
import static com.introproventures.graphql.jpa.query.support.GraphQLSupport.isDistinctArgument;
104+
import static com.introproventures.graphql.jpa.query.support.GraphQLSupport.isFirstArgument;
105+
import static com.introproventures.graphql.jpa.query.support.GraphQLSupport.isLogicalArgument;
106+
import static com.introproventures.graphql.jpa.query.support.GraphQLSupport.isPageArgument;
107+
import static com.introproventures.graphql.jpa.query.support.GraphQLSupport.isWhereArgument;
108+
import static graphql.introspection.Introspection.SchemaMetaFieldDef;
109+
import static graphql.introspection.Introspection.TypeMetaFieldDef;
110+
import static graphql.introspection.Introspection.TypeNameMetaFieldDef;
111+
import static java.util.stream.Collectors.groupingBy;
116112

117113
/**
118114
* Provides implemetation for GraphQL JPA Query Factory
@@ -143,6 +139,7 @@ public final class GraphQLJpaQueryFactory {
143139
private final GraphQLObjectType entityObjectType;
144140
private final int defaultFetchSize;
145141
private final RestrictedKeysProvider restrictedKeysProvider;
142+
private final boolean resultStream;
146143

147144
private GraphQLJpaQueryFactory(Builder builder) {
148145
this.entityManager = builder.entityManager;
@@ -153,6 +150,7 @@ private GraphQLJpaQueryFactory(Builder builder) {
153150
this.defaultDistinct = builder.defaultDistinct;
154151
this.defaultFetchSize = builder.defaultFetchSize;
155152
this.restrictedKeysProvider = builder.restrictedKeysProvider;
153+
this.resultStream = builder.resultStream;
156154
}
157155

158156
public DataFetchingEnvironment getQueryEnvironment(DataFetchingEnvironment environment,
@@ -260,7 +258,12 @@ protected <T> Stream<T> getResultStream(TypedQuery<T> query,
260258
logger.info("\nGraphQL JPQL Fetch Query String:\n {}", getJPQLQueryString(query));
261259
}
262260

263-
// Let's execute query and get wrap result into stream
261+
if (resultStream) {
262+
return query.getResultStream()
263+
.peek(entityManager::detach);
264+
}
265+
266+
// Let's execute query and wrap result into stream
264267
return query.getResultList()
265268
.stream()
266269
.peek(entityManager::detach);
@@ -1952,6 +1955,13 @@ public interface IBuildStage {
19521955
*/
19531956
public IBuildStage withDefaultDistinct(boolean defaultDistinct);
19541957

1958+
/**
1959+
* Builder method for resultStream parameter.
1960+
* @param resultStream field to set
1961+
* @return builder
1962+
*/
1963+
public IBuildStage withResultStream(boolean resultStream);
1964+
19551965
/**
19561966
* Builder method for defaultFetchSize parameter.
19571967
* @param defaultFetchSize field to set
@@ -1987,6 +1997,7 @@ public static final class Builder implements IEntityManagerStage, IEntityTypeSta
19871997
private boolean toManyDefaultOptional = true;
19881998
private boolean defaultDistinct = true;
19891999
private int defaultFetchSize = 100;
2000+
private boolean resultStream = false;
19902001

19912002
private Builder() {
19922003
}
@@ -2027,6 +2038,12 @@ public IBuildStage withDefaultDistinct(boolean defaultDistinct) {
20272038
return this;
20282039
}
20292040

2041+
@Override
2042+
public IBuildStage withResultStream(boolean resultStream) {
2043+
this.resultStream = resultStream;
2044+
return this;
2045+
}
2046+
20302047
@Override
20312048
public IBuildStage withDefaultFetchSize(int defaultFetchSize) {
20322049
this.defaultFetchSize = defaultFetchSize;
@@ -2038,7 +2055,7 @@ public IBuildStage withRestrictedKeysProvider(RestrictedKeysProvider restrictedK
20382055
this.restrictedKeysProvider = restrictedKeysProvider;
20392056
return this;
20402057
}
2041-
2058+
20422059
@Override
20432060
public GraphQLJpaQueryFactory build() {
20442061
Objects.requireNonNull(restrictedKeysProvider, "restrictedKeysProvider must not be null");

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ public class GraphQLJpaSchemaBuilder implements GraphQLSchemaBuilder {
130130
private int defaultFetchSize = 100;
131131
private int defaultPageLimitSize = 100;
132132
private boolean enableDefaultMaxResults = true;
133+
private boolean enableResultStream = false;
133134

134135
private RestrictedKeysProvider restrictedKeysProvider = (entityDescriptor) -> Optional.of(Collections.emptyList());
135136

@@ -216,6 +217,7 @@ private GraphQLFieldDefinition getQueryFieldByIdDefinition(EntityType<?> entityT
216217
.withSelectNodeName(entityObjectType.getName())
217218
.withToManyDefaultOptional(toManyDefaultOptional)
218219
.withRestrictedKeysProvider(restrictedKeysProvider)
220+
.withResultStream(enableResultStream)
219221
.build();
220222

221223
DataFetcher<Object> dataFetcher = GraphQLJpaSimpleDataFetcher.builder()
@@ -259,6 +261,7 @@ private GraphQLFieldDefinition getQueryFieldSelectDefinition(EntityType<?> entit
259261
.withDefaultDistinct(isDefaultDistinct)
260262
.withDefaultFetchSize(defaultFetchSize)
261263
.withRestrictedKeysProvider(restrictedKeysProvider)
264+
.withResultStream(enableResultStream)
262265
.build();
263266

264267
if(enableRelay) {
@@ -337,6 +340,7 @@ private GraphQLFieldDefinition getQueryFieldStreamDefinition(EntityType<?> entit
337340
.withToManyDefaultOptional(toManyDefaultOptional)
338341
.withDefaultDistinct(isDefaultDistinct)
339342
.withRestrictedKeysProvider(restrictedKeysProvider)
343+
.withResultStream(enableResultStream)
340344
.build();
341345

342346
DataFetcher<Object> dataFetcher = GraphQLJpaStreamDataFetcher.builder()
@@ -939,6 +943,7 @@ && isNotIgnoredOrder(attribute) ) {
939943
.withSelectNodeName(entityObjectType.getName())
940944
.withDefaultDistinct(isDefaultDistinct)
941945
.withRestrictedKeysProvider(restrictedKeysProvider)
946+
.withResultStream(enableResultStream)
942947
.build();
943948

944949
String dataLoaderKey = baseEntity.getName() + "." + attribute.getName();
@@ -975,6 +980,7 @@ else if (attribute instanceof PluralAttribute
975980
.withSelectNodeName(entityObjectType.getName())
976981
.withDefaultDistinct(isDefaultDistinct)
977982
.withRestrictedKeysProvider(restrictedKeysProvider)
983+
.withResultStream(enableResultStream)
978984
.build();
979985

980986
String dataLoaderKey = baseEntity.getName() + "." + attribute.getName();
@@ -1460,6 +1466,16 @@ public GraphQLJpaSchemaBuilder restrictedKeysProvider(RestrictedKeysProvider res
14601466

14611467
public RestrictedKeysProvider getRestrictedKeysProvider() {
14621468
return restrictedKeysProvider;
1463-
}
1469+
}
1470+
1471+
public boolean isEnableResultStream() {
1472+
return enableResultStream;
1473+
}
1474+
1475+
public GraphQLJpaSchemaBuilder enableResultStream(boolean enableResultStream) {
1476+
this.enableResultStream = enableResultStream;
1477+
1478+
return this;
1479+
}
14641480

14651481
}

graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/AbstractSpringBootTestSupport.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package com.introproventures.graphql.jpa.query;
22

33
import org.junit.runner.RunWith;
4-
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
5-
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
64
import org.springframework.test.context.TestPropertySource;
75
import org.springframework.test.context.junit4.SpringRunner;
86

graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/BooksSchemaBuildTest.java

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,35 @@
1616

1717
package com.introproventures.graphql.jpa.query.schema;
1818

19-
import static org.assertj.core.api.Assertions.assertThat;
20-
import static org.assertj.core.api.BDDAssertions.then;
21-
import static org.assertj.core.api.BDDAssertions.thenCode;
22-
2319
import java.util.Optional;
24-
2520
import javax.persistence.EntityManager;
26-
27-
import org.junit.Before;
28-
import org.junit.Test;
29-
import org.springframework.beans.factory.annotation.Autowired;
30-
import org.springframework.boot.autoconfigure.SpringBootApplication;
31-
import org.springframework.boot.test.context.SpringBootTest;
32-
import org.springframework.context.annotation.Bean;
33-
3421
import com.introproventures.graphql.jpa.query.AbstractSpringBootTestSupport;
3522
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
3623
import com.introproventures.graphql.jpa.query.schema.model.book.Author;
3724
import com.introproventures.graphql.jpa.query.schema.model.book.Book;
3825
import com.introproventures.graphql.jpa.query.schema.model.book_superclass.SuperAuthor;
3926
import com.introproventures.graphql.jpa.query.schema.model.book_superclass.SuperBook;
4027
import com.introproventures.graphql.jpa.query.schema.model.uuid.Thing;
41-
4228
import graphql.schema.GraphQLFieldDefinition;
4329
import graphql.schema.GraphQLList;
4430
import graphql.schema.GraphQLSchema;
31+
import org.junit.Before;
32+
import org.junit.Test;
33+
import org.springframework.beans.factory.annotation.Autowired;
34+
import org.springframework.boot.SpringBootConfiguration;
35+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
36+
import org.springframework.boot.test.context.SpringBootTest;
37+
import org.springframework.context.annotation.Bean;
38+
39+
import static org.assertj.core.api.Assertions.assertThat;
40+
import static org.assertj.core.api.BDDAssertions.then;
41+
import static org.assertj.core.api.BDDAssertions.thenCode;
4542

4643
@SpringBootTest
4744
public class BooksSchemaBuildTest extends AbstractSpringBootTestSupport {
4845

49-
@SpringBootApplication
46+
@SpringBootConfiguration
47+
@EnableAutoConfiguration
5048
static class TestConfiguration {
5149
@Bean
5250
public GraphQLSchemaBuilder graphQLSchemaBuilder(EntityManager entityManager) {

graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/CalculatedEntityTests.java

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,32 @@
11
package com.introproventures.graphql.jpa.query.schema;
22

3-
import static org.assertj.core.api.Assertions.assertThat;
4-
import static org.assertj.core.api.Assertions.tuple;
5-
import static org.assertj.core.api.BDDAssertions.then;
6-
import static org.assertj.core.util.Lists.list;
7-
83
import java.util.Optional;
9-
104
import javax.persistence.EntityManager;
11-
12-
import org.junit.Test;
13-
import org.springframework.beans.factory.annotation.Autowired;
14-
import org.springframework.boot.autoconfigure.SpringBootApplication;
15-
import org.springframework.boot.test.context.SpringBootTest;
16-
import org.springframework.context.annotation.Bean;
17-
import org.springframework.util.Assert;
18-
195
import com.introproventures.graphql.jpa.query.AbstractSpringBootTestSupport;
206
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor;
217
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
22-
238
import graphql.ExecutionResult;
249
import graphql.schema.GraphQLFieldDefinition;
2510
import graphql.schema.GraphQLSchema;
2611
import graphql.validation.ValidationErrorType;
12+
import org.junit.Test;
13+
import org.springframework.beans.factory.annotation.Autowired;
14+
import org.springframework.boot.SpringBootConfiguration;
15+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
16+
import org.springframework.boot.test.context.SpringBootTest;
17+
import org.springframework.context.annotation.Bean;
18+
import org.springframework.util.Assert;
19+
20+
import static org.assertj.core.api.Assertions.assertThat;
21+
import static org.assertj.core.api.Assertions.tuple;
22+
import static org.assertj.core.api.BDDAssertions.then;
23+
import static org.assertj.core.util.Lists.list;
2724

2825
@SpringBootTest
2926
public class CalculatedEntityTests extends AbstractSpringBootTestSupport {
30-
@SpringBootApplication
27+
28+
@SpringBootConfiguration
29+
@EnableAutoConfiguration
3130
static class Application {
3231
@Bean
3332
public GraphQLExecutor graphQLExecutor(final GraphQLSchemaBuilder graphQLSchemaBuilder) {

graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/EntityIntrospectorTest.java

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,35 @@
11
package com.introproventures.graphql.jpa.query.schema;
22

3-
import static org.assertj.core.api.Assertions.assertThat;
4-
import static org.assertj.core.api.Assertions.assertThatCode;
5-
import static org.mockito.Mockito.when;
6-
73
import java.util.NoSuchElementException;
84
import java.util.Optional;
9-
105
import javax.persistence.EntityManager;
116
import javax.persistence.metamodel.Attribute;
127
import javax.persistence.metamodel.EntityType;
138
import javax.persistence.metamodel.ManagedType;
14-
15-
import org.junit.Before;
16-
import org.junit.Test;
17-
import org.mockito.Mockito;
18-
import org.springframework.beans.factory.annotation.Autowired;
19-
import org.springframework.boot.autoconfigure.SpringBootApplication;
20-
import org.springframework.boot.test.context.SpringBootTest;
21-
229
import com.introproventures.graphql.jpa.query.AbstractSpringBootTestSupport;
2310
import com.introproventures.graphql.jpa.query.schema.impl.EntityIntrospector;
2411
import com.introproventures.graphql.jpa.query.schema.impl.EntityIntrospector.EntityIntrospectionResult;
2512
import com.introproventures.graphql.jpa.query.schema.impl.EntityIntrospector.EntityIntrospectionResult.AttributePropertyDescriptor;
2613
import com.introproventures.graphql.jpa.query.schema.model.calculated.CalculatedEntity;
2714
import com.introproventures.graphql.jpa.query.schema.model.calculated.ParentCalculatedEntity;
2815
import com.introproventures.graphql.jpa.query.schema.model.metamodel.ClassWithCustomMetamodel;
16+
import org.junit.Before;
17+
import org.junit.Test;
18+
import org.mockito.Mockito;
19+
import org.springframework.beans.factory.annotation.Autowired;
20+
import org.springframework.boot.SpringBootConfiguration;
21+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
22+
import org.springframework.boot.test.context.SpringBootTest;
23+
24+
import static org.assertj.core.api.Assertions.assertThat;
25+
import static org.assertj.core.api.Assertions.assertThatCode;
26+
import static org.mockito.Mockito.when;
2927

30-
@SpringBootTest
28+
@SpringBootTest(classes = EntityIntrospectorTest.Application.class)
3129
public class EntityIntrospectorTest extends AbstractSpringBootTestSupport {
3230

33-
@SpringBootApplication
31+
@SpringBootConfiguration
32+
@EnableAutoConfiguration
3433
static class Application {
3534
}
3635

0 commit comments

Comments
 (0)