Skip to content

Commit 85d2f3a

Browse files
authored
feat: add EXISTS/NOT_EXISTS subquery logical where criteria expressions (#151)
* feat: test exists criteria api * feat: add correlation subquery testers * feat: add singular EXISTS logical subquery expression * feat: add list EXISTS criteria expressions * feat: add NOT_EXISTS subquery criteria expression * feat: add SubqueryCriteriaExpression GraphQLInputObjectType * fix: add array EXISTS subquery support * feat: add custom attribute EXISTS subquery test * fix: disable show sql because of long log Travis failure * fix: implement missing equals() and hashCode() methods * fix: add implicit EXISTS subquery test for custom attributes * fix: enable openjdk11 in .travis.yaml
1 parent 17e0189 commit 85d2f3a

15 files changed

+1309
-41
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ sudo: required
33

44
jdk:
55
- oraclejdk8
6-
# - openjdk11
6+
- openjdk11
77

88
services:
99
- docker

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

+104-27
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ public class GraphQLJpaSchemaBuilder implements GraphQLSchemaBuilder {
104104
private Map<Class<?>, GraphQLOutputType> classCache = new HashMap<>();
105105
private Map<EntityType<?>, GraphQLObjectType> entityCache = new HashMap<>();
106106
private Map<ManagedType<?>, GraphQLInputObjectType> inputObjectCache = new HashMap<>();
107+
private Map<ManagedType<?>, GraphQLInputObjectType> subqueryInputObjectCache = new HashMap<>();
107108
private Map<Class<?>, GraphQLObjectType> embeddableOutputCache = new HashMap<>();
108109
private Map<Class<?>, GraphQLInputObjectType> embeddableInputCache = new HashMap<>();
109110

@@ -253,6 +254,18 @@ private GraphQLArgument computeWhereArgument(ManagedType<?> managedType) {
253254
.type(new GraphQLList(new GraphQLTypeReference(type)))
254255
.build()
255256
)
257+
.field(GraphQLInputObjectField.newInputObjectField()
258+
.name("EXISTS")
259+
.description("Logical EXISTS subquery expression")
260+
.type(new GraphQLList(getSubqueryInputType(managedType)))
261+
.build()
262+
)
263+
.field(GraphQLInputObjectField.newInputObjectField()
264+
.name("NOT_EXISTS")
265+
.description("Logical NOT EXISTS subquery expression")
266+
.type(new GraphQLList(getSubqueryInputType(managedType)))
267+
.build()
268+
)
256269
.fields(managedType.getAttributes().stream()
257270
.filter(this::isValidInput)
258271
.filter(this::isNotIgnored)
@@ -283,6 +296,58 @@ private String resolveWhereArgumentTypeName(ManagedType<?> managedType) {
283296
return namingStrategy.pluralize(typeName)+"CriteriaExpression";
284297
}
285298

299+
private String resolveSubqueryArgumentTypeName(ManagedType<?> managedType) {
300+
String typeName=resolveTypeName(managedType);
301+
302+
return namingStrategy.pluralize(typeName)+"SubqueryCriteriaExpression";
303+
}
304+
305+
private GraphQLInputObjectType getSubqueryInputType(ManagedType<?> managedType) {
306+
return subqueryInputObjectCache.computeIfAbsent(managedType, this::computeSubqueryInputType);
307+
}
308+
309+
private GraphQLInputObjectType computeSubqueryInputType(ManagedType<?> managedType) {
310+
String type=resolveSubqueryArgumentTypeName(managedType);
311+
312+
Builder whereInputObject = GraphQLInputObjectType.newInputObject()
313+
.name(type)
314+
.description("Where logical AND specification of the provided list of criteria expressions")
315+
.field(GraphQLInputObjectField.newInputObjectField()
316+
.name(OR)
317+
.description("Logical operation for expressions")
318+
.type(new GraphQLList(new GraphQLTypeReference(type)))
319+
.build()
320+
)
321+
.field(GraphQLInputObjectField.newInputObjectField()
322+
.name(AND)
323+
.description("Logical operation for expressions")
324+
.type(new GraphQLList(new GraphQLTypeReference(type)))
325+
.build()
326+
)
327+
.field(GraphQLInputObjectField.newInputObjectField()
328+
.name("EXISTS")
329+
.description("Logical EXISTS subquery expression")
330+
.type(new GraphQLList(new GraphQLTypeReference(type)))
331+
.build()
332+
)
333+
.field(GraphQLInputObjectField.newInputObjectField()
334+
.name("NOT_EXISTS")
335+
.description("Logical NOT EXISTS subquery expression")
336+
.type(new GraphQLList(new GraphQLTypeReference(type)))
337+
.build()
338+
)
339+
.fields(managedType.getAttributes().stream()
340+
.filter(this::isValidAssociation)
341+
.filter(this::isNotIgnored)
342+
.filter(this::isNotIgnoredFilter)
343+
.map(this::getWhereInputRelationField)
344+
.collect(Collectors.toList())
345+
);
346+
347+
return whereInputObject.build();
348+
349+
}
350+
286351
private String resolveTypeName(ManagedType<?> managedType) {
287352
String typeName="";
288353

@@ -313,31 +378,44 @@ private GraphQLInputObjectType computeWhereInputType(ManagedType<?> managedType)
313378
.name(type)
314379
.description("Where logical AND specification of the provided list of criteria expressions")
315380
.field(GraphQLInputObjectField.newInputObjectField()
316-
.name(OR)
317-
.description("Logical operation for expressions")
318-
.type(new GraphQLList(new GraphQLTypeReference(type)))
319-
.build()
381+
.name(OR)
382+
.description("Logical operation for expressions")
383+
.type(new GraphQLList(new GraphQLTypeReference(type)))
384+
.build()
320385
)
321386
.field(GraphQLInputObjectField.newInputObjectField()
322-
.name(AND)
323-
.description("Logical operation for expressions")
324-
.type(new GraphQLList(new GraphQLTypeReference(type)))
325-
.build()
387+
.name(AND)
388+
.description("Logical operation for expressions")
389+
.type(new GraphQLList(new GraphQLTypeReference(type)))
390+
.build()
391+
)
392+
.field(GraphQLInputObjectField.newInputObjectField()
393+
.name("EXISTS")
394+
.description("Logical EXISTS subquery expression")
395+
.type(new GraphQLList(getSubqueryInputType(managedType)))
396+
.build()
397+
)
398+
.field(GraphQLInputObjectField.newInputObjectField()
399+
.name("NOT_EXISTS")
400+
.description("Logical NOT EXISTS subquery expression")
401+
.type(new GraphQLList(getSubqueryInputType(managedType)))
402+
.build()
326403
)
327404
.fields(managedType.getAttributes().stream()
328-
.filter(this::isValidInput)
329-
.filter(this::isNotIgnored)
330-
.filter(this::isNotIgnoredFilter)
331-
.map(this::getWhereInputField)
332-
.collect(Collectors.toList())
405+
.filter(this::isValidInput)
406+
.filter(this::isNotIgnored)
407+
.filter(this::isNotIgnoredFilter)
408+
.map(this::getWhereInputField)
409+
.collect(Collectors.toList())
333410
)
334411
.fields(managedType.getAttributes().stream()
335-
.filter(this::isValidAssociation)
336-
.filter(this::isNotIgnored)
337-
.filter(this::isNotIgnoredFilter)
338-
.map(this::getWhereInputRelationField)
339-
.collect(Collectors.toList())
412+
.filter(this::isValidAssociation)
413+
.filter(this::isNotIgnored)
414+
.filter(this::isNotIgnoredFilter)
415+
.map(this::getWhereInputRelationField)
416+
.collect(Collectors.toList())
340417
);
418+
341419

342420
return whereInputObject.build();
343421

@@ -350,23 +428,22 @@ private GraphQLInputObjectField getWhereInputRelationField(Attribute<?,?> attrib
350428
String description = getSchemaDescription(attribute.getJavaMember());
351429

352430
return GraphQLInputObjectField.newInputObjectField()
353-
.name(attribute.getName())
354-
.description(description)
355-
.type(new GraphQLTypeReference(type))
356-
.build();
431+
.name(attribute.getName())
432+
.description(description)
433+
.type(new GraphQLTypeReference(type))
434+
.build();
357435
}
358436

359-
360437
private GraphQLInputObjectField getWhereInputField(Attribute<?,?> attribute) {
361438
GraphQLInputType type = getWhereAttributeType(attribute);
362439
String description = getSchemaDescription(attribute.getJavaMember());
363440

364441
if (type instanceof GraphQLInputType) {
365442
return GraphQLInputObjectField.newInputObjectField()
366-
.name(attribute.getName())
367-
.description(description)
368-
.type(type)
369-
.build();
443+
.name(attribute.getName())
444+
.description(description)
445+
.type(type)
446+
.build();
370447
}
371448

372449
throw new IllegalArgumentException("Attribute " + attribute.getName() + " cannot be mapped as an Input Argument");

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import java.util.stream.Collectors;
2222

2323
enum Logical {
24-
AND, OR;
24+
AND, OR, EXISTS, NOT_EXISTS;
2525

2626
private static Set<String> names = EnumSet.allOf(Logical.class)
2727
.stream()

0 commit comments

Comments
 (0)