Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions graphql-jpa-query-boot-starter/.project
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<name>org.springframework.ide.eclipse.core.springbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.springframework.ide.eclipse.core.springbuilder</name>
<name>org.springframework.ide.eclipse.boot.validation.springbootbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.springframework.ide.eclipse.boot.validation.springbootbuilder</name>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
Expand Down
6 changes: 3 additions & 3 deletions graphql-jpa-query-example/.project
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<name>org.springframework.ide.eclipse.core.springbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.springframework.ide.eclipse.core.springbuilder</name>
<name>org.springframework.ide.eclipse.boot.validation.springbootbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.springframework.ide.eclipse.boot.validation.springbootbuilder</name>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@

import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.persistence.EntityGraph;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
Expand All @@ -37,7 +35,7 @@

import graphql.language.Argument;
import graphql.language.Field;
import graphql.language.SelectionSet;
import graphql.language.Selection;
import graphql.schema.DataFetchingEnvironment;

/**
Expand All @@ -63,40 +61,47 @@ public Object get(DataFetchingEnvironment environment) {
Object source = environment.getSource();
Optional<Argument> whereArg = extractArgument(environment, field, GraphQLJpaSchemaBuilder.QUERY_WHERE_PARAM_NAME);

// Resolve collection query if where argument is present
if(whereArg.isPresent()) {
// // Create entity graph from selection
// EntityGraph<?> entityGraph = buildEntityGraph(new Field("select", new SelectionSet(Arrays.asList(field))));
//
// try {
// Object result = getQuery(environment, field, true)
// .setHint("javax.persistence.fetchgraph", entityGraph)
// .getSingleResult();
//
// return getAttributeValue(result, attribute);
// } catch (NoResultException e) {
// }
//
// return Collections.emptyList();
// Resolve collection query if where argument is present or any field in selection has orderBy argument
if(whereArg.isPresent() || hasSelectionAnyOrderBy(field)) {

EntityGraph<?> entityGraph = buildEntityGraph(new Field("select", new SelectionSet(Arrays.asList(field))));
//EntityGraph<?> entityGraph = buildEntityGraph(new Field("select", new SelectionSet(Arrays.asList(field))));

return getQuery(environment, field, true)
//.setHint("javax.persistence.fetchgraph", entityGraph) // TODO: fix runtime exception
.getResultList();

// .stream()
// .map(it -> (Tuple) it)
// .map(tuple -> tuple.get(attribute.getName()))
// .collect(Collectors.toList());
}

// Let hibernate resolve collection query
return getAttributeValue(source, attribute);

// Must do this to resolve where and orderBy on child fields
// return getQuery(environment, field, true).getResultList();
}

private boolean hasSelectionAnyOrderBy(Field field) {

if(!hasSelectionSet(field)) return false;

// Loop through all of the fields being requested
for(Selection selection : field.getSelectionSet().getSelections()) {
if (selection instanceof Field) {
Field selectedField = (Field) selection;

// "__typename" is part of the graphql introspection spec and has to be ignored by jpa
if(!"__typename".equals(selectedField.getName())) {

// Optional orderBy argument
Optional<Argument> orderBy = selectedField.getArguments().stream()
.filter(this::isOrderByArgument)
.findFirst();

if(orderBy.isPresent()) {
return true;
}
}
}
}

return false;

}
@SuppressWarnings( { "rawtypes", "unchecked" } )
@Override
protected TypedQuery<?> getQuery(DataFetchingEnvironment environment, Field field, boolean isDistinct) {
Expand Down Expand Up @@ -144,7 +149,7 @@ protected TypedQuery<?> getQuery(DataFetchingEnvironment environment, Field fiel
* @see http://stackoverflow.com/questions/7077464/how-to-get-singularattribute-mapped-value-of-a-persistent-object
*/
@SuppressWarnings("unchecked")
public <EntityType,FieldType> FieldType getAttributeValue(EntityType entity, SingularAttribute<EntityType, FieldType> field) {
public <EntityType, FieldType> FieldType getAttributeValue(EntityType entity, SingularAttribute<EntityType, FieldType> field) {
try {
Member member = field.getJavaMember();
if (member instanceof Method) {
Expand All @@ -167,7 +172,7 @@ public <EntityType,FieldType> FieldType getAttributeValue(EntityType entity, Sin
* @see http://stackoverflow.com/questions/7077464/how-to-get-singularattribute-mapped-value-of-a-persistent-object
*/
@SuppressWarnings("unchecked")
public <EntityType,FieldType> FieldType getAttributeValue(EntityType entity, PluralAttribute<EntityType, ?, FieldType> field) {
public <EntityType, FieldType> FieldType getAttributeValue(EntityType entity, PluralAttribute<EntityType, ?, FieldType> field) {
try {
Member member = field.getJavaMember();
if (member instanceof Method) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,52 +41,6 @@
import graphql.schema.DataFetchingEnvironmentImpl;
import graphql.schema.GraphQLObjectType;

/*
query Q($ids: [Long]!, $status: String!) {
ProcessInstancesQuery (
page:{start:1, limit: 10}
distinct: true
where: {
OR: {
processInstanceId: {
IN: $ids
}
status: {
LIKE: $status
}
}
lastModified:{
OR: {
AND: {
GT: "9/01/17 0:00 AM"
LT: "10/01/17 0:00 AM"
}
IS_NULL: true
}
}
}
) {
total
pages
select {
processInstanceId(orderBy:ASC)
processDefinitionId
status
tasks {
id
assignee,
name
variables {
id
name
type,
value
}
}
}
}
}
*/
/**
* JPA Query DataFetcher implementation that fetches entities with page and where criteria expressions
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.Bindable.BindableType;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.PluralAttribute;
import javax.persistence.metamodel.SingularAttribute;
Expand Down Expand Up @@ -150,7 +149,7 @@ protected final List<Argument> getFieldArguments(Field field, CriteriaQuery<?> q
Optional<Argument> orderByArgument = selectedField.getArguments().stream()
.filter(this::isOrderByArgument)
.findFirst();

if (orderByArgument.isPresent()) {
if ("DESC".equals(((EnumValue) orderByArgument.get().getValue()).getName()))
query.orderBy(cb.desc(fieldPath));
Expand All @@ -175,24 +174,7 @@ protected final List<Argument> getFieldArguments(Field field, CriteriaQuery<?> q
}
}
} else {
// // If this a collection attribute then we try eagerly fetch causing eager left join
// // Workaround fieldPath.getModel() is always null for PluralAttribute Hibernate implementation
// if(fieldPath instanceof PluralAttributePath) {
// PluralAttribute<?,?,?> attribute = ((PluralAttributePath<?>) fieldPath).getAttribute();
//
// // Foreign side is many and there are no filter arguments
// if((attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.ONE_TO_MANY
// || attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.MANY_TO_MANY)
// && selectedField.getArguments().isEmpty()
// ) {
// // Must use query.distinct(true) for fetch left join
// query.distinct(true);
// // Eagerly fetch all collection elements in parent query
// from.fetch(attribute.getName(), JoinType.LEFT);
// } else {
// // Do nothing
// }
// }
// Do nothing
}
}
}
Expand Down Expand Up @@ -303,11 +285,6 @@ protected Predicate getPredicate(CriteriaBuilder cb, Root<?> from, From<?,?> pat
}
}

private boolean isOuterJoin(From<?,?> from, String name) {
BindableType bindableType = from.get(name).getModel().getBindableType();
return (bindableType == BindableType.PLURAL_ATTRIBUTE) ? true : false;
}

@SuppressWarnings( "unchecked" )
private <R extends Value> R getValue(Argument argument) {
return (R) argument.getValue();
Expand Down Expand Up @@ -416,7 +393,8 @@ private Predicate getFieldPredicate(String fieldName, CriteriaBuilder cb, From<?

}

private PredicateFilter getPredicateFilter(ObjectField objectField, DataFetchingEnvironment environment, Argument argument) {
@SuppressWarnings("serial")
private PredicateFilter getPredicateFilter(ObjectField objectField, DataFetchingEnvironment environment, Argument argument) {
EnumSet<PredicateFilter.Criteria> options =
EnumSet.of(PredicateFilter.Criteria.valueOf(argument.getName()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,50 @@ public void queryOrderByFields() {
assertThat(result.toString()).isEqualTo(expected);
}

@Test
public void queryOrderByFieldsNested() {
//given:
String query = "query { Humans(where: {id: {EQ: \"1000\"}}) { select {name(orderBy: DESC) homePlanet friends { name(orderBy:DESC) } } } }";

String expected = "{Humans={select=["
+ "{name=Luke Skywalker, homePlanet=Tatooine, "
+ "friends=["
+ "{name=R2-D2}, "
+ "{name=Leia Organa}, "
+ "{name=Han Solo}, "
+ "{name=C-3PO}"
+ "]"
+ "}"
+ "]}}";

//when:
Object result = executor.execute(query).getData();

//then:
assertThat(result.toString()).isEqualTo(expected);
}

@Test
public void queryOrderByDefaultId() {
//given:
String query = "query { Humans { select { id } } }";

String expected = "{Humans={select=["
+ "{id=1000}, "
+ "{id=1001}, "
+ "{id=1002}, "
+ "{id=1003}, "
+ "{id=1004}"
+ "]}}";

//when:
Object result = executor.execute(query).getData();

//then:
assertThat(result.toString()).isEqualTo(expected);
}


@Test
public void queryByCollectionOfEnumsAtRootLevel() {
//given:
Expand Down