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:
parent
c33d0528a7
commit
10812c486d
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue