Repository: cayenne Updated Branches: refs/heads/master 3b63842ae -> c725bf09f
CAY-1960 ExpressionFactory.exp(..) , and(..), or(..) * changing style of positional binding of multiple names Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/c725bf09 Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/c725bf09 Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/c725bf09 Branch: refs/heads/master Commit: c725bf09fbbf15834947cd45ba9e7c136902fa90 Parents: 3b63842 Author: aadamchik <[email protected]> Authored: Thu Jan 22 11:43:19 2015 +0300 Committer: aadamchik <[email protected]> Committed: Thu Jan 22 11:50:48 2015 +0300 ---------------------------------------------------------------------- .../java/org/apache/cayenne/exp/Expression.java | 91 ++++++++++---------- .../cayenne/exp/Expression_ParamsTest.java | 6 +- 2 files changed, 47 insertions(+), 50 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cayenne/blob/c725bf09/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java index 41aabc0..105bcdd 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java @@ -26,6 +26,7 @@ import java.io.PrintWriter; import java.io.Serializable; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -232,8 +233,7 @@ public abstract class Expression implements Serializable, XMLSerializable { Expression e = (Expression) object; - if (e.getType() != getType() - || e.getOperandCount() != getOperandCount()) { + if (e.getType() != getType() || e.getOperandCount() != getOperandCount()) { return false; } @@ -262,13 +262,14 @@ public abstract class Expression implements Serializable, XMLSerializable { /** * Creates and returns a new Expression instance based on this expression, - * but with named parameters substituted with provided values. This is a - * positional style of binding. Names of variables in the expression are - * ignored and parameters are bound in order they are found in the - * expression. E.g. if the same name is mentioned twice, it can be bound to - * two different values. Also positional style would not allow subexpression - * pruning. If declared and provided parameters counts are mismatched, an + * but with parameters substituted with provided values. This is a + * positional style of binding. If a given parameter name is used more than + * once, only the first occurrence is treated as "position", subsequent + * occurrences are bound with the same value as the first one. If expression + * parameters count is different from the array parameter count, an * exception will be thrown. + * <p> + * positional style would not allow subexpression pruning. * * @since 4.0 */ @@ -283,8 +284,7 @@ public abstract class Expression implements Serializable, XMLSerializable { */ void inPlaceParamsArray(Object... parameters) { - InPlaceParamReplacer replacer = new InPlaceParamReplacer( - parameters == null ? new Object[0] : parameters); + InPlaceParamReplacer replacer = new InPlaceParamReplacer(parameters == null ? new Object[0] : parameters); traverse(replacer); replacer.onFinish(); } @@ -376,8 +376,7 @@ public abstract class Expression implements Serializable, XMLSerializable { * * @since 4.0 */ - public Expression joinExp(int type, Expression exp, - Expression... expressions) { + public Expression joinExp(int type, Expression exp, Expression... expressions) { Expression join = ExpressionFactory.expressionOfType(type); join.setOperand(0, this); join.setOperand(1, exp); @@ -604,8 +603,7 @@ public abstract class Expression implements Serializable, XMLSerializable { return (Expression) transformed; } - throw new ExpressionException("Invalid transformed expression: " - + transformed); + throw new ExpressionException("Invalid transformed expression: " + transformed); } /** @@ -623,8 +621,7 @@ public abstract class Expression implements Serializable, XMLSerializable { Object transformedChild; if (operand instanceof Expression) { - transformedChild = ((Expression) operand) - .transformExpression(transformer); + transformedChild = ((Expression) operand).transformExpression(transformer); } else if (transformer != null) { transformedChild = transformer.transform(operand); } else { @@ -633,8 +630,7 @@ public abstract class Expression implements Serializable, XMLSerializable { // prune null children only if there is a transformer and it // indicated so - boolean prune = transformer != null - && transformedChild == PRUNED_NODE; + boolean prune = transformer != null && transformedChild == PRUNED_NODE; if (!prune) { copy.setOperand(j, transformedChild); @@ -648,8 +644,7 @@ public abstract class Expression implements Serializable, XMLSerializable { } // all the children are processed, only now transform this copy - return (transformer != null) ? (Expression) transformer.transform(copy) - : copy; + return (transformer != null) ? (Expression) transformer.transform(copy) : copy; } /** @@ -662,8 +657,7 @@ public abstract class Expression implements Serializable, XMLSerializable { try { appendAsString(encoder.getPrintWriter()); } catch (IOException e) { - throw new CayenneRuntimeException( - "Unexpected IO exception appending to PrintWriter", e); + throw new CayenneRuntimeException("Unexpected IO exception appending to PrintWriter", e); } encoder.print("]]>"); } @@ -724,8 +718,8 @@ public abstract class Expression implements Serializable, XMLSerializable { * @since 4.0 * @throws IOException */ - public abstract void appendAsEJBQL(List<Object> parameterAccumulator, - Appendable out, String rootId) throws IOException; + public abstract void appendAsEJBQL(List<Object> parameterAccumulator, Appendable out, String rootId) + throws IOException; @Override public String toString() { @@ -733,8 +727,7 @@ public abstract class Expression implements Serializable, XMLSerializable { try { appendAsString(out); } catch (IOException e) { - throw new CayenneRuntimeException( - "Unexpected IO exception appending to StringBuilder", e); + throw new CayenneRuntimeException("Unexpected IO exception appending to StringBuilder", e); } return out.toString(); } @@ -755,8 +748,7 @@ public abstract class Expression implements Serializable, XMLSerializable { try { appendAsEJBQL(parameterAccumulator, out, rootId); } catch (IOException e) { - throw new CayenneRuntimeException( - "Unexpected IO exception appending to StringBuilder", e); + throw new CayenneRuntimeException("Unexpected IO exception appending to StringBuilder", e); } return out.toString(); } @@ -808,8 +800,7 @@ public abstract class Expression implements Serializable, XMLSerializable { if (pruneMissing) { return PRUNED_NODE; } else { - throw new ExpressionException( - "Missing required parameter: $" + name); + throw new ExpressionException("Missing required parameter: $" + name); } } else { Object value = parameters.get(name); @@ -818,8 +809,7 @@ public abstract class Expression implements Serializable, XMLSerializable { // TODO: andrus 8/14/2007 - shouldn't we also wrap non-null // object // values in ASTScalars? - return (value != null) ? ExpressionFactory - .wrapPathOperand(value) : new ASTScalar(null); + return (value != null) ? ExpressionFactory.wrapPathOperand(value) : new ASTScalar(null); } } @@ -829,6 +819,7 @@ public abstract class Expression implements Serializable, XMLSerializable { private Object[] parameters; private int i; + private Map<String, Object> seen; InPlaceParamReplacer(Object[] parameters) { this.parameters = parameters; @@ -836,19 +827,17 @@ public abstract class Expression implements Serializable, XMLSerializable { void onFinish() { if (i < parameters.length) { - throw new ExpressionException( - "Too many parameters to bind expression. Expected: " - + i + ", actual: " + parameters.length); + throw new ExpressionException("Too many parameters to bind expression. Expected: " + i + ", actual: " + + parameters.length); } } @Override - public void finishedChild(Expression node, int childIndex, - boolean hasMoreChildren) { + public void finishedChild(Expression node, int childIndex, boolean hasMoreChildren) { Object child = node.getOperand(childIndex); if (child instanceof ExpressionParameter) { - node.setOperand(childIndex, nextValue()); + node.setOperand(childIndex, nextValue(((ExpressionParameter) child).getName())); } // normally Object[] is an ASTList child else if (child instanceof Object[]) { @@ -856,26 +845,34 @@ public abstract class Expression implements Serializable, XMLSerializable { for (int i = 0; i < array.length; i++) { if (array[i] instanceof ExpressionParameter) { - array[i] = nextValue(); + array[i] = nextValue(((ExpressionParameter) array[i]).getName()); } } } } - private Object nextValue() { - if (i >= parameters.length) { - throw new ExpressionException( - "Too few parameters to bind expression: " - + parameters.length); + private Object nextValue(String name) { + + if (seen == null) { + seen = new HashMap<String, Object>(); } - Object p = parameters[i++]; + Object p; + if (seen.containsKey(name)) { + p = seen.get(name); + } else { + if (i >= parameters.length) { + throw new ExpressionException("Too few parameters to bind expression: " + parameters.length); + } + + p = parameters[i++]; + seen.put(name, p); + } // wrap lists (for now); also support null parameters // TODO: andrus 8/14/2007 - shouldn't we also wrap non-null // object values in ASTScalars? - return (p != null) ? ExpressionFactory.wrapPathOperand(p) - : new ASTScalar(null); + return (p != null) ? ExpressionFactory.wrapPathOperand(p) : new ASTScalar(null); } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/c725bf09/cayenne-server/src/test/java/org/apache/cayenne/exp/Expression_ParamsTest.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/Expression_ParamsTest.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/Expression_ParamsTest.java index 98a094d..502cbc5 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/exp/Expression_ParamsTest.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/Expression_ParamsTest.java @@ -48,11 +48,11 @@ public class Expression_ParamsTest { } @Test - public void testParams_Positional2() { + public void testParams_Positional_Repeating() { Expression e = ExpressionFactory.exp("a = $a or x = $x and y = $x"); - Expression ep = e.paramsArray("A", 5, 6); + Expression ep = e.paramsArray("A", 5); assertNotSame(e, ep); - assertEquals("(a = \"A\") or ((x = 5) and (y = 6))", ep.toString()); + assertEquals("(a = \"A\") or ((x = 5) and (y = 5))", ep.toString()); } @Test
