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 2013/05/24 20:30:27 UTC

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

Author: aadamchik
Date: Fri May 24 18:30:26 2013
New Revision: 1486152

URL: http://svn.apache.org/r1486152
Log:
CAY-1829 Make ResultIterator implement Iterable<T>, create ObjectContext.iterate method

wrapping DataRows iterator with (inefficient) object iterator

Added:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/ResultIteratorIterator.java
      - copied, changed from r1486133, cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/ResultIteratorIterator.java
Removed:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/ResultIteratorIterator.java
Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContext.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/DistinctResultIterator.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/JDBCResultIterator.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/LimitResultIterator.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextTest.java

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContext.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContext.java?rev=1486152&r1=1486151&r2=1486152&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContext.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContext.java Fri May 24 18:30:26 2013
@@ -62,6 +62,7 @@ import org.apache.cayenne.reflect.ToMany
 import org.apache.cayenne.reflect.ToOneProperty;
 import org.apache.cayenne.util.EventUtil;
 import org.apache.cayenne.util.GenericResponse;
+import org.apache.cayenne.util.ResultIteratorIterator;
 import org.apache.cayenne.util.Util;
 
 /**
@@ -784,7 +785,53 @@ public class DataContext extends BaseCon
     @SuppressWarnings("unchecked")
     @Override
     protected <T> ResultIterator<T> iterator(Select<T> query) {
-        return performIteratedQuery(query);
+        final ResultIterator<DataRow> rows = performIteratedQuery(query);
+
+        QueryMetadata md = query.getMetaData(getEntityResolver());
+        if (md.isFetchingDataRows()) {
+            return (ResultIterator<T>) rows;
+        } else {
+
+            // this is a bit optimized version of 'objectFromDataRow' with
+            // resolver cached for reuse... still the rest is pretty suboptimal
+            ClassDescriptor descriptor = md.getClassDescriptor();
+            final ObjectResolver resolver = new ObjectResolver(this, descriptor, true);
+            return new ResultIterator<T>() {
+
+                public Iterator<T> iterator() {
+                    return new ResultIteratorIterator<T>(this);
+                }
+
+                public List<T> allRows() {
+                    List<T> list = new ArrayList<T>();
+
+                    while (hasNextRow()) {
+                        list.add(nextRow());
+                    }
+
+                    return list;
+                }
+
+                public boolean hasNextRow() {
+                    return rows.hasNextRow();
+                }
+
+                public T nextRow() {
+                    DataRow row = rows.nextRow();
+                    List<T> objects = (List<T>) resolver
+                            .synchronizedObjectsFromDataRows(Collections.singletonList(row));
+                    return (T) objects.get(0);
+                }
+
+                public void skipRow() {
+                    rows.skipRow();
+                }
+
+                public void close() {
+                    rows.close();
+                }
+            };
+        }
     }
 
     /**
@@ -795,6 +842,11 @@ public class DataContext extends BaseCon
      * an internal Cayenne transaction that originated in this method stays open
      * until the iterator is closed. So users should normally close the iterator
      * within the same thread that opened it.
+     * <p>
+     * Note that 'performIteratedQuery' always returns ResultIterator over
+     * DataRows. Use
+     * {@link #iterate(Select, org.apache.cayenne.ResultIteratorCallback)} to
+     * get access to objects.
      */
     // TODO: deprecate once all selecting queries start implementing Select<T>
     // interface

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/DistinctResultIterator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/DistinctResultIterator.java?rev=1486152&r1=1486151&r2=1486152&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/DistinctResultIterator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/DistinctResultIterator.java Fri May 24 18:30:26 2013
@@ -31,6 +31,7 @@ import org.apache.cayenne.DataRow;
 import org.apache.cayenne.access.ResultIterator;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.util.ResultIteratorIterator;
 
 /**
  * A ResultIterator that does in-memory filtering of rows to return only

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/JDBCResultIterator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/JDBCResultIterator.java?rev=1486152&r1=1486151&r2=1486152&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/JDBCResultIterator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/JDBCResultIterator.java Fri May 24 18:30:26 2013
@@ -34,6 +34,7 @@ import org.apache.cayenne.access.ResultI
 import org.apache.cayenne.query.EntityResultSegment;
 import org.apache.cayenne.query.QueryMetadata;
 import org.apache.cayenne.query.ScalarResultSegment;
+import org.apache.cayenne.util.ResultIteratorIterator;
 
 /**
  * A ResultIterator over the underlying JDBC ResultSet.

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/LimitResultIterator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/LimitResultIterator.java?rev=1486152&r1=1486151&r2=1486152&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/LimitResultIterator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/LimitResultIterator.java Fri May 24 18:30:26 2013
@@ -25,6 +25,7 @@ import java.util.Map;
 import java.util.NoSuchElementException;
 
 import org.apache.cayenne.access.ResultIterator;
+import org.apache.cayenne.util.ResultIteratorIterator;
 
 /**
  * @since 3.0

Copied: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/ResultIteratorIterator.java (from r1486133, cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/ResultIteratorIterator.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/ResultIteratorIterator.java?p2=cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/ResultIteratorIterator.java&p1=cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/ResultIteratorIterator.java&r1=1486133&r2=1486152&rev=1486152&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/ResultIteratorIterator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/ResultIteratorIterator.java Fri May 24 18:30:26 2013
@@ -16,17 +16,17 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.access.jdbc;
+package org.apache.cayenne.util;
 
 import java.util.Iterator;
 
 import org.apache.cayenne.access.ResultIterator;
 
-class ResultIteratorIterator<T> implements Iterator<T> {
+public class ResultIteratorIterator<T> implements Iterator<T> {
 
     private ResultIterator<T> parent;
 
-    ResultIteratorIterator(ResultIterator<T> parent) {
+    public ResultIteratorIterator(ResultIterator<T> parent) {
         this.parent = parent;
     }
 

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextTest.java?rev=1486152&r1=1486151&r2=1486152&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextTest.java Fri May 24 18:30:26 2013
@@ -41,6 +41,7 @@ import org.apache.cayenne.DataRow;
 import org.apache.cayenne.Fault;
 import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.PersistenceState;
+import org.apache.cayenne.ResultIteratorCallback;
 import org.apache.cayenne.conn.PoolManager;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.exp.Expression;
@@ -112,11 +113,7 @@ public class DataContextTest extends Ser
         tGallery.setColumns("GALLERY_ID", "GALLERY_NAME");
 
         tPainting = new TableHelper(dbHelper, "PAINTING");
-        tPainting.setColumns(
-                "PAINTING_ID",
-                "PAINTING_TITLE",
-                "ARTIST_ID",
-                "ESTIMATED_PRICE");
+        tPainting.setColumns("PAINTING_ID", "PAINTING_TITLE", "ARTIST_ID", "ESTIMATED_PRICE");
     }
 
     protected void createSingleArtistDataSet() throws Exception {
@@ -169,8 +166,7 @@ public class DataContextTest extends Ser
     public void testCurrentSnapshot1() throws Exception {
         createSingleArtistDataSet();
 
-        SelectQuery query = new SelectQuery(Artist.class, ExpressionFactory.matchExp(
-                Artist.ARTIST_NAME_PROPERTY,
+        SelectQuery query = new SelectQuery(Artist.class, ExpressionFactory.matchExp(Artist.ARTIST_NAME_PROPERTY,
                 "artist1"));
         Artist artist = (Artist) context.performQuery(query).get(0);
 
@@ -183,8 +179,7 @@ public class DataContextTest extends Ser
         createSingleArtistDataSet();
 
         // test null values
-        SelectQuery query = new SelectQuery(Artist.class, ExpressionFactory.matchExp(
-                Artist.ARTIST_NAME_PROPERTY,
+        SelectQuery query = new SelectQuery(Artist.class, ExpressionFactory.matchExp(Artist.ARTIST_NAME_PROPERTY,
                 "artist1"));
         Artist artist = (Artist) context.performQuery(query).get(0);
 
@@ -203,8 +198,7 @@ public class DataContextTest extends Ser
         createSingleArtistDataSet();
 
         // test null values
-        SelectQuery query = new SelectQuery(Artist.class, ExpressionFactory.matchExp(
-                Artist.ARTIST_NAME_PROPERTY,
+        SelectQuery query = new SelectQuery(Artist.class, ExpressionFactory.matchExp(Artist.ARTIST_NAME_PROPERTY,
                 "artist1"));
         Artist artist = (Artist) context.performQuery(query).get(0);
 
@@ -226,7 +220,8 @@ public class DataContextTest extends Ser
         createGalleriesAndExhibitsDataSet();
 
         // Exhibit with Gallery as Fault must still include Gallery
-        // Artist and Exhibit (Exhibit has unresolved to-one to gallery as in the
+        // Artist and Exhibit (Exhibit has unresolved to-one to gallery as in
+        // the
         // CAY-96 bug report)
 
         ObjectId eId = new ObjectId("Exhibit", Exhibit.EXHIBIT_ID_PK_COLUMN, 2);
@@ -236,15 +231,17 @@ public class DataContextTest extends Ser
 
         DataRow snapshot = context.currentSnapshot(e);
 
-        // assert that after taking a snapshot, we have FK in, but the relationship
+        // assert that after taking a snapshot, we have FK in, but the
+        // relationship
         // is still a Fault
         assertTrue(e.readPropertyDirectly(Exhibit.TO_GALLERY_PROPERTY) instanceof Fault);
         assertEquals(new Integer(33002), snapshot.get("GALLERY_ID"));
     }
 
     /**
-     * Tests how CHAR field is handled during fetch. Some databases (Oracle...) would pad
-     * a CHAR column with extra spaces, returned to the client. Cayenne should trim it.
+     * Tests how CHAR field is handled during fetch. Some databases (Oracle...)
+     * would pad a CHAR column with extra spaces, returned to the client.
+     * Cayenne should trim it.
      */
     public void testCharFetch() throws Exception {
         createSingleArtistDataSet();
@@ -255,9 +252,9 @@ public class DataContextTest extends Ser
     }
 
     /**
-     * Tests how CHAR field is handled during fetch in the WHERE clause. Some databases
-     * (Oracle...) would pad a CHAR column with extra spaces, returned to the client.
-     * Cayenne should trim it.
+     * Tests how CHAR field is handled during fetch in the WHERE clause. Some
+     * databases (Oracle...) would pad a CHAR column with extra spaces, returned
+     * to the client. Cayenne should trim it.
      */
     public void testCharInQualifier() throws Exception {
         createArtistsDataSet();
@@ -269,8 +266,8 @@ public class DataContextTest extends Ser
     }
 
     /**
-     * Test fetching query with multiple relationship paths between the same 2 entities
-     * used in qualifier.
+     * Test fetching query with multiple relationship paths between the same 2
+     * entities used in qualifier.
      */
     public void testMultiObjRelFetch() throws Exception {
         createArtistsAndPaintingsDataSet();
@@ -284,8 +281,8 @@ public class DataContextTest extends Ser
     }
 
     /**
-     * Test fetching query with multiple relationship paths between the same 2 entities
-     * used in qualifier.
+     * Test fetching query with multiple relationship paths between the same 2
+     * entities used in qualifier.
      */
     public void testMultiDbRelFetch() throws Exception {
         createArtistsAndPaintingsDataSet();
@@ -320,9 +317,7 @@ public class DataContextTest extends Ser
         // verify that the result is not messed up
 
         SelectQuery query = new SelectQuery(Artist.class);
-        Ordering ordering = new Ordering(
-                Artist.ARTIST_NAME_PROPERTY,
-                SortOrder.ASCENDING_INSENSITIVE);
+        Ordering ordering = new Ordering(Artist.ARTIST_NAME_PROPERTY, SortOrder.ASCENDING_INSENSITIVE);
         query.addOrdering(ordering);
         query.setDistinct(true);
 
@@ -340,7 +335,7 @@ public class DataContextTest extends Ser
         assertEquals("artISt4", objects.get(3).getArtistName());
         assertEquals("aRtist5", objects.get(4).getArtistName());
     }
