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 2009/10/08 10:51:27 UTC

svn commit: r823092 - in /cayenne/main/trunk: docs/doc/src/main/resources/ framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/ framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/ framework/...

Author: aadamchik
Date: Thu Oct  8 08:51:26 2009
New Revision: 823092

URL: http://svn.apache.org/viewvc?rev=823092&view=rev
Log:
CAY-1145 EJBQL: Implement support for relationship-ending paths in SELECT clause

patch by Olga Tkachova

Modified:
    cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.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/main/java/org/apache/cayenne/ejbql/parser/Compiler.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/EJBQLQueryTest.java

Modified: cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt?rev=823092&r1=823091&r2=823092&view=diff
==============================================================================
--- cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt (original)
+++ cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt Thu Oct  8 08:51:26 2009
@@ -17,6 +17,7 @@
 CAY-132 Intelligent lazy fault detection
 CAY-419 Collections aren't supported with in-memory filtering
 CAY-1116 Add generated PK support to SQLite
+CAY-1145 EJBQL: Implement support for relationship-ending paths in SELECT clause
 CAY-1220 A function to auto-map the DB relationships
 CAY-1225 Controlling JDBC Driver setting "fetchSize" in a SelectQuery
 CAY-1227 Modeler support for flattened attributes

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java?rev=823092&r1=823091&r2=823092&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java Thu Oct  8 08:51:26 2009
@@ -105,7 +105,7 @@
         return true;
     }
 
-    private void resolveJoin(boolean inner) {
+    protected void resolveJoin(boolean inner) {
 
         EJBQLJoinAppender joinAppender = context.getTranslatorFactory().getJoinAppender(
                 context);
@@ -209,7 +209,7 @@
         }
     }
 
