You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2010/01/14 17:21:03 UTC

svn commit: r899270 - in /cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src: main/java/org/apache/cayenne/access/jdbc/ test/java/org/apache/cayenne/access/

Author: aadamchik
Date: Thu Jan 14 16:21:02 2010
New Revision: 899270

URL: http://svn.apache.org/viewvc?rev=899270&view=rev
Log:
CAY-1069 EJBQL: support paths across flattened relationships

patch by Ksenia Khailenko - flattened attributes

Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLJoinAppender.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectColumnsTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextFlattenedAttributesTest.java

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLJoinAppender.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLJoinAppender.java?rev=899270&r1=899269&r2=899270&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLJoinAppender.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLJoinAppender.java Thu Jan 14 16:21:02 2010
@@ -18,6 +18,7 @@
  ****************************************************************/
 package org.apache.cayenne.access.jdbc;
 
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -32,6 +33,9 @@
 import org.apache.cayenne.map.DbJoin;
 import org.apache.cayenne.map.DbRelationship;
 import org.apache.cayenne.map.Entity;
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.query.EntityResultSegment;
+import org.apache.cayenne.util.CayenneMapEntry;
 
 /**
  * Handles appending joins to the content buffer at a marked position.
@@ -226,6 +230,7 @@
     public String appendTable(EJBQLTableId id) {
 
         DbEntity dbEntity = id.getDbEntity(context);
+        
         String tableName = dbEntity.getFullyQualifiedName();
         String alias;
 
@@ -233,11 +238,14 @@
             // TODO: andrus 1/5/2007 - if the same table is joined more than once, this
             // will create an incorrect alias.
             alias = context.getTableAlias(id.getEntityId(), tableName);
-
+            
             // not using "AS" to separate table name and alias name - OpenBase doesn't
             // support
             // "AS", and the rest of the databases do not care
             context.append(' ').append(tableName).append(' ').append(alias);
+            
+            generateJoinsForFlattenedAttributes(id, alias);
+           
         }
         else {
             context.append(' ').append(tableName);
@@ -274,6 +282,71 @@
         return alias;
     }
 
+    /**
+     * Generates Joins statements for those flattened attributes that appear after the
+     * FROM clause, e.g. in WHERE, ORDER BY, etc clauses. Flattened attributes of the
+     * entity from the SELECT clause are processed earlier and therefore are omitted.
+     * 
+     * @param id table to JOIN id
+     * @param alias table alias
+     */
+    private void generateJoinsForFlattenedAttributes(EJBQLTableId id, String alias) {
+        String entityName = context
+                .getEntityDescriptor(id.getEntityId())
+                .getEntity()
+                .getName();
+        boolean isProcessingOmitted = false;
+        // if the dbPath is not null, all attributes of the entity are processed earlier
+        isProcessingOmitted = id.getDbPath() != null;
+        String sourceExpression = context.getCompiledExpression().getSource();
+
+        List<Object> resultSetMapping = context.getMetadata().getResultSetMapping();
+        for (Object mapping : resultSetMapping) {
+            if (mapping instanceof EntityResultSegment) {
+                if (entityName.equals(((EntityResultSegment) mapping)
+                        .getClassDescriptor()
+                        .getEntity()
+                        .getName())) {
+                    // if entity is included into SELECT clause, all its attributes are processed earlier
+                    isProcessingOmitted = true;
+                    break;
+                }
+
+            }
+        }
+
+        if (!isProcessingOmitted) {
+            Collection<ObjAttribute> attributes = context.getEntityDescriptor(
+                    id.getEntityId()).getEntity().getAttributes();
+            for (ObjAttribute objAttribute : attributes) {
+                if (objAttribute.isFlattened()
+                        && sourceExpression.contains(id.getEntityId()
+                                + "."
+                                + objAttribute.getName())) {
+                    // joins for attribute are generated if it is flattened and appears in original statement
+                    Iterator<CayenneMapEntry> dbPathIterator = objAttribute
+                            .getDbPathIterator();
+                    while (dbPathIterator.hasNext()) {
+                        CayenneMapEntry next = dbPathIterator.next();
+                        if (next instanceof DbRelationship) {
+                            DbRelationship rel = (DbRelationship) next;
+                            context.append(" JOIN ");
+                            String targetEntityName = rel.getTargetEntityName();
+                            String subqueryTargetAlias = context.getTableAlias(id
+                                    .getEntityId(), targetEntityName);
+                            context.append(targetEntityName).append(' ').append(
+                                    subqueryTargetAlias);
+                            generateJoiningExpression(rel, context.getTableAlias(id
+                                    .getEntityId(), rel.getSourceEntity().getName()), subqueryTargetAlias);
+                        }
+
+                    }
+                }
+
+            }
+        }
+    }
+
     private EJBQLExpression ejbqlQualifierForEntityAndSubclasses(
             Expression qualifier,
             String entityId) {

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectColumnsTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectColumnsTranslator.java?rev=899270&r1=899269&r2=899270&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectColumnsTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectColumnsTranslator.java Thu Jan 14 16:21:02 2010
@@ -22,6 +22,7 @@
 import java.util.Iterator;
 import java.util.Map;
 
+import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.dba.TypesMapping;
 import org.apache.cayenne.ejbql.EJBQLBaseVisitor;
 import org.apache.cayenne.ejbql.EJBQLException;
@@ -134,9 +135,45 @@
                 DbEntity table = currentEntity.getDbEntity();
                 String alias = this.lastAlias != null ? lastAlias : context
                         .getTableAlias(idPath, table.getFullyQualifiedName());
+                if (attribute.isFlattened()) {
+                    Iterator<?> dbPathIterator = attribute.getDbPathIterator();
+                    EJBQLTableId lhsId = new EJBQLTableId(idPath);
+
+                    while (dbPathIterator.hasNext()) {
+                        Object pathPart = dbPathIterator.next();
+                        // DbRelationships not processed, because they will be processed
+                        // later when appending table
+                        if (pathPart == null) {
+                            throw new CayenneRuntimeException(
+                                    "ObjAttribute has no component: "
+                                            + attribute.getName());
+                        }
+                        else if (pathPart instanceof DbAttribute) {
+                            DbAttribute dbAttribute = (DbAttribute) pathPart;
+                            appendColumn(
+                                    attribute,
+                                    context.getTableAlias(
+                                            lhsId.getEntityId(),
+                                            dbAttribute.getEntity().getName()),
+                                    dbAttribute);
 
-                DbAttribute dbAttribute = attribute.getDbAttribute();
+                        }
 
+                    }
+
+                }
+                else {
+
+                    DbAttribute dbAttribute = attribute.getDbAttribute();
+
+                    appendColumn(attribute, alias, dbAttribute);
+                }
+            }
+
+            private void appendColumn(
+                    ObjAttribute attribute,
+                    String alias,
+                    DbAttribute dbAttribute) {
                 if (context.isAppendingResultColumns()) {
                     context.append(" #result('");
                 }
@@ -163,6 +200,7 @@
                             .append(")");
                 }
             }
