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/07/09 21:58:13 UTC

svn commit: r962674 - in /cayenne/main/branches/STABLE-3.0: docs/doc/src/main/resources/ framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ framewo...

Author: aadamchik
Date: Fri Jul  9 19:58:13 2010
New Revision: 962674

URL: http://svn.apache.org/viewvc?rev=962674&view=rev
Log:
CAY-1452 EJBQL query scalar result is not supported

patch by Xenia Khailenko with some minor changes from me

Modified:
    cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ClientServerChannelQueryAction.java
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/CayenneContextEJBQLTest.java

Modified: cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt?rev=962674&r1=962673&r2=962674&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt (original)
+++ cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt Fri Jul  9 19:58:13 2010
@@ -19,6 +19,7 @@ CAY-1380 Support for Escaped LIKE Clause
 CAY-1402 Ability to use Terminating "@size" in Nested Properties Against Collections
 CAY-1416 ExpressionFactory.noMatchExp.toEJBQL() produces incorrect output
 CAY-1417 EJBQL doesn't support null numeric parameters
+CAY-1452 EJBQL query scalar result is not supported
 CAY-1455 "NULL" JDBC type is shown for DbAttribute data types in the Modeler
 CAY-1458 Document Vertical Inheritance
 

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ClientServerChannelQueryAction.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ClientServerChannelQueryAction.java?rev=962674&r1=962673&r2=962674&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ClientServerChannelQueryAction.java (original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ClientServerChannelQueryAction.java Fri Jul  9 19:58:13 2010
@@ -20,7 +20,6 @@
 package org.apache.cayenne.access;
 
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 
 import org.apache.cayenne.CayenneRuntimeException;
@@ -28,6 +27,7 @@ import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.Persistent;
 import org.apache.cayenne.QueryResponse;
 import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.query.EntityResultSegment;
 import org.apache.cayenne.query.PrefetchTreeNode;
 import org.apache.cayenne.query.Query;
 import org.apache.cayenne.query.QueryMetadata;
@@ -173,37 +173,105 @@ class ClientServerChannelQueryAction {
 
     private List toClientObjects(List serverObjects) {
 
-        // create a list copy even if it is empty to ensure that we have a
-        // clean serializable list...
-        List clientObjects = new ArrayList(serverObjects.size());
-
         if (!serverObjects.isEmpty()) {
-            ObjectDetachOperation op = new ObjectDetachOperation(serverResolver
-                    .getClientEntityResolver());
-            Iterator it = serverObjects.iterator();
-            PrefetchTreeNode prefetchTree = serverMetadata.getPrefetchTree();
-
-            while (it.hasNext()) {
-                Persistent object = (Persistent) it.next();
-                ObjectId id = object.getObjectId();
-
-                // sanity check
-                if (id == null) {
-                    throw new CayenneRuntimeException(
-                            "Server returned an object without an id: " + object);
-                }
-
-                // have to resolve descriptor here for every object, as
-                // often a query will not have any info indicating the
-                // entity type
-                ClassDescriptor serverDescriptor = serverResolver.getClassDescriptor(id
-                        .getEntityName());
 
-                clientObjects.add(op.detach(object, serverDescriptor, prefetchTree));
+            List<Object> rsMapping = serverMetadata.getResultSetMapping();
+
+            if (rsMapping == null) {
+                return singleObjectConversion(serverObjects);
+            }
+            else {
+                if (rsMapping.size() == 1) {
+                    if (rsMapping.get(0) instanceof EntityResultSegment) {
+                        return singleObjectConversion(serverObjects);
+                    }
+                    else {
+                        // we can return a single scalar result unchanged (hmm... a scalar
+                        // Object[] can also be returned unchanged)...
+                        return serverObjects;
+                    }
+                }
+                else {
+                    return processMixedResult(serverObjects, rsMapping);
+                }
             }
         }
 
+        return new ArrayList<Object>(3);
+    }
+
+    private List<Object[]> processMixedResult(
+            List<Object[]> serverObjects,
+            List<Object> rsMapping) {
+
+        // must clone the list to ensure we do not mess up the server list that can be
+        // used elsewhere (e.g. it can be cached).
+        List<Object[]> clientObjects = new ArrayList<Object[]>(serverObjects.size());
+
+        ObjectDetachOperation op = new ObjectDetachOperation(serverResolver
+                .getClientEntityResolver());
+        int width = rsMapping.size();
+
+        for (Object[] serverObject : serverObjects) {
+
+            Object[] clientObject = new Object[width];
+
+            for (int i = 0; i < width; i++) {
+                if (rsMapping.get(i) instanceof EntityResultSegment) {
+
+                    clientObject[i] = convertSingleObject(serverMetadata
+                            .getPrefetchTree(), op, serverObject[i]);
+                }
+                else {
+                    clientObject[i] = serverObject[i];
+                }
+            }
+
+            clientObjects.add(clientObject);
+        }
+
         return clientObjects;
     }
 
+    private List<?> singleObjectConversion(List<?> serverObjects) {
+
+        // must clone the list to ensure we do not mess up the server list that can be
+        // used elsewhere (e.g. it can be cached).
+        List<Object> clientObjects = new ArrayList<Object>(serverObjects.size());
+
+        ObjectDetachOperation op = new ObjectDetachOperation(serverResolver
+                .getClientEntityResolver());
+
+        PrefetchTreeNode prefetchTree = serverMetadata.getPrefetchTree();
+
+        for (Object serverObject : serverObjects) {
+            clientObjects.add(convertSingleObject(prefetchTree, op, serverObject));
+        }
+
+        return clientObjects;
+    }
+
+    private Object convertSingleObject(
+            PrefetchTreeNode prefetchTree,
+            ObjectDetachOperation op,
+            Object serverObject) {
+
+        Persistent object = (Persistent) serverObject;
+        ObjectId id = object.getObjectId();
+
+        // sanity check
+        if (id == null) {
+            throw new CayenneRuntimeException("Server returned an object without an id: "
+                    + object);
+        }
+
+        // have to resolve descriptor here for every object, as
+        // often a query will not have any info indicating the
+        // entity type
+        ClassDescriptor serverDescriptor = serverResolver.getClassDescriptor(id
+                .getEntityName());
+
+        return op.detach(object, serverDescriptor, prefetchTree);
+    }
+
 }

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java?rev=962674&r1=962673&r2=962674&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java (original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java Fri Jul  9 19:58:13 2010
@@ -36,6 +36,7 @@ import org.apache.cayenne.graph.GraphDif
 import org.apache.cayenne.graph.GraphDiffCompressor;
 import org.apache.cayenne.graph.GraphEvent;
 import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.query.EntityResultSegment;
 import org.apache.cayenne.query.Query;
 import org.apache.cayenne.query.QueryMetadata;
 import org.apache.cayenne.reflect.ClassDescriptor;
@@ -129,32 +130,26 @@ public class ClientChannel implements Da
                     if (response.isList()) {
 
                         List objects = response.currentList();
-
+                        DeepMergeOperation merger = new DeepMergeOperation(context);
                         if (!objects.isEmpty()) {
-
-                            DeepMergeOperation merger = new DeepMergeOperation(context);
-
-                            // subclass descriptors will be resolved on the fly... here
-                            // find objects base descriptor.
-                            ListIterator it = objects.listIterator();
-                            while (it.hasNext()) {
-                                Persistent object = (Persistent) it.next();
-                                ObjectId id = object.getObjectId();
-
-                                // sanity check
-                                if (id == null) {
-                                    throw new CayenneRuntimeException(
-                                            "Server returned an object without an id: "
-                                                    + object);
+                            List<Object> rsMapping = info.getResultSetMapping();
+                            if (rsMapping == null) {
+                                convertSingleObjects(resolver, objects, merger);
+                            }
+                            else {
+                                if (rsMapping.size() == 1) {
+                                    if (rsMapping.get(0) instanceof EntityResultSegment) {
+                                        convertSingleObjects(resolver, objects, merger);
+                                    }
                                 }
+                                else {
+                                    processMixedResult(
+                                            resolver,
+                                            objects,
+                                            merger,
+                                            rsMapping);
 
-                                // have to resolve descriptor here for every object, as
-                                // often a query will not have any info indicating the
-                                // entity type
-                                ClassDescriptor descriptor = resolver
-                                        .getClassDescriptor(id.getEntityName());
-
-                                it.set(merger.merge(object, descriptor));
+                                }
                             }
                         }
                     }
@@ -165,6 +160,54 @@ public class ClientChannel implements Da
         return response;
     }
 
+    private void processMixedResult(
+            EntityResolver resolver,
+            List<Object[]> objects,
+            DeepMergeOperation merger,
+            List<Object> rsMapping) {
+
+        int width = rsMapping.size();
+        for (int i = 0; i < width; i++) {
+            if (rsMapping.get(i) instanceof EntityResultSegment) {
+                for (Object[] object : objects) {
+                    object[i] = convertObject(resolver, merger, (Persistent) object[i]);
+                }
+            }
+        }
+    }
+
+    private void convertSingleObjects(
+            EntityResolver resolver,
+            List objects,
+            DeepMergeOperation merger) {
+
+        ListIterator it = objects.listIterator();
+        while (it.hasNext()) {
+            Object next = it.next();
+            it.set(convertObject(resolver, merger, (Persistent) next));
+        }
+    }
+
+    private Object convertObject(
+            EntityResolver resolver,
+            DeepMergeOperation merger,
+            Persistent object) {
+
+        ObjectId id = object.getObjectId();
+
+        // sanity check
+        if (id == null) {
+            throw new CayenneRuntimeException("Server returned an object without an id: "
+                    + object);
+        }
+
+        // have to resolve descriptor here for every object, as often a query will not
+        // have any info indicating the entity type
+        ClassDescriptor descriptor = resolver.getClassDescriptor(id.getEntityName());
+
+        return merger.merge(object, descriptor);
+    }
+
     public GraphDiff onSync(
             ObjectContext originatingContext,
             GraphDiff changes,

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/CayenneContextEJBQLTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/CayenneContextEJBQLTest.java?rev=962674&r1=962673&r2=962674&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/CayenneContextEJBQLTest.java (original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/CayenneContextEJBQLTest.java Fri Jul  9 19:58:13 2010
@@ -46,7 +46,7 @@ public class CayenneContextEJBQLTest ext
 
     public void testEJBQLSelect() throws Exception {
         createTestData("testEJBQLSelect");
-        
+
         DataContext context = createDataContext();
         ClientServerChannel clientServerChannel = new ClientServerChannel(context);
         UnitLocalConnection connection = new UnitLocalConnection(
@@ -58,6 +58,43 @@ public class CayenneContextEJBQLTest ext
         EJBQLQuery query = new EJBQLQuery("SELECT a FROM MtTable1 a");
 
         List<ClientMtTable1> results = clientContext.performQuery(query);
+
+        assertEquals(2, results.size());
+    }
+
+    public void testEJBQLSelectScalar() throws Exception {
+        createTestData("testEJBQLSelect");
+        DataContext context = createDataContext();
+        ClientServerChannel clientServerChannel = new ClientServerChannel(context);
+        UnitLocalConnection connection = new UnitLocalConnection(
+                clientServerChannel,
+                LocalConnection.HESSIAN_SERIALIZATION);
+        ClientChannel channel = new ClientChannel(connection);
+        CayenneContext clientContext = new CayenneContext(channel);
+
+        EJBQLQuery query = new EJBQLQuery("SELECT COUNT(a) FROM MtTable1 a");
+
+        List<Long> results = clientContext.performQuery(query);
+        assertEquals(Long.valueOf(2), results.get(0));
+    }
+
+    public void testEJBQLSelectMixed() throws Exception {
+        createTestData("testEJBQLSelect");
+        DataContext context = createDataContext();
+        ClientServerChannel clientServerChannel = new ClientServerChannel(context);
+        UnitLocalConnection connection = new UnitLocalConnection(
+                clientServerChannel,
+                LocalConnection.HESSIAN_SERIALIZATION);
+        ClientChannel channel = new ClientChannel(connection);
+        CayenneContext clientContext = new CayenneContext(channel);
+
+        EJBQLQuery query = new EJBQLQuery(
+                "SELECT COUNT(a), a, a.serverAttribute1  FROM MtTable1 a Group By a");
+
+        List<Object[]> results = clientContext.performQuery(query);
         assertEquals(2, results.size());
+        assertEquals(Long.valueOf(1), results.get(0)[0]);
+        assertTrue(results.get(0)[1] instanceof ClientMtTable1);
+        assertEquals("s1", results.get(0)[2]);
     }
 }