diff --git a/graphql-jpa-query-example-merge/src/main/resources/books.sql b/graphql-jpa-query-example-merge/src/main/resources/books.sql index 928d6a3d5..50a35ec5f 100644 --- a/graphql-jpa-query-example-merge/src/main/resources/books.sql +++ b/graphql-jpa-query-example-merge/src/main/resources/books.sql @@ -7,3 +7,16 @@ insert into book (id, title, author_id, genre) values (5, 'The Cherry Orchard', insert into book (id, title, author_id, genre) values (6, 'The Seagull', 4, 'PLAY'); insert into book (id, title, author_id, genre) values (7, 'Three Sisters', 4, 'PLAY'); insert into author (id, name, genre) values (8, 'Igor Dianov', 'JAVA'); + +insert into book_tags (book_id, tags) values (2, 'war'), (2, 'piece'); +insert into book_tags (book_id, tags) values (3, 'anna'), (3, 'karenina'); +insert into book_tags (book_id, tags) values (5, 'cherry'), (5, 'orchard'); +insert into book_tags (book_id, tags) values (6, 'seagull'); +insert into book_tags (book_id, tags) values (7, 'three'), (7, 'sisters'); + +insert into author_phone_numbers(phone_number, author_id) values + ('1-123-1234', 1), + ('1-123-5678', 1), + ('4-123-1234', 4), + ('4-123-5678', 4); + \ No newline at end of file diff --git a/graphql-jpa-query-example-model-books/src/main/java/com/introproventures/graphql/jpa/query/schema/model/book/Book.java b/graphql-jpa-query-example-model-books/src/main/java/com/introproventures/graphql/jpa/query/schema/model/book/Book.java index e1c1dd3a6..ce8045270 100644 --- a/graphql-jpa-query-example-model-books/src/main/java/com/introproventures/graphql/jpa/query/schema/model/book/Book.java +++ b/graphql-jpa-query-example-model-books/src/main/java/com/introproventures/graphql/jpa/query/schema/model/book/Book.java @@ -17,18 +17,29 @@ package com.introproventures.graphql.jpa.query.schema.model.book; import java.util.Date; +import java.util.LinkedHashSet; +import java.util.Set; -import javax.persistence.*; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.Transient; +import com.introproventures.graphql.jpa.query.annotation.GraphQLDescription; import com.introproventures.graphql.jpa.query.annotation.GraphQLIgnore; import com.introproventures.graphql.jpa.query.annotation.GraphQLIgnoreFilter; import com.introproventures.graphql.jpa.query.annotation.GraphQLIgnoreOrder; + import lombok.Data; import lombok.EqualsAndHashCode; @Data @Entity -@EqualsAndHashCode(exclude="author") +@EqualsAndHashCode(exclude= {"author", "tags"}) public class Book { @Id Long id; @@ -38,6 +49,10 @@ public class Book { @GraphQLIgnoreOrder @GraphQLIgnoreFilter String description; + + @ElementCollection(fetch = FetchType.LAZY) + @GraphQLDescription("A set of user-defined tags") + private Set tags = new LinkedHashSet<>(); @ManyToOne(fetch=FetchType.LAZY, optional = false) Author author; diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java index 88ccc93f4..dd42d963c 100644 --- a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java +++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java @@ -218,20 +218,20 @@ protected final List getFieldPredicates(Field field, CriteriaQuery // Let's do fugly conversion // the many end is a collection, and it is always optional by default (empty collection) isOptional = optionalArgument.map(it -> getArgumentValue(environment, it, Boolean.class)) - .orElse(toManyDefaultOptional); + .orElse(toManyDefaultOptional); - // Let's apply join to retrieve associated collection - fetch = reuseFetch(from, selectedField.getName(), isOptional); - - // Let's fetch element collections to avoid filtering their values used where search criteria GraphQLObjectType objectType = getObjectType(environment); EntityType entityType = getEntityType(objectType); PluralAttribute attribute = (PluralAttribute) entityType.getAttribute(selectedField.getName()); + // Let's join fetch element collections to avoid filtering their values used where search criteria if(PersistentAttributeType.ELEMENT_COLLECTION == attribute.getPersistentAttributeType()) { - from.fetch(selectedField.getName()); - } + from.fetch(selectedField.getName(), JoinType.LEFT); + } else { + // Let's apply fetch join to retrieve associated plural attributes + fetch = reuseFetch(from, selectedField.getName(), isOptional); + } } // Let's build join fetch graph to avoid Hibernate error: // "query specified join fetching, but the owner of the fetched association was not present in the select list" diff --git a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/GraphQLExecutorTests.java b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/GraphQLExecutorTests.java index f5e4230ec..6a31f39e0 100644 --- a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/GraphQLExecutorTests.java +++ b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/GraphQLExecutorTests.java @@ -1611,4 +1611,41 @@ public void queryWithEnumParameterShouldExecuteWithNoError() { "War and Peace") ); } + + // https://github.com/introproventures/graphql-jpa-query/issues/198 + @Test + public void queryOptionalElementCollections() { + //given + String query = "{ Author(id: 8) { id name phoneNumbers books { id title tags } } }"; + + String expected = "{Author={id=8, name=Igor Dianov, phoneNumbers=[], books=[]}}"; + + //when + Object result = executor.execute(query).getData(); + + // then + assertThat(result.toString()).isEqualTo(expected); + } + + @Test + public void queryElementCollectionsWithWhereCriteriaExpression() { + //given: + String query = "query {" + + " Books(where: {tags: {EQ: \"war\"}}) {" + + " select {" + + " id" + + " title" + + " tags" + + " }" + + " }" + + "}"; + + String expected = "{Books={select=[{id=2, title=War and Peace, tags=[piece, war]}]}}"; + + //when: + Object result = executor.execute(query).getData(); + + //then: + assertThat(result.toString()).isEqualTo(expected); + } } \ No newline at end of file diff --git a/graphql-jpa-query-schema/src/test/resources/data.sql b/graphql-jpa-query-schema/src/test/resources/data.sql index 53820a03d..4d32f5b5c 100644 --- a/graphql-jpa-query-schema/src/test/resources/data.sql +++ b/graphql-jpa-query-schema/src/test/resources/data.sql @@ -126,6 +126,12 @@ insert into book (id, title, author_id, genre, publication_date, description) values (7, 'Three Sisters', 4, 'PLAY', '1900-01-01', 'The play is sometimes included on the short list of Chekhov''s outstanding plays, along with The Cherry Orchard, The Seagull and Uncle Vanya.[1]'); insert into author (id, name, genre) values (8, 'Igor Dianov', 'JAVA'); +insert into book_tags (book_id, tags) values (2, 'war'), (2, 'piece'); +insert into book_tags (book_id, tags) values (3, 'anna'), (3, 'karenina'); +insert into book_tags (book_id, tags) values (5, 'cherry'), (5, 'orchard'); +insert into book_tags (book_id, tags) values (6, 'seagull'); +insert into book_tags (book_id, tags) values (7, 'three'), (7, 'sisters'); + insert into author_phone_numbers(phone_number, author_id) values ('1-123-1234', 1), ('1-123-5678', 1),