-    private void processTerminatingRelationship(ObjRelationship relationship) {
+    protected void processTerminatingRelationship(ObjRelationship relationship) {
 
         if (relationship.isSourceIndependentFromTargetChange()) {
 

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=823092&r1=823091&r2=823092&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 Oct  8 08:51:26 2009
@@ -18,12 +18,20 @@
  ****************************************************************/
 package org.apache.cayenne.access.jdbc;
 
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.cayenne.dba.TypesMapping;
 import org.apache.cayenne.ejbql.EJBQLBaseVisitor;
 import org.apache.cayenne.ejbql.EJBQLException;
 import org.apache.cayenne.ejbql.EJBQLExpression;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbRelationship;
 import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.ObjRelationship;
 
 /**
  * Translator of the EJBQL select clause.
@@ -66,6 +74,62 @@
             }
 
             @Override
+            protected void processTerminatingRelationship(ObjRelationship relationship) {
+
+                Map<String, String> xfields = null;
+                if (context.isAppendingResultColumns()) {
+                    xfields = context.nextEntityResult().getFields();
+                }
+
+                final Map<String, String> fields = xfields;
+
+                Collection<DbAttribute> dbAttr = ((ObjEntity) relationship
+                        .getTargetEntity()).getDbEntity().getAttributes();
+
+                DbRelationship dbRelationship = relationship.getDbRelationships().get(0);
+                DbEntity table = (DbEntity) dbRelationship.getTargetEntity();
+
+                Iterator<DbAttribute> it = dbAttr.iterator();
+                if (dbAttr.size() > 0) {
+                    this.resolveJoin(false);
+                }
+
+                String alias = this.lastAlias != null ? lastAlias : context
+                        .getTableAlias(idPath, table.getFullyQualifiedName());
+
+                boolean first = true;
+                while (it.hasNext()) {
+
+                    context.append(!first ? ", " : " ");
+
+                    DbAttribute dbAttribute = it.next();
+
+                    if (context.isAppendingResultColumns()) {
+                        context.append(" #result('");
+                    }
+                    else {
+                        context.append(' ');
+                    }
+
+                    context.append(alias).append('.').append(dbAttribute.getName());
+
+                    if (context.isAppendingResultColumns()) {
+
+                        String javaType = TypesMapping.getJavaBySqlType(dbAttribute
+                                .getType());
+                        String columnLabel = fields.get(dbAttribute.getName());
+
+                        context.append("' '").append(javaType).append("' '").append(
+                                columnLabel).append("' '").append(columnLabel).append(
+                                "' " + dbAttribute.getType()).append(")");
+                    }
+
+                    first = false;
+                }
+
+            }
+
+            @Override
             protected void processTerminatingAttribute(ObjAttribute attribute) {
                 DbEntity table = currentEntity.getDbEntity();
                 String alias = this.lastAlias != null ? lastAlias : context
@@ -100,7 +164,6 @@
                 }
             }
         };
-
         expression.visit(pathTranslator);
         return false;
     }
@@ -111,4 +174,5 @@
                 context));
         return false;
     }
+
 }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java?rev=823092&r1=823091&r2=823092&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java Thu Oct  8 08:51:26 2009
@@ -84,11 +84,57 @@
     CompiledExpression compile(String source, EJBQLExpression parsed) {
         parsed.visit(new CompilationVisitor());
 
+        Map<EJBQLPath, Integer> pathsInSelect = new HashMap<EJBQLPath, Integer>();
+
+        if (parsed != null) {
+            for (int i = 0; i < parsed.getChildrenCount(); i++) {
+                if (parsed.getChild(i) instanceof EJBQLSelectClause) {
+
+                    EJBQLExpression parsedTemp = parsed.getChild(i);
+                    boolean stop = false;
+
+                    while (parsedTemp.getChildrenCount() > 0 && !stop) {
+                        EJBQLExpression newParsedTemp = null;
+                        for (int j = 0; j < parsedTemp.getChildrenCount(); j++) {
+                            if (parsedTemp.getChild(j) instanceof EJBQLSelectExpression) {
+                                for (int k = 0; k < parsedTemp
+                                        .getChild(j)
+                                        .getChildrenCount(); k++) {
+
+                                    if (parsedTemp.getChild(j).getChild(k) instanceof EJBQLPath) {
+                                        pathsInSelect.put((EJBQLPath) parsedTemp
+                                                .getChild(j)
+                                                .getChild(k), j);
+
+                                    }
+                                }
+                            }
+                            else {
+                                if (parsedTemp.getChild(j).getChildrenCount() == 0) {
+                                    stop = true;
+                                }
+                                else {
+                                    newParsedTemp = parsedTemp.getChild(j);
+                                }
+                            }
+                        }
+
+                        if (!stop && newParsedTemp != null) {
+                            parsedTemp = newParsedTemp;
+                        }
+                        else {
+                            stop = true;
+                        }
+                    }
+                }
+            }
+        }
+
         // postprocess paths, now that all id vars are resolved
         if (paths != null) {
+            int elenent = 0;
             for (EJBQLPath path : paths) {
                 String id = normalizeIdPath(path.getId());
-
                 ClassDescriptor descriptor = descriptorsById.get(id);
                 if (descriptor == null) {
                     throw new EJBQLException("Unmapped id variable: " + id);
@@ -96,22 +142,41 @@
 
                 StringBuilder buffer = new StringBuilder(id);
 
+                ObjRelationship incoming = null;
+                String pathRelationshipString = "";
+
                 for (int i = 1; i < path.getChildrenCount(); i++) {
 
                     String pathChunk = path.getChild(i).getText();
                     buffer.append('.').append(pathChunk);
 
                     Property property = descriptor.getProperty(pathChunk);
+
                     if (property instanceof ArcProperty) {
-                        ObjRelationship incoming = ((ArcProperty) property)
-                                .getRelationship();
+                        incoming = ((ArcProperty) property).getRelationship();
                         descriptor = ((ArcProperty) property).getTargetDescriptor();
-                        String pathString = buffer.substring(0, buffer.length());
+                        pathRelationshipString = buffer.substring(0, buffer.length());
 
-                        descriptorsById.put(pathString, descriptor);
-                        incomingById.put(pathString, incoming);
+                        descriptorsById.put(pathRelationshipString, descriptor);
+                        incomingById.put(pathRelationshipString, incoming);
+                        
                     }
                 }
+
+                
+                if (pathsInSelect.size() > 0
+                        && incoming != null
+                        && pathRelationshipString.length() > 0
+                        && pathRelationshipString.equals(buffer.toString())) {
+                    
+                    EJBQLIdentifier ident = new EJBQLIdentifier(0);
+                    ident.text = pathRelationshipString;
+                    
+                    resultComponents.remove(pathsInSelect.get(path).intValue());
+                    resultComponents.add(pathsInSelect.get(path).intValue(), ident);
+                    rootId = pathRelationshipString;
+                };
+                elenent++;
             }
         }
 
@@ -139,6 +204,7 @@
             }
 
             compiled.setResult(mapping);
+            
         }
 
         return compiled;
@@ -147,6 +213,9 @@
     private EntityResult compileEntityResult(EJBQLExpression expression, int position) {
         String id = expression.getText().toLowerCase();
         ClassDescriptor descriptor = descriptorsById.get(id);
+        if (descriptor == null) {
+            descriptor = descriptorsById.get(expression.getText());
+        }
         final EntityResult entityResult = new EntityResult(descriptor.getObjectClass());
         final String prefix = "ec" + position + "_";
         final int[] index = {
@@ -197,7 +266,8 @@
         }
 
         // append inheritance discriminator columns...
-        Iterator<ObjAttribute> discriminatorColumns = descriptor.getDiscriminatorColumns();
+        Iterator<ObjAttribute> discriminatorColumns = descriptor
+                .getDiscriminatorColumns();
         while (discriminatorColumns.hasNext()) {
             ObjAttribute column = discriminatorColumns.next();
 

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/EJBQLQueryTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/EJBQLQueryTest.java?rev=823092&r1=823091&r2=823092&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/EJBQLQueryTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/EJBQLQueryTest.java Thu Oct  8 08:51:26 2009
@@ -24,6 +24,7 @@
 import java.util.Map;
 
 import org.apache.art.Artist;
+import org.apache.art.Painting;
 import org.apache.cayenne.DataRow;
 import org.apache.cayenne.access.DataContext;
 import org.apache.cayenne.ejbql.EJBQLCompiledExpression;
@@ -69,7 +70,7 @@
 
     public void testCacheStrategy() throws Exception {
         deleteTestData();
-        
+
         insertValue();
         DataContext contex = createDataContext();
         String ejbql = "select a FROM Artist a";
@@ -92,7 +93,7 @@
 
     public void testDataRows() throws Exception {
         deleteTestData();
-        
+
         insertValue();
         String ejbql = "select a FROM Artist a";
         EJBQLQuery query = new EJBQLQuery(ejbql);
@@ -101,7 +102,7 @@
 
         Map row = (Map) artists.get(0);
         String artistName = (String) row.get("ARTIST_NAME");
-       
+
         assertTrue(row instanceof DataRow);
 
         Artist artist = (Artist) createDataContext().objectFromDataRow(
@@ -121,6 +122,19 @@
         }
     }
 
+    private void insertPaintValue() {
+        DataContext context = createDataContext();
+
+        for (int i = 0; i < 2; i++) {
+            Artist art = context.newObject(Artist.class);
+            art.setArtistName("a" + i);
+            Painting obj = context.newObject(Painting.class);
+            obj.setToArtist(art);
+            obj.setPaintingTitle("title" + i);
+            context.commitChanges();
+        }
+    }
+
     public void testGetExpression() {
         String ejbql = "select a FROM Artist a";
         EJBQLQuery query = new EJBQLQuery(ejbql);
@@ -175,37 +189,78 @@
         assertTrue(md.isResolvingInherited());
         assertEquals(QueryCacheStrategy.NO_CACHE, md.getCacheStrategy());
     }
-    
-    public void testEncodeAsXML() {
+
+    public void testSelectRelationship() {
+
+        insertPaintValue();
+        DataContext contex = createDataContext();
         
+        String ejbql = "SELECT p.toArtist FROM Painting p"; 
+        EJBQLQuery query = new EJBQLQuery(ejbql);
+
+        List result = contex.performQuery(query);
+
+        assertNotNull(result);
+        assertEquals(2, result.size());
+
+        assertEquals(Artist.class, result.get(0).getClass());
+
+        
+        String ejbql2 = "SELECT p.toArtist, p FROM Painting p"; 
+        EJBQLQuery query2 = new EJBQLQuery(ejbql2);
+
+        List result2 = contex.performQuery(query2);
+
+        assertNotNull(result2);
+        assertEquals(2, result2.size());
+        assertEquals(2, ((Object[])result2.get(0)).length);
+        
+        assertEquals(Artist.class,((Object[])result2.get(0))[0].getClass());
+        assertEquals(Painting.class,((Object[])result2.get(0))[1].getClass());
+        
+        String ejbql3 = "SELECT p.toArtist, p.paintingTitle FROM Painting p"; 
+        EJBQLQuery query3 = new EJBQLQuery(ejbql3);
+
+        List result3 = contex.performQuery(query3);
+
+        assertNotNull(result3);
+        assertEquals(2, result3.size());
+        assertEquals(2, ((Object[])result3.get(0)).length);
+        
+        assertEquals(Artist.class,((Object[])result3.get(0))[0].getClass());
+        assertEquals(String.class,((Object[])result3.get(0))[1].getClass());
+    }
+
+    public void testEncodeAsXML() {
+
         String ejbql = "select a FROM Artist a";
         String name = "Test";
-        
+
         StringWriter w = new StringWriter();
         XMLEncoder e = new XMLEncoder(new PrintWriter(w));
-        
+
         String separator = System.getProperty("line.separator");
-        
+
         StringBuffer s = new StringBuffer("<query name=\"");
         s.append(name);
         s.append("\" factory=\"");
         s.append("org.apache.cayenne.map.EjbqlBuilder");
         s.append("\">");
         s.append(separator);
-      
+
         EJBQLQuery query = new EJBQLQuery(ejbql);
-        
+
         if (query.getEjbqlStatement() != null) {
             s.append("<ejbql><![CDATA[");
             s.append(query.getEjbqlStatement());
             s.append("]]></ejbql>");
         }
         s.append(separator);
-        s.append("</query>");     
+        s.append("</query>");
         s.append(separator);
         query.setName(name);
         query.encodeAsXML(e);
-        
+
         assertEquals(w.getBuffer().toString(), s.toString());
     }
 }