Skip to content

Commit 007014b

Browse files
authored
feat: BETWEEN and NOT_BETWEEN where criterias (#69)
1 parent d576bab commit 007014b

File tree

7 files changed

+190
-16
lines changed

7 files changed

+190
-16
lines changed

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,12 @@
3737
import javax.persistence.metamodel.SingularAttribute;
3838
import javax.persistence.metamodel.Type;
3939

40-
import org.slf4j.Logger;
41-
import org.slf4j.LoggerFactory;
42-
4340
import com.introproventures.graphql.jpa.query.annotation.GraphQLDescription;
4441
import com.introproventures.graphql.jpa.query.annotation.GraphQLIgnore;
4542
import com.introproventures.graphql.jpa.query.schema.GraphQLSchemaBuilder;
4643
import com.introproventures.graphql.jpa.query.schema.JavaScalars;
4744
import com.introproventures.graphql.jpa.query.schema.NamingStrategy;
4845
import com.introproventures.graphql.jpa.query.schema.impl.PredicateFilter.Criteria;
49-
5046
import graphql.Assert;
5147
import graphql.Scalars;
5248
import graphql.schema.Coercing;
@@ -64,6 +60,8 @@
6460
import graphql.schema.GraphQLType;
6561
import graphql.schema.GraphQLTypeReference;
6662
import graphql.schema.PropertyDataFetcher;
63+
import org.slf4j.Logger;
64+
import org.slf4j.LoggerFactory;
6765

6866
/**
6967
* JPA specific schema builder implementation of {code #GraphQLSchemaBuilder} interface
@@ -378,7 +376,19 @@ private GraphQLInputType getWhereAttributeType(Attribute<?,?> attribute) {
378376
.description("Not In criteria")
379377
.type(new GraphQLList(getAttributeType(attribute)))
380378
.build()
381-
);
379+
)
380+
.field(GraphQLInputObjectField.newInputObjectField()
381+
.name(Criteria.BETWEEN.name())
382+
.description("Between criteria")
383+
.type(new GraphQLList(getAttributeType(attribute)))
384+
.build()
385+
)
386+
.field(GraphQLInputObjectField.newInputObjectField()
387+
.name(Criteria.NOT_BETWEEN.name())
388+
.description("Not Between criteria")
389+
.type(new GraphQLList(getAttributeType(attribute)))
390+
.build()
391+
);
382392

383393
GraphQLInputType answer = builder.build();
384394

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

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ protected Predicate addOrNull(Path<?> root, Predicate p) {
9090
protected Predicate getStringPredicate(Path<String> root, PredicateFilter filter) {
9191
Expression<String> fieldValue;
9292

93-
// list or arrays only for in and not in
93+
// list or arrays only for in and not in, between and not between
9494
Predicate arrayValuePredicate = mayBeArrayValuePredicate(root, filter);
9595

9696
if(arrayValuePredicate == null) {
@@ -199,10 +199,22 @@ protected Predicate mayBeArrayValuePredicate(Path<?> path, PredicateFilter filte
199199
} else if (filter.getCriterias().contains(PredicateFilter.Criteria.NE)
200200
|| filter.getCriterias().contains(PredicateFilter.Criteria.NIN)) {
201201
return cb.not(path.in((Object[]) filter.getValue()));
202+
} else if (!filter.getCriterias().contains(PredicateFilter.Criteria.NE)
203+
&& (filter.getCriterias().contains(Criteria.BETWEEN) || filter.getCriterias().contains(Criteria.NOT_BETWEEN))) {
204+
205+
Object[] values = (Object[]) filter.getValue();
206+
if (values.length == 2) {
207+
Expression<String> name = path.get(filter.getField());
208+
Predicate between = cb.between(name, cb.literal((String) values[0]), cb.literal((String) values[1]));
209+
if (filter.getCriterias().contains(Criteria.BETWEEN))
210+
return between;
211+
return cb.not(between);
212+
}
202213
}
203214
} else if ((filter.getValue() instanceof Collection)) {
204215
if (!filter.getCriterias().contains(PredicateFilter.Criteria.NE)
205-
&& !filter.getCriterias().contains(PredicateFilter.Criteria.NIN)) {
216+
&& !filter.getCriterias().contains(PredicateFilter.Criteria.NIN) &&
217+
!(filter.getCriterias().contains(Criteria.NOT_BETWEEN) || filter.getCriterias().contains(Criteria.BETWEEN))) {
206218
CriteriaBuilder.In<Object> in = cb.in(path);
207219
for(Object n : (Collection<?>) filter.getValue()) {
208220
in.value(n);
@@ -211,6 +223,21 @@ protected Predicate mayBeArrayValuePredicate(Path<?> path, PredicateFilter filte
211223
} else if (filter.getCriterias().contains(PredicateFilter.Criteria.NE)
212224
|| filter.getCriterias().contains(PredicateFilter.Criteria.NIN)) {
213225
return cb.not(path.in((Collection<?>) filter.getValue()));
226+
} else if (!filter.getCriterias().contains(PredicateFilter.Criteria.NE)
227+
&& (filter.getCriterias().contains(Criteria.NOT_BETWEEN) || filter.getCriterias().contains(Criteria.BETWEEN))) {
228+
Expression name = (Expression) path;
229+
Collection<?> collection = (Collection<?>) filter.getValue();
230+
if (collection.size() == 2) {
231+
Object[] values = collection.toArray();
232+
Expression fromValue = cb.literal(values[0]);
233+
Expression toValue = cb.literal(values[1]);
234+
Predicate between = cb.between(name, fromValue, toValue);
235+
if (filter.getCriterias().contains(Criteria.BETWEEN)) {
236+
return between;
237+
}
238+
239+
return cb.not(between);
240+
}
214241
}
215242
}
216243

@@ -261,6 +288,27 @@ protected Predicate getDatePredicate(Path<? extends Date> root, PredicateFilter
261288
}
262289
// LE or default
263290
return cb.lessThanOrEqualTo(root, (Date) filter.getValue());
291+
} else if (filter.getValue().getClass().isArray() || filter.getValue() instanceof Collection) {
292+
if (!filter.getCriterias().contains(PredicateFilter.Criteria.NE)
293+
&& (filter.getCriterias().contains(Criteria.BETWEEN) || filter.getCriterias().contains(Criteria.NOT_BETWEEN))) {
294+
295+
Object[] values;
296+
if (filter.getValue().getClass().isArray()) {
297+
values = (Object[]) filter.getValue();
298+
} else {
299+
values = ((Collection<?>) filter.getValue()).toArray();
300+
}
301+
302+
if (values.length == 2) {
303+
Expression<Date> name = (Expression<Date>) root;
304+
Expression<Date> fromDate = cb.literal((Date) values[0]);
305+
Expression<Date> toDate = cb.literal((Date) values[1]);
306+
Predicate between = cb.between(name, fromDate, toDate);
307+
if (filter.getCriterias().contains(Criteria.BETWEEN))
308+
return between;
309+
return cb.not(between);
310+
}
311+
}
264312
}
265313
return null;
266314
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,14 @@ public enum Criteria {
9595
* Not In condition
9696
*/
9797
NIN,
98+
/**
99+
* Between condition
100+
*/
101+
BETWEEN,
102+
/**
103+
* Not Between condition
104+
*/
105+
NOT_BETWEEN
98106
}
99107

