CAY-2163 Property.path() , ExpressionFactory.pathExp()

(also switching some docs to Property API)


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/83571185
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/83571185
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/83571185

Branch: refs/heads/master
Commit: 83571185859a9588c40917f98a54ee8b67402454
Parents: 94d4d83
Author: Andrus Adamchik <and...@objectstyle.com>
Authored: Sun Dec 11 10:55:41 2016 +0300
Committer: Andrus Adamchik <and...@objectstyle.com>
Committed: Sun Dec 11 11:18:15 2016 +0300

----------------------------------------------------------------------
 .../apache/cayenne/exp/ExpressionFactory.java   |  18 +
 .../java/org/apache/cayenne/exp/Property.java   |  19 +-
 .../cayenne/exp/ExpressionFactoryTest.java      |  20 +-
 .../org/apache/cayenne/exp/PropertyTest.java    | 377 ++++++++++---------
 docs/doc/src/main/resources/RELEASE-NOTES.txt   |  10 +
 .../cayenne-guide/src/docbkx/expressions.xml    |  89 +++--
 6 files changed, 299 insertions(+), 234 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/83571185/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 cbef42d..b440f8a 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
@@ -860,6 +860,24 @@ public class ExpressionFactory {
        }
 
        /**
+        * @param pathSpec a String "obj:" path.
+        * @since 4.0
+        * @return a new "obj:" path expression for the specified String path.
+        */
+       public static Expression pathExp(String pathSpec) {
+               return new ASTObjPath(pathSpec);
+       }
+
+       /**
+        * @param pathSpec a String db: path.
+        * @since 4.0
+        * @return a new "db:" path expression for the specified String path.
+        */
+       public static Expression dbPathExp(String pathSpec) {
+               return new ASTDbPath(pathSpec);
+       }
+
+       /**
         * A convenience shortcut for boolean true expression.
         * 
         * @since 3.0

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83571185/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 5560014..b9ae1c6 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
@@ -77,16 +77,18 @@ public class Property<E> {
     }
 
     /**
-     * @return Constructs a property path by appending the argument to the
-     * existing property separated by a dot
+     * Constructs a property path by appending the argument to the existing 
property separated by a dot.
+     *
+     * @return a newly created Property object.
      */
     public Property<Object> dot(String property) {
         return new Property<Object>(getName() + "." + property);
     }
 
     /**
-     * @return Constructs a property path by appending the argument to the
-     * existing property separated by a dot
+     * Constructs a new property path by appending the argument to the 
existing property separated by a dot.
+     *
+     * @return a newly created Property object.
      */
     public <T> Property<T> dot(Property<T> property) {
         return new Property<T>(getName() + "." + property.getName());
@@ -106,6 +108,15 @@ public class Property<E> {
     }
 
     /**
+     * Converts this property to a path expression.
+     *
+     * @return a newly created expression.
+     */
+    public Expression path() {
+        return ExpressionFactory.pathExp(getName());
+    }
+
+    /**
      * @return An expression representing null.
      */
     public Expression isNull() {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83571185/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java
index 57ff918..3cf4a46 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java
@@ -175,7 +175,7 @@ public class ExpressionFactoryTest {
 
        @Test
        public void testInExp2() throws Exception {
-               List<Object> v = new ArrayList<Object>();
+               List<Object> v = new ArrayList<>();
                v.add("a");
                v.add("b");
                Expression exp = ExpressionFactory.inExp("abc", v);
@@ -184,7 +184,7 @@ public class ExpressionFactoryTest {
 
        @Test
        public void testInExp3() throws Exception {
-               List<Object> v = new ArrayList<Object>();
+               List<Object> v = new ArrayList<>();
                Expression exp = ExpressionFactory.inExp("abc", v);
                assertEquals(Expression.FALSE, exp.getType());
        }
@@ -308,7 +308,7 @@ public class ExpressionFactoryTest {
 
                // check for N in (1..5)
                for (int n = 1; n <= 5; n++) {
-                       Collection<Expression> list = new 
ArrayList<Expression>();
+                       Collection<Expression> list = new ArrayList<>();
 
                        // populate map
                        for (int i = 1; i <= n; i++) {
@@ -342,7 +342,7 @@ public class ExpressionFactoryTest {
        public void testAnd_Collection_OneElement() {
                Expression e1 = ExpressionFactory.matchExp("a", 1);
 
-               Collection<Expression> c = Arrays.asList(e1);
+               Collection<Expression> c = Collections.singletonList(e1);
                Expression e = ExpressionFactory.and(c);
 
                assertEquals("a = 1", e.toString());
@@ -457,8 +457,18 @@ public class ExpressionFactoryTest {
        }
 
        @Test
-       public void testExp_Vararg_InAsValues() throws Exception {
+       public void testExp_Vararg_InAsValues() {
                Expression e = ExpressionFactory.exp("k1 in ($ap, $bp)", "a", 
"b");
                assertEquals("k1 in (\"a\", \"b\")", e.toString());
        }
+
+       @Test
+       public void testPathExp() {
+               assertEquals("abc.xyz", 
ExpressionFactory.pathExp("abc.xyz").toString());
+       }
+
+       @Test
+       public void testDbPathExp() {
+               assertEquals("db:abc.xyz", 
ExpressionFactory.dbPathExp("abc.xyz").toString());
+       }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83571185/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 0026f66..5984a94 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
@@ -31,189 +31,196 @@ import org.junit.Test;
 
 public class PropertyTest {
 
-       @Test
-       public void testIn() {
-               Property<String> p = new Property<String>("x.y");
-
-               Expression e1 = p.in("a");
-               assertEquals("x.y in (\"a\")", e1.toString());
-
-               Expression e2 = p.in("a", "b");
-               assertEquals("x.y in (\"a\", \"b\")", e2.toString());
-
-               Expression e3 = p.in(Arrays.asList("a", "b"));
-               assertEquals("x.y in (\"a\", \"b\")", e3.toString());
-       }
-
-       @Test
-       public void testGetFrom() {
-               TstJavaBean bean = new TstJavaBean();
-               bean.setIntField(7);
-               final Property<Integer> INT_FIELD = new 
Property<Integer>("intField");
-               assertEquals(Integer.valueOf(7), INT_FIELD.getFrom(bean));
-       }
-
-       @Test
-       public void testGetFromNestedProperty() {
-               TstJavaBean bean = new TstJavaBean();
-               TstJavaBean nestedBean = new TstJavaBean();
-               nestedBean.setIntField(7);
-               bean.setObjectField(nestedBean);
-               final Property<Integer> OBJECT_FIELD_INT_FIELD = new 
Property<Integer>("objectField.intField");
-               assertEquals(Integer.valueOf(7), 
OBJECT_FIELD_INT_FIELD.getFrom(bean));
-       }
-
-       @Test
-       public void testGetFromNestedNull() {
-               TstJavaBean bean = new TstJavaBean();
-               bean.setObjectField(null);
-               Property<Integer> OBJECT_FIELD_INT_FIELD = new 
Property<Integer>("objectField.intField");
-               assertNull(OBJECT_FIELD_INT_FIELD.getFrom(bean));
-       }
-
-       @Test
-       public void testGetFromAll() {
-               TstJavaBean bean = new TstJavaBean();
-               bean.setIntField(7);
-
-               TstJavaBean bean2 = new TstJavaBean();
-               bean2.setIntField(8);
-
-               List<TstJavaBean> beans = Arrays.asList(bean, bean2);
-
-               final Property<Integer> INT_FIELD = new 
Property<Integer>("intField");
-               assertEquals(Arrays.asList(7, 8), INT_FIELD.getFromAll(beans));
-       }
-
-       @Test
-       public void testSetIn() {
-               TstJavaBean bean = new TstJavaBean();
-               final Property<Integer> INT_FIELD = new 
Property<Integer>("intField");
-               INT_FIELD.setIn(bean, 7);
-               assertEquals(7, bean.getIntField());
-       }
-
-       @Test
-       public void testSetInNestedProperty() {
-               TstJavaBean bean = new TstJavaBean();
-               bean.setObjectField(new TstJavaBean());
-
-               final Property<Integer> OBJECT_FIELD_INT_FIELD = new 
Property<Integer>("objectField.intField");
-
-               OBJECT_FIELD_INT_FIELD.setIn(bean, 7);
-               assertEquals(7, ((TstJavaBean) 
bean.getObjectField()).getIntField());
-       }
-
-       @Test
-       public void testSetInNestedNull() {
-               TstJavaBean bean = new TstJavaBean();
-               bean.setObjectField(null);
-               final Property<Integer> OBJECT_FIELD_INT_FIELD = new 
Property<Integer>("objectField.intField");
-               OBJECT_FIELD_INT_FIELD.setIn(bean, 7);
-       }
-
-       @Test
-       public void testSetInAll() {
-               TstJavaBean bean = new TstJavaBean();
-               TstJavaBean bean2 = new TstJavaBean();
-               List<TstJavaBean> beans = Arrays.asList(bean, bean2);
-
-               final Property<Integer> INT_FIELD = new 
Property<Integer>("intField");
-               INT_FIELD.setInAll(beans, 7);
-               assertEquals(7, bean.getIntField());
-               assertEquals(7, bean2.getIntField());
-       }
-
-       @Test
-       public void testEquals() {
-               final Property<Integer> INT_FIELD = new 
Property<Integer>("intField");
-               final Property<Integer> INT_FIELD2 = new 
Property<Integer>("intField");
-
-               assertTrue(INT_FIELD != INT_FIELD2);
-               assertTrue(INT_FIELD.equals(INT_FIELD2));
-       }
-
-       @Test
-       public void testHashCode() {
-               final Property<Integer> INT_FIELD = new 
Property<Integer>("intField");
-               final Property<Integer> INT_FIELD2 = new 
Property<Integer>("intField");
-               final Property<Long> LONG_FIELD = new 
Property<Long>("longField");
-
-               assertTrue(INT_FIELD.hashCode() == INT_FIELD2.hashCode());
-               assertTrue(INT_FIELD.hashCode() != LONG_FIELD.hashCode());
-       }
-
-       @Test
-       public void testOuter() {
-               Property<String> inner = new Property<String>("xyz");
-               assertEquals("xyz+", inner.outer().getName());
-
-               Property<String> inner1 = new Property<String>("xyz.xxx");
-               assertEquals("xyz.xxx+", inner1.outer().getName());
-
-               Property<String> outer = new Property<String>("xyz+");
-               assertEquals("xyz+", outer.outer().getName());
-       }
-
-       @Test
-       public void testLike() {
-               Property<String> p = new Property<String>("prop");
-               Expression e = p.like("abc");
-               assertEquals("prop like \"abc\"", e.toString());
-       }
-
-       @Test
-       public void testLikeIgnoreCase() {
-               Property<String> p = new Property<String>("prop");
-               Expression e = p.likeIgnoreCase("abc");
-               assertEquals("prop likeIgnoreCase \"abc\"", e.toString());
-       }
-
-       @Test
-       public void testLike_NoEscape() {
-               Property<String> p = new Property<String>("prop");
-               Expression e = p.like("ab%c");
-               assertEquals("prop like \"ab%c\"", e.toString());
-               assertEquals(0, ((PatternMatchNode) e).getEscapeChar());
-       }
-
-       @Test
-       public void testContains() {
-               Property<String> p = new Property<String>("prop");
-               Expression e = p.contains("abc");
-               assertEquals("prop like \"%abc%\"", e.toString());
-               assertEquals(0, ((PatternMatchNode) e).getEscapeChar());
-       }
-
-       @Test
-       public void testStartsWith() {
-               Property<String> p = new Property<String>("prop");
-               Expression e = p.startsWith("abc");
-               assertEquals("prop like \"abc%\"", e.toString());
-               assertEquals(0, ((PatternMatchNode) e).getEscapeChar());
-       }
-
-       @Test
-       public void testEndsWith() {
-               Property<String> p = new Property<String>("prop");
-               Expression e = p.endsWith("abc");
-               assertEquals("prop like \"%abc\"", e.toString());
-               assertEquals(0, ((PatternMatchNode) e).getEscapeChar());
-       }
-       
-       @Test
-       public void testContains_Escape1() {
-               Property<String> p = new Property<String>("prop");
-               Expression e = p.contains("a%bc");
-               assertEquals("prop like \"%a!%bc%\"", e.toString());
-               assertEquals('!', ((PatternMatchNode) e).getEscapeChar());
-       }
-       
-       @Test
-       public void testContains_Escape2() {
-               Property<String> p = new Property<String>("prop");
-               Expression e = p.contains("a_!bc");
-               assertEquals("prop like \"%a#_!bc%\"", e.toString());
-               assertEquals('#', ((PatternMatchNode) e).getEscapeChar());
-       }
+    @Test
+    public void testPath() {
+        Property<String> p = new Property<>("x.y");
+        Expression pp = p.path();
+        assertEquals(ExpressionFactory.exp("x.y"), pp);
+    }
+
+    @Test
+    public void testIn() {
+        Property<String> p = new Property<>("x.y");
+
+        Expression e1 = p.in("a");
+        assertEquals("x.y in (\"a\")", e1.toString());
+
+        Expression e2 = p.in("a", "b");
+        assertEquals("x.y in (\"a\", \"b\")", e2.toString());
+
+        Expression e3 = p.in(Arrays.asList("a", "b"));
+        assertEquals("x.y in (\"a\", \"b\")", e3.toString());
+    }
+
+    @Test
+    public void testGetFrom() {
+        TstJavaBean bean = new TstJavaBean();
+        bean.setIntField(7);
+        Property<Integer> INT_FIELD = new Property<>("intField");
+        assertEquals(Integer.valueOf(7), INT_FIELD.getFrom(bean));
+    }
+
+    @Test
+    public void testGetFromNestedProperty() {
+        TstJavaBean bean = new TstJavaBean();
+        TstJavaBean nestedBean = new TstJavaBean();
+        nestedBean.setIntField(7);
+        bean.setObjectField(nestedBean);
+        Property<Integer> OBJECT_FIELD_INT_FIELD = new 
Property<>("objectField.intField");
+        assertEquals(Integer.valueOf(7), OBJECT_FIELD_INT_FIELD.getFrom(bean));
+    }
+
+    @Test
+    public void testGetFromNestedNull() {
+        TstJavaBean bean = new TstJavaBean();
+        bean.setObjectField(null);
+        Property<Integer> OBJECT_FIELD_INT_FIELD = new 
Property<>("objectField.intField");
+        assertNull(OBJECT_FIELD_INT_FIELD.getFrom(bean));
+    }
+
+    @Test
+    public void testGetFromAll() {
+        TstJavaBean bean = new TstJavaBean();
+        bean.setIntField(7);
+
+        TstJavaBean bean2 = new TstJavaBean();
+        bean2.setIntField(8);
+
+        List<TstJavaBean> beans = Arrays.asList(bean, bean2);
+
+        Property<Integer> INT_FIELD = new Property<>("intField");
+        assertEquals(Arrays.asList(7, 8), INT_FIELD.getFromAll(beans));
+    }
+
+    @Test
+    public void testSetIn() {
+        TstJavaBean bean = new TstJavaBean();
+        Property<Integer> INT_FIELD = new Property<>("intField");
+        INT_FIELD.setIn(bean, 7);
+        assertEquals(7, bean.getIntField());
+    }
+
+    @Test
+    public void testSetInNestedProperty() {
+        TstJavaBean bean = new TstJavaBean();
+        bean.setObjectField(new TstJavaBean());
+
+        Property<Integer> OBJECT_FIELD_INT_FIELD = new 
Property<>("objectField.intField");
+
+        OBJECT_FIELD_INT_FIELD.setIn(bean, 7);
+        assertEquals(7, ((TstJavaBean) bean.getObjectField()).getIntField());
+    }
+
+    @Test
+    public void testSetInNestedNull() {
+        TstJavaBean bean = new TstJavaBean();
+        bean.setObjectField(null);
+        Property<Integer> OBJECT_FIELD_INT_FIELD = new 
Property<>("objectField.intField");
+        OBJECT_FIELD_INT_FIELD.setIn(bean, 7);
+    }
+
+    @Test
+    public void testSetInAll() {
+        TstJavaBean bean = new TstJavaBean();
+        TstJavaBean bean2 = new TstJavaBean();
+        List<TstJavaBean> beans = Arrays.asList(bean, bean2);
+
+        Property<Integer> INT_FIELD = new Property<>("intField");
+        INT_FIELD.setInAll(beans, 7);
+        assertEquals(7, bean.getIntField());
+        assertEquals(7, bean2.getIntField());
+    }
+
+    @Test
+    public void testEquals() {
+        Property<Integer> INT_FIELD = new Property<>("intField");
+        Property<Integer> INT_FIELD2 = new Property<>("intField");
+
+        assertTrue(INT_FIELD != INT_FIELD2);
+        assertTrue(INT_FIELD.equals(INT_FIELD2));
+    }
+
+    @Test
+    public void testHashCode() {
+        Property<Integer> INT_FIELD = new Property<>("intField");
+        Property<Integer> INT_FIELD2 = new Property<>("intField");
+        Property<Long> LONG_FIELD = new Property<>("longField");
+
+        assertTrue(INT_FIELD.hashCode() == INT_FIELD2.hashCode());
+        assertTrue(INT_FIELD.hashCode() != LONG_FIELD.hashCode());
+    }
+
+    @Test
+    public void testOuter() {
+        Property<String> inner = new Property<>("xyz");
+        assertEquals("xyz+", inner.outer().getName());
+
+        Property<String> inner1 = new Property<>("xyz.xxx");
+        assertEquals("xyz.xxx+", inner1.outer().getName());
+
+        Property<String> outer = new Property<>("xyz+");
+        assertEquals("xyz+", outer.outer().getName());
+    }
+
+    @Test
+    public void testLike() {
+        Property<String> p = new Property<>("prop");
+        Expression e = p.like("abc");
+        assertEquals("prop like \"abc\"", e.toString());
+    }
+
+    @Test
+    public void testLikeIgnoreCase() {
+        Property<String> p = new Property<>("prop");
+        Expression e = p.likeIgnoreCase("abc");
+        assertEquals("prop likeIgnoreCase \"abc\"", e.toString());
+    }
+
+    @Test
+    public void testLike_NoEscape() {
+        Property<String> p = new Property<>("prop");
+        Expression e = p.like("ab%c");
+        assertEquals("prop like \"ab%c\"", e.toString());
+        assertEquals(0, ((PatternMatchNode) e).getEscapeChar());
+    }
+
+    @Test
+    public void testContains() {
+        Property<String> p = new Property<>("prop");
+        Expression e = p.contains("abc");
+        assertEquals("prop like \"%abc%\"", e.toString());
+        assertEquals(0, ((PatternMatchNode) e).getEscapeChar());
+    }
+
+    @Test
+    public void testStartsWith() {
+        Property<String> p = new Property<>("prop");
+        Expression e = p.startsWith("abc");
+        assertEquals("prop like \"abc%\"", e.toString());
+        assertEquals(0, ((PatternMatchNode) e).getEscapeChar());
+    }
+
+    @Test
+    public void testEndsWith() {
+        Property<String> p = new Property<>("prop");
+        Expression e = p.endsWith("abc");
+        assertEquals("prop like \"%abc\"", e.toString());
+        assertEquals(0, ((PatternMatchNode) e).getEscapeChar());
+    }
+
+    @Test
+    public void testContains_Escape1() {
+        Property<String> p = new Property<>("prop");
+        Expression e = p.contains("a%bc");
+        assertEquals("prop like \"%a!%bc%\"", e.toString());
+        assertEquals('!', ((PatternMatchNode) e).getEscapeChar());
+    }
+
+    @Test
+    public void testContains_Escape2() {
+        Property<String> p = new Property<>("prop");
+        Expression e = p.contains("a_!bc");
+        assertEquals("prop like \"%a#_!bc%\"", e.toString());
+        assertEquals('#', ((PatternMatchNode) e).getEscapeChar());
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83571185/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 626e549..3cccbd6 100644
--- a/docs/doc/src/main/resources/RELEASE-NOTES.txt
+++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt
@@ -8,6 +8,16 @@ To browse individual bug reports check out project issue 
tracker:
 https://issues.apache.org/jira/browse/CAY
 
 ----------------------------------
+Release: 4.0.M5
+Date:
+----------------------------------
+Changes/New Features:
+
+CAY-2153 Property.path() , ExpressionFactory.pathExp()
+
+Bug Fixes:
+
+----------------------------------
 Release: 4.0.M4
 Date:
 ----------------------------------

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83571185/docs/docbook/cayenne-guide/src/docbkx/expressions.xml
----------------------------------------------------------------------
diff --git a/docs/docbook/cayenne-guide/src/docbkx/expressions.xml 
b/docs/docbook/cayenne-guide/src/docbkx/expressions.xml
index dd87c1d..48e7462 100644
--- a/docs/docbook/cayenne-guide/src/docbkx/expressions.xml
+++ b/docs/docbook/cayenne-guide/src/docbkx/expressions.xml
@@ -208,39 +208,52 @@ Expression qualifier1 = template.params(p1);
         </para>
     </section>
     <section xml:id="expressions-with-expressionfactory">
-        <title>Creating Expressions with API</title>
+        <title>Creating Expressions via API</title>
         <para>Creating expressions from Strings is a powerful and dynamic 
approach, however a safer
-            alternative is to use Java API. It provides some degree of 
compile-time checking of
-            expressions validity. The API is cenetred around ExpressionFactory 
class, and the
-            Expression class. ExpressionFactory contains a number of rather 
self-explanatory factory
-            methods. We won&apos;t be going over all of them in detail, but 
will rather show a few
-            general examples and some gotchas. </para>
-        <para>The following code recreates the expression from the previous 
chapter, but now using
-            expression
-            API:<programlisting language="java">// String expression: name 
like &apos;A%&apos; and price &lt; 1000
-Expression e1 = ExpressionFactory.likeExp(Painting.NAME_PROPERTY, 
&quot;A%&quot;);
-Expression e2 = ExpressionFactory.lessExp(Painting.PRICE_PROPERTY, 1000);
-Expression finalExp = e1.andExp(e2); </programlisting>This
-            is more verbose than creating it from String, but it is also more 
resilient to the
-            entity properties renaming and precludes semantic errors in the 
expression String.<note>
+            alternative is to use Java API. It provides compile-time checking 
of expressions
+            validity. The API in question is provided by 
<code>ExpressionFactory</code> class (that
+            we've seen already), <code>Property</code> class and 
<code>Expression</code> class
+            itself. <code>ExpressionFactory</code> contains a number of 
self-explanatory static
+            methods that can be used to build expressions. E.g.:</para>
+        <para>
+            <programlisting language="java">// String expression: name like 
&apos;A%&apos; and price &lt; 1000
+Expression e1 = ExpressionFactory.likeExp("name", &quot;A%&quot;);
+Expression e2 = ExpressionFactory.lessExp("price, 1000);
+Expression finalExp = e1.andExp(e2); </programlisting>
+            <note>
                 <para>The last line in the example above shows how to create a 
new expression by
-                    &quot;chaining&quot; 2 other epxressions. A common error 
when chaining expressions is to
-                    assume that &quot;andExp&quot; and &quot;orExp&quot; 
append another expression to the current
-                    expression. In fact a new expression is created. I.e. 
Expression API treats
-                    existing expressions as immutable.</para>
-            </note></para>
+                    &quot;chaining&quot; two other epxressions. A common error 
when chaining
+                    expressions is to assume that &quot;andExp&quot; and 
&quot;orExp&quot; append
+                    another expression to the current expression. In fact a 
new expression is
+                    created. I.e. Expression API treats existing expressions 
as immutable.</para>
+            </note>
+        </para>
         <para>As discussed earlier, Cayenne supports aliases in path 
Expressions, allowing to
             control how SQL joins are generated if the same path is 
encountered more than once in
             the same Expression. Two ExpressionFactory methods allow to 
implicitly generate aliases
             to &quot;split&quot; match paths into individual joins if
             needed:<programlisting language="java">Expression 
matchAllExp(String path, Collection values)
 Expression matchAllExp(String path, Object... values)</programlisting></para>
-        <para>&quot;Path&quot; argument to both of these methods can use a 
split character (a pipe symbol &apos;|&apos;)
-            instead of dot to indicate that relationship following a path 
should be split into a
-            separate set of joins, one per collection value. There can only be 
one split at most in
-            any given path. Split must always precede a relationship. E.g. 
&quot;|exhibits.paintings&quot;,
-            &quot;exhibits|paintings&quot;, etc. Internally Cayenne would 
generate distinct aliases for each
-            of the split expressions, forcing separate joins.</para>
+        <para>&quot;Path&quot; argument to both of these methods can use a 
split character (a pipe
+            symbol &apos;|&apos;) instead of dot to indicate that relationship 
following a path
+            should be split into a separate set of joins, one per collection 
value. There can only
+            be one split at most in any given path. Split must always precede 
a relationship. E.g.
+                <code>"|exhibits.paintings"</code>, 
<code>"exhibits|paintings"</code>, etc.
+            Internally Cayenne would generate distinct aliases for each of the 
split expressions,
+            forcing separate joins.</para>
+        <para>While ExpressionFactory is pretty powerful, there's an even 
easier way to create
+            expression using static Property objects generated by Cayenne for 
each persistent class.
+            Some
+            examples:<programlisting>// Artist.NAME is generated by Cayenne 
and has a type of Property&lt;String>
+Expression e1 = Artist.NAME.eq("Pablo");
+
+// Chaining multiple properties into a path..
+// Painting.ARTIST is generated by Cayenne and has a type of 
Property&lt;Artist>
+Expression e2 = 
Painting.ARTIST.dot(Artist.NAME).eq("Pablo");</programlisting></para>
+        <para>Property objects provide the API mostly analogius to 
ExpressionFactory, though it is
+            significantly shorter and is aware of the value types. It provides 
compile-time checks
+            of both property names and types of arguments in conditions. We 
will use Property-based
+            API in further examples.</para>
     </section>
     <section xml:id="expressions-in-memory">
         <title>Evaluating Expressions in Memory</title>
@@ -249,18 +262,17 @@ Expression matchAllExp(String path, Object... 
values)</programlisting></para>
             is done by the database engine. However the same expressions can 
also be used for
             accessing object properties, calculating values, in-memory 
filtering. </para>
         <para>Checking whether an object satisfies an
-            expression:<programlisting language="java">Expression e = 
ExpressionFactory.inExp(User.NAME_PROPERTY, &quot;John&quot;, &quot;Bob&quot;);
-User user = ...
-if(e.match(user)) {
+            expression:<programlisting language="java">Expression e = 
Artist.NAME.in(&quot;John&quot;, &quot;Bob&quot;);
+Artist artist = ...
+if(e.match(artist)) {
    ...
 }</programlisting>Reading
             property
-            value:<programlisting language="java">Expression e = 
Expression.fromString(User.NAME_PROPERTY);
-String name = e.evaluate(user);</programlisting></para>
+            value:<programlisting language="java">String name = 
Artist.NAME.path().evaluate(artist);</programlisting></para>
         <para>Filtering a list of
-            objects:<programlisting language="java">Expression e = 
ExpressionFactory.inExp(User.NAME_PROPERTY, &quot;John&quot;, &quot;Bob&quot;);
-List&lt;User&gt; unfiltered = ...
-List&lt;User&gt; filtered = 
e.filterObjects(unfiltered);</programlisting></para>
+            objects:<programlisting language="java">Expression e = 
Artist.NAME.in(&quot;John&quot;, &quot;Bob&quot;);
+List&lt;Artist&gt; unfiltered = ...
+List&lt;Artist&gt; filtered = 
e.filterObjects(unfiltered);</programlisting></para>
         <para>
             <note>
                 <para>Current limitation of in-memory expressions is that no 
collections are
@@ -272,21 +284,18 @@ List&lt;User&gt; filtered = 
e.filterObjects(unfiltered);</programlisting></para>
     <section xml:id="expressions-to-ejbql">
         <title>Translating Expressions to EJBQL</title>
         <para>
-            <link linkend="ejbqlquery">EJBQL</link> is a textual query 
language that can be used with Cayenne.
-            In some situations, it is convenient to be able to convert 
Expression instances into EJBQL.
-            Expressions support this conversion.  An example is shown below.
-
+            <link linkend="ejbqlquery">EJBQL</link> is a textual query 
language that can be used
+            with Cayenne. In some situations, it is convenient to be able to 
convert Expression
+            instances into EJBQL. Expressions support this conversion. An 
example is shown below.
             <programlisting language="java">String serial = ...
-Expression e = ExpressionFactory.matchExp(Pkg.SERIAL_PROPERTY, serial);
+Expression e = Pkg.SERIAL.eq(serial);
 List&lt;Object&gt; params = new ArrayList&lt;Object&gt;();
 EJBQLQuery query = new EJBQLQuery("SELECT p FROM Pkg p WHERE " + 
e.toEJBQL(params,&quot;p&quot;);
 
 for(int i=0;i&lt;params.size();i++) {
   query.setParameter(i+1, params.get(i));
 }</programlisting>
-
             This would be equivalent to the following purely EJBQL querying 
logic;
-
             <programlisting language="java">EJBQLQuery query = new 
EJBQLQuery("SELECT p FROM Pkg p WHERE p.serial = ?1");
 query.setParameter(1,serial);</programlisting>
         </para>

Reply via email to