+
         };
         expression.visit(pathTranslator);
         return false;

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextFlattenedAttributesTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextFlattenedAttributesTest.java?rev=899270&r1=899269&r2=899270&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextFlattenedAttributesTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextFlattenedAttributesTest.java Thu Jan 14 16:21:02 2010
@@ -28,6 +28,7 @@
 
 import org.apache.art.Artist;
 import org.apache.art.CompoundPainting;
+import org.apache.art.Gallery;
 import org.apache.cayenne.Cayenne;
 import org.apache.cayenne.PersistenceState;
 import org.apache.cayenne.exp.ExpressionFactory;
@@ -203,11 +204,10 @@
     
     public void testSelectEJQBQLCollectionTheta() throws Exception {
         populateTables();
-        EJBQLQuery query = new EJBQLQuery("SELECT a FROM CompoundPainting cp, Artist a "
+        EJBQLQuery query = new EJBQLQuery("SELECT DISTINCT a FROM CompoundPainting cp, Artist a "
                 + "WHERE a.artistName=cp.artistName ORDER BY a.artistName");
                
-        //TODO fails while the support for flattened attributes would not be added
-        /*List<?> objects = context.performQuery(query);
+        List<?> objects = context.performQuery(query);
 
         assertNotNull(objects);
         assertEquals(4, objects.size());
@@ -217,7 +217,7 @@
             Artist artist = (Artist) i.next();
             assertEquals("artist" + index, artist.getArtistName());
             index++;
-        }*/
+        }
     }
     
     public void testSelectEJQBQLLike() throws Exception {
@@ -265,41 +265,31 @@
                 "SELECT g FROM Gallery g WHERE " +
                 "(SELECT COUNT(cp) FROM CompoundPainting cp WHERE g.galleryName=cp.galleryName) = 4");
                 
-               
-        // TODO fails while the support for flattened attributes would not be added
-        /*List<?> objects = context.performQuery(query);
+        List<?> objects = context.performQuery(query);
 
         assertNotNull(objects);
-        assertEquals(2, objects.size());
-        Iterator<?> i = objects.iterator();
-        int index=1;
-        while (i.hasNext()) {
-            Gallery gallery = (Gallery) i.next();
-            assertEquals("gallery" + index, gallery.getGalleryName());
-            index++;
-        }*/
+        assertEquals(1, objects.size());
+        Gallery gallery = (Gallery) objects.get(0);
+        assertEquals("gallery2", gallery.getGalleryName());
+        
     }
     
     public void testSelectEJQBQLHaving() throws Exception {
         populateTables();
         EJBQLQuery query = new EJBQLQuery(
-                "SELECT cp.artistName FROM CompoundPainting cp " +
-                "GROUP BY cp.artistName " +
-                "HAVING cp.artistName IN ('artist1')");
+                "SELECT cp.galleryName, COUNT(a) from  Artist a, CompoundPainting cp "+
+                "WHERE cp.artistName = a.artistName "+
+                "GROUP BY cp.galleryName " +
+                "HAVING cp.galleryName LIKE 'gallery1'");
                 
                
-        // TODO fails while the support for flattened attributes would not be added
-        /* List<?> objects = context.performQuery(query);
+        List<Object[]> objects = context.performQuery(query);
 
         assertNotNull(objects);
-        assertEquals(2, objects.size());
-        Iterator<?> i = objects.iterator();
-        int index=1;
-        while (i.hasNext()) {
-            CompoundPainting painting = (CompoundPainting) i.next();
-            assertEquals("painting" + index, painting.getPaintingTitle());
-            index++;
-        }*/
+        assertEquals(1, objects.size());
+        Object[] galleryItem = objects.get(0);
+        assertEquals("gallery1", galleryItem[0]);
+        assertEquals(3L, galleryItem[1]);
     }
     
     public void testInsert() {