Repository: cayenne
Updated Branches:
  refs/heads/master 89439015f -> eb0373e81


http://git-wip-us.apache.org/repos/asf/cayenne/blob/c1272b17/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionUtils.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionUtils.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionUtils.java
new file mode 100644
index 0000000..7325b15
--- /dev/null
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionUtils.java
@@ -0,0 +1,52 @@
+/*****************************************************************
+ *   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.HashMap;
+import java.util.Map;
+
+/**
+ * @since 4.2
+ */
+class ExpressionUtils {
+
+    static void parsePath(ASTPath pathExp, Object path) throws ParseException {
+        if (path != null && path.toString().contains("#")) {
+            String[] pathSegments = path.toString().split("\\.");
+            Map<String, String> aliasMap = new HashMap<>();
+            for (int i = 0; i < pathSegments.length; i++) {
+                if (pathSegments[i].contains("#")) {
+                    String[] splitedSegment = pathSegments[i].split("#");
+                    splitedSegment[0] += splitedSegment[1].endsWith("+") ? "+" 
: "";
+                    splitedSegment[1] = splitedSegment[1].endsWith("+") ? 
splitedSegment[1].substring(0, splitedSegment[1].length() - 1) : 
splitedSegment[1];
+                    if (aliasMap.putIfAbsent(splitedSegment[1], 
splitedSegment[0]) != null && 
!aliasMap.get(splitedSegment[1]).equals(splitedSegment[0])) {
+                        throw new ParseException("Can't add the same alias to 
different path segments.");
+                    }
+                    pathSegments[i] = splitedSegment[1];
+                }
+            }
+            pathExp.setPath(String.join(".", pathSegments));
+            pathExp.setPathAliases(aliasMap);
+        } else {
+            pathExp.setPath(path);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c1272b17/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
 
b/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
index 39dddea..d77c01e 100644
--- 
a/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
+++ 
b/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
@@ -37,6 +37,7 @@ package org.apache.cayenne.exp.parser;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.ExpressionUtils;
 
 /**
   * Parser of Cayenne Expressions. 
@@ -579,11 +580,11 @@ void pathExpression() : {
 }
 {
    (
-             t = <PROPERTY_PATH> { jjtThis.setPath(t.image); } #ObjPath(0)
+             t = <PROPERTY_PATH> { ExpressionUtils.parsePath(jjtThis, 
t.image); } #ObjPath(0)
    |
-     "obj:"  t = <PROPERTY_PATH> { jjtThis.setPath(t.image); } #ObjPath(0)
+     "obj:"  t = <PROPERTY_PATH> { ExpressionUtils.parsePath(jjtThis, 
t.image); } #ObjPath(0)
    |
-     "db:"   t = <PROPERTY_PATH> { jjtThis.setPath(t.image); } #DbPath(0)
+     "db:"   t = <PROPERTY_PATH> { ExpressionUtils.parsePath(jjtThis, 
t.image); } #DbPath(0)
    |
      "enum:" t = <PROPERTY_PATH> { jjtThis.setEnumValue(t.image); } #Enum(0)
    )
@@ -599,7 +600,7 @@ TOKEN : {
 
 TOKEN :
 {
-  < IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* (["+"])? >
+  < IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* (["#"]<LETTER> 
(<LETTER>|<DIGIT>)*)? (["+"])? >
 |
   < #LETTER: ["_","a"-"z","A"-"Z"] >
 |

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c1272b17/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 60a44d9..fad6864 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
@@ -31,8 +31,10 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.exp.parser.ASTLike;
 import org.apache.cayenne.exp.parser.ASTLikeIgnoreCase;
+import org.apache.cayenne.exp.parser.ASTObjPath;
 import org.apache.cayenne.exp.parser.ASTTrim;
 import org.junit.Before;
 import org.junit.Test;
@@ -513,6 +515,26 @@ public class ExpressionFactoryTest {
                assertEquals(ASTTrim.class, e.getClass());
        }
 
+       @Test
+       public void testExpWithAlias() {
+               Expression expression = 
ExpressionFactory.exp("paintings#p1.galleries#p2.name = 'Test'");
+               assertEquals("p1.p2.name", expression.getOperand(0).toString());
+               assertEquals("paintings", 
((ASTObjPath)expression.getOperand(0)).getPathAliases().get("p1"));
+               assertEquals("galleries", 
((ASTObjPath)expression.getOperand(0)).getPathAliases().get("p2"));
+       }
+
+       @Test
+       public void testExpWithAliasAndOuterJoin() {
+               Expression expression = 
ExpressionFactory.exp("paintings#p1+.name = 'Test'");
+               assertEquals("p1.name", expression.getOperand(0).toString());
+               assertEquals("paintings+", 
((ASTObjPath)expression.getOperand(0)).getPathAliases().get("p1"));
+       }
+
+       @Test(expected = CayenneRuntimeException.class)
+       public void testExpWithTheSameAliasToDiffSegments() {
+               ExpressionFactory.exp("paintings#p1.gallery#p1.name = 'Test'");
+       }
+
     // CAY-2081
     @Test(expected = ExpressionException.class)
     public void testExceptionInParse() {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c1272b17/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
index 45fdee7..37b3f16 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
@@ -150,8 +150,8 @@ public class PathAliasesIT extends ServerCase {
 
     @Test
     public void testAliasForPath() {
-        ASTPath astPath = new ASTObjPath("a.galleryName");
-        astPath.setPathAliases(Collections.singletonMap("a", 
"paintingArray.toGallery"));
+        ASTPath astPath = new ASTObjPath("paintingArray.a.galleryName");
+        astPath.setPathAliases(Collections.singletonMap("a", "toGallery"));
         ASTEqual astEqual = new ASTEqual(astPath, "tate modern");
         List<Object[]> artists = ObjectSelect.columnQuery(Artist.class, 
Artist.ARTIST_NAME, PropertyFactory.createBase(astPath, String.class))
                 .where(astEqual)
@@ -194,4 +194,124 @@ public class PathAliasesIT extends ServerCase {
         
query.and(Artist.PAINTING_ARRAY.dot(Painting.TO_GALLERY).alias("p1").dot(Gallery.GALLERY_NAME).eq("g1"));
         query.select(context);
     }
+
+    @Test
+    public void testExpWithAliases() {
+        Expression e1 = ExpressionFactory.exp("paintingArray#p1.paintingTitle 
= 'painting2'");
+        Expression e2 = ExpressionFactory.exp("paintingArray#p2.paintingTitle 
= 'painting4'");
+        List<Artist> artists = ObjectSelect.query(Artist.class)
+                .where(e1)
+                .and(e2)
+                .select(context);
+        assertEquals(1, artists.size());
+        assertEquals("artist4", artists.get(0).getArtistName());
+    }
+
+    @Test
+    public void testExpWithSeveralAliases() {
+        Expression e1 = 
ExpressionFactory.exp("paintingArray#p1.toGallery#g1.galleryName = 'tate 
modern'");
+        List<Artist> artists = ObjectSelect.query(Artist.class)
+                .where(e1)
+                .orderBy(Artist.ARTIST_NAME.asc())
+                .select(context);
+        assertEquals(5, artists.size());
+        assertEquals("artist1", artists.get(0).getArtistName());
+    }
+
+    @Test
+    public void testMiddleAliasForExp() {
+        Expression e1 = 
ExpressionFactory.exp("paintingArray.toGallery.paintingArray#p1.paintingTitle = 
'painting2'");
+        Expression e2 = 
ExpressionFactory.exp("paintingArray.toGallery.paintingArray#p2.paintingTitle = 
'painting4'");
+        List<Artist> artists = ObjectSelect.query(Artist.class)
+                .where(e1)
+                .and(e2)
+                .select(context);
+        assertEquals(1, artists.size());
+        assertEquals("artist4", artists.get(0).getArtistName());
+    }
+
+    @Test
+    public void testEntityPropertyAliasesInExp() {
+        Painting painting2 = Cayenne.objectForPK(context, Painting.class, 2);
+        Painting painting4 = Cayenne.objectForPK(context, Painting.class, 4);
+
+        SelectQuery<Artist> query = SelectQuery.query(Artist.class);
+        Expression e1 = ExpressionFactory.and(
+                ExpressionFactory.exp("paintingArray#p1 = $painting1", 
painting2),
+                ExpressionFactory.exp("paintingArray#p2 = $painting2", 
painting4));
+        query.setQualifier(e1);
+        List<Artist> artists = query.select(context);
+        assertEquals(1, artists.size());
+        assertEquals("artist4", artists.get(0).getArtistName());
+    }
+
+    @Test
+    public void testAliasForPathExp() {
+        ASTPath astPath = new ASTObjPath("paintingArray.p1.galleryName");
+        astPath.setPathAliases(Collections.singletonMap("a", "toGallery"));
+        ASTEqual astEqual = new ASTEqual(astPath, "test gallery");
+        Expression e1 = 
ExpressionFactory.exp("paintingArray.toGallery#p1.galleryName");
+        List<Object[]> artists = ObjectSelect.columnQuery(Artist.class, 
Artist.ARTIST_NAME, PropertyFactory.createBase(e1, String.class))
+                .where(astEqual)
+                .select(context);
+        assertEquals(1, artists.size());
+        assertEquals("artist4", artists.get(0)[0]);
+        assertEquals("test gallery", artists.get(0)[1]);
+    }
+
+    @Test
+    public void testTheSameAliasesForExp() {
+        Expression e1 = 
ExpressionFactory.exp("paintingArray#p1.paintingTitle");
+        Expression e2 = 
ExpressionFactory.exp("paintingArray#p2.paintingTitle");
+        Expression e3 = ExpressionFactory.exp("paintingArray#p1.paintingTitle 
= 'painting2'");
+        Expression e4 = ExpressionFactory.exp("paintingArray#p2.paintingTitle 
= 'painting4'");
+        List<Object[]> results = ObjectSelect.columnQuery(Artist.class,
+                Artist.ARTIST_NAME,
+                PropertyFactory.createBase(e1, String.class),
+                PropertyFactory.createBase(e2, String.class))
+                .where(e3)
+                .and(e4)
+                .select(context);
+        assertEquals(1, results.size());
+        assertEquals("artist4", results.get(0)[0]);
+        assertEquals("painting2", results.get(0)[1]);
+        assertEquals("painting4", results.get(0)[2]);
+    }
+
+    @Test
+    public void testOrderWithAliasForExp() {
+        Expression e1 = 
ExpressionFactory.exp("paintingArray#p1.estimatedPrice");
+        ObjectSelect<Artist> query = ObjectSelect.query(Artist.class)
+                .orderBy(PropertyFactory.createBase(e1, Number.class).asc())
+                .prefetch(Artist.PAINTING_ARRAY.disjoint());
+        List<Artist> artists = query.select(context);
+        assertEquals(5, artists.size());
+        assertEquals(2, artists.get(0).getPaintingArray().size());
+    }
+
+    @Test
+    public void testAggregationWithAliasesForExp() {
+        Expression e1 = ExpressionFactory.exp("paintingArray#p1");
+        List<Object[]> artistAndPaintingCount = 
ObjectSelect.columnQuery(Artist.class, Artist.ARTIST_NAME, 
Artist.PAINTING_ARRAY.count())
+                .having(PropertyFactory.createBase(e1, 
Number.class).count().lt(5L))
+                .select(context);
+        assertEquals(4, artistAndPaintingCount.size());
+        assertTrue((Long)artistAndPaintingCount.get(0)[1] < 5);
+    }
+
+    @Test(expected = CayenneRuntimeException.class)
+    public void testPrefetchWithAliasesForExp() {
+        Expression e1 = ExpressionFactory.exp("paintingArray#p1");
+        ObjectSelect<Artist> query = ObjectSelect.query(Artist.class);
+        query.prefetch(PropertyFactory.createList("p1", e1, 
Painting.class).disjoint());
+        query.select(context);
+    }
+
+    @Test(expected = CayenneRuntimeException.class)
+    public void testExpWithAliasNotToRelSegment() {
+        Expression e1 = ExpressionFactory.exp("paintingArray.paintingTitle#p1 
= 'painting2'");
+        ObjectSelect.query(Artist.class)
+               .where(e1)
+               .select(context);
+    }
 }

Reply via email to