Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.sidhant92.boolparser.application;

import static com.github.sidhant92.boolparser.constant.NodeType.UNARY;
import java.util.Collections;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -72,17 +73,31 @@ private boolean evaluateToken(final Node node, final Map<String, Object> data) {
}
}

private boolean evaluateComparisonToken(final ComparisonNode comparisonToken, final Map<String, Object> data) {
final Optional<Object> fieldDataOptional = ValueUtils.getValueFromMap(comparisonToken.getField(), data);
private Optional<Object> getValue(final Node node, final Map<String, Object> data) {
switch (node.getTokenType()) {
case FIELD:
return ValueUtils.getValueFromMap(((FieldNode) node).getField(), data);
case UNARY:
final UnaryNode unaryNode = (UnaryNode) node;
return Optional.of(unaryNode.getValue());
default:
if (node instanceof ArithmeticBaseNode) {
return Optional.of(arithmeticExpressionEvaluator.evaluate(node, data));
}
return Optional.of(evaluateToken(node, data));
}
}

final Object fieldData = comparisonToken.isNullCheck() ? fieldDataOptional.orElse("null") : fieldDataOptional.orElseThrow(
() -> new DataNotFoundException(comparisonToken.getField()));
final Object value = comparisonToken.isNullCheck() ? "null" : comparisonToken.getValue() instanceof ArithmeticBaseNode ? arithmeticExpressionEvaluator.evaluate(
comparisonToken.getValue(), data) : comparisonToken.getValue();
final DataType dataType = ValueUtils.getDataType(value);
final DataType fieldDataType = ValueUtils.getDataType(fieldData);
return operatorService.evaluateLogicalOperator(comparisonToken.getOperator(), ContainerDataType.PRIMITIVE, fieldData, fieldDataType,
Collections.singletonList(Pair.of(value, dataType)));
private boolean evaluateComparisonToken(final ComparisonNode comparisonToken, final Map<String, Object> data) {
final Optional<Object> leftValueOptional = getValue(comparisonToken.getLeft(), data);

final Object leftData = comparisonToken.isNullCheck() ? leftValueOptional.orElse("null") : leftValueOptional.orElseThrow(
() -> new DataNotFoundException(((FieldNode) comparisonToken.getLeft()).getField()));
final Object rightData = comparisonToken.isNullCheck() ? "null" : getValue(comparisonToken.getRight(), data).get();
final DataType rightDataType = ValueUtils.getDataType(rightData);
final DataType leftDataType = ValueUtils.getDataType(leftData);
return operatorService.evaluateLogicalOperator(comparisonToken.getOperator(), ContainerDataType.PRIMITIVE, leftData, leftDataType,
Collections.singletonList(Pair.of(rightData, rightDataType)));
}

private boolean evaluateNumericRangeToken(final NumericRangeNode numericRangeToken, final Map<String, Object> data) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
@Setter
@Builder
public class ComparisonNode extends Node {
private final String field;
private final Node left;

private final Node value;
private final Node right;

private final Operator operator;

Expand All @@ -32,6 +32,6 @@ public NodeType getTokenType() {
}

public boolean isNullCheck() {
return Operator.getEqualityOperators().contains(this.operator) && this.value instanceof FieldNode && ((FieldNode) this.value).isNull();
return Operator.getEqualityOperators().contains(this.operator) && (this.right instanceof FieldNode && ((FieldNode) this.right).isNull() || this.left instanceof FieldNode && ((FieldNode) this.left).isNull());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,17 @@ private Node mapContextToNode(final ParseTree ctx) {
}

private FieldNode mapTypesExpressionContextField(BooleanExpressionParser.TypesExpressionContext ctx) {
return new FieldNode(ctx.getText());
final String value = StringUtils.isBlank(ctx.getText()) ? defaultField : ctx.getText();
return new FieldNode(value);
}

private Node mapTypesExpressionContext(BooleanExpressionParser.TypesExpressionContext ctx) {
if (ctx.start.getType() == BooleanExpressionLexer.FIELD) {
return mapTypesExpressionContextField(ctx);
}
if (StringUtils.isBlank(ctx.getText())) {
return mapTypesExpressionContextField(ctx);
}
final DataType dataType = getDataType(ctx.start);
final Object value = ValueUtils.convertValue(ctx.start.getText(), dataType);
return new UnaryNode(dataType, value);
Expand All @@ -150,15 +154,19 @@ private ArithmeticFunctionNode mapArithmeticFunctionExpressionContext(BooleanExp
}

private ComparisonNode mapComparatorExpressionContext(BooleanExpressionParser.ComparatorExpressionContext ctx) {
final String variableName = getField(ctx.left.getText());
final Operator operator = Operator.getOperatorFromSymbol(ctx.op.getText()).orElse(Operator.EQUALS);
if (!(ctx.right instanceof BooleanExpressionParser.TypesExpressionContext) && !currentNodes.isEmpty()) {
final Node value = currentNodes.pop();
return new ComparisonNode(variableName, value, operator, DataType.INTEGER);
return new ComparisonNode(mapContextToNode(ctx.left), value, operator, DataType.INTEGER);
} else {
if (ctx.left instanceof BooleanExpressionParser.ParentExpressionContext && !currentNodes.isEmpty()) {
final DataType dataType = getDataType(ctx.right.getStart());
final Node value = mapContextToNode(ctx.right);
return new ComparisonNode(currentNodes.pop(), value, operator, dataType);
}
final DataType dataType = getDataType(ctx.right.getStart());
final Node value = mapContextToNode(ctx.right);
return new ComparisonNode(variableName, value, operator, dataType);
return new ComparisonNode(mapContextToNode(ctx.left), value, operator, dataType);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,15 @@ public void testNumericGreaterThanCorrectExpression() {
assertTrue(booleanOptional.get());
}

@Test
public void testNumericGreaterThanCorrectExpressionInverted() {
final Map<String, Object> data = new HashMap<>();
data.put("age", 24);
final Try<Boolean> booleanOptional = booleanExpressionEvaluator.evaluate("20 < age", data);
assertTrue(booleanOptional.isSuccess());
assertTrue(booleanOptional.get());
}

@Test
public void testNumericGreaterThanCorrectExpressionWithField() {
final Map<String, Object> data = new HashMap<>();
Expand Down Expand Up @@ -553,6 +562,15 @@ public void testComparisonWithArithmeticTrueCondition() {
assertTrue(booleanOptional.get());
}

@Test
public void testComparisonWithArithmeticTrueConditionInverted() {
final Map<String, Object> data = new HashMap<>();
data.put("age", "20");
final Try<Boolean> booleanOptional = booleanExpressionEvaluator.evaluate("(5 + 10) < age", data);
assertTrue(booleanOptional.isSuccess());
assertTrue(booleanOptional.get());
}

@Test
public void testComparisonWithArithmeticFunction() {
final Map<String, Object> data = new HashMap<>();
Expand Down Expand Up @@ -614,6 +632,15 @@ public void testNullCheck() {
assertEquals(resultOptional.get(), true);
}

@Test
public void testNullCheckInverted() {
final Map<String, Object> data = new HashMap<>();
data.put("a", 2.7);
final Try<Boolean> resultOptional = booleanExpressionEvaluator.evaluate("null = b", data);
assertTrue(resultOptional.isSuccess());
assertEquals(resultOptional.get(), true);
}

@Test
public void testNullCheck1() {
final Map<String, Object> data = new HashMap<>();
Expand All @@ -640,4 +667,13 @@ public void testBooleanNullCheck() {
assertTrue(resultOptional.isSuccess());
assertEquals(resultOptional.get(), true);
}

@Test
public void testArithmeticFunctionAndComparison() {
final Map<String, Object> data = new HashMap<>();
data.put("a", "test");
final Try<Boolean> resultOptional = booleanExpressionEvaluator.evaluate("len(a) = 4", data);
assertTrue(resultOptional.isSuccess());
assertEquals(resultOptional.get(), true);
}
}
Loading