Skip to content

Commit baf521e

Browse files
committed
Implement IN and BETWEEN operator
1 parent 05e5d07 commit baf521e

File tree

3 files changed

+225
-76
lines changed

3 files changed

+225
-76
lines changed

engine/src/main/java/io/graphqlcrud/Filters.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ public static GraphQLInputObjectType.Builder floatInputBuilder() {
6868
.field(GraphQLInputObjectField.newInputObjectField().name("lt").type(Scalars.GraphQLFloat))
6969
.field(GraphQLInputObjectField.newInputObjectField().name("ge").type(Scalars.GraphQLFloat))
7070
.field(GraphQLInputObjectField.newInputObjectField().name("gt").type(Scalars.GraphQLFloat))
71-
.field(GraphQLInputObjectField.newInputObjectField().name("in").type(GraphQLList.list(GraphQLNonNull.nonNull(Scalars.GraphQLFloat))));
71+
.field(GraphQLInputObjectField.newInputObjectField().name("in").type(GraphQLList.list(GraphQLNonNull.nonNull(Scalars.GraphQLFloat))))
72+
.field(GraphQLInputObjectField.newInputObjectField().name("between").type(GraphQLList.list(GraphQLNonNull.nonNull(Scalars.GraphQLFloat))));
7273
}
7374

