Skip to content

Commit 5385a41

Browse files
authored
feat: add support for variable where criteria expressions (#162)
* feat: add support for variable where criteria expressions * Add GraphQLWhereVariableBindingsTests and fix variable name mismatch issue (#164) * chore: consolidate tests for where variable bindings * fix: polish conversion of ArrayValue
1 parent 8028d12 commit 5385a41

File tree

3 files changed

+463
-19
lines changed

3 files changed

+463
-19
lines changed

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

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.util.Map;
3131
import java.util.NoSuchElementException;
3232
import java.util.Optional;
33+
import java.util.function.Function;
3334
import java.util.stream.Collectors;
3435
import java.util.stream.IntStream;
3536
import java.util.stream.Stream;
@@ -57,10 +58,12 @@
5758

5859
import com.introproventures.graphql.jpa.query.annotation.GraphQLDefaultOrderBy;
5960
import com.introproventures.graphql.jpa.query.schema.impl.PredicateFilter.Criteria;
61+
6062
import graphql.GraphQLException;
6163
import graphql.execution.ValuesResolver;
6264
import graphql.language.Argument;
6365
import graphql.language.ArrayValue;
66+
import graphql.language.AstValueHelper;
6467
import graphql.language.BooleanValue;
6568
import graphql.language.Comment;
6669
import graphql.language.EnumValue;
@@ -79,6 +82,7 @@
7982
import graphql.schema.DataFetcher;
8083
import graphql.schema.DataFetchingEnvironment;
8184
import graphql.schema.DataFetchingEnvironmentBuilder;
85+
import graphql.schema.GraphQLArgument;
8286
import graphql.schema.GraphQLFieldDefinition;
8387
import graphql.schema.GraphQLList;
8488
import graphql.schema.GraphQLObjectType;
@@ -378,12 +382,29 @@ protected Predicate getPredicate(CriteriaBuilder cb, Root<?> from, From<?,?> pat
378382

379383

380384
@SuppressWarnings( "unchecked" )
381-
private <R extends Value> R getValue(Argument argument) {
382-
return (R) argument.getValue();
385+
private <R extends Value<?>> R getValue(Argument argument, DataFetchingEnvironment environment) {
386+
Value<?> value = argument.getValue();
387+
388+
if(VariableReference.class.isInstance(value)) {
389+
String variableName = VariableReference.class.cast(value)
390+
.getName();
391+
392+
Object variableValue = environment.getExecutionContext()
393+
.getVariables()
394+
.get(variableName);
395+
396+
GraphQLArgument graphQLArgument = environment.getExecutionStepInfo()
397+
.getFieldDefinition()
398+
.getArgument(argument.getName());
399+
400+
return (R) AstValueHelper.astFromValue(variableValue, graphQLArgument.getType());
401+
}
402+
403+
return (R) value;
383404
}
384405

385406
protected Predicate getWherePredicate(CriteriaBuilder cb, Root<?> root, From<?,?> path, DataFetchingEnvironment environment, Argument argument) {
386-
ObjectValue whereValue = getValue(argument);
407+
ObjectValue whereValue = getValue(argument, environment);
387408

388409
if(whereValue.getChildren().isEmpty())
389410
return cb.conjunction();
@@ -404,7 +425,7 @@ protected Predicate getWherePredicate(CriteriaBuilder cb, Root<?> root, From<?,
404425
@SuppressWarnings({"unchecked", "rawtypes"})
405426
protected Predicate getArgumentPredicate(CriteriaBuilder cb, From<?,?> from,
406427
DataFetchingEnvironment environment, Argument argument) {
407-
ObjectValue whereValue = getValue(argument);
428+
ObjectValue whereValue = getValue(argument, environment);
408429

409430
if (whereValue.getChildren().isEmpty())
410431
return cb.disjunction();
@@ -494,7 +515,7 @@ protected Predicate getArgumentsPredicate(CriteriaBuilder cb,
494515
From<?, ?> path,
495516
DataFetchingEnvironment environment,
496517
Argument argument) {
497-
ArrayValue whereValue = getValue(argument);
518+
ArrayValue whereValue = getValue(argument, environment);
498519

499520
if (whereValue.getValues().isEmpty())
500521
return cb.disjunction();
@@ -896,22 +917,41 @@ else if (value instanceof VariableReference) {
896917
return argumentValue;
897918
}
898919
} else if (value instanceof ArrayValue) {
899-
Object convertedValue = environment.getArgument(argument.getName());
900-
if (convertedValue != null && !getJavaType(environment, argument).isEnum()) {
901-
// unwrap [[EnumValue{name='value'}]]
902-
if(convertedValue instanceof Collection
903-
&& ((Collection) convertedValue).stream().allMatch(it->it instanceof Collection)) {
904-
convertedValue = ((Collection) convertedValue).iterator().next();
920+
Collection arrayValue = environment.getArgument(argument.getName());
921+
922+
if (arrayValue != null) {
923+
// Let's unwrap array of array values
924+
if(arrayValue.stream()
925+
.allMatch(it->it instanceof Collection)) {
926+
arrayValue = Collection.class.cast(arrayValue.iterator()
927+
.next());
905928
}
906-
907-
if(convertedValue instanceof Collection
908-
&& ((Collection) convertedValue).stream().anyMatch(it->it instanceof Value)) {
909-
return ((Collection) convertedValue).stream()
910-
.map((it) -> convertValue(environment, argument, (Value) it))
911-
.collect(Collectors.toList());
929+
930+
// Let's convert enum types, i.e. array of strings or EnumValue into Java type
931+
if(getJavaType(environment, argument).isEnum()) {
932+
Function<Object, Value> objectValue = (obj) -> Value.class.isInstance(obj)
933+
? Value.class.cast(obj)
934+
: new EnumValue(obj.toString());
935+
// Return real typed resolved array values converted into Java enums
936+
return arrayValue.stream()
937+
.map((it) -> convertValue(environment,
938+
argument,
939+
objectValue.apply(it)))
940+
.collect(Collectors.toList());
941+
}
942+
// Let's try handle Ast Value types
943+
else if(arrayValue.stream()
944+
.anyMatch(it->it instanceof Value)) {
945+
return arrayValue.stream()
946+
.map(it -> convertValue(environment,
947+
argument,
948+
Value.class.cast(it)))
949+
.collect(Collectors.toList());
950+
}
951+
// Return real typed resolved array value, i.e. Date, UUID, Long
952+
else {
953+
return arrayValue;
912954
}
913-
// Return real typed resolved array value
914-
return convertedValue;
915955
} else {
916956
// Wrap converted values in ArrayList
917957
return ((ArrayValue) value).getValues().stream()

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@
4545
import org.springframework.test.context.junit4.SpringRunner;
4646
import org.springframework.util.Assert;
4747

48+
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor;
49+
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
50+
51+
import graphql.ErrorType;
52+
import graphql.ExecutionResult;
53+
import graphql.GraphQLError;
54+
import graphql.validation.ValidationError;
55+
4856

4957
@RunWith(SpringRunner.class)
5058
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
@@ -1440,4 +1448,5 @@ public void queryForTransientMethodAnnotatedWithGraphQLIgnoreShouldFail() {
14401448
.extracting("validationErrorType", "queryPath")
14411449
.containsOnly(tuple(ValidationErrorType.FieldUndefined, list("Books", "select", "authorName")));
14421450
}
1451+
14431452
}

0 commit comments

Comments
 (0)