Skip to content

Commit c261ec9

Browse files
committed
feat: add support for variable where criteria expressions
1 parent 4bf7596 commit c261ec9

File tree

2 files changed

+167
-12
lines changed

2 files changed

+167
-12
lines changed

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

Lines changed: 49 additions & 6 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(variableName);
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();
@@ -897,7 +918,29 @@ else if (value instanceof VariableReference) {
897918
}
898919
} else if (value instanceof ArrayValue) {
899920
Object convertedValue = environment.getArgument(argument.getName());
900-
if (convertedValue != null && !getJavaType(environment, argument).isEnum()) {
921+
922+
if (convertedValue != null && getJavaType(environment, argument).isEnum()) {
923+
924+
Function<Object, Value> f = (obj) -> Value.class.isInstance(obj)
925+
? Value.class.cast(obj)
926+
: new EnumValue(obj.toString());
927+
928+
// unwrap [[EnumValue{name='value'}]]
929+
if(convertedValue instanceof Collection
930+
&& ((Collection) convertedValue).stream().allMatch(it->it instanceof Collection)) {
931+
convertedValue = ((Collection) convertedValue).iterator().next();
932+
}
933+
934+
if(convertedValue instanceof Collection) {
935+
return ((Collection) convertedValue).stream()
936+
.map((it) -> convertValue(environment, argument, f.apply(it)))
937+
.collect(Collectors.toList());
938+
}
939+
// Return real typed resolved array value
940+
return convertValue(environment, argument, f.apply(convertedValue));
941+
}
942+
else
943+
if (convertedValue != null && !getJavaType(environment, argument).isEnum()) {
901944
// unwrap [[EnumValue{name='value'}]]
902945
if(convertedValue instanceof Collection
903946
&& ((Collection) convertedValue).stream().allMatch(it->it instanceof Collection)) {

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

Lines changed: 118 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,18 @@
1818

1919
import static org.assertj.core.api.Assertions.assertThat;
2020

21+
import java.util.AbstractMap;
2122
import java.util.Arrays;
23+
import java.util.Collections;
2224
import java.util.HashMap;
2325
import java.util.List;
2426
import java.util.Map;
27+
import java.util.Map.Entry;
28+
import java.util.stream.Collectors;
29+
import java.util.stream.Stream;
2530

2631
import javax.persistence.EntityManager;
2732

28-
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor;
29-
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
30-
import graphql.ErrorType;
31-
import graphql.ExecutionResult;
32-
import graphql.GraphQLError;
33-
import graphql.validation.ValidationError;
3433
import org.junit.Test;
3534
import org.junit.runner.RunWith;
3635
import org.springframework.beans.factory.annotation.Autowired;
@@ -42,6 +41,14 @@
4241
import org.springframework.test.context.junit4.SpringRunner;
4342
import org.springframework.util.Assert;
4443

44+
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor;
45+
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
46+
47+
import graphql.ErrorType;
48+
import graphql.ExecutionResult;
49+
import graphql.GraphQLError;
50+
import graphql.validation.ValidationError;
51+
4552

4653
@RunWith(SpringRunner.class)
4754
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
@@ -1415,4 +1422,109 @@ public void queryForAuthorsWithExlicitOptionalBooksTrue() {
14151422
// then
14161423
assertThat(result.toString()).isEqualTo(expected);
14171424
}
1425+
1426+
@Test
1427+
public void queryBooksWithWhereVariableCriteriaExpression() {
1428+
//given
1429+
String query = "query($where: BooksCriteriaExpression) {" +
1430+
" Books (where: $where) {" +
1431+
" select {" +
1432+
" id" +
1433+
" title" +
1434+
" genre" +
1435+
" }" +
1436+
" }" +
1437+
"}";
1438+
1439+
Map<String, Object> variables = map(entry("where",
1440+
map(entry("title",
1441+
map(entry("LIKE",
1442+
"War"))))));
1443+
String expected = "{Books={select=["
1444+
+ "{id=2, title=War and Peace, genre=NOVEL}"
1445+
+ "]}}";
1446+
1447+
//when
1448+
Object result = executor.execute(query, variables).getData();
1449+
1450+
// then
1451+
assertThat(result.toString()).isEqualTo(expected);
1452+
}
1453+
1454+
@Test
1455+
public void queryBooksWithWhereVariableCriteriaEnumListExpression() {
1456+
//given
1457+
String query = "query($where: BooksCriteriaExpression) {" +
1458+
" Books (where: $where) {" +
1459+
" select {" +
1460+
" id" +
1461+
" title" +
1462+
" genre" +
1463+
" }" +
1464+
" }" +
1465+
"}";
1466+
1467+
Map<String, Object> variables = map(entry("where",
1468+
map(entry("genre",
1469+
map(entry("IN",
1470+
Arrays.asList("NOVEL")))))));
1471+
1472+
String expected = "{Books={select=["
1473+
+ "{id=2, title=War and Peace, genre=NOVEL}, "
1474+
+ "{id=3, title=Anna Karenina, genre=NOVEL}"
1475+
+ "]}}";
1476+
1477+
//when
1478+
Object result = executor.execute(query, variables).getData();
1479+
1480+
// then
1481+
assertThat(result.toString()).isEqualTo(expected);
1482+
}
1483+
1484+
@Test
1485+
public void queryBooksWithWhereVariableCriteriaEnumExpression() {
1486+
//given
1487+
String query = "query($where: BooksCriteriaExpression) {" +
1488+
" Books (where: $where) {" +
1489+
" select {" +
1490+
" id" +
1491+
" title" +
1492+
" genre" +
1493+
" }" +
1494+
" }" +
1495+
"}";
1496+
1497+
Map<String, Object> variables = map(entry("where",
1498+
map(entry("genre",
1499+
map(entry("IN",
1500+
"NOVEL"))))));
1501+
String expected = "{Books={select=["
1502+
+ "{id=2, title=War and Peace, genre=NOVEL}, "
1503+
+ "{id=3, title=Anna Karenina, genre=NOVEL}"
1504+
+ "]}}";
1505+
1506+
//when
1507+
Object result = executor.execute(query, variables).getData();
1508+
1509+
// then
1510+
assertThat(result.toString()).isEqualTo(expected);
1511+
}
1512+
1513+
1514+
@SafeVarargs
1515+
static <K, V> Map<K, V> map(Entry<? extends K, ? extends V>... entries) {
1516+
if (entries.length == 0) { // implicit null check of entries array
1517+
return Collections.emptyMap();
1518+
} else if (entries.length == 1) {
1519+
return Collections.singletonMap(entries[0].getKey(), entries[0].getValue());
1520+
} else {
1521+
return Stream.of(entries)
1522+
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
1523+
}
1524+
}
1525+
1526+
static <K, V> Entry<K, V> entry(K k, V v) {
1527+
return new AbstractMap.SimpleImmutableEntry<>(k, v);
1528+
}
1529+
14181530
}

0 commit comments

Comments
 (0)