Skip to content

Commit 6552cb8

Browse files
authored
fix: add query support for entities with @EmbeddedId attribute (#180)
1 parent 50df533 commit 6552cb8

File tree

6 files changed

+229
-4
lines changed

6 files changed

+229
-4
lines changed

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@
1919
import java.lang.reflect.Constructor;
2020
import java.math.BigDecimal;
2121
import java.math.BigInteger;
22-
import java.time.*;
22+
import java.time.Instant;
23+
import java.time.LocalDate;
24+
import java.time.LocalDateTime;
25+
import java.time.LocalTime;
26+
import java.time.OffsetDateTime;
27+
import java.time.ZonedDateTime;
2328
import java.util.ArrayList;
2429
import java.util.Collection;
2530
import java.util.Date;
@@ -37,6 +42,7 @@
3742
import javax.persistence.metamodel.PluralAttribute;
3843

3944
import com.introproventures.graphql.jpa.query.schema.impl.PredicateFilter.Criteria;
45+
4046
import graphql.language.NullValue;
4147

4248
/**
@@ -783,8 +789,7 @@ private Object getValue(Object object, Class<?> type) {
783789
Object arg = NullValue.class.isInstance(object) ? null : object;
784790
return constructor.newInstance(arg);
785791
}
786-
} catch (Exception e) {
787-
e.printStackTrace();
792+
} catch (Exception ignored) {
788793
}
789794

790795
return object;

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

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
import static graphql.introspection.Introspection.TypeMetaFieldDef;
2020
import static graphql.introspection.Introspection.TypeNameMetaFieldDef;
2121

22+
import java.beans.BeanInfo;
23+
import java.beans.Introspector;
24+
import java.beans.PropertyDescriptor;
25+
import java.lang.reflect.Method;
2226
import java.util.AbstractMap.SimpleEntry;
2327
import java.util.ArrayList;
2428
import java.util.Arrays;
@@ -969,11 +973,52 @@ else if (value instanceof EnumValue) {
969973
return ((BooleanValue) value).isValue();
970974
} else if (value instanceof FloatValue) {
971975
return ((FloatValue) value).getValue();
976+
} else if (value instanceof ObjectValue) {
977+
Class javaType = getJavaType(environment, argument);
978+
979+
try {
980+
Object beanValue = javaType.getConstructor()
981+
.newInstance();
982+
983+
Map<String, Object> objectValue = environment.getArgument(argument.getName());
984+
985+
objectValue.entrySet()
986+
.stream()
987+
.forEach(e -> {
988+
setPropertyValue(beanValue,
989+
e.getKey(),
990+
e.getValue());
991+
});
992+
993+
return beanValue;
994+
995+
} catch (Exception e1) {
996+
// TODO
997+
}
998+
972999
}
9731000

974-
//return value.toString();
9751001
return value;
9761002
}
1003+
1004+
private void setPropertyValue(Object javaBean, String propertyName, Object propertyValue) {
1005+
try {
1006+
BeanInfo bi = Introspector.getBeanInfo(javaBean.getClass());
1007+
PropertyDescriptor pds[] = bi.getPropertyDescriptors();
1008+
for (PropertyDescriptor pd : pds) {
1009+
if (pd.getName().equals(propertyName)) {
1010+
Method setter = pd.getWriteMethod();
1011+
setter.setAccessible(true);
1012+
1013+
if (setter != null) {
1014+
setter.invoke(javaBean, new Object[] {propertyValue} );
1015+
}
1016+
}
1017+
}
1018+
} catch (Exception ignored) {
1019+
// TODO
1020+
}
1021+
}
9771022

9781023
/**
9791024
* Resolve Java type from associated query argument JPA model attribute
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package com.introproventures.graphql.jpa.query.embeddedid;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import javax.persistence.EntityManager;
6+
7+
import org.junit.Test;
8+
import org.junit.runner.RunWith;
9+
import org.springframework.beans.factory.annotation.Autowired;
10+
import org.springframework.boot.autoconfigure.SpringBootApplication;
11+
import org.springframework.boot.test.context.SpringBootTest;
12+
import org.springframework.context.annotation.Bean;
13+
import org.springframework.test.context.TestPropertySource;
14+
import org.springframework.test.context.junit4.SpringRunner;
15+
16+
import com.introproventures.graphql.jpa.query.schema.GraphQLExecutor;
17+
import com.introproventures.graphql.jpa.query.schema.GraphQLSchemaBuilder;
18+
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor;
19+
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
20+
21+
@RunWith(SpringRunner.class)
22+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE,
23+
properties = "spring.datasource.data=EntityWithEmbeddedIdTest.sql")
24+
@TestPropertySource({"classpath:hibernate.properties"})
25+
public class EntityWithEmbeddedIdTest {
26+
27+
@SpringBootApplication
28+
static class Application {
29+
@Bean
30+
public GraphQLExecutor graphQLExecutor(final GraphQLSchemaBuilder graphQLSchemaBuilder) {
31+
return new GraphQLJpaExecutor(graphQLSchemaBuilder.build());
32+
}
33+
34+
@Bean
35+
public GraphQLSchemaBuilder graphQLSchemaBuilder(final EntityManager entityManager) {
36+
return new GraphQLJpaSchemaBuilder(entityManager)
37+
.name("EntityWithEmbeddedIdTest");
38+
}
39+
}
40+
41+
@Autowired
42+
private GraphQLExecutor executor;
43+
44+
@Test
45+
public void queryBookWithEmbeddedId() {
46+
//given
47+
String query = "query {" +
48+
" Book(" +
49+
" bookId: {"
50+
+ " title: \"War and Piece\"" +
51+
" language: \"Russian\"" +
52+
" }" +
53+
" )" +
54+
" {" +
55+
" bookId {" +
56+
" title" +
57+
" language" +
58+
" }" +
59+
" description" +
60+
" }" +
61+
"}";
62+
63+
String expected = "{Book={bookId={title=War and Piece, language=Russian}, description=War and Piece Novel}}";
64+
65+
//when
66+
Object result = executor.execute(query).getData();
67+
68+
// then
69+
assertThat(result.toString()).isEqualTo(expected);
70+
}
71+
72+
@Test
73+
public void queryBooksWithyWithEmbeddedId() {
74+
//given
75+
String query = "query {" +
76+
" Books {" +
77+
" total" +
78+
" pages" +
79+
" select {" +
80+
" bookId {" +
81+
" title" +
82+
" language" +
83+
" }" +
84+
" description" +
85+
" }" +
86+
" }" +
87+
"}";
88+
89+
String expected = "{Books={total=2, pages=1, select=["
90+
+ "{bookId={title=Witch Of Water, language=English}, description=Witch Of Water Fantasy}, "
91+
+ "{bookId={title=War and Piece, language=Russian}, description=War and Piece Novel}"
92+
+ "]}}";
93+
94+
//when
95+
Object result = executor.execute(query).getData();
96+
97+
// then
98+
assertThat(result.toString()).isEqualTo(expected);
99+
}
100+
101+
@Test
102+
public void queryBooksWithyWithEmbeddedIdWhereCriteriaExpression() {
103+
//given
104+
String query = "query {" +
105+
" Books( " +
106+
" where: {" +
107+
" bookId: {" +
108+
" EQ: {" +
109+
" title: \"War and Piece\"" +
110+
" language: \"Russian\"" +
111+
" }" +
112+
" }" +
113+
" }" +
114+
" ){" +
115+
" total" +
116+
" pages" +
117+
" select {" +
118+
" bookId {" +
119+
" title" +
120+
" language" +
121+
" }" +
122+
" description" +
123+
" }" +
124+
" }" +
125+
"}";
126+
127+
String expected = "{Books={total=1, pages=1, select=["
128+
+ "{bookId={title=War and Piece, language=Russian}, description=War and Piece Novel}"
129+
+ "]}}";
130+
131+
//when
132+
Object result = executor.execute(query).getData();
133+
134+
// then
135+
assertThat(result.toString()).isEqualTo(expected);
136+
}
137+
138+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.introproventures.graphql.jpa.query.embeddedid.model;
2+
3+
4+
import javax.persistence.EmbeddedId;
5+
import javax.persistence.Entity;
6+
7+
import lombok.Data;
8+
9+
@Data
10+
@Entity
11+
public class Book {
12+
13+
@EmbeddedId
14+
private BookId bookId;
15+
16+
private String description;
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.introproventures.graphql.jpa.query.embeddedid.model;
2+
3+
4+
import java.io.Serializable;
5+
6+
import javax.persistence.Embeddable;
7+
8+
import lombok.Data;
9+
10+
@Data
11+
@Embeddable
12+
public class BookId implements Serializable {
13+
private static final long serialVersionUID = 1L;
14+
15+
private String title;
16+
private String language;
17+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
insert into Book(title, language, description) values
2+
('War and Piece', 'Russian', 'War and Piece Novel'),
3+
('Witch Of Water', 'English', 'Witch Of Water Fantasy');

0 commit comments

Comments
 (0)