IDEMPIERE-4824 Boolean Logic Expression Enhancements (#748)

* IDEMPIERE-4824 Boolean Logic Expression Enhancements

Fix comparison operator not working for timestamp value
This commit is contained in:
hengsin 2021-06-29 22:36:50 +08:00 committed by GitHub
parent c33d0528a7
commit 10812c486d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 78 additions and 9 deletions

View File

@ -25,6 +25,8 @@
package org.idempiere.expression.logic;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.compiere.util.Evaluatee;
@ -88,18 +90,35 @@ public class EvaluationVisitor extends SimpleBooleanBaseVisitor<Object> {
return super.visit(ctx.expression());
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public Object visitComparatorExpression(SimpleBooleanParser.ComparatorExpressionContext ctx) {
if (ctx.op.EQ() != null) {
return isEqual(ctx);
} else if (ctx.op.LE() != null) {
return asBigDecimal(ctx.left).compareTo(asBigDecimal(ctx.right)) <= 0;
Comparable leftValue = asComparable(ctx.left);
Comparable rightValue = asComparable(ctx.right);
if (leftValue == null || rightValue == null)
return Boolean.FALSE;
return leftValue.compareTo(rightValue) <= 0;
} else if (ctx.op.GE() != null) {
return asBigDecimal(ctx.left).compareTo(asBigDecimal(ctx.right)) >= 0;
Comparable leftValue = asComparable(ctx.left);
Comparable rightValue = asComparable(ctx.right);
if (leftValue == null || rightValue == null)
return Boolean.FALSE;
return leftValue.compareTo(rightValue) >= 0;
} else if (ctx.op.LT() != null) {
return asBigDecimal(ctx.left).compareTo(asBigDecimal(ctx.right)) < 0;
Comparable leftValue = asComparable(ctx.left);
Comparable rightValue = asComparable(ctx.right);
if (leftValue == null || rightValue == null)
return Boolean.FALSE;
return leftValue.compareTo(rightValue) < 0;
} else if (ctx.op.GT() != null) {
return asBigDecimal(ctx.left).compareTo(asBigDecimal(ctx.right)) > 0;
Comparable leftValue = asComparable(ctx.left);
Comparable rightValue = asComparable(ctx.right);
if (leftValue == null || rightValue == null)
return Boolean.FALSE;
return leftValue.compareTo(rightValue) > 0;
} else if (ctx.op.NE() != null) {
return !(isEqual(ctx));
} else if (ctx.op.RE() != null) {
@ -215,13 +234,35 @@ public class EvaluationVisitor extends SimpleBooleanBaseVisitor<Object> {
return (boolean) visit(ctx);
}
private BigDecimal asBigDecimal(SimpleBooleanParser.ExpressionContext ctx) {
private static final Pattern jdbcTimestampPattern = Pattern.compile(".*[-].*[-].*[:].*[:].*");
@SuppressWarnings("rawtypes")
private Comparable asComparable(SimpleBooleanParser.ExpressionContext ctx) {
Object value = visit(ctx);
if (value instanceof String)
return new BigDecimal((String)value);
else if (value instanceof BigDecimal)
if (value instanceof String) {
String s = (String) value;
if (Util.isEmpty(s, true))
return null;
Matcher matcher = jdbcTimestampPattern.matcher(s);
if (matcher.matches()) {
try {
return Timestamp.valueOf(s);
} catch (Exception e) {}
}
try {
return new BigDecimal(s);
} catch (Exception e) {}
} else if (value instanceof BigDecimal) {
return (BigDecimal)value;
} else if (value instanceof Timestamp) {
return (Timestamp)value;
}
//fall back to comparable and string
if (value instanceof Comparable)
return (Comparable)value;
else
return new BigDecimal(value.toString());
return value.toString();
}
}

View File

@ -33,6 +33,7 @@ import static org.junit.jupiter.api.Assertions.fail;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
@ -44,6 +45,7 @@ import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Evaluatee;
import org.compiere.util.LegacyLogicEvaluator;
import org.compiere.util.TimeUtil;
import org.idempiere.expression.logic.LogicEvaluator;
import org.idempiere.test.AbstractTestCase;
import org.junit.jupiter.api.Test;
@ -492,6 +494,32 @@ public class LogicExpressionTest extends AbstractTestCase {
assertTrue(exceptions.isEmpty(), "Found " + exceptions.size() + " logic expression with invalid syntax in AD");
}
@Test
public void testDateExpression() {
String expr = "@DateAcct@<@DateOrdered@";
Timestamp today = TimeUtil.getDay(System.currentTimeMillis());
Env.setContext(Env.getCtx(), "DateAcct", (Timestamp)null);
Env.setContext(Env.getCtx(), "DateOrdered", (Timestamp)null);
assertFalse(LegacyLogicEvaluator.evaluateLogic(evaluatee, expr));
Env.setContext(Env.getCtx(), "DateAcct", today);
assertFalse(LegacyLogicEvaluator.evaluateLogic(evaluatee, expr));
Env.setContext(Env.getCtx(), "DateOrdered", today);
assertFalse(LegacyLogicEvaluator.evaluateLogic(evaluatee, expr));
Env.setContext(Env.getCtx(), "DateAcct", TimeUtil.addDays(today, -1));
assertTrue(LegacyLogicEvaluator.evaluateLogic(evaluatee, expr));
Env.setContext(Env.getCtx(), "DateAcct", (Timestamp)null);
Env.setContext(Env.getCtx(), "DateOrdered", (Timestamp)null);
assertFalse(LogicEvaluator.evaluateLogic(evaluatee, expr));
Env.setContext(Env.getCtx(), "DateAcct", today);
assertFalse(LogicEvaluator.evaluateLogic(evaluatee, expr));
Env.setContext(Env.getCtx(), "DateOrdered", today);
assertFalse(LogicEvaluator.evaluateLogic(evaluatee, expr));
Env.setContext(Env.getCtx(), "DateAcct", TimeUtil.addDays(today, -1));
assertTrue(LogicEvaluator.evaluateLogic(evaluatee, expr));
}
private static class ContextEvaluatee implements Evaluatee {
@Override