Repository: cayenne Updated Branches: refs/heads/master 3f8a8f196 -> 44bad6412
CAY-2211 shortcuts for SQL functions in Property class Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/44bad641 Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/44bad641 Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/44bad641 Branch: refs/heads/master Commit: 44bad641295010807ecd47e6fe5cb7d904f8177a Parents: 3f8a8f1 Author: Nikita Timofeev <stari...@gmail.com> Authored: Thu Jan 26 11:13:38 2017 +0300 Committer: Nikita Timofeev <stari...@gmail.com> Committed: Thu Jan 26 11:13:38 2017 +0300 ---------------------------------------------------------------------- .../apache/cayenne/exp/ExpressionFactory.java | 9 + .../cayenne/exp/FunctionExpressionFactory.java | 42 ++- .../java/org/apache/cayenne/exp/Property.java | 168 ++++++++++- .../org/apache/cayenne/exp/PropertyTest.java | 279 ++++++++++++++++--- .../apache/cayenne/query/ColumnSelectIT.java | 18 +- 5 files changed, 450 insertions(+), 66 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cayenne/blob/44bad641/cayenne-server/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java index 8d132a9..e9fa6b0 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java @@ -52,6 +52,7 @@ import org.apache.cayenne.exp.parser.ASTNotLikeIgnoreCase; import org.apache.cayenne.exp.parser.ASTObjPath; import org.apache.cayenne.exp.parser.ASTOr; import org.apache.cayenne.exp.parser.ASTPath; +import org.apache.cayenne.exp.parser.ASTScalar; import org.apache.cayenne.exp.parser.ASTSubtract; import org.apache.cayenne.exp.parser.ASTTrue; import org.apache.cayenne.exp.parser.ExpressionParser; @@ -1295,6 +1296,14 @@ public class ExpressionFactory { } /** + * Wrap value into ASTScalar + * @since 4.0 + */ + static Expression wrapScalarValue(Object value) { + return new ASTScalar(value); + } + + /** * Parses string, converting it to Expression. If string does not represent * a semantically correct expression, an ExpressionException is thrown. * http://git-wip-us.apache.org/repos/asf/cayenne/blob/44bad641/cayenne-server/src/main/java/org/apache/cayenne/exp/FunctionExpressionFactory.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/FunctionExpressionFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/FunctionExpressionFactory.java index 89a8893..e4cbf07 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/FunctionExpressionFactory.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/FunctionExpressionFactory.java @@ -243,17 +243,24 @@ public class FunctionExpressionFactory { } /** + * <p> * Factory method for expression to call CONCAT(string1, string2, ...) function - * Can be used like: + * </p> + * <p> + * Can be used like: <pre> * Expression concat = concatExp(SomeClass.POPERTY_1.getPath(), SomeClass.PROPERTY_2.getPath()); - * + * </pre> + * </p> + * <p> * SQL generation note: - * - if DB supports CONCAT function with vararg then it will be used - * - if DB supports CONCAT function with two args but also supports concat operator, then operator (eg ||) will be used - * - if DB supports only CONCAT function with two args then it will be used what can lead to SQL exception if + * <ul> + * <li> if DB supports CONCAT function with vararg then it will be used + * <li> if DB supports CONCAT function with two args but also supports concat operator, then operator (eg ||) will be used + * <li> if DB supports only CONCAT function with two args then it will be used what can lead to SQL exception if * used with more than two arguments - * - * Currently only known DB with limited concatenation functionality is Openbase. + * </ul> + * </p> + * <p>Currently only known DB with limited concatenation functionality is Openbase.</p> * * @param expressions array of expressions * @return CONCAT() call expression @@ -267,17 +274,24 @@ public class FunctionExpressionFactory { } /** + * <p> * Factory method for expression to call CONCAT(string1, string2, ...) function - * Can be used like: + * </p> + * <p> + * Can be used like:<pre> * Expression concat = concatExp("property1", "property2"); - * + * </pre> + * </p> + * <p> * SQL generation note: - * - if DB supports CONCAT function with vararg then it will be used - * - if DB supports CONCAT function with two args but also supports concat operator, then operator (eg ||) will be used - * - if DB supports only CONCAT function with two args then it will be used what can lead to SQL exception if + * <ul> + * <li> if DB supports CONCAT function with vararg then it will be used + * <li> if DB supports CONCAT function with two args but also supports concat operator, then operator (eg ||) will be used + * <li> if DB supports only CONCAT function with two args then it will be used what can lead to SQL exception if * used with more than two arguments - * - * Currently only known DB with limited concatenation functionality is Openbase. + * </ul> + * </p> + * <p>Currently only Openbase DB has limited concatenation functionality.</p> * * @param paths array of paths * @return CONCAT() call expression http://git-wip-us.apache.org/repos/asf/cayenne/blob/44bad641/cayenne-server/src/main/java/org/apache/cayenne/exp/Property.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/Property.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/Property.java index f1bb1ce..59eb17d 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/Property.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/Property.java @@ -30,14 +30,16 @@ import java.util.List; /** * <p> - * A property in a DataObject. + * A property in a {@link org.apache.cayenne.DataObject}. * </p> * <p> - * Used to construct Expressions quickly and with type-safety, and to construct Orderings + * Used to construct Expressions quickly and with type-safety, and to construct Orderings. * </p> * <p> - * Instances of this class are immutable - * Construct via factory methods Property.create(..) + * Instances of this class are immutable. + * </p> + * <p> + * Must be created via factory methods {@link Property#create(String, Class) Property.create(..)} * </p> * * @param <E> The type this property returns. @@ -50,6 +52,17 @@ import java.util.List; */ public class Property<E> { + /** + * <p>Property that can be used in COUNT(*) queries</p> + * <p> + * <pre>{@code + * List<Object[]> result = ObjectSelect + * .columnQuery(Artist.class, Property.COUNT, Artist.ARTIST_NAME) + * .having(Property.COUNT.gt(1L)) + * .select(context); + * }</pre> + * </p> + */ public static final Property<Long> COUNT = Property.create(FunctionExpressionFactory.countExp(), Long.class); /** @@ -59,13 +72,11 @@ public class Property<E> { /** * Expression provider for the property - * @since 4.0 */ private final ExpressionProvider expressionProvider; /** * Explicit type of the property - * @since 4.0 */ private final Class<? super E> type; @@ -106,7 +117,6 @@ public class Property<E> { * @param name of the property (will be used as alias for the expression) * @param expression expression for property * @param type of the property - * @since 4.0 * * @see Property#create(String, Expression, Class) */ @@ -129,7 +139,6 @@ public class Property<E> { } /** - * @since 4.0 * @return alias for this property */ public String getAlias() { @@ -149,7 +158,7 @@ public class Property<E> { } /** - * @since 4.0 + * @return expression that represents this Property */ public Expression getExpression() { return expressionProvider.get(); @@ -635,26 +644,146 @@ public class Property<E> { } } + /** + * @see FunctionExpressionFactory#countExp(Expression) + */ public Property<Long> count() { return create(FunctionExpressionFactory.countExp(getExpression()), Long.class); } + /** + * @see FunctionExpressionFactory#maxExp(Expression) + */ public Property<E> max() { return create(FunctionExpressionFactory.maxExp(getExpression()), getType()); } + /** + * @see FunctionExpressionFactory#minExp(Expression) + */ public Property<E> min() { return create(FunctionExpressionFactory.minExp(getExpression()), getType()); } + /** + * @see FunctionExpressionFactory#avgExp(Expression) + */ public Property<E> avg() { return create(FunctionExpressionFactory.avgExp(getExpression()), getType()); } + /** + * @see FunctionExpressionFactory#sumExp(Expression) + */ public Property<E> sum() { return create(FunctionExpressionFactory.sumExp(getExpression()), getType()); } + /** + * @see FunctionExpressionFactory#modExp(Expression, Number) + */ + public Property<E> mod(Number number) { + return create(FunctionExpressionFactory.modExp(getExpression(), number), getType()); + } + + /** + * @see FunctionExpressionFactory#absExp(Expression) + */ + public Property<E> abs() { + return create(FunctionExpressionFactory.absExp(getExpression()), getType()); + } + + /** + * @see FunctionExpressionFactory#sqrtExp(Expression) + */ + public Property<E> sqrt() { + return create(FunctionExpressionFactory.sqrtExp(getExpression()), getType()); + } + + /** + * @see FunctionExpressionFactory#lengthExp(Expression) + */ + public Property<Integer> length() { + return create(FunctionExpressionFactory.lengthExp(getExpression()), Integer.class); + } + + /** + * @see FunctionExpressionFactory#locateExp(String, Expression) + */ + public Property<Integer> locate(String string) { + return create(FunctionExpressionFactory.locateExp(ExpressionFactory.wrapScalarValue(string), getExpression()), Integer.class); + } + + /** + * @see FunctionExpressionFactory#locateExp(Expression, Expression) + */ + public Property<Integer> locate(Property<? extends String> property) { + return create(FunctionExpressionFactory.locateExp(property.getExpression(), getExpression()), Integer.class); + } + + /** + * @see FunctionExpressionFactory#trimExp(Expression) + */ + public Property<String> trim() { + return create(FunctionExpressionFactory.trimExp(getExpression()), String.class); + } + + /** + * @see FunctionExpressionFactory#upperExp(Expression) + */ + public Property<String> upper() { + return create(FunctionExpressionFactory.upperExp(getExpression()), String.class); + } + + /** + * @see FunctionExpressionFactory#lowerExp(Expression) + */ + public Property<String> lower() { + return create(FunctionExpressionFactory.lowerExp(getExpression()), String.class); + } + + /** + * <p>Arguments will be converted as follows: + * <ul> + * <li>if argument is a {@link Property} than its expression will be used</li> + * <li>if argument is a {@link Expression} than it will be used as is </li> + * <li>all other values will be converted to String</li> + * </ul> + * </p> + * <p> + * Usage: + * <pre>{@code + * Property<String> fullName = Artist.FIRST_NAME.concat(" ", Artist.SECOND_NAME); + * }</pre> + * </p> + * @see FunctionExpressionFactory#concatExp(Expression...) + */ + public Property<String> concat(Object... args) { + Expression[] exp = new Expression[args.length + 1]; + int i = 0; + exp[i++] = getExpression(); + for(Object arg : args) { + if(arg instanceof Property) { + exp[i++] = ((Property) arg).getExpression(); + } else if(arg instanceof Expression) { + exp[i++] = (Expression) arg; + } else if(arg != null) { + exp[i++] = ExpressionFactory.wrapScalarValue(arg.toString()); + } + } + return create(FunctionExpressionFactory.concatExp(exp), String.class); + } + + /** + * @see FunctionExpressionFactory#substringExp(Expression, int, int) + */ + public Property<String> substring(int offset, int length) { + return create(FunctionExpressionFactory.substringExp(getExpression(), offset, length), String.class); + } + + /** + * Creates alias with different name for this property + */ public Property<E> alias(String alias) { return new Property<>(alias, this.getExpression(), this.getType()); } @@ -663,18 +792,39 @@ public class Property<E> { return type; } + /** + * Creates property with name and type + * @see Property#create(Expression, Class) + * @see Property#create(String, Expression, Class) + */ public static <T> Property<T> create(String name, Class<? super T> type) { return new Property<>(name, type); } + /** + * Creates property with expression and type + * @see Property#create(String, Class) + * @see Property#create(String, Expression, Class) + */ public static <T> Property<T> create(Expression expression, Class<? super T> type) { return new Property<>(null, expression, type); } + /** + * Creates property with name, expression and type + * @see Property#create(String, Class) + * @see Property#create(Expression, Class) + */ public static <T> Property<T> create(String name, Expression expression, Class<? super T> type) { return new Property<>(name, expression, type); } + /** + * Since Expression is mutable we need to provide clean Expression for every getter call. + * So to keep Property itself immutable we use ExpressionProvider. + * @see Property#Property(String, Class) + * @see Property#Property(String, Expression, Class) + */ private interface ExpressionProvider { Expression get(); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/44bad641/cayenne-server/src/test/java/org/apache/cayenne/exp/PropertyTest.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/PropertyTest.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/PropertyTest.java index a489d37..83b5868 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/exp/PropertyTest.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/PropertyTest.java @@ -26,7 +26,23 @@ import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.List; +import org.apache.cayenne.exp.parser.ASTAbs; +import org.apache.cayenne.exp.parser.ASTAvg; +import org.apache.cayenne.exp.parser.ASTConcat; +import org.apache.cayenne.exp.parser.ASTCount; +import org.apache.cayenne.exp.parser.ASTLength; +import org.apache.cayenne.exp.parser.ASTLocate; +import org.apache.cayenne.exp.parser.ASTLower; +import org.apache.cayenne.exp.parser.ASTMax; +import org.apache.cayenne.exp.parser.ASTMin; +import org.apache.cayenne.exp.parser.ASTMod; import org.apache.cayenne.exp.parser.ASTObjPath; +import org.apache.cayenne.exp.parser.ASTScalar; +import org.apache.cayenne.exp.parser.ASTSqrt; +import org.apache.cayenne.exp.parser.ASTSubstring; +import org.apache.cayenne.exp.parser.ASTSum; +import org.apache.cayenne.exp.parser.ASTTrim; +import org.apache.cayenne.exp.parser.ASTUpper; import org.apache.cayenne.exp.parser.PatternMatchNode; import org.apache.cayenne.reflect.TstJavaBean; import org.junit.Test; @@ -35,14 +51,14 @@ public class PropertyTest { @Test public void testPath() { - Property<String> p = new Property<>("x.y"); + Property<String> p = Property.create("x.y", String.class); Expression pp = p.path(); assertEquals(ExpressionFactory.exp("x.y"), pp); } @Test public void testIn() { - Property<String> p = new Property<>("x.y"); + Property<String> p = Property.create("x.y", String.class); Expression e1 = p.in("a"); assertEquals("x.y in (\"a\")", e1.toString()); @@ -58,7 +74,7 @@ public class PropertyTest { public void testGetFrom() { TstJavaBean bean = new TstJavaBean(); bean.setIntField(7); - Property<Integer> INT_FIELD = new Property<>("intField"); + Property<Integer> INT_FIELD = Property.create("intField", Integer.class); assertEquals(Integer.valueOf(7), INT_FIELD.getFrom(bean)); } @@ -68,7 +84,7 @@ public class PropertyTest { TstJavaBean nestedBean = new TstJavaBean(); nestedBean.setIntField(7); bean.setObjectField(nestedBean); - Property<Integer> OBJECT_FIELD_INT_FIELD = new Property<>("objectField.intField"); + Property<Integer> OBJECT_FIELD_INT_FIELD = Property.create("objectField.intField", Integer.class); assertEquals(Integer.valueOf(7), OBJECT_FIELD_INT_FIELD.getFrom(bean)); } @@ -76,7 +92,7 @@ public class PropertyTest { public void testGetFromNestedNull() { TstJavaBean bean = new TstJavaBean(); bean.setObjectField(null); - Property<Integer> OBJECT_FIELD_INT_FIELD = new Property<>("objectField.intField"); + Property<Integer> OBJECT_FIELD_INT_FIELD = Property.create("objectField.intField", Integer.class); assertNull(OBJECT_FIELD_INT_FIELD.getFrom(bean)); } @@ -90,14 +106,14 @@ public class PropertyTest { List<TstJavaBean> beans = Arrays.asList(bean, bean2); - Property<Integer> INT_FIELD = new Property<>("intField"); + Property<Integer> INT_FIELD = Property.create("intField", Integer.class); assertEquals(Arrays.asList(7, 8), INT_FIELD.getFromAll(beans)); } @Test public void testSetIn() { TstJavaBean bean = new TstJavaBean(); - Property<Integer> INT_FIELD = new Property<>("intField"); + Property<Integer> INT_FIELD = Property.create("intField", Integer.class); INT_FIELD.setIn(bean, 7); assertEquals(7, bean.getIntField()); } @@ -107,7 +123,7 @@ public class PropertyTest { TstJavaBean bean = new TstJavaBean(); bean.setObjectField(new TstJavaBean()); - Property<Integer> OBJECT_FIELD_INT_FIELD = new Property<>("objectField.intField"); + Property<Integer> OBJECT_FIELD_INT_FIELD = Property.create("objectField.intField", Integer.class); OBJECT_FIELD_INT_FIELD.setIn(bean, 7); assertEquals(7, ((TstJavaBean) bean.getObjectField()).getIntField()); @@ -117,7 +133,7 @@ public class PropertyTest { public void testSetInNestedNull() { TstJavaBean bean = new TstJavaBean(); bean.setObjectField(null); - Property<Integer> OBJECT_FIELD_INT_FIELD = new Property<>("objectField.intField"); + Property<Integer> OBJECT_FIELD_INT_FIELD = Property.create("objectField.intField", Integer.class); OBJECT_FIELD_INT_FIELD.setIn(bean, 7); } @@ -127,7 +143,7 @@ public class PropertyTest { TstJavaBean bean2 = new TstJavaBean(); List<TstJavaBean> beans = Arrays.asList(bean, bean2); - Property<Integer> INT_FIELD = new Property<>("intField"); + Property<Integer> INT_FIELD = Property.create("intField", Integer.class); INT_FIELD.setInAll(beans, 7); assertEquals(7, bean.getIntField()); assertEquals(7, bean2.getIntField()); @@ -135,8 +151,8 @@ public class PropertyTest { @Test public void testEqualsWithName() { - Property<Integer> INT_FIELD = new Property<>("intField"); - Property<Integer> INT_FIELD2 = new Property<>("intField"); + Property<Integer> INT_FIELD = Property.create("intField", Integer.class); + Property<Integer> INT_FIELD2 = Property.create("intField", Integer.class); assertTrue(INT_FIELD != INT_FIELD2); assertTrue(INT_FIELD.equals(INT_FIELD2)); @@ -144,9 +160,9 @@ public class PropertyTest { @Test public void testHashCodeWithName() { - Property<Integer> INT_FIELD = new Property<>("intField"); - Property<Integer> INT_FIELD2 = new Property<>("intField"); - Property<Long> LONG_FIELD = new Property<>("longField"); + Property<Integer> INT_FIELD = Property.create("intField", Integer.class); + Property<Integer> INT_FIELD2 = Property.create("intField", Integer.class); + Property<Long> LONG_FIELD = Property.create("longField", Long.class); assertTrue(INT_FIELD.hashCode() == INT_FIELD2.hashCode()); assertTrue(INT_FIELD.hashCode() != LONG_FIELD.hashCode()); @@ -154,8 +170,8 @@ public class PropertyTest { @Test public void testEqualsWithNameAndType() { - Property<Integer> INT_FIELD = new Property<>("intField", Integer.class); - Property<Integer> INT_FIELD2 = new Property<>("intField", Integer.class); + Property<Integer> INT_FIELD = Property.create("intField", Integer.class); + Property<Integer> INT_FIELD2 = Property.create("intField", Integer.class); assertTrue(INT_FIELD != INT_FIELD2); assertTrue(INT_FIELD.equals(INT_FIELD2)); @@ -163,9 +179,9 @@ public class PropertyTest { @Test public void testHashCodeWithNameAndType() { - Property<Integer> INT_FIELD = new Property<>("intField", Integer.class); - Property<Integer> INT_FIELD2 = new Property<>("intField", Integer.class); - Property<Long> LONG_FIELD = new Property<>("longField", Long.class); + Property<Integer> INT_FIELD = Property.create("intField", Integer.class); + Property<Integer> INT_FIELD2 = Property.create("intField", Integer.class); + Property<Long> LONG_FIELD = Property.create("longField", Long.class); assertTrue(INT_FIELD.hashCode() == INT_FIELD2.hashCode()); assertTrue(INT_FIELD.hashCode() != LONG_FIELD.hashCode()); @@ -192,33 +208,33 @@ public class PropertyTest { @Test public void testOuter() { - Property<String> inner = new Property<>("xyz"); + Property<String> inner = Property.create("xyz", String.class); assertEquals("xyz+", inner.outer().getName()); - Property<String> inner1 = new Property<>("xyz.xxx"); + Property<String> inner1 = Property.create("xyz.xxx", String.class); assertEquals("xyz.xxx+", inner1.outer().getName()); - Property<String> outer = new Property<>("xyz+"); + Property<String> outer = Property.create("xyz+", String.class); assertEquals("xyz+", outer.outer().getName()); } @Test public void testLike() { - Property<String> p = new Property<>("prop"); + Property<String> p = Property.create("prop", String.class); Expression e = p.like("abc"); assertEquals("prop like \"abc\"", e.toString()); } @Test public void testLikeIgnoreCase() { - Property<String> p = new Property<>("prop"); + Property<String> p = Property.create("prop", String.class); Expression e = p.likeIgnoreCase("abc"); assertEquals("prop likeIgnoreCase \"abc\"", e.toString()); } @Test public void testLike_NoEscape() { - Property<String> p = new Property<>("prop"); + Property<String> p = Property.create("prop", String.class); Expression e = p.like("ab%c"); assertEquals("prop like \"ab%c\"", e.toString()); assertEquals(0, ((PatternMatchNode) e).getEscapeChar()); @@ -226,7 +242,7 @@ public class PropertyTest { @Test public void testContains() { - Property<String> p = new Property<>("prop"); + Property<String> p = Property.create("prop", String.class); Expression e = p.contains("abc"); assertEquals("prop like \"%abc%\"", e.toString()); assertEquals(0, ((PatternMatchNode) e).getEscapeChar()); @@ -234,7 +250,7 @@ public class PropertyTest { @Test public void testStartsWith() { - Property<String> p = new Property<>("prop"); + Property<String> p = Property.create("prop", String.class); Expression e = p.startsWith("abc"); assertEquals("prop like \"abc%\"", e.toString()); assertEquals(0, ((PatternMatchNode) e).getEscapeChar()); @@ -242,7 +258,7 @@ public class PropertyTest { @Test public void testEndsWith() { - Property<String> p = new Property<>("prop"); + Property<String> p = Property.create("prop", String.class); Expression e = p.endsWith("abc"); assertEquals("prop like \"%abc\"", e.toString()); assertEquals(0, ((PatternMatchNode) e).getEscapeChar()); @@ -250,7 +266,7 @@ public class PropertyTest { @Test public void testContains_Escape1() { - Property<String> p = new Property<>("prop"); + Property<String> p = Property.create("prop", String.class); Expression e = p.contains("a%bc"); assertEquals("prop like \"%a!%bc%\"", e.toString()); assertEquals('!', ((PatternMatchNode) e).getEscapeChar()); @@ -258,7 +274,7 @@ public class PropertyTest { @Test public void testContains_Escape2() { - Property<String> p = new Property<>("prop"); + Property<String> p = Property.create("prop", String.class); Expression e = p.contains("a_!bc"); assertEquals("prop like \"%a#_!bc%\"", e.toString()); assertEquals('#', ((PatternMatchNode) e).getEscapeChar()); @@ -271,4 +287,205 @@ public class PropertyTest { Expression ex = p.getExpression(); assertEquals("test.path", ex.toString()); } + + @SuppressWarnings("deprecation") + @Test + public void testDeprecatedConstruct() { + Property<String> p = new Property<>("p"); + assertNull(p.getType()); + assertEquals("p", p.getName()); + assertEquals(new ASTObjPath("p"), p.getExpression()); + } + + @Test + public void testCreationWithName() { + Property<String> p1 = new Property<>("p1", String.class); + assertEquals(String.class, p1.getType()); + assertEquals("p1", p1.getName()); + assertEquals(new ASTObjPath("p1"), p1.getExpression()); + + Property<String> p2 = Property.create("p1", String.class); + assertEquals(p1, p2); + } + + @Test + public void testCreationWithExp() { + Expression exp = FunctionExpressionFactory.currentTime(); + + Property<String> p1 = new Property<>(null, exp, String.class); + assertEquals(String.class, p1.getType()); + assertEquals(null, p1.getName()); + assertEquals(exp, p1.getExpression()); + + Property<String> p2 = Property.create(exp, String.class); + assertEquals(p1, p2); + } + + @Test + public void testCreationWithNameAndExp() { + Expression exp = FunctionExpressionFactory.currentTime(); + + Property<String> p1 = new Property<>("p1", exp, String.class); + assertEquals(String.class, p1.getType()); + assertEquals("p1", p1.getName()); + assertEquals(exp, p1.getExpression()); + + Property<String> p2 = Property.create("p1", exp, String.class); + assertEquals(p1, p2); + } + + @Test + public void testAlias() { + Expression exp = FunctionExpressionFactory.currentTime(); + + Property<String> p1 = new Property<>("p1", exp, String.class); + assertEquals(String.class, p1.getType()); + assertEquals("p1", p1.getName()); + assertEquals(exp, p1.getExpression()); + + Property<String> p2 = p1.alias("p2"); + assertEquals(String.class, p2.getType()); + assertEquals("p2", p2.getName()); + assertEquals(exp, p2.getExpression()); + } + + @Test + public void testCount() { + Property<String> p = Property.create("test", String.class); + Property<Long> newProp = p.count(); + assertTrue(newProp.getExpression() instanceof ASTCount); + assertEquals(p.getExpression(), newProp.getExpression().getOperand(0)); + } + + @Test + public void testMin() { + Property<String> p = Property.create("test", String.class); + Property<String> newProp = p.min(); + assertTrue(newProp.getExpression() instanceof ASTMin); + assertEquals(p.getExpression(), newProp.getExpression().getOperand(0)); + } + + @Test + public void testMax() { + Property<String> p = Property.create("test", String.class); + Property<String> newProp = p.max(); + assertTrue(newProp.getExpression() instanceof ASTMax); + assertEquals(p.getExpression(), newProp.getExpression().getOperand(0)); + } + + @Test + public void testSum() { + Property<String> p = Property.create("test", String.class); + Property<String> newProp = p.sum(); + assertTrue(newProp.getExpression() instanceof ASTSum); + assertEquals(p.getExpression(), newProp.getExpression().getOperand(0)); + } + + @Test + public void testAvg() { + Property<String> p = Property.create("test", String.class); + Property<String> newProp = p.avg(); + assertTrue(newProp.getExpression() instanceof ASTAvg); + assertEquals(p.getExpression(), newProp.getExpression().getOperand(0)); + } + + @Test + public void testAbs() { + Property<String> p = Property.create("test", String.class); + Property<String> newProp = p.abs(); + assertTrue(newProp.getExpression() instanceof ASTAbs); + assertEquals(p.getExpression(), newProp.getExpression().getOperand(0)); + } + + @Test + public void testMod() { + Property<String> p = Property.create("test", String.class); + Property<String> newProp = p.mod(3.0); + assertTrue(newProp.getExpression() instanceof ASTMod); + assertEquals(p.getExpression(), newProp.getExpression().getOperand(0)); + assertEquals(3.0, newProp.getExpression().getOperand(1)); + } + + @Test + public void testSqrt() { + Property<String> p = Property.create("test", String.class); + Property<String> newProp = p.sqrt(); + assertTrue(newProp.getExpression() instanceof ASTSqrt); + assertEquals(p.getExpression(), newProp.getExpression().getOperand(0)); + } + + @Test + public void testLength() { + Property<String> p = Property.create("test", String.class); + Property<Integer> newProp = p.length(); + assertTrue(newProp.getExpression() instanceof ASTLength); + assertEquals(p.getExpression(), newProp.getExpression().getOperand(0)); + } + + @Test + public void testLocateString() { + Property<String> p = Property.create("test", String.class); + Property<Integer> newProp = p.locate("test"); + assertTrue(newProp.getExpression() instanceof ASTLocate); + assertEquals("test", newProp.getExpression().getOperand(0)); + assertEquals(p.getExpression(), newProp.getExpression().getOperand(1)); + } + + @Test + public void testLocateProperty() { + Property<String> p = Property.create("test", String.class); + Property<String> p2 = Property.create("test2", String.class); + Property<Integer> newProp = p.locate(p2); + assertTrue(newProp.getExpression() instanceof ASTLocate); + assertEquals(p.getExpression(), newProp.getExpression().getOperand(1)); + assertEquals(p2.getExpression(), newProp.getExpression().getOperand(0)); + } + + @Test + public void testSustring() { + Property<String> p = Property.create("test", String.class); + Property<String> newProp = p.substring(1, 2); + assertTrue(newProp.getExpression() instanceof ASTSubstring); + assertEquals(p.getExpression(), newProp.getExpression().getOperand(0)); + assertEquals(1, newProp.getExpression().getOperand(1)); + assertEquals(2, newProp.getExpression().getOperand(2)); + } + + @Test + public void testTrim() { + Property<String> p = Property.create("test", String.class); + Property<String> newProp = p.trim(); + assertTrue(newProp.getExpression() instanceof ASTTrim); + assertEquals(p.getExpression(), newProp.getExpression().getOperand(0)); + } + + @Test + public void testLower() { + Property<String> p = Property.create("test", String.class); + Property<String> newProp = p.lower(); + assertTrue(newProp.getExpression() instanceof ASTLower); + assertEquals(p.getExpression(), newProp.getExpression().getOperand(0)); + } + + @Test + public void testUpper() { + Property<String> p = Property.create("test", String.class); + Property<String> newProp = p.upper(); + assertTrue(newProp.getExpression() instanceof ASTUpper); + assertEquals(p.getExpression(), newProp.getExpression().getOperand(0)); + } + + @Test + public void testConcat() { + Property<String> p = Property.create("test", String.class); + Property<String> p2 = Property.create("concat", String.class); + Expression exp = new ASTScalar(3); + + Property<String> newProp = p.concat("string", exp, p2); + assertTrue(newProp.getExpression() instanceof ASTConcat); + assertEquals(p.getExpression(), newProp.getExpression().getOperand(0)); + assertEquals("string", newProp.getExpression().getOperand(1)); + assertEquals(3, newProp.getExpression().getOperand(2)); // getOperand unwrapping ASTScalar + assertEquals(p2.getExpression(), newProp.getExpression().getOperand(3)); + } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/44bad641/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java b/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java index 613b659..4319398 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java @@ -117,7 +117,7 @@ public class ColumnSelectIT extends ServerCase { @Test(expected = Exception.class) public void testHavingOnNonGroupByColumn() throws Exception { - Property<String> nameSubstr = Property.create(substringExp(Artist.ARTIST_NAME.path(), 1, 6), String.class); + Property<String> nameSubstr = Artist.ARTIST_NAME.substring(1, 6); Object[] q = ObjectSelect.columnQuery(Artist.class, nameSubstr, Property.COUNT) .having(Artist.ARTIST_NAME.like("artist%")) @@ -139,10 +139,10 @@ public class ColumnSelectIT extends ServerCase { @Test public void testSelectHavingWithExpressionAlias() throws Exception { - Property<String> nameSubstr = Property.create("name_substr", substringExp(Artist.ARTIST_NAME.path(), 1, 6), String.class); Object[] q = null; try { - q = ObjectSelect.columnQuery(Artist.class, nameSubstr, Property.COUNT) + q = ObjectSelect + .columnQuery(Artist.class, Artist.ARTIST_NAME.substring(1, 6).alias("name_substr"), Property.COUNT) .having(Property.COUNT.gt(10L)) .selectOne(context); } catch (CayenneRuntimeException ex) { @@ -160,10 +160,9 @@ public class ColumnSelectIT extends ServerCase { @Test public void testSelectHavingWithExpressionNoAlias() throws Exception { - Property<String> nameSubstr = Property.create(substringExp(Artist.ARTIST_NAME.path(), 1, 6), String.class); Object[] q = null; try { - q = ObjectSelect.columnQuery(Artist.class, nameSubstr, Property.COUNT) + q = ObjectSelect.columnQuery(Artist.class, Artist.ARTIST_NAME.substring(1, 6), Property.COUNT) .having(Property.COUNT.gt(10L)) .selectOne(context); } catch (CayenneRuntimeException ex) { @@ -179,13 +178,10 @@ public class ColumnSelectIT extends ServerCase { @Test public void testSelectWhereAndHaving() throws Exception { - Property<String> nameFirstLetter = Property.create(substringExp(Artist.ARTIST_NAME.path(), 1, 1), String.class); - Property<String> nameSubstr = Property.create("name_substr", substringExp(Artist.ARTIST_NAME.path(), 1, 6), String.class); - Object[] q = null; try { - q = ObjectSelect.columnQuery(Artist.class, nameSubstr, Property.COUNT) - .where(nameFirstLetter.eq("a")) + q = ObjectSelect.columnQuery(Artist.class, Artist.ARTIST_NAME.substring(1, 6).alias("name_substr"), Property.COUNT) + .where(Artist.ARTIST_NAME.substring(1, 1).eq("a")) .having(Property.COUNT.gt(10L)) .selectOne(context); } catch (CayenneRuntimeException ex) { @@ -336,7 +332,5 @@ public class ColumnSelectIT extends ServerCase { .count(Artist.DATE_OF_BIRTH) .selectOne(context); assertEquals(count2, count3); - - } }