Repository: cayenne Updated Branches: refs/heads/master 5c805019a -> 2667f0126
CAY-2231 Support for collections in new functional expressions and old math expressions Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/2667f012 Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/2667f012 Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/2667f012 Branch: refs/heads/master Commit: 2667f0126a6a2a3abafbb174898998aae66e8a80 Parents: 5c80501 Author: Nikita Timofeev <stari...@gmail.com> Authored: Thu Feb 16 15:49:52 2017 +0300 Committer: Nikita Timofeev <stari...@gmail.com> Committed: Thu Feb 16 15:49:52 2017 +0300 ---------------------------------------------------------------------- .../org/apache/cayenne/exp/parser/ASTAbs.java | 9 +- .../org/apache/cayenne/exp/parser/ASTAdd.java | 33 +---- .../exp/parser/ASTAggregateFunctionCall.java | 7 +- .../cayenne/exp/parser/ASTBitwiseAnd.java | 34 ++---- .../cayenne/exp/parser/ASTBitwiseLeftShift.java | 34 ++---- .../cayenne/exp/parser/ASTBitwiseNot.java | 18 ++- .../apache/cayenne/exp/parser/ASTBitwiseOr.java | 39 ++---- .../exp/parser/ASTBitwiseRightShift.java | 34 +----- .../cayenne/exp/parser/ASTBitwiseXor.java | 37 ++---- .../apache/cayenne/exp/parser/ASTConcat.java | 12 +- .../cayenne/exp/parser/ASTCurrentDate.java | 7 +- .../cayenne/exp/parser/ASTCurrentTime.java | 7 +- .../cayenne/exp/parser/ASTCurrentTimestamp.java | 7 +- .../apache/cayenne/exp/parser/ASTDivide.java | 32 +---- .../cayenne/exp/parser/ASTFunctionCall.java | 2 +- .../apache/cayenne/exp/parser/ASTLength.java | 9 +- .../apache/cayenne/exp/parser/ASTLocate.java | 21 ++-- .../org/apache/cayenne/exp/parser/ASTLower.java | 9 +- .../org/apache/cayenne/exp/parser/ASTMod.java | 10 ++ .../apache/cayenne/exp/parser/ASTMultiply.java | 32 +---- .../org/apache/cayenne/exp/parser/ASTSqrt.java | 9 +- .../apache/cayenne/exp/parser/ASTSubstring.java | 22 ++-- .../apache/cayenne/exp/parser/ASTSubtract.java | 31 +---- .../org/apache/cayenne/exp/parser/ASTTrim.java | 10 +- .../org/apache/cayenne/exp/parser/ASTUpper.java | 9 +- .../exp/parser/EvaluatedBitwiseNode.java | 57 +++++++++ .../cayenne/exp/parser/EvaluatedMathNode.java | 58 +++++++++ .../cayenne/exp/parser/EvaluatedNode.java | 85 +++++++++++++ .../exp/parser/ASTFunctionCallStringIT.java | 2 +- .../cayenne/exp/parser/ASTSubstringTest.java | 2 +- .../ExpressionCollectionEvaluationIT.java | 122 +++++++++++++++++++ docs/doc/src/main/resources/RELEASE-NOTES.txt | 1 + 32 files changed, 497 insertions(+), 304 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAbs.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAbs.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAbs.java index b5220bb..e49972c 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAbs.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAbs.java @@ -36,12 +36,17 @@ public class ASTAbs extends ASTFunctionCall { } @Override - protected Object evaluateNode(Object o) throws Exception { - double n = ConversionUtil.toDouble(evaluateChild(0, o), 0.0); + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { + double n = ConversionUtil.toDouble(o, 0.0); return Math.abs(n); } @Override + protected int getRequiredChildrenCount() { + return 1; + } + + @Override public Expression shallowCopy() { return new ASTAbs(id); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAdd.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAdd.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAdd.java index de484ef..8554bdc 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAdd.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAdd.java @@ -20,16 +20,16 @@ package org.apache.cayenne.exp.parser; import java.math.BigDecimal; +import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import org.apache.cayenne.exp.Expression; -import org.apache.cayenne.util.ConversionUtil; /** * "Add" Expression. */ -public class ASTAdd extends SimpleNode { +public class ASTAdd extends EvaluatedMathNode { private static final long serialVersionUID = -8622963819149351988L; @@ -42,13 +42,7 @@ public class ASTAdd extends SimpleNode { } public ASTAdd(Object[] nodes) { - super(ExpressionParserTreeConstants.JJTADD); - int len = nodes.length; - for (int i = 0; i < len; i++) { - jjtAddChild(wrapChild(nodes[i]), i); - } - - connectChildren(); + this(Arrays.asList(nodes)); } public ASTAdd(Collection<?> nodes) { @@ -58,29 +52,12 @@ public class ASTAdd extends SimpleNode { for (int i = 0; i < len; i++) { jjtAddChild(wrapChild(it.next()), i); } - connectChildren(); } @Override - protected Object evaluateNode(Object o) throws Exception { - int len = jjtGetNumChildren(); - if (len == 0) { - return null; - } - - BigDecimal result = null; - for (int i = 0; i < len; i++) { - BigDecimal value = ConversionUtil.toBigDecimal(evaluateChild(i, o)); - - if (value == null) { - return null; - } - - result = (i == 0) ? value : result.add(value); - } - - return result; + protected BigDecimal op(BigDecimal result, BigDecimal arg) { + return result.add(arg); } /** http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAggregateFunctionCall.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAggregateFunctionCall.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAggregateFunctionCall.java index 641f711..626edf8 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAggregateFunctionCall.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAggregateFunctionCall.java @@ -35,7 +35,12 @@ public abstract class ASTAggregateFunctionCall extends ASTFunctionCall { } @Override - protected Object evaluateNode(Object o) throws Exception { + protected int getRequiredChildrenCount() { + return 0; + } + + @Override + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { throw new UnsupportedOperationException("In-memory evaluation of aggregate functions not implemented yet."); } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseAnd.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseAnd.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseAnd.java index 9fe8a2f..10fd9a5 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseAnd.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseAnd.java @@ -18,18 +18,18 @@ ****************************************************************/ package org.apache.cayenne.exp.parser; +import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import org.apache.cayenne.exp.Expression; -import org.apache.cayenne.util.ConversionUtil; /** * Bitwise conjunction (AND or '&') expression * * @since 3.1 */ -public class ASTBitwiseAnd extends SimpleNode { +public class ASTBitwiseAnd extends EvaluatedBitwiseNode { private static final long serialVersionUID = -1482206814209874743L; @@ -42,13 +42,7 @@ public class ASTBitwiseAnd extends SimpleNode { } public ASTBitwiseAnd(Object[] nodes) { - super(ExpressionParserTreeConstants.JJTBITWISEAND); - int len = nodes.length; - for (int i = 0; i < len; i++) { - jjtAddChild(wrapChild(nodes[i]), i); - } - - connectChildren(); + this(Arrays.asList(nodes)); } public ASTBitwiseAnd(Collection<Object> nodes) { @@ -58,27 +52,13 @@ public class ASTBitwiseAnd extends SimpleNode { for (int i = 0; i < len; i++) { jjtAddChild(wrapChild(it.next()), i); } + + connectChildren(); } @Override - protected Object evaluateNode(Object o) throws Exception { - int len = jjtGetNumChildren(); - if (len == 0) { - return null; - } - - Long result = null; - for (int i = 0; i < len; i++) { - Long value = ConversionUtil.toLong(evaluateChild(i, o), Long.MIN_VALUE); - - if (value == Long.MIN_VALUE) { - return null; - } - - result = (i == 0) ? value : result & value; - } - - return result; + protected long op(long result, long arg) { + return result & arg; } @Override http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseLeftShift.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseLeftShift.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseLeftShift.java index d7c8606..2410129 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseLeftShift.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseLeftShift.java @@ -18,18 +18,18 @@ ****************************************************************/ package org.apache.cayenne.exp.parser; +import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import org.apache.cayenne.exp.Expression; -import org.apache.cayenne.util.ConversionUtil; /** * Bitwise left shift '<<' operation. * * @since 4.0 */ -public class ASTBitwiseLeftShift extends SimpleNode { +public class ASTBitwiseLeftShift extends EvaluatedBitwiseNode { private static final long serialVersionUID = -954784931828996446L; @@ -42,13 +42,7 @@ public class ASTBitwiseLeftShift extends SimpleNode { } public ASTBitwiseLeftShift(Object[] nodes) { - super(ExpressionParserTreeConstants.JJTBITWISELEFTSHIFT); - int len = nodes.length; - for (int i = 0; i < len; i++) { - jjtAddChild(wrapChild(nodes[i]), i); - } - - connectChildren(); + this(Arrays.asList(nodes)); } public ASTBitwiseLeftShift(Collection<Object> nodes) { @@ -58,27 +52,13 @@ public class ASTBitwiseLeftShift extends SimpleNode { for (int i = 0; i < len; i++) { jjtAddChild(wrapChild(it.next()), i); } + + connectChildren(); } @Override - protected Object evaluateNode(Object o) throws Exception { - int len = jjtGetNumChildren(); - if (len == 0) { - return null; - } - - Long result = null; - for (int i = 0; i < len; i++) { - Long value = ConversionUtil.toLong(evaluateChild(i, o), Long.MIN_VALUE); - - if (value == Long.MIN_VALUE) { - return null; - } - - result = (i == 0) ? value : result << value; - } - - return result; + protected long op(long result, long arg) { + return result << arg; } @Override http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseNot.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseNot.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseNot.java index a86761f..50a970e 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseNot.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseNot.java @@ -26,7 +26,7 @@ import org.apache.cayenne.util.ConversionUtil; * * @since 3.1 */ -public class ASTBitwiseNot extends SimpleNode { +public class ASTBitwiseNot extends EvaluatedNode { private static final long serialVersionUID = 1L; ASTBitwiseNot(int id) { @@ -44,21 +44,17 @@ public class ASTBitwiseNot extends SimpleNode { } @Override - protected Object evaluateNode(Object o) throws Exception { - - int len = jjtGetNumChildren(); - if (len != 1) { - return Boolean.FALSE; - } - - long value = ConversionUtil.toLong(evaluateChild(0, o), Long.MIN_VALUE); - + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { + long value = ConversionUtil.toLong(o, Long.MIN_VALUE); if (value == Long.MIN_VALUE) { return null; } - return ~value; + } + @Override + protected int getRequiredChildrenCount() { + return 1; } @Override http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseOr.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseOr.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseOr.java index 8b3060c..87ad19d 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseOr.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseOr.java @@ -18,11 +18,11 @@ ****************************************************************/ package org.apache.cayenne.exp.parser; +import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import org.apache.cayenne.exp.Expression; -import org.apache.cayenne.util.ConversionUtil; /** @@ -30,7 +30,7 @@ import org.apache.cayenne.util.ConversionUtil; * * @since 3.1 */ -public class ASTBitwiseOr extends SimpleNode { +public class ASTBitwiseOr extends EvaluatedBitwiseNode { private static final long serialVersionUID = 1L; ASTBitwiseOr(int id) { @@ -42,13 +42,7 @@ public class ASTBitwiseOr extends SimpleNode { } public ASTBitwiseOr(Object[] nodes) { - super(ExpressionParserTreeConstants.JJTBITWISEOR); - int len = nodes.length; - for (int i = 0; i < len; i++) { - jjtAddChild(wrapChild(nodes[i]), i); - } - - connectChildren(); + this(Arrays.asList(nodes)); } public ASTBitwiseOr(Collection<Object> nodes) { @@ -58,30 +52,15 @@ public class ASTBitwiseOr extends SimpleNode { for (int i = 0; i < len; i++) { jjtAddChild(wrapChild(it.next()), i); } + connectChildren(); } - - @Override - protected Object evaluateNode(Object o) throws Exception { - int len = jjtGetNumChildren(); - if (len == 0) { - return null; - } - - Long result = null; - for (int i = 0; i < len; i++) { - Long value = ConversionUtil.toLong(evaluateChild(i, o), Long.MIN_VALUE); - - if (value == Long.MIN_VALUE) { - return null; - } - result = (i == 0) ? value : result | value; - } - - return result; - } + @Override + protected long op(long result, long arg) { + return result | arg; + } - @Override + @Override protected String getExpressionOperator(int index) { return "|"; } http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseRightShift.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseRightShift.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseRightShift.java index 8e09f26..b34d3e1 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseRightShift.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseRightShift.java @@ -18,18 +18,18 @@ ****************************************************************/ package org.apache.cayenne.exp.parser; +import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import org.apache.cayenne.exp.Expression; -import org.apache.cayenne.util.ConversionUtil; /** * Bitwise right shift '>>' operation. * * @since 4.0 */ -public class ASTBitwiseRightShift extends SimpleNode { +public class ASTBitwiseRightShift extends EvaluatedBitwiseNode { private static final long serialVersionUID = 1L; ASTBitwiseRightShift(int id) { @@ -41,13 +41,7 @@ public class ASTBitwiseRightShift extends SimpleNode { } public ASTBitwiseRightShift(Object[] nodes) { - super(ExpressionParserTreeConstants.JJTBITWISERIGHTSHIFT); - int len = nodes.length; - for (int i = 0; i < len; i++) { - jjtAddChild(wrapChild(nodes[i]), i); - } - - connectChildren(); + this(Arrays.asList(nodes)); } public ASTBitwiseRightShift(Collection<Object> nodes) { @@ -57,28 +51,12 @@ public class ASTBitwiseRightShift extends SimpleNode { for (int i = 0; i < len; i++) { jjtAddChild(wrapChild(it.next()), i); } + connectChildren(); } @Override - protected Object evaluateNode(Object o) throws Exception { - int len = jjtGetNumChildren(); - if (len == 0) { - return null; - } - - Long result = null; - for (int i = 0; i < len; i++) { - Long value = ConversionUtil.toLong(evaluateChild(i, o), - Long.MIN_VALUE); - - if (value == Long.MIN_VALUE) { - return null; - } - - result = (i == 0) ? value : result >> value; - } - - return result; + protected long op(long result, long arg) { + return result >> arg; } @Override http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseXor.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseXor.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseXor.java index dfbd38b..4585d65 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseXor.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBitwiseXor.java @@ -18,18 +18,18 @@ ****************************************************************/ package org.apache.cayenne.exp.parser; +import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import org.apache.cayenne.exp.Expression; -import org.apache.cayenne.util.ConversionUtil; /** * Bitwise exclusive disjunction (XOR or '^') operation. * * @since 3.1 */ -public class ASTBitwiseXor extends SimpleNode { +public class ASTBitwiseXor extends EvaluatedBitwiseNode { private static final long serialVersionUID = 1L; ASTBitwiseXor(int id) { @@ -41,13 +41,7 @@ public class ASTBitwiseXor extends SimpleNode { } public ASTBitwiseXor(Object[] nodes) { - super(ExpressionParserTreeConstants.JJTBITWISEXOR); - int len = nodes.length; - for (int i = 0; i < len; i++) { - jjtAddChild(wrapChild(nodes[i]), i); - } - - connectChildren(); + this(Arrays.asList(nodes)); } public ASTBitwiseXor(Collection<Object> nodes) { @@ -57,28 +51,13 @@ public class ASTBitwiseXor extends SimpleNode { for (int i = 0; i < len; i++) { jjtAddChild(wrapChild(it.next()), i); } + connectChildren(); } - - @Override - protected Object evaluateNode(Object o) throws Exception { - int len = jjtGetNumChildren(); - if (len == 0) { - return null; - } - Long result = null; - for (int i = 0; i < len; i++) { - Long value = ConversionUtil.toLong(evaluateChild(i, o), Long.MIN_VALUE); - - if (value == Long.MIN_VALUE) { - return null; - } - - result = (i == 0) ? value : result ^ value; - } - - return result; - } + @Override + protected long op(long result, long arg) { + return result ^ arg; + } @Override protected String getExpressionOperator(int index) { http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTConcat.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTConcat.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTConcat.java index 1bfb336..9d4d954 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTConcat.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTConcat.java @@ -36,10 +36,16 @@ public class ASTConcat extends ASTFunctionCall { } @Override - protected Object evaluateNode(Object o) throws Exception { + protected int getRequiredChildrenCount() { + return 1; + } + + @Override + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { StringBuilder sb = new StringBuilder(); - for(int i=0; i<getOperandCount(); i++) { - sb.append(ConversionUtil.toString(evaluateChild(i, o))); + sb.append(ConversionUtil.toString(o)); + for(int i=1; i<evaluatedChildren.length; i++) { + sb.append(ConversionUtil.toString(evaluatedChildren[i])); } return sb.toString(); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentDate.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentDate.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentDate.java index 035fd44..e2b3df2 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentDate.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentDate.java @@ -42,7 +42,12 @@ public class ASTCurrentDate extends ASTFunctionCall { } @Override - protected Object evaluateNode(Object o) throws Exception { + protected int getRequiredChildrenCount() { + return 0; + } + + @Override + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { return new Date(); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTime.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTime.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTime.java index 1ef54bf..292a264 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTime.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTime.java @@ -42,7 +42,12 @@ public class ASTCurrentTime extends ASTFunctionCall { } @Override - protected Object evaluateNode(Object o) throws Exception { + protected int getRequiredChildrenCount() { + return 0; + } + + @Override + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { return new Date(); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTimestamp.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTimestamp.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTimestamp.java index e1d56c0..e14dd58 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTimestamp.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTimestamp.java @@ -42,7 +42,12 @@ public class ASTCurrentTimestamp extends ASTFunctionCall { } @Override - protected Object evaluateNode(Object o) throws Exception { + protected int getRequiredChildrenCount() { + return 0; + } + + @Override + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { return new Date(); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTDivide.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTDivide.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTDivide.java index 7e48b8c..b9759e1 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTDivide.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTDivide.java @@ -20,18 +20,18 @@ package org.apache.cayenne.exp.parser; import java.math.BigDecimal; +import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import org.apache.cayenne.exp.Expression; -import org.apache.cayenne.util.ConversionUtil; /** * "Divide" expression. * * @since 1.1 */ -public class ASTDivide extends SimpleNode { +public class ASTDivide extends EvaluatedMathNode { private static final long serialVersionUID = -5086569683844539310L; @@ -44,13 +44,7 @@ public class ASTDivide extends SimpleNode { } public ASTDivide(Object[] nodes) { - super(ExpressionParserTreeConstants.JJTDIVIDE); - int len = nodes.length; - for (int i = 0; i < len; i++) { - jjtAddChild(wrapChild(nodes[i]), i); - } - - connectChildren(); + this(Arrays.asList(nodes)); } public ASTDivide(Collection<?> nodes) { @@ -65,24 +59,8 @@ public class ASTDivide extends SimpleNode { } @Override - protected Object evaluateNode(Object o) throws Exception { - int len = jjtGetNumChildren(); - if (len == 0) { - return null; - } - - BigDecimal result = null; - for (int i = 0; i < len; i++) { - BigDecimal value = ConversionUtil.toBigDecimal(evaluateChild(i, o)); - - if (value == null) { - return null; - } - - result = (i == 0) ? value : result.divide(value, BigDecimal.ROUND_HALF_EVEN); - } - - return result; + protected BigDecimal op(BigDecimal result, BigDecimal arg) { + return result.divide(arg, BigDecimal.ROUND_HALF_EVEN); } /** http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTFunctionCall.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTFunctionCall.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTFunctionCall.java index c8d7f06..2902db3 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTFunctionCall.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTFunctionCall.java @@ -27,7 +27,7 @@ import org.apache.cayenne.exp.Expression; /** * @since 4.0 */ -public abstract class ASTFunctionCall extends SimpleNode { +public abstract class ASTFunctionCall extends EvaluatedNode { private String functionName; http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLength.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLength.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLength.java index e12512e..91247db 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLength.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLength.java @@ -36,8 +36,8 @@ public class ASTLength extends ASTFunctionCall { } @Override - protected Object evaluateNode(Object o) throws Exception { - String s1 = ConversionUtil.toString(evaluateChild(0, o)); + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { + String s1 = ConversionUtil.toString(o); if (s1 == null) { return null; } @@ -45,6 +45,11 @@ public class ASTLength extends ASTFunctionCall { } @Override + protected int getRequiredChildrenCount() { + return 1; + } + + @Override public Expression shallowCopy() { return new ASTLength(id); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLocate.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLocate.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLocate.java index d26dbb5..addf4f6 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLocate.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLocate.java @@ -40,24 +40,23 @@ public class ASTLocate extends ASTFunctionCall { } @Override - protected Object evaluateNode(Object o) throws Exception { - int len = jjtGetNumChildren(); - if (len < 2) { - return 0L; - } - - String substr = ConversionUtil.toString(evaluateChild(0, o)); - String str = ConversionUtil.toString(evaluateChild(1, o)); + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { + String substr = ConversionUtil.toString(o); + String str = ConversionUtil.toString(evaluatedChildren[1]); int offset = 0; - if(len > 2) { - offset = ConversionUtil.toInt(evaluateChild(2, o), 0); + if(evaluatedChildren.length > 2) { + offset = ConversionUtil.toInt(evaluatedChildren[2], 0); } - // +1 to comply with SQL return str.indexOf(substr, offset) + 1; } @Override + protected int getRequiredChildrenCount() { + return 2; + } + + @Override public Expression shallowCopy() { return new ASTLocate(id); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLower.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLower.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLower.java index 78b6f80..2a29a11 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLower.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLower.java @@ -37,8 +37,13 @@ public class ASTLower extends ASTFunctionCall { } @Override - protected Object evaluateNode(Object o) throws Exception { - String s1 = ConversionUtil.toString(evaluateChild(0, o)); + protected int getRequiredChildrenCount() { + return 1; + } + + @Override + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { + String s1 = ConversionUtil.toString(o); if (s1 == null) { return null; } http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMod.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMod.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMod.java index c4f79a7..268fa9c 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMod.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMod.java @@ -46,6 +46,16 @@ public class ASTMod extends ASTFunctionCall { } @Override + protected int getRequiredChildrenCount() { + return 0; + } + + @Override + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { + return null; + } + + @Override public Expression shallowCopy() { return new ASTMod(id); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMultiply.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMultiply.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMultiply.java index 4b7ee0e..edc9c70 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMultiply.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMultiply.java @@ -20,6 +20,7 @@ package org.apache.cayenne.exp.parser; import java.math.BigDecimal; +import java.util.Arrays; import java.util.Collection; import java.util.Iterator; @@ -31,7 +32,7 @@ import org.apache.cayenne.util.ConversionUtil; * * @since 1.1 */ -public class ASTMultiply extends SimpleNode { +public class ASTMultiply extends EvaluatedMathNode { private static final long serialVersionUID = -8146316633842448974L; @@ -44,13 +45,7 @@ public class ASTMultiply extends SimpleNode { } public ASTMultiply(Object[] nodes) { - super(ExpressionParserTreeConstants.JJTMULTIPLY); - int len = nodes.length; - for (int i = 0; i < len; i++) { - jjtAddChild(wrapChild(nodes[i]), i); - } - - connectChildren(); + this(Arrays.asList(nodes)); } public ASTMultiply(Collection<?> nodes) { @@ -60,27 +55,12 @@ public class ASTMultiply extends SimpleNode { for (int i = 0; i < len; i++) { jjtAddChild(wrapChild(it.next()), i); } + connectChildren(); } @Override - protected Object evaluateNode(Object o) throws Exception { - int len = jjtGetNumChildren(); - if (len == 0) { - return null; - } - - BigDecimal result = null; - for (int i = 0; i < len; i++) { - BigDecimal value = ConversionUtil.toBigDecimal(evaluateChild(i, o)); - - if (value == null) { - return null; - } - - result = (i == 0) ? value : result.multiply(value); - } - - return result; + protected BigDecimal op(BigDecimal result, BigDecimal arg) { + return result.multiply(arg); } /** http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSqrt.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSqrt.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSqrt.java index 71e8e32..41a7a4a 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSqrt.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSqrt.java @@ -36,8 +36,13 @@ public class ASTSqrt extends ASTFunctionCall { } @Override - protected Object evaluateNode(Object o) throws Exception { - double n = ConversionUtil.toDouble(evaluateChild(0, o), 0.0); + protected int getRequiredChildrenCount() { + return 1; + } + + @Override + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { + double n = ConversionUtil.toDouble(o, 0.0); return Math.sqrt(n); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSubstring.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSubstring.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSubstring.java index 33ac4e0..de3d4af 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSubstring.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSubstring.java @@ -27,7 +27,6 @@ import org.apache.cayenne.util.ConversionUtil; */ public class ASTSubstring extends ASTFunctionCall { - ASTSubstring(int id) { super(id, "SUBSTRING"); } @@ -37,27 +36,28 @@ public class ASTSubstring extends ASTFunctionCall { } @Override - protected Object evaluateNode(Object o) throws Exception { - int len = jjtGetNumChildren(); - if (len != 3) { - return null; - } - - String s1 = ConversionUtil.toString(evaluateChild(0, o)); + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { + String s1 = ConversionUtil.toString(o); if (s1 == null) { return null; } - int offset = ConversionUtil.toInt(evaluateChild(1, o), 0); - int length = ConversionUtil.toInt(evaluateChild(2, o), 0); + int offset = ConversionUtil.toInt(evaluatedChildren[1], 0); + int length = ConversionUtil.toInt(evaluatedChildren[2], 0); if(length == 0) { return null; } - return s1.substring(offset, offset + length); + return s1.substring(offset - 1, offset - 1 + length); // - 1 to comply with SQL } @Override + protected int getRequiredChildrenCount() { + return 3; + } + + + @Override public Expression shallowCopy() { return new ASTSubstring(id); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSubtract.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSubtract.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSubtract.java index 732b050..ce68e40 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSubtract.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSubtract.java @@ -21,18 +21,18 @@ package org.apache.cayenne.exp.parser; import java.math.BigDecimal; +import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import org.apache.cayenne.exp.Expression; -import org.apache.cayenne.util.ConversionUtil; /** * "Subtract" expression. * * @since 1.1 */ -public class ASTSubtract extends SimpleNode { +public class ASTSubtract extends EvaluatedMathNode { ASTSubtract(int id) { super(id); } @@ -42,12 +42,7 @@ public class ASTSubtract extends SimpleNode { } public ASTSubtract(Object[] nodes) { - super(ExpressionParserTreeConstants.JJTSUBTRACT); - int len = nodes.length; - for (int i = 0; i < len; i++) { - jjtAddChild(wrapChild(nodes[i]), i); - } - connectChildren(); + this(Arrays.asList(nodes)); } public ASTSubtract(Collection<?> nodes) { @@ -61,24 +56,8 @@ public class ASTSubtract extends SimpleNode { } @Override - protected Object evaluateNode(Object o) throws Exception { - int len = jjtGetNumChildren(); - if (len == 0) { - return null; - } - - BigDecimal result = null; - for (int i = 0; i < len; i++) { - BigDecimal value = ConversionUtil.toBigDecimal(evaluateChild(i, o)); - - if (value == null) { - return null; - } - - result = (i == 0) ? value : result.subtract(value); - } - - return result; + protected BigDecimal op(BigDecimal result, BigDecimal arg) { + return result.subtract(arg); } /** http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTTrim.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTTrim.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTTrim.java index f037dd0..5c4af1a 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTTrim.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTTrim.java @@ -41,12 +41,16 @@ public class ASTTrim extends ASTFunctionCall { } @Override - protected Object evaluateNode(Object o) throws Exception { - String s1 = ConversionUtil.toString(evaluateChild(0, o)); + protected int getRequiredChildrenCount() { + return 1; + } + + @Override + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { + String s1 = ConversionUtil.toString(o); if (s1 == null) { return null; } - return s1.trim(); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTUpper.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTUpper.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTUpper.java index 60716fc..602edd3 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTUpper.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTUpper.java @@ -36,8 +36,13 @@ public class ASTUpper extends ASTFunctionCall { } @Override - protected Object evaluateNode(Object o) throws Exception { - String s1 = ConversionUtil.toString(evaluateChild(0, o)); + protected int getRequiredChildrenCount() { + return 1; + } + + @Override + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { + String s1 = ConversionUtil.toString(o); if (s1 == null) { return null; } http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/EvaluatedBitwiseNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/EvaluatedBitwiseNode.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/EvaluatedBitwiseNode.java new file mode 100644 index 0000000..c19deee --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/EvaluatedBitwiseNode.java @@ -0,0 +1,57 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.exp.parser; + +import org.apache.cayenne.util.ConversionUtil; + +/** + * @since 4.0 + */ +public abstract class EvaluatedBitwiseNode extends EvaluatedNode { + + protected EvaluatedBitwiseNode(int i) { + super(i); + } + + @Override + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { + Long result = ConversionUtil.toLong(o, Long.MIN_VALUE); + if(result == Long.MIN_VALUE) { + return null; + } + for (int i = 1; i < evaluatedChildren.length; i++) { + Long value = ConversionUtil.toLong(evaluateChild(i, o), Long.MIN_VALUE); + if (value == Long.MIN_VALUE) { + return null; + } + + result = op(result, value); + } + + return result; + } + + @Override + protected int getRequiredChildrenCount() { + return 1; + } + + protected abstract long op(long result, long arg); +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/EvaluatedMathNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/EvaluatedMathNode.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/EvaluatedMathNode.java new file mode 100644 index 0000000..d0177c2 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/EvaluatedMathNode.java @@ -0,0 +1,58 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.exp.parser; + +import java.math.BigDecimal; + +import org.apache.cayenne.util.ConversionUtil; + +/** + * @since 4.0 + */ +public abstract class EvaluatedMathNode extends EvaluatedNode { + protected EvaluatedMathNode(int i) { + super(i); + } + + @Override + protected int getRequiredChildrenCount() { + return 1; + } + + @Override + protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception { + BigDecimal result = ConversionUtil.toBigDecimal(o); + if(result == null) { + return null; + } + for (int i = 1; i < evaluatedChildren.length; i++) { + BigDecimal value = ConversionUtil.toBigDecimal(evaluatedChildren[i]); + if (value == null) { + return null; + } + result = op(result, value); + } + + return result; + } + + abstract protected BigDecimal op(BigDecimal result, BigDecimal arg); + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/EvaluatedNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/EvaluatedNode.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/EvaluatedNode.java new file mode 100644 index 0000000..96d962b --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/EvaluatedNode.java @@ -0,0 +1,85 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.exp.parser; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * @since 4.0 + */ +public abstract class EvaluatedNode extends SimpleNode { + + protected EvaluatedNode(int i) { + super(i); + } + + @Override + protected Object evaluateNode(Object o) throws Exception { + int len = jjtGetNumChildren(); + int requiredLen = getRequiredChildrenCount(); + if (len < requiredLen) { + return null; + } + + if(requiredLen == 0) { + return evaluateSubNode(null, null); + } + + final Object[] evaluatedChildren = new Object[len]; + for(int i=0; i<len; i++) { + evaluatedChildren[i] = evaluateChild(i, o); + } + + Object firstChild = evaluatedChildren[0]; + + // convert Map, keep Map keys + if(firstChild instanceof Map) { + @SuppressWarnings("unchecked") + Map<Object, Object> child = (Map<Object, Object>) firstChild; + Map<Object, Object> result = new HashMap<>(child.size()); + for(Map.Entry<Object, Object> entry : child.entrySet()) { + result.put(entry.getKey(), evaluateSubNode(entry.getValue(), evaluatedChildren)); + } + return result; + } + + // convert collection + if (firstChild instanceof Collection) { + @SuppressWarnings("unchecked") + Collection<Object> child = (Collection<Object>) firstChild; + Collection<Object> result = new ArrayList<>(child.size()); + for(Object c : child) { + result.add(evaluateSubNode(c, evaluatedChildren)); + } + return result; + } + + // convert scalar + return evaluateSubNode(firstChild, evaluatedChildren); + } + + abstract protected int getRequiredChildrenCount(); + + abstract protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception; + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTFunctionCallStringIT.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTFunctionCallStringIT.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTFunctionCallStringIT.java index 58a69dd..47d6373 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTFunctionCallStringIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTFunctionCallStringIT.java @@ -163,7 +163,7 @@ public class ASTFunctionCallStringIT extends ServerCase { @Test public void testASTSubstringParse() { Expression exp = ExpressionFactory.exp("SUBSTRING('123456789', 3, 2)"); - assertEquals("45", exp.evaluate(new Object())); + assertEquals("34", exp.evaluate(new Object())); } @Test http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTSubstringTest.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTSubstringTest.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTSubstringTest.java index ee6a74a..2b35ab0 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTSubstringTest.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTSubstringTest.java @@ -44,7 +44,7 @@ public class ASTSubstringTest { Object res = exp.evaluateNode(a); assertTrue(res instanceof String); - assertEquals("34567890", res); + assertEquals("23456789", res); } @Test http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ExpressionCollectionEvaluationIT.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ExpressionCollectionEvaluationIT.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ExpressionCollectionEvaluationIT.java new file mode 100644 index 0000000..685a7d4 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ExpressionCollectionEvaluationIT.java @@ -0,0 +1,122 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.exp.parser; + +import java.math.BigDecimal; +import java.util.Collections; +import java.util.List; + +import org.apache.cayenne.access.DataContext; +import org.apache.cayenne.di.Inject; +import org.apache.cayenne.exp.Expression; +import org.apache.cayenne.exp.ExpressionFactory; +import org.apache.cayenne.exp.Property; +import org.apache.cayenne.query.ObjectSelect; +import org.apache.cayenne.test.jdbc.DBHelper; +import org.apache.cayenne.test.jdbc.TableHelper; +import org.apache.cayenne.testdo.testmap.Artist; +import org.apache.cayenne.unit.di.server.CayenneProjects; +import org.apache.cayenne.unit.di.server.ServerCase; +import org.apache.cayenne.unit.di.server.UseServerRuntime; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * @since 4.0 + */ +@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT) +public class ExpressionCollectionEvaluationIT extends ServerCase { + + @Inject + private DataContext context; + + @Inject + private DBHelper dbHelper; + + @Before + public void createArtistsDataSet() throws Exception { + TableHelper tArtist = new TableHelper(dbHelper, "ARTIST"); + tArtist.setColumns("ARTIST_ID", "ARTIST_NAME", "DATE_OF_BIRTH"); + tArtist.insert(1, "artist1", new java.sql.Date(System.currentTimeMillis())); + + TableHelper tGallery = new TableHelper(dbHelper, "GALLERY"); + tGallery.setColumns("GALLERY_ID", "GALLERY_NAME"); + tGallery.insert(1, "tate modern"); + + TableHelper tPaintings = new TableHelper(dbHelper, "PAINTING"); + tPaintings.setColumns("PAINTING_ID", "PAINTING_TITLE", "ARTIST_ID", "GALLERY_ID", "ESTIMATED_PRICE"); + for (int i = 1; i <= 3; i++) { + tPaintings.insert(i, i + "painting" + (Math.pow(10, i)), 1, 1, i * 100); + } + + tPaintings.insert(4, "4painting", null, 1, 10000); +// tPaintings.insert(5, "5painting", 1, 1, null); + } + + @Test + public void testSubstringWithCollection() { + testExpression("SUBSTRING(paintingArray.paintingTitle, 1, 1)", String.class); + } + + @Test + public void testTrimWithCollection() { + testExpression("TRIM(paintingArray.paintingTitle)", String.class); + } + + @Test + public void testUpperWithCollection() { + testExpression("UPPER(paintingArray.paintingTitle)", String.class); + } + + @Test + public void testLowerWithCollection() { + testExpression("LOWER(paintingArray.paintingTitle)", String.class); + } + + @Test + public void testLengthWithCollection() { + testExpression("LENGTH(paintingArray.paintingTitle)", Integer.class); + } + + @Test + public void testConcatWithCollection() { + testExpression("CONCAT(paintingArray.paintingTitle, ' ', 'xyz')", String.class); + } + + @Test + public void testMathWithCollection() { + testExpression("paintingArray.estimatedPrice + 2", BigDecimal.class); + } + + private <T extends Comparable<T>> void testExpression(String expStr, Class<T> tClass) { + Expression exp = ExpressionFactory.exp(expStr); + Object res = exp.evaluate(ObjectSelect.query(Artist.class).prefetch(Artist.PAINTING_ARRAY.disjoint()).selectOne(context)); + List<T> sqlResult = ObjectSelect.query(Artist.class).column(Property.create(exp, tClass)).orderBy("db:paintingArray.PAINTING_ID").select(context); + + Collections.sort((List)res); + Collections.sort(sqlResult); + + assertEquals(3, sqlResult.size()); + assertEquals(res, sqlResult); + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2667f012/docs/doc/src/main/resources/RELEASE-NOTES.txt ---------------------------------------------------------------------- diff --git a/docs/doc/src/main/resources/RELEASE-NOTES.txt b/docs/doc/src/main/resources/RELEASE-NOTES.txt index 94d9729..7a1cdf7 100644 --- a/docs/doc/src/main/resources/RELEASE-NOTES.txt +++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt @@ -31,6 +31,7 @@ CAY-2212 cdbimport cleanup and configuration schema refactoring CAY-2223 JCacheQueryCache - a query cache provider to plug in JCache implementers CAY-2225 Extensible CacheInvalidationFilter logic CAY-2228 Deprecate multiple cache groups in caching and query API +CAY-2231 Support for collections in new functional expressions and old math expressions CAY-2232 Proper conversion to String for new functional expressions CAY-2235 Deprecate Query.getDataMap() method