From 488d3af7ffcf70dbec309e438c765bfcf7367baa Mon Sep 17 00:00:00 2001 From: Sidhant Aggarwal <10743214+sidhant92@users.noreply.github.com> Date: Sun, 29 Oct 2023 11:45:54 +0530 Subject: [PATCH] default field support --- build.gradle | 2 +- .../BooleanExpressionEvaluator.java | 8 ++++++-- .../parser/BoolExpressionParser.java | 2 ++ .../boolparser/parser/antlr/BoolParser.java | 17 ++++++++++------ .../parser/antlr/BooleanFilterListener.java | 20 +++++++++++++++---- .../BooleanExpressionEvaluatorTest.java | 18 +++++++++++++++++ 6 files changed, 54 insertions(+), 13 deletions(-) diff --git a/build.gradle b/build.gradle index a34b52d..12fc55f 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ sourceCompatibility = 1.8 targetCompatibility = 1.8 group 'com.github.sidhant92' -version = "1.0.0" +version = "1.1.0" apply plugin: "com.dipien.semantic-version" diff --git a/src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java b/src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java index 94961c7..c76e4d2 100644 --- a/src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java +++ b/src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java @@ -34,11 +34,15 @@ public BooleanExpressionEvaluator(final BoolExpressionParser boolExpressionParse operatorService = new OperatorService(); } - public Try evaluate(final String expression, final Map data) { - final Try tokenOptional = boolExpressionParser.parseExpression(expression); + public Try evaluate(final String expression, final Map data, final String defaultField) { + final Try tokenOptional = boolExpressionParser.parseExpression(expression, defaultField); return tokenOptional.map(node -> evaluateToken(node, data)); } + public Try evaluate(final String expression, final Map data) { + return evaluate(expression, data, null); + } + private boolean evaluateToken(final Node node, final Map data) { switch (node.getTokenType()) { case COMPARISON: diff --git a/src/main/java/com/github/sidhant92/boolparser/parser/BoolExpressionParser.java b/src/main/java/com/github/sidhant92/boolparser/parser/BoolExpressionParser.java index e5c72aa..c9aee89 100644 --- a/src/main/java/com/github/sidhant92/boolparser/parser/BoolExpressionParser.java +++ b/src/main/java/com/github/sidhant92/boolparser/parser/BoolExpressionParser.java @@ -9,4 +9,6 @@ */ public interface BoolExpressionParser { Try parseExpression(final String expression); + + Try parseExpression(final String expression, final String defaultField); } diff --git a/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BoolParser.java b/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BoolParser.java index 7745c6d..52c3b04 100644 --- a/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BoolParser.java +++ b/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BoolParser.java @@ -28,25 +28,30 @@ public BoolParser(final int maxCacheSize) { this.cache = Caffeine.newBuilder().maximumSize(maxCacheSize).build(); } + @Override + public Try parseExpression(final String expression, final String defaultField) { + return Try.of(() -> getNode(expression, defaultField)); + } + @Override public Try parseExpression(final String expression) { - return Try.of(() -> getNode(expression)); + return Try.of(() -> getNode(expression, null)); } - private Node getNode(final String expression) { + private Node getNode(final String expression, final String defaultField) { if (useCache) { - return cache.get(expression, this::parse); + return cache.get(expression, ex -> parse(ex, defaultField)); } - return parse(expression); + return parse(expression, defaultField); } - private Node parse(final String expression) { + private Node parse(final String expression, final String defaultField) { final BooleanExpressionLexer filterLexer = new BooleanExpressionLexer(CharStreams.fromString(expression)); final CommonTokenStream commonTokenStream = new CommonTokenStream(filterLexer); final BooleanExpressionParser filterParser = new BooleanExpressionParser(commonTokenStream); final ParseTree parseTree = filterParser.parse(); - final BooleanFilterListener listener = new BooleanFilterListener(); + final BooleanFilterListener listener = new BooleanFilterListener(defaultField); parseTreeWalker.walk(listener, parseTree); return listener.getNode(); diff --git a/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterListener.java b/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterListener.java index 4008afa..f887946 100644 --- a/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterListener.java +++ b/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterListener.java @@ -1,8 +1,10 @@ package com.github.sidhant92.boolparser.parser.antlr; import java.util.List; +import java.util.Objects; import java.util.Stack; import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import com.github.sidhant92.boolparser.constant.DataType; import com.github.sidhant92.boolparser.constant.LogicalOperationType; @@ -25,7 +27,10 @@ public class BooleanFilterListener extends BooleanExpressionBaseListener { private org.antlr.v4.runtime.Token lastToken; - public BooleanFilterListener() { + private String defaultField; + + public BooleanFilterListener(final String defaultField) { + this.defaultField = defaultField; this.node = null; this.lastToken = null; this.currentNodes = new Stack<>(); @@ -37,7 +42,7 @@ public Node getNode() { @Override public void exitComparatorExpression(BooleanExpressionParser.ComparatorExpressionContext ctx) { - final String variableName = ctx.left.getText(); + final String variableName = getField(ctx.left.getText()); final DataType dataType = getDataType(ctx.right.getStart()); final Operator operator = Operator.getOperatorFromSymbol(ctx.op.getText()).orElse(Operator.EQUALS); currentNodes.add(new ComparisonNode(variableName, ValueUtils.convertValue(ctx.right.getText(), dataType), operator, dataType)); @@ -46,7 +51,7 @@ public void exitComparatorExpression(BooleanExpressionParser.ComparatorExpressio @Override public void exitToExpression(BooleanExpressionParser.ToExpressionContext ctx) { - final String field = ctx.field.getText(); + final String field = getField(ctx.field.getText()); final DataType lowerDataType = getDataType(ctx.lower.start); final Object lowerValue = ValueUtils.convertValue(ctx.lower.start.getText(), lowerDataType); final DataType upperDataType = getDataType(ctx.upper.start); @@ -57,7 +62,7 @@ public void exitToExpression(BooleanExpressionParser.ToExpressionContext ctx) { @Override public void exitInExpression(BooleanExpressionParser.InExpressionContext ctx) { - final String field = ctx.field.getText(); + final String field = getField(ctx.field.getText()); final List> items = ctx.data.children .stream() .filter(child -> child instanceof BooleanExpressionParser.TypesContext) @@ -71,6 +76,13 @@ public void exitInExpression(BooleanExpressionParser.InExpressionContext ctx) { super.exitInExpression(ctx); } + private String getField(final String field) { + if (Objects.isNull(defaultField)) { + return field; + } + return StringUtils.isBlank(field) ? defaultField : field; + } + private DataType getDataType(final org.antlr.v4.runtime.Token token) { switch (token.getType()) { case BooleanExpressionLexer.DECIMAL: diff --git a/src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java b/src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java index 555d7d4..d140aef 100644 --- a/src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java +++ b/src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java @@ -419,4 +419,22 @@ public void testStringEqualityWithQuotes() { assertTrue(booleanOptional.isSuccess()); assertTrue(booleanOptional.get()); } + + @Test + public void testDefaultFieldTrue() { + final Map data = new HashMap<>(); + data.put("age", 19); + final Try booleanOptional = booleanExpressionEvaluator.evaluate(">= 18 AND < 20", data, "age"); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testDefaultFieldFalse() { + final Map data = new HashMap<>(); + data.put("age", 17); + final Try booleanOptional = booleanExpressionEvaluator.evaluate(">= 18 AND < 20", data, "age"); + assertTrue(booleanOptional.isSuccess()); + assertFalse(booleanOptional.get()); + } }