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; package org.idempiere.expression.logic;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.compiere.util.Evaluatee; import org.compiere.util.Evaluatee;
@ -88,18 +90,35 @@ public class EvaluationVisitor extends SimpleBooleanBaseVisitor<Object> {
return super.visit(ctx.expression()); return super.visit(ctx.expression());
} }
@SuppressWarnings({"unchecked", "rawtypes"})
@Override @Override
public Object visitComparatorExpression(SimpleBooleanParser.ComparatorExpressionContext ctx) { public Object visitComparatorExpression(SimpleBooleanParser.ComparatorExpressionContext ctx) {
if (ctx.op.EQ() != null) { if (ctx.op.EQ() != null) {
return isEqual(ctx); return isEqual(ctx);
} else if (ctx.op.LE() != null) { } 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) { } 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) { } 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) { } 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) { } else if (ctx.op.NE() != null) {
return !(isEqual(ctx)); return !(isEqual(ctx));
} else if (ctx.op.RE() != null) { } else if (ctx.op.RE() != null) {
@ -215,13 +234,35 @@ public class EvaluationVisitor extends SimpleBooleanBaseVisitor<Object> {
return (boolean) visit(ctx); 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); Object value = visit(ctx);
if (value instanceof String) if (value instanceof String) {
return new BigDecimal((String)value); String s = (String) value;
else if (value instanceof BigDecimal) 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; 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 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.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -44,6 +45,7 @@ import org.compiere.util.DB;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.Evaluatee; import org.compiere.util.Evaluatee;
import org.compiere.util.LegacyLogicEvaluator; import org.compiere.util.LegacyLogicEvaluator;
import org.compiere.util.TimeUtil;
import org.idempiere.expression.logic.LogicEvaluator; import org.idempiere.expression.logic.LogicEvaluator;
import org.idempiere.test.AbstractTestCase; import org.idempiere.test.AbstractTestCase;
import org.junit.jupiter.api.Test; 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"); 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 { private static class ContextEvaluatee implements Evaluatee {
@Override @Override