Skip to content

Commit a5f4269

Browse files
committed
make left side of comparison generic
1 parent 1d62964 commit a5f4269

File tree

5 files changed

+103
-44
lines changed

5 files changed

+103
-44
lines changed

src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.github.sidhant92.boolparser.application;
22

3+
import static com.github.sidhant92.boolparser.constant.NodeType.UNARY;
34
import java.util.Collections;
45
import java.util.List;
56
import java.util.Map;
@@ -72,17 +73,31 @@ private boolean evaluateToken(final Node node, final Map<String, Object> data) {
7273
}
7374
}
7475

75-
private boolean evaluateComparisonToken(final ComparisonNode comparisonToken, final Map<String, Object> data) {
76-
final Optional<Object> fieldDataOptional = ValueUtils.getValueFromMap(comparisonToken.getField(), data);
76+
private Optional<Object> getValue(final Node node, final Map<String, Object> data) {
77+
switch (node.getTokenType()) {
78+
case FIELD:
79+
return ValueUtils.getValueFromMap(((FieldNode) node).getField(), data);
80+
case UNARY:
81+
final UnaryNode unaryNode = (UnaryNode) node;
82+
return Optional.of(unaryNode.getValue());
83+
default:
84+
if (node instanceof ArithmeticBaseNode) {
85+
return Optional.of(arithmeticExpressionEvaluator.evaluate(node, data));
86+
}
87+
return Optional.of(evaluateToken(node, data));
88+
}
89+
}
7790

78-
final Object fieldData = comparisonToken.isNullCheck() ? fieldDataOptional.orElse("null") : fieldDataOptional.orElseThrow(
79-
() -> new DataNotFoundException(comparisonToken.getField()));
80-
final Object value = comparisonToken.isNullCheck() ? "null" : comparisonToken.getValue() instanceof ArithmeticBaseNode ? arithmeticExpressionEvaluator.evaluate(
81-
comparisonToken.getValue(), data) : comparisonToken.getValue();
82-
final DataType dataType = ValueUtils.getDataType(value);
83-
final DataType fieldDataType = ValueUtils.getDataType(fieldData);
84-
return operatorService.evaluateLogicalOperator(comparisonToken.getOperator(), ContainerDataType.PRIMITIVE, fieldData, fieldDataType,
85-
Collections.singletonList(Pair.of(value, dataType)));
91+
private boolean evaluateComparisonToken(final ComparisonNode comparisonToken, final Map<String, Object> data) {
92+
final Optional<Object> leftValueOptional = getValue(comparisonToken.getLeft(), data);
93+
94+
final Object leftData = comparisonToken.isNullCheck() ? leftValueOptional.orElse("null") : leftValueOptional.orElseThrow(
95+
() -> new DataNotFoundException(((FieldNode) comparisonToken.getLeft()).getField()));
96+
final Object rightData = comparisonToken.isNullCheck() ? "null" : getValue(comparisonToken.getRight(), data).get();
97+
final DataType rightDataType = ValueUtils.getDataType(rightData);
98+
final DataType leftDataType = ValueUtils.getDataType(leftData);
99+
return operatorService.evaluateLogicalOperator(comparisonToken.getOperator(), ContainerDataType.PRIMITIVE, leftData, leftDataType,
100+
Collections.singletonList(Pair.of(rightData, rightDataType)));
86101
}
87102

88103
private boolean evaluateNumericRangeToken(final NumericRangeNode numericRangeToken, final Map<String, Object> data) {

src/main/java/com/github/sidhant92/boolparser/domain/logical/ComparisonNode.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
@Setter
1919
@Builder
2020
public class ComparisonNode extends Node {
21-
private final String field;
21+
private final Node left;
2222

23-
private final Node value;
23+
private final Node right;
2424

2525
private final Operator operator;
2626

@@ -32,6 +32,6 @@ public NodeType getTokenType() {
3232
}
3333

3434
public boolean isNullCheck() {
35-
return Operator.getEqualityOperators().contains(this.operator) && this.value instanceof FieldNode && ((FieldNode) this.value).isNull();
35+
return Operator.getEqualityOperators().contains(this.operator) && (this.right instanceof FieldNode && ((FieldNode) this.right).isNull() || this.left instanceof FieldNode && ((FieldNode) this.left).isNull());
3636
}
3737
}

src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterListener.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,17 @@ private Node mapContextToNode(final ParseTree ctx) {
126126
}
127127

128128
private FieldNode mapTypesExpressionContextField(BooleanExpressionParser.TypesExpressionContext ctx) {
129-
return new FieldNode(ctx.getText());
129+
final String value = StringUtils.isBlank(ctx.getText()) ? defaultField : ctx.getText();
130+
return new FieldNode(value);
130131
}
131132

132133
private Node mapTypesExpressionContext(BooleanExpressionParser.TypesExpressionContext ctx) {
133134
if (ctx.start.getType() == BooleanExpressionLexer.FIELD) {
134135
return mapTypesExpressionContextField(ctx);
135136
}
137+
if (StringUtils.isBlank(ctx.getText())) {
138+
return mapTypesExpressionContextField(ctx);
139+
}
136140
final DataType dataType = getDataType(ctx.start);
137141
final Object value = ValueUtils.convertValue(ctx.start.getText(), dataType);
138142
return new UnaryNode(dataType, value);
@@ -150,15 +154,19 @@ private ArithmeticFunctionNode mapArithmeticFunctionExpressionContext(BooleanExp
150154
}
151155

152156
private ComparisonNode mapComparatorExpressionContext(BooleanExpressionParser.ComparatorExpressionContext ctx) {
153-
final String variableName = getField(ctx.left.getText());
154157
final Operator operator = Operator.getOperatorFromSymbol(ctx.op.getText()).orElse(Operator.EQUALS);
155158
if (!(ctx.right instanceof BooleanExpressionParser.TypesExpressionContext) && !currentNodes.isEmpty()) {
156159
final Node value = currentNodes.pop();
157-
return new ComparisonNode(variableName, value, operator, DataType.INTEGER);
160+
return new ComparisonNode(mapContextToNode(ctx.left), value, operator, DataType.INTEGER);
158161
} else {
162+
if (ctx.left instanceof BooleanExpressionParser.ParentExpressionContext && !currentNodes.isEmpty()) {
163+
final DataType dataType = getDataType(ctx.right.getStart());
164+
final Node value = mapContextToNode(ctx.right);
165+
return new ComparisonNode(currentNodes.pop(), value, operator, dataType);
166+
}
159167
final DataType dataType = getDataType(ctx.right.getStart());
160168
final Node value = mapContextToNode(ctx.right);
161-
return new ComparisonNode(variableName, value, operator, dataType);
169+
return new ComparisonNode(mapContextToNode(ctx.left), value, operator, dataType);
162170
}
163171
}
164172

src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,15 @@ public void testNumericGreaterThanCorrectExpression() {
112112
assertTrue(booleanOptional.get());
113113
}
114114

115+
@Test
116+
public void testNumericGreaterThanCorrectExpressionInverted() {
117+
final Map<String, Object> data = new HashMap<>();
118+
data.put("age", 24);
119+
final Try<Boolean> booleanOptional = booleanExpressionEvaluator.evaluate("20 < age", data);
120+
assertTrue(booleanOptional.isSuccess());
121+
assertTrue(booleanOptional.get());
122+
}
123+
115124
@Test
116125
public void testNumericGreaterThanCorrectExpressionWithField() {
117126
final Map<String, Object> data = new HashMap<>();
@@ -553,6 +562,15 @@ public void testComparisonWithArithmeticTrueCondition() {
553562
assertTrue(booleanOptional.get());
554563
}
555564

565+
@Test
566+
public void testComparisonWithArithmeticTrueConditionInverted() {
567+
final Map<String, Object> data = new HashMap<>();
568+
data.put("age", "20");
569+
final Try<Boolean> booleanOptional = booleanExpressionEvaluator.evaluate("(5 + 10) < age", data);
570+
assertTrue(booleanOptional.isSuccess());
571+
assertTrue(booleanOptional.get());
572+
}
573+
556574
@Test
557575
public void testComparisonWithArithmeticFunction() {
558576
final Map<String, Object> data = new HashMap<>();
@@ -614,6 +632,15 @@ public void testNullCheck() {
614632
assertEquals(resultOptional.get(), true);
615633
}
616634

635+
@Test
636+
public void testNullCheckInverted() {
637+
final Map<String, Object> data = new HashMap<>();
638+
data.put("a", 2.7);
639+
final Try<Boolean> resultOptional = booleanExpressionEvaluator.evaluate("null = b", data);
640+
assertTrue(resultOptional.isSuccess());
641+
assertEquals(resultOptional.get(), true);
642+
}
643+
617644
@Test
618645
public void testNullCheck1() {
619646
final Map<String, Object> data = new HashMap<>();
@@ -640,4 +667,13 @@ public void testBooleanNullCheck() {
640667
assertTrue(resultOptional.isSuccess());
641668
assertEquals(resultOptional.get(), true);
642669
}
670+
671+
@Test
672+
public void testArithmeticFunctionAndComparison() {
673+
final Map<String, Object> data = new HashMap<>();
674+
data.put("a", "test");
675+
final Try<Boolean> resultOptional = booleanExpressionEvaluator.evaluate("len(a) = 4", data);
676+
assertTrue(resultOptional.isSuccess());
677+
assertEquals(resultOptional.get(), true);
678+
}
643679
}

0 commit comments

Comments
 (0)