diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/JpaPredicateBuilder.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/JpaPredicateBuilder.java index 173c1f2ae..86f3402cd 100644 --- a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/JpaPredicateBuilder.java +++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/JpaPredicateBuilder.java @@ -19,7 +19,12 @@ import java.lang.reflect.Constructor; import java.math.BigDecimal; import java.math.BigInteger; -import java.time.*; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -37,6 +42,7 @@ import javax.persistence.metamodel.PluralAttribute; import com.introproventures.graphql.jpa.query.schema.impl.PredicateFilter.Criteria; + import graphql.language.NullValue; /** @@ -783,8 +789,7 @@ private Object getValue(Object object, Class type) { Object arg = NullValue.class.isInstance(object) ? null : object; return constructor.newInstance(arg); } - } catch (Exception e) { - e.printStackTrace(); + } catch (Exception ignored) { } return object; 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 ee92c789b..44d476878 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 @@ -19,6 +19,10 @@ import static graphql.introspection.Introspection.TypeMetaFieldDef; import static graphql.introspection.Introspection.TypeNameMetaFieldDef; +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Arrays; @@ -969,11 +973,52 @@ else if (value instanceof EnumValue) { return ((BooleanValue) value).isValue(); } else if (value instanceof FloatValue) { return ((FloatValue) value).getValue(); + } else if (value instanceof ObjectValue) { + Class javaType = getJavaType(environment, argument); + + try { + Object beanValue = javaType.getConstructor() + .newInstance(); + + Map objectValue = environment.getArgument(argument.getName()); + + objectValue.entrySet() + .stream() + .forEach(e -> { + setPropertyValue(beanValue, + e.getKey(), + e.getValue()); + }); + + return beanValue; + + } catch (Exception e1) { + // TODO + } + } - //return value.toString(); return value; } + + private void setPropertyValue(Object javaBean, String propertyName, Object propertyValue) { + try { + BeanInfo bi = Introspector.getBeanInfo(javaBean.getClass()); + PropertyDescriptor pds[] = bi.getPropertyDescriptors(); + for (PropertyDescriptor pd : pds) { + if (pd.getName().equals(propertyName)) { + Method setter = pd.getWriteMethod(); + setter.setAccessible(true); + + if (setter != null) { + setter.invoke(javaBean, new Object[] {propertyValue} ); + } + } + } + } catch (Exception ignored) { + // TODO + } + } /** * Resolve Java type from associated query argument JPA model attribute diff --git a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/embeddedid/EntityWithEmbeddedIdTest.java b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/embeddedid/EntityWithEmbeddedIdTest.java new file mode 100644 index 000000000..a801e5091 --- /dev/null +++ b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/embeddedid/EntityWithEmbeddedIdTest.java @@ -0,0 +1,138 @@ +package com.introproventures.graphql.jpa.query.embeddedid; + +import static org.assertj.core.api.Assertions.assertThat; + +import javax.persistence.EntityManager; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import com.introproventures.graphql.jpa.query.schema.GraphQLExecutor; +import com.introproventures.graphql.jpa.query.schema.GraphQLSchemaBuilder; +import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor; +import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, + properties = "spring.datasource.data=EntityWithEmbeddedIdTest.sql") +@TestPropertySource({"classpath:hibernate.properties"}) +public class EntityWithEmbeddedIdTest { + + @SpringBootApplication + static class Application { + @Bean + public GraphQLExecutor graphQLExecutor(final GraphQLSchemaBuilder graphQLSchemaBuilder) { + return new GraphQLJpaExecutor(graphQLSchemaBuilder.build()); + } + + @Bean + public GraphQLSchemaBuilder graphQLSchemaBuilder(final EntityManager entityManager) { + return new GraphQLJpaSchemaBuilder(entityManager) + .name("EntityWithEmbeddedIdTest"); + } + } + + @Autowired + private GraphQLExecutor executor; + + @Test + public void queryBookWithEmbeddedId() { + //given + String query = "query {" + + " Book(" + + " bookId: {" + + " title: \"War and Piece\"" + + " language: \"Russian\"" + + " }" + + " )" + + " {" + + " bookId {" + + " title" + + " language" + + " }" + + " description" + + " }" + + "}"; + + String expected = "{Book={bookId={title=War and Piece, language=Russian}, description=War and Piece Novel}}"; + + //when + Object result = executor.execute(query).getData(); + + // then + assertThat(result.toString()).isEqualTo(expected); + } + + @Test + public void queryBooksWithyWithEmbeddedId() { + //given + String query = "query {" + + " Books {" + + " total" + + " pages" + + " select {" + + " bookId {" + + " title" + + " language" + + " }" + + " description" + + " }" + + " }" + + "}"; + + String expected = "{Books={total=2, pages=1, select=[" + + "{bookId={title=Witch Of Water, language=English}, description=Witch Of Water Fantasy}, " + + "{bookId={title=War and Piece, language=Russian}, description=War and Piece Novel}" + + "]}}"; + + //when + Object result = executor.execute(query).getData(); + + // then + assertThat(result.toString()).isEqualTo(expected); + } + + @Test + public void queryBooksWithyWithEmbeddedIdWhereCriteriaExpression() { + //given + String query = "query {" + + " Books( " + + " where: {" + + " bookId: {" + + " EQ: {" + + " title: \"War and Piece\"" + + " language: \"Russian\"" + + " }" + + " }" + + " }" + + " ){" + + " total" + + " pages" + + " select {" + + " bookId {" + + " title" + + " language" + + " }" + + " description" + + " }" + + " }" + + "}"; + + String expected = "{Books={total=1, pages=1, select=[" + + "{bookId={title=War and Piece, language=Russian}, description=War and Piece Novel}" + + "]}}"; + + //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/java/com/introproventures/graphql/jpa/query/embeddedid/model/Book.java b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/embeddedid/model/Book.java new file mode 100644 index 000000000..c7a4812f1 --- /dev/null +++ b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/embeddedid/model/Book.java @@ -0,0 +1,17 @@ +package com.introproventures.graphql.jpa.query.embeddedid.model; + + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; + +import lombok.Data; + +@Data +@Entity +public class Book { + + @EmbeddedId + private BookId bookId; + + private String description; +} \ No newline at end of file diff --git a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/embeddedid/model/BookId.java b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/embeddedid/model/BookId.java new file mode 100644 index 000000000..e01144d40 --- /dev/null +++ b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/embeddedid/model/BookId.java @@ -0,0 +1,17 @@ +package com.introproventures.graphql.jpa.query.embeddedid.model; + + +import java.io.Serializable; + +import javax.persistence.Embeddable; + +import lombok.Data; + +@Data +@Embeddable +public class BookId implements Serializable { + private static final long serialVersionUID = 1L; + + private String title; + private String language; +} \ No newline at end of file diff --git a/graphql-jpa-query-schema/src/test/resources/EntityWithEmbeddedIdTest.sql b/graphql-jpa-query-schema/src/test/resources/EntityWithEmbeddedIdTest.sql new file mode 100644 index 000000000..555bab4f0 --- /dev/null +++ b/graphql-jpa-query-schema/src/test/resources/EntityWithEmbeddedIdTest.sql @@ -0,0 +1,3 @@ +insert into Book(title, language, description) values +('War and Piece', 'Russian', 'War and Piece Novel'), +('Witch Of Water', 'English', 'Witch Of Water Fantasy'); \ No newline at end of file