7475
public static GraphQLInputObjectType.Builder intInputBuilder() {
@@ -79,7 +80,8 @@ public static GraphQLInputObjectType.Builder intInputBuilder() {
7980
.field(GraphQLInputObjectField.newInputObjectField().name("lt").type(Scalars.GraphQLInt))
8081
.field(GraphQLInputObjectField.newInputObjectField().name("ge").type(Scalars.GraphQLInt))
8182
.field(GraphQLInputObjectField.newInputObjectField().name("gt").type(Scalars.GraphQLInt))
82-
.field(GraphQLInputObjectField.newInputObjectField().name("in").type(GraphQLList.list(GraphQLNonNull.nonNull(Scalars.GraphQLInt))));
83+
.field(GraphQLInputObjectField.newInputObjectField().name("in").type(GraphQLList.list(GraphQLNonNull.nonNull(Scalars.GraphQLInt))))
84+
.field(GraphQLInputObjectField.newInputObjectField().name("between").type(GraphQLList.list(GraphQLNonNull.nonNull(Scalars.GraphQLInt))));
8385
}
8486

8587
public static GraphQLInputObjectType.Builder orderByInputBuilder() {

engine/src/main/java/io/graphqlcrud/SQLQueryBuilderVisitor.java

+146-60
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package io.graphqlcrud;
1717

18+
import java.math.BigDecimal;
19+
import java.math.BigInteger;
1820
import java.util.*;
1921
import java.util.concurrent.atomic.AtomicInteger;
2022

@@ -269,82 +271,161 @@ public void visitArgument(Field field, GraphQLFieldDefinition definition, GraphQ
269271
}
270272
}
271273

272-
public Condition visitStringValue(Value v, org.jooq.Field left, String conditionName) {
274+
public Condition visitStringValue(String value, org.jooq.Field left, String conditionName) {
273275
Condition c = null;
274-
if(conditionName.equals("eq"))
275-
c = left.eq(((StringValue)v).getValue());
276-
else if(conditionName.equals("ne"))
277-
c = left.ne(((StringValue) v).getValue());
278-
else if(conditionName.equals("lt"))
279-
c = left.lt(((StringValue) v).getValue());
280-
else if(conditionName.equals("le"))
281-
c = left.le(((StringValue) v).getValue());
282-
else if(conditionName.equals("gt"))
283-
c = left.gt(((StringValue) v).getValue());
284-
else if(conditionName.equals("ge"))
285-
c = left.in(((StringValue) v).getValue());
286-
else if(conditionName.equals("contains"))
287-
c = left.contains(((StringValue) v).getValue());
288-
else if(conditionName.equals("startsWith"))
289-
c = left.startsWith(((StringValue) v).getValue());
290-
else if(conditionName.equals("endsWith"))
291-
c = left.endsWith(((StringValue) v).getValue());
276+
switch (conditionName) {
277+
case "eq":
278+
c = left.eq(value);
279+
break;
280+
case "ne":
281+
c = left.ne(value);
282+
break;
283+
case "lt":
284+
c = left.lt(value);
285+
break;
286+
case "le":
287+
c = left.le(value);
288+
break;
289+
case "gt":
290+
c = left.gt(value);
291+
break;
292+
case "ge":
293+
c = left.in(value);
294+
break;
295+
case "contains":
296+
c = left.contains(value);
297+
break;
298+
case "startsWith":
299+
c = left.startsWith(value);
300+
break;
301+
case "endsWith":
302+
c = left.endsWith(value);
303+
break;
304+
default:
305+
throw new RuntimeException("Unexpected value: " + conditionName);
306+
}
292307
return c;
293308
}
294309

295-
public Condition visitBooleanValue(Value v, org.jooq.Field left, String conditionName) {
310+
public Condition visitBooleanValue(Boolean value, org.jooq.Field left, String conditionName) {
296311
Condition c = null;
297-
if(conditionName.equals("eq"))
298-
c = left.eq(((BooleanValue)v).isValue());
299-
else if(conditionName.equals("ne"))
300-
c = left.ne(((BooleanValue) v).isValue());
312+
switch (conditionName) {
313+
case "eq":
314+
c = left.eq(value);
315+
break;
316+
case "ne":
317+
c = left.ne(value);
318+
break;
319+
default:
320+
throw new RuntimeException("Unexpected value: " + conditionName);
321+
}
301322
return c;
302323
}
303324

304-
public Condition visitIntValue(Value v, org.jooq.Field left, String conditionName) {
325+
public Condition visitIntValue(BigInteger value, org.jooq.Field left, String conditionName) {
305326
Condition c = null;
306-
if(conditionName.equals("eq"))
307-
c = left.eq(((IntValue)v).getValue());
308-
else if(conditionName.equals("ne"))
309-
c = left.ne(((IntValue) v).getValue());
310-
else if(conditionName.equals("lt"))
311-
c = left.lt(((IntValue) v).getValue());
312-
else if(conditionName.equals("le"))
313-
c = left.le(((IntValue) v).getValue());
314-
else if(conditionName.equals("gt"))
315-
c = left.gt(((IntValue) v).getValue());
316-
else if(conditionName.equals("ge"))
317-
c = left.ge(((IntValue) v).getValue());
327+
switch (conditionName) {
328+
case "eq":
329+
c = left.eq(value);
330+
break;
331+
case "ne":
332+
c = left.ne(value);
333+
break;
334+
case "lt":
335+
c = left.lt(value);
336+
break;
337+
case "le":
338+
c = left.le(value);
339+
break;
340+
case "gt":
341+
c = left.gt(value);
342+
break;
343+
case "ge":
344+
c = left.ge(value);
345+
break;
346+
default:
347+
throw new RuntimeException("Unexpected value: " + conditionName);
348+
}
318349
return c;
319350
}
320351

321-
public Condition visitFloatValue(Value v, org.jooq.Field left, String conditionName) {
352+
public Condition visitFloatValue(BigDecimal value, org.jooq.Field left, String conditionName) {
322353
Condition c = null;
323-
if(conditionName.equals("eq"))
324-
c = left.eq(((FloatValue)v).getValue());
325-
else if(conditionName.equals("ne"))
326-
c = left.ne(((FloatValue) v).getValue());
327-
else if(conditionName.equals("lt"))
328-
c = left.lt(((FloatValue) v).getValue());
329-
else if(conditionName.equals("le"))
330-
c = left.le(((FloatValue) v).getValue());
331-
else if(conditionName.equals("gt"))
332-
c = left.gt(((FloatValue) v).getValue());
333-
else if(conditionName.equals("ge"))
334-
c = left.ge(((FloatValue) v).getValue());
354+
switch (conditionName) {
355+
case "eq":
356+
c = left.eq(value);
357+
break;
358+
case "ne":
359+
c = left.ne(value);
360+
break;
361+
case "lt":
362+
c = left.lt(value);
363+
break;
364+
case "le":
365+
c = left.le(value);
366+
break;
367+
case "gt":
368+
c = left.gt(value);
369+
break;
370+
case "ge":
371+
c = left.ge(value);
372+
break;
373+
default:
374+
throw new RuntimeException("Unexpected value: " + conditionName);
375+
}
376+
return c;
377+
}
378+
379+
380+
public Condition visitArrayValue(List<Value> v, org.jooq.Field left, String conditionName) {
381+
Condition c = null;
382+
switch (conditionName) {
383+
case "between":
384+
if (v.get(0) instanceof FloatValue) {
385+
c = left.between(((FloatValue) v.get(0)).getValue(), ((FloatValue) v.get(1)).getValue());
386+
} else if (v.get(0) instanceof IntValue) {
387+
c = left.between(((IntValue) v.get(0)).getValue(), ((IntValue) v.get(1)).getValue());
388+
}
389+
break;
390+
case "in":
391+
if (v.get(0) instanceof StringValue) {
392+
List<String> list = new ArrayList<>();
393+
for (Value value : v) {
394+
list.add(((StringValue) value).getValue());
395+
}
396+
c = left.in(list);
397+
} else if (v.get(0) instanceof FloatValue) {
398+
List<BigDecimal> list = new ArrayList<>();
399+
for (Value value : v) {
400+
list.add(((FloatValue) value).getValue());
401+
}
402+
c = left.in(list);
403+
} else if (v.get(0) instanceof IntValue) {
404+
List<BigInteger> list = new ArrayList<>();
405+
for (Value value : v) {
406+
list.add(((IntValue) value).getValue());
407+
}
408+
c = left.in(list);
409+
}
410+
break;
411+
default:
412+
throw new RuntimeException("Unexpected value: " + conditionName);
413+
}
335414
return c;
336415
}
337416

338417
public Condition visitValueType(Value v, org.jooq.Field left, String conditionName) {
339418
Condition c = null;
340419
if (v instanceof StringValue) {
341-
c = visitStringValue(v,left,conditionName);
420+
c = visitStringValue(((StringValue) v).getValue(),left,conditionName);
342421
} else if (v instanceof BooleanValue) {
343-
c = visitBooleanValue(v,left,conditionName);
422+
c = visitBooleanValue(((BooleanValue) v).isValue(),left,conditionName);
344423
} else if (v instanceof IntValue) {
345-
c = visitIntValue(v,left,conditionName);
424+
c = visitIntValue(((IntValue) v).getValue(),left,conditionName);
346425
} else if (v instanceof FloatValue) {
347-
c = visitFloatValue(v,left,conditionName);
426+
c = visitFloatValue(((FloatValue) v).getValue(),left,conditionName);
427+
} else if(v instanceof ArrayValue) {
428+
c = visitArrayValue(((ArrayValue) v).getValues(),left,conditionName);
348429
}
349430
return c;
350431
}
@@ -362,12 +443,15 @@ public void visitFilterInputs(Value argumentValue, VistorContext vistorContext,
362443
left = field(name(vistorContext.alias, field.getName()));
363444
org.jooq.Field<Object> finalLeft = left;
364445
String finalConditionName = conditionName;
365-
field.getValue().getChildren().forEach(child -> {
366-
Condition condition = visitValueType(((ObjectField) child).getValue(), finalLeft, ((ObjectField) child).getName());
367-
visitCondition(finalConditionName, condition);
368-
});
446+
for(Object object : field.getValue().getChildren()) {
447+
if(object instanceof ObjectField) {
448+
Condition condition = visitValueType(((ObjectField) object).getValue(), finalLeft, ((ObjectField) object).getName());
449+
visitCondition(finalConditionName, condition);
450+
}
451+
}
369452
}
370-
visitFilterInputs(field.getValue(), vistorContext, conditionName);
453+
if(field.getValue() instanceof ObjectValue)
454+
visitFilterInputs(field.getValue(), vistorContext, conditionName);
371455
}
372456
}
373457
}
@@ -378,7 +462,9 @@ public void visitCondition(String conditionName, Condition conditionValue) {
378462
vistorContext.condition = conditionValue;
379463
}
380464
else {
381-
if(conditionName.equals("and")) {
465+
if(conditionName == null) {
466+
vistorContext.condition = vistorContext.condition.and(conditionValue);
467+
} else if(conditionName.equals("and")) {
382468
vistorContext.condition = vistorContext.condition.and(conditionValue);
383469
} else if (conditionName.equals("or")) {
384470
vistorContext.condition = vistorContext.condition.or(conditionValue);

engine/src/test/java/io/graphqlcrud/SQLDataFetcherTest.java

+75-14
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,55 @@ public void simpleFilterQuery() throws Exception {
218218
"order by \"g0\".\"SSN\"";
219219
Assertions.assertEquals(expected,result);
220220

221+
String query1 = "{\n" +
222+
" accounts (filter: {\n" +
223+
" ACCOUNT_ID: {\n" +
224+
" in: [19980001,19980005,19990009]\n" +
225+
" },\n" +
226+
" and: {\n" +
227+
" STATUS: {\n" +
228+
" eq: \"Personal\"\n" +
229+
" }\n" +
230+
" }\n" +
231+
" }) {\n" +
232+
" ACCOUNT_ID\n" +
233+
" SSN\n" +
234+
" STATUS\n" +
235+
" }\n" +
236+
"}";
237+
String result1 = executeSQL(query1);
238+
String expected1 = "select\n" +
239+
" \"g0\".\"ACCOUNT_ID\" \"ACCOUNT_ID\",\n" +
240+
" \"g0\".\"SSN\" \"SSN\",\n" +
241+
" \"g0\".\"STATUS\" \"STATUS\"\n" +
242+
"from PUBLIC.ACCOUNT \"g0\"\n" +
243+
"where (\n" +
244+
" \"g0\".\"ACCOUNT_ID\" in (\n" +
245+
" 19980001, 19980005, 19990009\n" +
246+
" )\n" +
247+
" and \"g0\".\"STATUS\" = 'Personal'\n" +
248+
")\n" +
249+
"order by \"g0\".\"ACCOUNT_ID\"";
250+
Assertions.assertEquals(expected1,result1);
251+
252+
String query2 = "{\n" +
253+
" accounts (filter: {\n" +
254+
" ACCOUNT_ID: {\n" +
255+
" between: [19980001,19980005]\n" +
256+
" }\n" +
257+
" }) {\n" +
258+
" ACCOUNT_ID\n" +
259+
" STATUS\n" +
260+
" }\n" +
261+
"}";
262+
String result2 = executeSQL(query2);
263+
String expected2 = "select\n" +
264+
" \"g0\".\"ACCOUNT_ID\" \"ACCOUNT_ID\",\n" +
265+
" \"g0\".\"STATUS\" \"STATUS\"\n" +
266+
"from PUBLIC.ACCOUNT \"g0\"\n" +
267+
"where \"g0\".\"ACCOUNT_ID\" between 19980001 and 19980005\n" +
268+
"order by \"g0\".\"ACCOUNT_ID\"";
269+
Assertions.assertEquals(expected2,result2);
221270
}
222271

223272
@Test
@@ -284,29 +333,41 @@ public void nestedFilterQuery() throws Exception{
284333
public void simpleAndOrFilterQuery() throws Exception {
285334
String query = "{\n" +
286335
" customers (filter: {\n" +
287-
" and: {\n" +
288-
" LASTNAME: {\n" +
289-
" eq: \"Smith\"\n" +
290-
" },\n" +
291-
" or: {\n" +
292-
" LASTNAME: {\n" +
293-
" eq: \"Doe\"\n" +
294-
" }\n" +
336+
" LASTNAME: {\n" +
337+
" eq: \"Smith\"\n" +
338+
" },\n" +
339+
" FIRSTNAME: {\n" +
340+
" eq: \"John\"\n" +
341+
" },\n" +
342+
" or: {\n" +
343+
" SSN: {\n" +
344+
" eq: \"CST01002\"\n" +
295345
" }\n" +
296346
" }\n" +
297347
" }) {\n" +
298-
" SSN\n" +
299348
" FIRSTNAME\n" +
349+
" LASTNAME\n" +
350+
" addreses {\n" +
351+
" STATE\n" +
352+
" }\n" +
300353
" }\n" +
301354
"}";
302355
String result = executeSQL(query);
303-
String expected = "select\n" +
304-
" \"g0\".\"SSN\" \"SSN\",\n" +
305-
" \"g0\".\"FIRSTNAME\" \"FIRSTNAME\"\n" +
356+
String expected ="select\n" +
357+
" \"g0\".\"FIRSTNAME\" \"FIRSTNAME\",\n" +
358+
" \"g0\".\"LASTNAME\" \"LASTNAME\",\n" +
359+
" (\n" +
360+
" select json_arrayagg(json_object(key 'STATE' value \"g1\".\"STATE\"))\n" +
361+
" from PUBLIC.ADDRESS \"g1\"\n" +
362+
" where \"g0\".\"SSN\" = \"g1\".\"SSN\"\n" +
363+
" ) \"addreses\"\n" +
306364
"from PUBLIC.CUSTOMER \"g0\"\n" +
307365
"where (\n" +
308-
" \"g0\".\"LASTNAME\" = 'Smith'\n" +
309-
" or \"g0\".\"LASTNAME\" = 'Doe'\n" +
366+
" (\n" +
367+
" \"g0\".\"LASTNAME\" = 'Smith'\n" +
368+
" and \"g0\".\"FIRSTNAME\" = 'John'\n" +
369+
" )\n" +
370+
" or \"g0\".\"SSN\" = 'CST01002'\n" +
310371
")\n" +
311372
"order by \"g0\".\"SSN\"";
312373
Assertions.assertEquals(expected,result);

0 commit comments

Comments
 (0)