Skip to content

feat: add EXISTS/NOT_EXISTS subquery logical where criteria expressions #151

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jun 11, 2019
Merged
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ sudo: required

jdk:
- oraclejdk8
# - openjdk11
- openjdk11

services:
- docker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ public class GraphQLJpaSchemaBuilder implements GraphQLSchemaBuilder {
private Map<Class<?>, GraphQLOutputType> classCache = new HashMap<>();
private Map<EntityType<?>, GraphQLObjectType> entityCache = new HashMap<>();
private Map<ManagedType<?>, GraphQLInputObjectType> inputObjectCache = new HashMap<>();
private Map<ManagedType<?>, GraphQLInputObjectType> subqueryInputObjectCache = new HashMap<>();
private Map<Class<?>, GraphQLObjectType> embeddableOutputCache = new HashMap<>();
private Map<Class<?>, GraphQLInputObjectType> embeddableInputCache = new HashMap<>();

Expand Down Expand Up @@ -253,6 +254,18 @@ private GraphQLArgument computeWhereArgument(ManagedType<?> managedType) {
.type(new GraphQLList(new GraphQLTypeReference(type)))
.build()
)
.field(GraphQLInputObjectField.newInputObjectField()
.name("EXISTS")
.description("Logical EXISTS subquery expression")
.type(new GraphQLList(getSubqueryInputType(managedType)))
.build()
)
.field(GraphQLInputObjectField.newInputObjectField()
.name("NOT_EXISTS")
.description("Logical NOT EXISTS subquery expression")
.type(new GraphQLList(getSubqueryInputType(managedType)))
.build()
)
.fields(managedType.getAttributes().stream()
.filter(this::isValidInput)
.filter(this::isNotIgnored)
Expand Down Expand Up @@ -283,6 +296,58 @@ private String resolveWhereArgumentTypeName(ManagedType<?> managedType) {
return namingStrategy.pluralize(typeName)+"CriteriaExpression";
}

private String resolveSubqueryArgumentTypeName(ManagedType<?> managedType) {
String typeName=resolveTypeName(managedType);

return namingStrategy.pluralize(typeName)+"SubqueryCriteriaExpression";
}

private GraphQLInputObjectType getSubqueryInputType(ManagedType<?> managedType) {
return subqueryInputObjectCache.computeIfAbsent(managedType, this::computeSubqueryInputType);
}

private GraphQLInputObjectType computeSubqueryInputType(ManagedType<?> managedType) {
String type=resolveSubqueryArgumentTypeName(managedType);

Builder whereInputObject = GraphQLInputObjectType.newInputObject()
.name(type)
.description("Where logical AND specification of the provided list of criteria expressions")
.field(GraphQLInputObjectField.newInputObjectField()
.name(OR)
.description("Logical operation for expressions")
.type(new GraphQLList(new GraphQLTypeReference(type)))
.build()
)
.field(GraphQLInputObjectField.newInputObjectField()
.name(AND)
.description("Logical operation for expressions")
.type(new GraphQLList(new GraphQLTypeReference(type)))
.build()
)
.field(GraphQLInputObjectField.newInputObjectField()
.name("EXISTS")
.description("Logical EXISTS subquery expression")
.type(new GraphQLList(new GraphQLTypeReference(type)))
.build()
)
.field(GraphQLInputObjectField.newInputObjectField()
.name("NOT_EXISTS")
.description("Logical NOT EXISTS subquery expression")
.type(new GraphQLList(new GraphQLTypeReference(type)))
.build()
)
.fields(managedType.getAttributes().stream()
.filter(this::isValidAssociation)
.filter(this::isNotIgnored)
.filter(this::isNotIgnoredFilter)
.map(this::getWhereInputRelationField)
.collect(Collectors.toList())
);

return whereInputObject.build();

}

private String resolveTypeName(ManagedType<?> managedType) {
String typeName="";

Expand Down Expand Up @@ -313,31 +378,44 @@ private GraphQLInputObjectType computeWhereInputType(ManagedType<?> managedType)
.name(type)
.description("Where logical AND specification of the provided list of criteria expressions")
.field(GraphQLInputObjectField.newInputObjectField()
.name(OR)
.description("Logical operation for expressions")
.type(new GraphQLList(new GraphQLTypeReference(type)))
.build()
.name(OR)
.description("Logical operation for expressions")
.type(new GraphQLList(new GraphQLTypeReference(type)))
.build()
)
.field(GraphQLInputObjectField.newInputObjectField()
.name(AND)
.description("Logical operation for expressions")
.type(new GraphQLList(new GraphQLTypeReference(type)))
.build()
.name(AND)
.description("Logical operation for expressions")
.type(new GraphQLList(new GraphQLTypeReference(type)))
.build()
)
.field(GraphQLInputObjectField.newInputObjectField()
.name("EXISTS")
.description("Logical EXISTS subquery expression")
.type(new GraphQLList(getSubqueryInputType(managedType)))
.build()
)
.field(GraphQLInputObjectField.newInputObjectField()
.name("NOT_EXISTS")
.description("Logical NOT EXISTS subquery expression")
.type(new GraphQLList(getSubqueryInputType(managedType)))
.build()
)
.fields(managedType.getAttributes().stream()
.filter(this::isValidInput)
.filter(this::isNotIgnored)
.filter(this::isNotIgnoredFilter)
.map(this::getWhereInputField)
.collect(Collectors.toList())
.filter(this::isValidInput)
.filter(this::isNotIgnored)
.filter(this::isNotIgnoredFilter)
.map(this::getWhereInputField)
.collect(Collectors.toList())
)
.fields(managedType.getAttributes().stream()
.filter(this::isValidAssociation)
.filter(this::isNotIgnored)
.filter(this::isNotIgnoredFilter)
.map(this::getWhereInputRelationField)
.collect(Collectors.toList())
.filter(this::isValidAssociation)
.filter(this::isNotIgnored)
.filter(this::isNotIgnoredFilter)
.map(this::getWhereInputRelationField)
.collect(Collectors.toList())
);


return whereInputObject.build();

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

return GraphQLInputObjectField.newInputObjectField()
.name(attribute.getName())
.description(description)
.type(new GraphQLTypeReference(type))
.build();
.name(attribute.getName())
.description(description)
.type(new GraphQLTypeReference(type))
.build();
}


private GraphQLInputObjectField getWhereInputField(Attribute<?,?> attribute) {
GraphQLInputType type = getWhereAttributeType(attribute);
String description = getSchemaDescription(attribute.getJavaMember());

if (type instanceof GraphQLInputType) {
return GraphQLInputObjectField.newInputObjectField()
.name(attribute.getName())
.description(description)
.type(type)
.build();
.name(attribute.getName())
.description(description)
.type(type)
.build();
}

throw new IllegalArgumentException("Attribute " + attribute.getName() + " cannot be mapped as an Input Argument");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import java.util.stream.Collectors;

enum Logical {
AND, OR;
AND, OR, EXISTS, NOT_EXISTS;

private static Set<String> names = EnumSet.allOf(Logical.class)
.stream()
Expand Down
Loading