-    
+
     public void testSelect_DataRows() throws Exception {
         createArtistsAndPaintingsDataSet();
 
@@ -360,12 +355,8 @@ public class DataContextTest extends Ser
 
         assertNotNull(objects);
         assertEquals(7, objects.size());
-        assertTrue(
-                "Artist expected, got " + objects.get(0).getClass(),
-                objects.get(0) instanceof Artist);
+        assertTrue("Artist expected, got " + objects.get(0).getClass(), objects.get(0) instanceof Artist);
     }
-    
-    
 
     public void testPerformSelectQuery2() throws Exception {
         createArtistsAndPaintingsDataSet();
@@ -376,17 +367,13 @@ public class DataContextTest extends Ser
         expressions.add(ExpressionFactory.matchExp("artistName", "artist5"));
         expressions.add(ExpressionFactory.matchExp("artistName", "artist21"));
 
-        SelectQuery query = new SelectQuery(Artist.class, ExpressionFactory.joinExp(
-                Expression.OR,
-                expressions));
+        SelectQuery query = new SelectQuery(Artist.class, ExpressionFactory.joinExp(Expression.OR, expressions));
 
         List<?> objects = context.performQuery(query);
 
         assertNotNull(objects);
         assertEquals(3, objects.size());
-        assertTrue(
-                "Artist expected, got " + objects.get(0).getClass(),
-                objects.get(0) instanceof Artist);
+        assertTrue("Artist expected, got " + objects.get(0).getClass(), objects.get(0) instanceof Artist);
     }
 
     public void testPerformQuery_Routing() {
@@ -394,24 +381,18 @@ public class DataContextTest extends Ser
         QueryMetadata md = mock(QueryMetadata.class);
         when(query.getMetaData(any(EntityResolver.class))).thenReturn(md);
         context.performGenericQuery(query);
-        verify(query).route(
-                any(QueryRouter.class),
-                eq(context.getEntityResolver()),
-                (Query) isNull());
+        verify(query).route(any(QueryRouter.class), eq(context.getEntityResolver()), (Query) isNull());
     }
 
     public void testPerformNonSelectingQuery() throws Exception {
 
         createSingleArtistDataSet();
 
-        SelectQuery select = new SelectQuery(
-                Painting.class,
-                Expression.fromString("db:PAINTING_ID = 1"));
+        SelectQuery select = new SelectQuery(Painting.class, Expression.fromString("db:PAINTING_ID = 1"));
 
         assertEquals(0, context.performQuery(select).size());
 
-        SQLTemplate query = new SQLTemplate(
-                Painting.class,
+        SQLTemplate query = new SQLTemplate(Painting.class,
                 "INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE) "
                         + "VALUES (1, 'PX', 33001, 1)");
         context.performNonSelectingQuery(query);
@@ -421,8 +402,7 @@ public class DataContextTest extends Ser
     public void testPerformNonSelectingQueryCounts1() throws Exception {
         createArtistsDataSet();
 
-        SQLTemplate query = new SQLTemplate(
-                Painting.class,
+        SQLTemplate query = new SQLTemplate(Painting.class,
                 "INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE) "
                         + "VALUES ($pid, '$pt', $aid, $price)");
 
@@ -445,8 +425,7 @@ public class DataContextTest extends Ser
 
         createArtistsDataSet();
 
-        SQLTemplate query = new SQLTemplate(
-                Painting.class,
+        SQLTemplate query = new SQLTemplate(Painting.class,
                 "INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE) "
                         + "VALUES ($pid, '$pt', $aid, #bind($price 'DECIMAL' 2))");
 
@@ -531,9 +510,7 @@ public class DataContextTest extends Ser
 
         assertNotNull(objects);
         assertEquals(7, objects.size());
-        assertTrue(
-                "Map expected, got " + objects.get(0).getClass(),
-                objects.get(0) instanceof Map<?, ?>);
+        assertTrue("Map expected, got " + objects.get(0).getClass(), objects.get(0) instanceof Map<?, ?>);
     }
 
     public void testCommitChangesRO1() throws Exception {
@@ -545,8 +522,7 @@ public class DataContextTest extends Ser
         try {
             context.commitChanges();
             fail("Inserting a 'read-only' object must fail.");
-        }
-        catch (Exception ex) {
+        } catch (Exception ex) {
             // exception is expected,
             // must blow on saving new "read-only" object.
         }
@@ -555,8 +531,7 @@ public class DataContextTest extends Ser
     public void testCommitChangesRO2() throws Exception {
         createArtistsDataSet();
 
-        SelectQuery query = new SelectQuery(ROArtist.class, ExpressionFactory.matchExp(
-                Artist.ARTIST_NAME_PROPERTY,
+        SelectQuery query = new SelectQuery(ROArtist.class, ExpressionFactory.matchExp(Artist.ARTIST_NAME_PROPERTY,
                 "artist1"));
         ROArtist a1 = (ROArtist) context.performQuery(query).get(0);
         a1.writeProperty(ROArtist.ARTIST_NAME_PROPERTY, "abc");
@@ -564,8 +539,7 @@ public class DataContextTest extends Ser
         try {
             context.commitChanges();
             fail("Updating a 'read-only' object must fail.");
-        }
-        catch (Exception ex) {
+        } catch (Exception ex) {
             // exception is expected,
             // must blow on saving new "read-only" object.
         }
@@ -575,8 +549,7 @@ public class DataContextTest extends Ser
 
         createArtistsDataSet();
 
-        SelectQuery query = new SelectQuery(ROArtist.class, ExpressionFactory.matchExp(
-                Artist.ARTIST_NAME_PROPERTY,
+        SelectQuery query = new SelectQuery(ROArtist.class, ExpressionFactory.matchExp(Artist.ARTIST_NAME_PROPERTY,
                 "artist1"));
         ROArtist a1 = (ROArtist) context.performQuery(query).get(0);
         context.deleteObjects(a1);
@@ -584,8 +557,7 @@ public class DataContextTest extends Ser
         try {
             context.commitChanges();
             fail("Deleting a 'read-only' object must fail.");
-        }
-        catch (Exception ex) {
+        } catch (Exception ex) {
             // exception is expected,
             // must blow on saving new "read-only" object.
         }
@@ -594,8 +566,7 @@ public class DataContextTest extends Ser
     public void testCommitChangesRO4() throws Exception {
         createArtistsDataSet();
 
-        SelectQuery query = new SelectQuery(ROArtist.class, ExpressionFactory.matchExp(
-                Artist.ARTIST_NAME_PROPERTY,
+        SelectQuery query = new SelectQuery(ROArtist.class, ExpressionFactory.matchExp(Artist.ARTIST_NAME_PROPERTY,
                 "artist1"));
         ROArtist a1 = (ROArtist) context.performQuery(query).get(0);
 
@@ -606,15 +577,32 @@ public class DataContextTest extends Ser
         assertEquals(PersistenceState.MODIFIED, a1.getPersistenceState());
         try {
             context.commitChanges();
-        }
-        catch (Exception ex) {
-            fail("Updating 'read-only' object's to-many must succeed, instead an exception was thrown: "
-                    + ex);
+        } catch (Exception ex) {
+            fail("Updating 'read-only' object's to-many must succeed, instead an exception was thrown: " + ex);
         }
 
         assertEquals(PersistenceState.COMMITTED, a1.getPersistenceState());
     }
 
+    public void testIterate() throws Exception {
+
+        createArtistsDataSet();
+
+        SelectQuery<Artist> q1 = new SelectQuery<Artist>(Artist.class);
+
+        context.iterate(q1, new ResultIteratorCallback<Artist>() {
+            public void iterate(ResultIterator<Artist> iterator) {
+                int count = 0;
+
+                for (Artist a : iterator) {
+                    count++;
+                }
+
+                assertEquals(7, count);
+            }
+        });
+    }
+
     public void testPerformIteratedQuery1() throws Exception {
 
         createArtistsDataSet();
@@ -630,8 +618,7 @@ public class DataContextTest extends Ser
             }
 
             assertEquals(7, count);
-        }
-        finally {
+        } finally {
             it.close();
         }
     }
@@ -652,13 +639,9 @@ public class DataContextTest extends Ser
                 Artist artist = context.objectFromDataRow(Artist.class, row);
                 List<?> paintings = artist.getPaintingArray();
                 assertNotNull(paintings);
-                assertEquals(
-                        "Expected one painting for artist: " + artist,
-                        1,
-                        paintings.size());
+                assertEquals("Expected one painting for artist: " + artist, 1, paintings.size());
             }
-        }
-        finally {
+        } finally {
             // change allowed connections back
             changeMaxConnections(-1);
             it.close();
@@ -666,8 +649,8 @@ public class DataContextTest extends Ser
     }
 
     /**
-     * Tests that hasChanges performs correctly when an object is "modified" and the
-     * property is simply set to the same value (an unreal modification)
+     * Tests that hasChanges performs correctly when an object is "modified" and
+     * the property is simply set to the same value (an unreal modification)
      */
     public void testHasChangesPhantom() {
 
@@ -679,15 +662,18 @@ public class DataContextTest extends Ser
         // Set again to *exactly* the same value
         artist.setArtistName(artistName);
 
-        // note that since 1.2 the polciy is for hasChanges to return true for phantom
-        // modifications, as there is no way to detect some more subtle modifications like
-        // a change of the master related object, until we actually create the PKs
+        // note that since 1.2 the polciy is for hasChanges to return true for
+        // phantom
+        // modifications, as there is no way to detect some more subtle
+        // modifications like
+        // a change of the master related object, until we actually create the
+        // PKs
         assertTrue(context.hasChanges());
     }
 
     /**
-     * Tests that hasChanges performs correctly when an object is "modified" and the
-     * property is simply set to the same value (an unreal modification)
+     * Tests that hasChanges performs correctly when an object is "modified" and
+     * the property is simply set to the same value (an unreal modification)
      */
     public void testHasChangesRealModify() {
         Artist artist = (Artist) context.newObject("Artist");
@@ -751,10 +737,7 @@ public class DataContextTest extends Ser
 
         // testing this...
         context.deleteObjects(hollow);
-        assertSame(
-                hollow,
-                context.getGraphManager().getNode(
-                        new ObjectId("Artist", "ARTIST_ID", 33001)));
+        assertSame(hollow, context.getGraphManager().getNode(new ObjectId("Artist", "ARTIST_ID", 33001)));
         assertEquals("artist1", hollow.getArtistName());
 
         assertEquals(PersistenceState.DELETED, hollow.getPersistenceState());