100108
private final String field;

graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/GraphQLExecutorTests.java

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
import javax.persistence.EntityManager;
2424

25+
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor;
26+
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
2527
import org.junit.Test;
2628
import org.junit.runner.RunWith;
2729
import org.springframework.beans.factory.annotation.Autowired;
@@ -33,9 +35,6 @@
3335
import org.springframework.test.context.junit4.SpringRunner;
3436
import org.springframework.util.Assert;
3537

36-
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor;
37-
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
38-
3938
@RunWith(SpringRunner.class)
4039
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
4140
@TestPropertySource({"classpath:hibernate.properties"})
@@ -389,7 +388,76 @@ public void queryForEntityWithEmeddableTypeAndWhere() {
389388
// then
390389
assertThat(result.toString()).isEqualTo(expected);
391390
}
392-
391+
392+
@Test
393+
public void queryWithNumericBetweenPredicate() {
394+
//given:
395+
String query = "query { Books ( where: { id: {BETWEEN: [2, 5]}}) { select { id title} } }";
396+
397+
String expected = "{Books={select=[" +
398+
"{id=2, title=War and Peace}, " +
399+
"{id=3, title=Anna Karenina}, " +
400+
"{id=5, title=The Cherry Orchard}" +
401+
"]}}";
402+
403+
//when:
404+
Object result = executor.execute(query).getData();
405+
406+
//then:
407+
assertThat(result.toString()).isEqualTo(expected);
408+
}
409+
410+
@Test
411+
public void queryWithNumericNotBetweenPredicate() {
412+
//given:
413+
String query = "query { Books ( where: { id: {NOT_BETWEEN: [2, 5]}}) { select { id title} } }";
414+
415+
String expected = "{Books={select=[" +
416+
"{id=6, title=The Seagull}, " +
417+
"{id=7, title=Three Sisters}" +
418+
"]}}";
419+
420+
//when:
421+
Object result = executor.execute(query).getData();
422+
423+
//then:
424+
assertThat(result.toString()).isEqualTo(expected);
425+
}
426+
427+
@Test
428+
public void queryWithDateBetweenPredicate() {
429+
//given:
430+
String query = "query { Books ( where: { publicationDate: {BETWEEN: [\"1869-01-01\", \"1896-01-01\"]}}) { select { id title publicationDate} } }";
431+
432+
String expected = "{Books={select=[" +
433+
"{id=2, title=War and Peace, publicationDate=1869-01-01 00:00:00.0}, " +
434+
"{id=3, title=Anna Karenina, publicationDate=1877-04-01 00:00:00.0}" +
435+
"]}}";
436+
437+
//when:
438+
Object result = executor.execute(query).getData();
439+
440+
//then:
441+
assertThat(result.toString()).isEqualTo(expected);
442+
}
443+
444+
@Test
445+
public void queryWithDateNotBetweenPredicate() {
446+
//given:
447+
String query = "query { Books ( where: { publicationDate: {NOT_BETWEEN: [\"1869-01-01\", \"1896-01-01\"]}}) { select { id title publicationDate} } }";
448+
449+
String expected = "{Books={select=[" +
450+
"{id=5, title=The Cherry Orchard, publicationDate=1904-01-17 00:00:00.0}, " +
451+
"{id=6, title=The Seagull, publicationDate=1896-10-17 00:00:00.0}, " +
452+
"{id=7, title=Three Sisters, publicationDate=1900-01-01 00:00:00.0}" +
453+
"]}}";
454+
455+
//when:
456+
Object result = executor.execute(query).getData();
457+
458+
//then:
459+
assertThat(result.toString()).isEqualTo(expected);
460+
}
393461

394462

395463
}

graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/StarwarsQueryExecutorTests.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,5 +555,40 @@ public void queryWithTypenameSimple() {
555555
//then:
556556
assertThat(result.toString()).isEqualTo(expected);
557557
}
558+
559+
@Test
560+
public void queryWithStringBetweenPredicate() {
561+
//given:
562+
String query = "query { Humans ( where: { id: {BETWEEN: [\"1001\", \"1003\"]}}) { select { id } } }";
563+
564+
String expected = "{Humans={select=["
565+
+ "{id=1001}, "
566+
+ "{id=1002}, "
567+
+ "{id=1003}"
568+
+ "]}}";
569+
570+
//when:
571+
Object result = executor.execute(query).getData();
572+
573+
//then:
574+
assertThat(result.toString()).isEqualTo(expected);
575+
}
576+
577+
@Test
578+
public void queryWithStringNotBetweenPredicate() {
579+
//given:
580+
String query = "query { Humans ( where: { id: {NOT_BETWEEN: [\"1001\", \"1003\"]}}) { select { id } } }";
581+
582+
String expected = "{Humans={select=["
583+
+ "{id=1000}, "
584+
+ "{id=1004}"
585+
+ "]}}";
586+
587+
//when:
588+
Object result = executor.execute(query).getData();
589+
590+
//then:
591+
assertThat(result.toString()).isEqualTo(expected);
592+
}
558593

559594
}

graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/model/book/Book.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.introproventures.graphql.jpa.query.schema.model.book;
1818

19+
import java.util.Date;
20+
1921
import javax.persistence.Entity;
2022
import javax.persistence.EnumType;
2123
import javax.persistence.Enumerated;
@@ -38,4 +40,6 @@ public class Book {
3840

3941
@Enumerated(EnumType.STRING)
4042
Genre genre;
43+
44+
Date publicationDate;
4145
}

graphql-jpa-query-schema/src/test/resources/data.sql

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,13 @@ insert into thing (id, type) values
108108

109109
-- Books
110110
insert into author (id, name, genre) values (1, 'Leo Tolstoy', 'NOVEL');
111-
insert into book (id, title, author_id, genre) values (2, 'War and Peace', 1, 'NOVEL');
112-
insert into book (id, title, author_id, genre) values (3, 'Anna Karenina', 1, 'NOVEL');
111+
insert into book (id, title, author_id, genre, publication_date) values (2, 'War and Peace', 1, 'NOVEL', '1869-01-01');
112+
insert into book (id, title, author_id, genre, publication_date) values (3, 'Anna Karenina', 1, 'NOVEL', '1877-04-01');
113113
insert into author (id, name, genre) values (4, 'Anton Chekhov', 'PLAY');
114-
insert into book (id, title, author_id, genre) values (5, 'The Cherry Orchard', 4, 'PLAY');
115-
insert into book (id, title, author_id, genre) values (6, 'The Seagull', 4, 'PLAY');
116-
insert into book (id, title, author_id, genre) values (7, 'Three Sisters', 4, 'PLAY');
114+
insert into book (id, title, author_id, genre, publication_date) values (5, 'The Cherry Orchard', 4, 'PLAY', '1904-01-17');
115+
insert into book (id, title, author_id, genre, publication_date) values (6, 'The Seagull', 4, 'PLAY', '1896-10-17');
116+
insert into book (id, title, author_id, genre, publication_date) values (7, 'Three Sisters', 4, 'PLAY', '1900-01-01');
117+
117118
insert into author_phone_numbers(phone_number, author_id) values
118119
('1-123-1234', 1),
119120
('1-123-5678', 1),

0 commit comments

Comments
 (0)