From 4a882b537c3c5fffe49c01a4b4a69dc3fba300fd Mon Sep 17 00:00:00 2001 From: rbygrave Date: Fri, 14 Nov 2014 21:26:32 +1300 Subject: [PATCH] #197 - Add Query findEach() findEachWhile() ... as better method names for findVisit(). More consistent with forEach() methods --- .../java/com/avaje/ebean/EbeanServer.java | 24 ++++++ .../java/com/avaje/ebean/ExpressionList.java | 22 ++++- src/main/java/com/avaje/ebean/Model.java | 31 +++++++ src/main/java/com/avaje/ebean/Query.java | 82 +++++++++++++++---- .../com/avaje/ebean/QueryEachConsumer.java | 41 ++++++++++ .../avaje/ebean/QueryEachWhileConsumer.java | 45 ++++++++++ .../server/core/DefaultServer.java | 73 +++++++---------- .../server/core/OrmQueryRequest.java | 28 ++++++- .../server/core/SpiOrmQueryRequest.java | 14 +++- .../server/expression/JunctionExpression.java | 10 +++ .../server/querydefn/DefaultOrmQuery.java | 26 +++--- .../util/DefaultExpressionList.java | 24 +++--- .../avaje/tests/query/TestQueryFindEach.java | 67 +++++++++++++++ .../tests/query/TestQueryFindEachWhile.java | 69 ++++++++++++++++ 14 files changed, 461 insertions(+), 95 deletions(-) create mode 100644 src/main/java/com/avaje/ebean/QueryEachConsumer.java create mode 100644 src/main/java/com/avaje/ebean/QueryEachWhileConsumer.java create mode 100644 src/test/java/com/avaje/tests/query/TestQueryFindEach.java create mode 100644 src/test/java/com/avaje/tests/query/TestQueryFindEachWhile.java diff --git a/src/main/java/com/avaje/ebean/EbeanServer.java b/src/main/java/com/avaje/ebean/EbeanServer.java index 64bdcbed2..e730a4b35 100644 --- a/src/main/java/com/avaje/ebean/EbeanServer.java +++ b/src/main/java/com/avaje/ebean/EbeanServer.java @@ -457,6 +457,30 @@ public interface EbeanServer { * Execute the query visiting the results. This is similar to findIterate in * that not all the result beans need to be held in memory at the same time * and as such is go for processing large queries. + * + * @see Query#findEach(QueryEachConsumer) + */ + public void findEach(Query query, QueryEachConsumer consumer, Transaction transaction); + + /** + * Execute the query visiting the results. This is similar to findIterate in + * that not all the result beans need to be held in memory at the same time + * and as such is go for processing large queries. + * + * @see Query#findEachWhile(QueryEachWhileConsumer) + */ + public void findEachWhile(Query query, QueryEachWhileConsumer consumer, Transaction transaction); + + /** + * Deprecated in favor of #findEachWhile which is functionally exactly the same + * but has a much better name. + *

+ * Execute the query visiting the results. This is similar to findIterate in + * that not all the result beans need to be held in memory at the same time + * and as such is go for processing large queries. + *

+ * + * @deprecated */ public void findVisit(Query query, QueryResultVisitor visitor, Transaction transaction); diff --git a/src/main/java/com/avaje/ebean/ExpressionList.java b/src/main/java/com/avaje/ebean/ExpressionList.java index dee737d88..b991e3553 100644 --- a/src/main/java/com/avaje/ebean/ExpressionList.java +++ b/src/main/java/com/avaje/ebean/ExpressionList.java @@ -102,9 +102,25 @@ public interface ExpressionList extends Serializable { public QueryIterator findIterate(); /** - * Execute the query visiting the results. - * - * @see Query#findVisit(QueryResultVisitor) + * Execute the query process the beans one at a time. + * + * @see Query#findEach(QueryEachConsumer) + */ + public void findEach(QueryEachConsumer consumer); + + /** + * Execute the query processing the beans one at a time with the ability to + * stop processing before reading all the beans. + * + * @see Query#findEachWhile(QueryEachWhileConsumer) + */ + public void findEachWhile(QueryEachWhileConsumer consumer); + + /** + * Deprecated in favor of #findEachWhile which is functionally exactly the same + * but has a much better name. + * + * @deprecated */ public void findVisit(QueryResultVisitor visitor); diff --git a/src/main/java/com/avaje/ebean/Model.java b/src/main/java/com/avaje/ebean/Model.java index d57311474..0dfc9d44f 100644 --- a/src/main/java/com/avaje/ebean/Model.java +++ b/src/main/java/com/avaje/ebean/Model.java @@ -328,6 +328,37 @@ public abstract class Model { return query().findIds(); } + /** + * Execute the query consuming each bean one at a time. + *

+ * This is generally used to process large queries where unlike findList + * you do not want to hold all the results in memory at once but instead + * process them one at a time (requiring far less memory). + *

+ * Equivalent to {@link Query#findEach(QueryEachConsumer)} + */ + public void findEach(QueryEachConsumer consumer) { + query().findEach(consumer); + } + + /** + * Execute the query consuming each bean one at a time. + *

+ * This is similar to #findEach except that you return boolean + * true to continue processing beans and return false to stop + * processing early. + *

+ *

+ * This is generally used to process large queries where unlike findList + * you do not want to hold all the results in memory at once but instead + * process them one at a time (requiring far less memory). + *

+ * Equivalent to {@link Query#findEachWhile(QueryEachWhileConsumer)} + */ + public void findEachWhile(QueryEachWhileConsumer consumer) { + query().findEachWhile(consumer); + } + /** * Retrieves all entities of the given type. *

diff --git a/src/main/java/com/avaje/ebean/Query.java b/src/main/java/com/avaje/ebean/Query.java index 8110ac2cc..96fb71093 100644 --- a/src/main/java/com/avaje/ebean/Query.java +++ b/src/main/java/com/avaje/ebean/Query.java @@ -446,37 +446,89 @@ public interface Query extends Serializable { */ public QueryIterator findIterate(); + /** + * This is deprecated in favor of #findEachWhile. + *

+ * This is functionally exactly the same as #findEachWhile. It is + * replaced by findEachWhile because the method name is much better. + *

+ * + * @param visitor + * the visitor used to process the queried beans. + * + * @deprecated + */ + public void findVisit(QueryResultVisitor visitor); + + /** + * Execute the query processing the beans one at a time. + *

+ * This method is appropriate to process very large query results as the + * beans are consumed one at a time and do not need to be held in memory + * (unlike #findList #findSet etc) + *

+ *

+ * Compared with #findEachWhile this will always process all the beans where as + * #findEachWhile provides a way to stop processing the query result early before + * all the beans have been read. + *

+ *

+ * This method is functionally equivalent to findIterate() but instead of using an + * iterator uses the QueryEachConsumer (SAM) interface which is better suited to use + * with Java8 closures. + *

+ * + *
+   *
+   * Query<Customer> query = server.find(Customer.class)
+   *     .where().gt("id", 0)
+   *     .orderBy("id")
+   *     .setMaxRows(2);
+   *
+   * query.findVisit((Customer customer) -> {
+   *
+   *     // do something with customer
+   *     System.out.println("-- visit " + customer);
+   * });
+   * 
+ * + * @param consumer + * the consumer used to process the queried beans. + */ + public void findEach(QueryEachConsumer consumer); + /** * Execute the query using callbacks to a visitor to process the resulting * beans one at a time. *

- * Similar to findIterate() this query method does not require all the result - * beans to be all held in memory at once and as such is useful for processing - * large queries. + * This method is functionally equivalent to findIterate() but instead of using an + * iterator uses the QueryEachWhileConsumer (SAM) interface which is better suited to use + * with Java8 closures. *

- * + + * *
-   * 
+   *
    * Query<Customer> query = server.find(Customer.class)
    *     .fetch("contacts", new FetchConfig().query(2))
    *     .where().gt("id", 0)
    *     .orderBy("id")
    *     .setMaxRows(2);
-   * 
-   * query.findVisit(new QueryResultVisitor<Customer>() {
-   * 
-   *   public boolean accept(Customer customer) {
+   *
+   * query.findEachWhile((Customer customer) -> {
+   *
    *     // do something with customer
    *     System.out.println("-- visit " + customer);
-   *     return true;
-   *   }
+   *
+   *     // return true to continue processing or false to stop
+   *     return (customer.getId() < 40);
    * });
    * 
- * - * @param visitor - * the visitor used to process the queried beans. + * + * @param consumer + * the consumer used to process the queried beans. */ - public void findVisit(QueryResultVisitor visitor); + public void findEachWhile(QueryEachWhileConsumer consumer); /** * Execute the query returning the list of objects. diff --git a/src/main/java/com/avaje/ebean/QueryEachConsumer.java b/src/main/java/com/avaje/ebean/QueryEachConsumer.java new file mode 100644 index 000000000..7e9761426 --- /dev/null +++ b/src/main/java/com/avaje/ebean/QueryEachConsumer.java @@ -0,0 +1,41 @@ +package com.avaje.ebean; + +/** + * Used to process a query result one bean at a time via a callback to this + * visitor. + *

+ * If you wish to stop further processing return false from the accept method. + *

+ *

+ * Unlike findList() and findSet() using a QueryResultVisitor does not require + * all the beans in the query result to be held in memory at once. This makes + * QueryResultVisitor useful for processing large queries. + *

+ * + *
+ *
+ * Query<Customer> query = server.find(Customer.class)
+ *     .where().gt("id", 0)
+ *     .orderBy("id")
+ *     .setMaxRows(2);
+ *
+ * query.findVisit((Customer customer) -> {
+ *
+ *     // do something with customer
+ *     System.out.println("-- visit " + customer);
+ * });
+ * 
+ * + * @param + * the type of entity bean being queried. + */ +public interface QueryEachConsumer { + + /** + * Process the bean. + * + * @param bean + * the entity bean to process + */ + public void accept(T bean); +} diff --git a/src/main/java/com/avaje/ebean/QueryEachWhileConsumer.java b/src/main/java/com/avaje/ebean/QueryEachWhileConsumer.java new file mode 100644 index 000000000..1b503099c --- /dev/null +++ b/src/main/java/com/avaje/ebean/QueryEachWhileConsumer.java @@ -0,0 +1,45 @@ +package com.avaje.ebean; + +/** + * Used to process a query result one bean at a time via a callback to this + * visitor. + *

+ * If you wish to stop further processing return false from the accept method. + *

+ *

+ * Unlike findList() and findSet() using a QueryResultVisitor does not require + * all the beans in the query result to be held in memory at once. This makes + * QueryResultVisitor useful for processing large queries. + *

+ *

+ *

+ *
+ * Query<Customer> query = server.find(Customer.class)
+ *     .fetch("contacts", new FetchConfig().query(2))
+ *     .where().gt("id", 0)
+ *     .orderBy("id")
+ *     .setMaxRows(2);
+ *
+ * query.findEachWhile((Customer customer) -> {
+ *
+ *     // do something with customer
+ *     System.out.println("-- visit " + customer);
+ *
+ *     // return true to continue processing or false to stop
+ *     return (customer.getId() < 40);
+ * });
+ * 
+ * + * @param the type of entity bean being queried. + */ +public interface QueryEachWhileConsumer { + + /** + * Process the bean and return true if you want to continue processing more + * beans. Return false if you want to stop processing further. + * + * @param bean the entity bean to process + * @return true to continue processing more beans or false to stop. + */ + public boolean accept(T bean); +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java index b3810aaa5..03172c75d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java @@ -17,36 +17,10 @@ import javax.management.MBeanServer; import javax.management.ObjectName; import javax.persistence.PersistenceException; +import com.avaje.ebean.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.avaje.ebean.AdminAutofetch; -import com.avaje.ebean.BackgroundExecutor; -import com.avaje.ebean.BeanState; -import com.avaje.ebean.CallableSql; -import com.avaje.ebean.Ebean; -import com.avaje.ebean.ExpressionFactory; -import com.avaje.ebean.Filter; -import com.avaje.ebean.FutureIds; -import com.avaje.ebean.FutureList; -import com.avaje.ebean.FutureRowCount; -import com.avaje.ebean.PagedList; -import com.avaje.ebean.PagingList; -import com.avaje.ebean.Query; -import com.avaje.ebean.QueryIterator; -import com.avaje.ebean.QueryResultVisitor; -import com.avaje.ebean.SqlFutureList; -import com.avaje.ebean.SqlQuery; -import com.avaje.ebean.SqlRow; -import com.avaje.ebean.SqlUpdate; -import com.avaje.ebean.Transaction; -import com.avaje.ebean.TxCallable; -import com.avaje.ebean.TxIsolation; -import com.avaje.ebean.TxRunnable; -import com.avaje.ebean.TxScope; -import com.avaje.ebean.TxType; -import com.avaje.ebean.Update; -import com.avaje.ebean.ValuePair; import com.avaje.ebean.bean.BeanCollection; import com.avaje.ebean.bean.CallStack; import com.avaje.ebean.bean.EntityBean; @@ -273,17 +247,14 @@ public final class DefaultServer implements SpiEbeanServer { List spiPlugins = new ArrayList(); - final Iterator plugins = ServiceLoader.load(SpiEbeanPlugin.class).iterator(); - - while (plugins.hasNext()) { - SpiEbeanPlugin plugin = plugins.next(); + for (SpiEbeanPlugin plugin : ServiceLoader.load(SpiEbeanPlugin.class)) { spiPlugins.add(plugin); plugin.setup(this, this.getDatabasePlatform(), config.getServerConfig()); if (plugin instanceof DdlGenerator) { // backwards compatible - ddlGenerator = (DdlGenerator)plugin; - } + ddlGenerator = (DdlGenerator) plugin; + } } if (ddlGenerator == null) { @@ -1413,12 +1384,27 @@ public final class DefaultServer implements SpiEbeanServer { SpiOrmQueryRequest request = createQueryRequest(Type.LIST, query, t); - try { - request.initTransIfRequired(); - request.findVisit(visitor); - } finally { - // do nothing - findVisit garuntee's cleanup of the transaction if required - } + request.initTransIfRequired(); + request.findVisit(visitor); + // no try finally - findVisit guarantee's cleanup of the transaction if required + } + + public void findEach(Query query, QueryEachConsumer consumer, Transaction t) { + + SpiOrmQueryRequest request = createQueryRequest(Type.LIST, query, t); + + request.initTransIfRequired(); + request.findEach(consumer); + // no try finally - findVisit guarantee's cleanup of the transaction if required + } + + public void findEachWhile(Query query, QueryEachWhileConsumer consumer, Transaction t) { + + SpiOrmQueryRequest request = createQueryRequest(Type.LIST, query, t); + + request.initTransIfRequired(); + request.findEachWhile(consumer); + // no try finally - findVisit guarantee's cleanup of the transaction if required } public QueryIterator findIterate(Query query, Transaction t) { @@ -1542,7 +1528,7 @@ public final class DefaultServer implements SpiEbeanServer { @Override public void markAsDirty(Object bean) { - if (bean instanceof EntityBean == false) { + if (!(bean instanceof EntityBean)) { throw new IllegalArgumentException("This bean is not an EntityBean?"); } // mark the bean as dirty (so that an update will not get skipped) @@ -1650,7 +1636,7 @@ public final class DefaultServer implements SpiEbeanServer { if (bean == null) { throw new IllegalArgumentException(Message.msg("bean.isnull")); } - if (bean instanceof EntityBean == false) { + if (!(bean instanceof EntityBean)) { throw new IllegalArgumentException("Was expecting an EntityBean but got a "+bean.getClass()); } return (EntityBean)bean; @@ -1959,10 +1945,7 @@ public final class DefaultServer implements SpiEbeanServer { public boolean isSupportedType(java.lang.reflect.Type genericType) { TypeInfo typeInfo = ParamTypeHelper.getTypeInfo(genericType); - if (typeInfo == null) { - return false; - } - return getBeanDescriptor(typeInfo.getBeanType()) != null; + return typeInfo != null && getBeanDescriptor(typeInfo.getBeanType()) != null; } public Object getBeanId(Object bean) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java index e64eacd8d..b3b701f38 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java @@ -6,9 +6,7 @@ import java.util.Set; import javax.persistence.PersistenceException; -import com.avaje.ebean.QueryIterator; -import com.avaje.ebean.QueryResultVisitor; -import com.avaje.ebean.RawSql; +import com.avaje.ebean.*; import com.avaje.ebean.bean.BeanCollection; import com.avaje.ebean.bean.PersistenceContext; import com.avaje.ebean.event.BeanFinder; @@ -234,6 +232,30 @@ public final class OrmQueryRequest extends BeanRequest implements BeanQueryRe return idList.getIdList(); } + public void findEach(QueryEachConsumer consumer) { + QueryIterator it = queryEngine.findIterate(this); + try { + while (it.hasNext()) { + consumer.accept(it.next()); + } + } finally { + it.close(); + } + } + + public void findEachWhile(QueryEachWhileConsumer consumer) { + QueryIterator it = queryEngine.findIterate(this); + try { + while (it.hasNext()) { + if (!consumer.accept(it.next())) { + break; + } + } + } finally { + it.close(); + } + } + public void findVisit(QueryResultVisitor visitor) { QueryIterator it = queryEngine.findIterate(this); try { diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java b/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java index 8837a516d..52c5e1508 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java @@ -4,6 +4,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import com.avaje.ebean.QueryEachConsumer; +import com.avaje.ebean.QueryEachWhileConsumer; import com.avaje.ebean.QueryIterator; import com.avaje.ebean.QueryResultVisitor; import com.avaje.ebean.bean.BeanCollection; @@ -65,7 +67,17 @@ public interface SpiOrmQueryRequest { */ public void findVisit(QueryResultVisitor visitor); - /** + /** + * Execute the find returning a QueryIterator and visitor pattern. + */ + public void findEach(QueryEachConsumer consumer); + + /** + * Execute the find returning a QueryIterator and visitor pattern. + */ + public void findEachWhile(QueryEachWhileConsumer consumer); + + /** * Execute the find returning a QueryIterator. */ public QueryIterator findIterate(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java index 6bb654df3..4edaca7b9 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java @@ -218,6 +218,16 @@ abstract class JunctionExpression implements Junction, SpiExpression, Expr return exprList.findIds(); } + @Override + public void findEach(QueryEachConsumer consumer) { + exprList.findEach(consumer); + } + + @Override + public void findEachWhile(QueryEachWhileConsumer consumer) { + exprList.findEachWhile(consumer); + } + public void findVisit(QueryResultVisitor visitor) { exprList.findVisit(visitor); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 607cdc0f5..de67a9949 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -8,22 +8,8 @@ import java.util.Set; import javax.persistence.PersistenceException; -import com.avaje.ebean.EbeanServer; -import com.avaje.ebean.Expression; -import com.avaje.ebean.ExpressionFactory; -import com.avaje.ebean.ExpressionList; -import com.avaje.ebean.FetchConfig; -import com.avaje.ebean.FutureIds; -import com.avaje.ebean.FutureList; -import com.avaje.ebean.FutureRowCount; -import com.avaje.ebean.OrderBy; +import com.avaje.ebean.*; import com.avaje.ebean.OrderBy.Property; -import com.avaje.ebean.PagedList; -import com.avaje.ebean.PagingList; -import com.avaje.ebean.Query; -import com.avaje.ebean.QueryIterator; -import com.avaje.ebean.QueryResultVisitor; -import com.avaje.ebean.RawSql; import com.avaje.ebean.bean.BeanCollectionTouched; import com.avaje.ebean.bean.CallStack; import com.avaje.ebean.bean.EntityBean; @@ -911,6 +897,16 @@ public class DefaultOrmQuery implements SpiQuery { server.findVisit(this, visitor, null); } + @Override + public void findEachWhile(QueryEachWhileConsumer consumer) { + server.findEachWhile(this, consumer, null); + } + + @Override + public void findEach(QueryEachConsumer consumer) { + server.findEach(this, consumer, null); + } + public QueryIterator findIterate() { return server.findIterate(this, null); } diff --git a/src/main/java/com/avaje/ebeaninternal/util/DefaultExpressionList.java b/src/main/java/com/avaje/ebeaninternal/util/DefaultExpressionList.java index 467fd9aae..44c81522a 100644 --- a/src/main/java/com/avaje/ebeaninternal/util/DefaultExpressionList.java +++ b/src/main/java/com/avaje/ebeaninternal/util/DefaultExpressionList.java @@ -6,19 +6,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import com.avaje.ebean.Expression; -import com.avaje.ebean.ExpressionFactory; -import com.avaje.ebean.ExpressionList; -import com.avaje.ebean.FutureIds; -import com.avaje.ebean.FutureList; -import com.avaje.ebean.FutureRowCount; -import com.avaje.ebean.Junction; -import com.avaje.ebean.OrderBy; -import com.avaje.ebean.PagedList; -import com.avaje.ebean.PagingList; -import com.avaje.ebean.Query; -import com.avaje.ebean.QueryIterator; -import com.avaje.ebean.QueryResultVisitor; +import com.avaje.ebean.*; import com.avaje.ebean.event.BeanQueryRequest; import com.avaje.ebean.text.PathProperties; import com.avaje.ebeaninternal.api.HashQueryPlanBuilder; @@ -172,6 +160,16 @@ public class DefaultExpressionList implements SpiExpressionList { return query.findIds(); } + @Override + public void findEach(QueryEachConsumer consumer) { + query.findEach(consumer); + } + + @Override + public void findEachWhile(QueryEachWhileConsumer consumer) { + query.findEachWhile(consumer); + } + public void findVisit(QueryResultVisitor visitor) { query.findVisit(visitor); } diff --git a/src/test/java/com/avaje/tests/query/TestQueryFindEach.java b/src/test/java/com/avaje/tests/query/TestQueryFindEach.java new file mode 100644 index 000000000..113e37218 --- /dev/null +++ b/src/test/java/com/avaje/tests/query/TestQueryFindEach.java @@ -0,0 +1,67 @@ +package com.avaje.tests.query; + +import com.avaje.ebean.*; +import com.avaje.tests.model.basic.Customer; +import com.avaje.tests.model.basic.ResetBasicData; +import org.junit.Assert; +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicInteger; + +public class TestQueryFindEach extends BaseTestCase { + + @Test + public void test() { + + ResetBasicData.reset(); + + EbeanServer server = Ebean.getServer(null); + + Query query + = server.find(Customer.class) + .setAutofetch(false) + .fetch("contacts", new FetchConfig().query(2)).where().gt("id", 0).orderBy("id") + .setMaxRows(2); + + final AtomicInteger counter = new AtomicInteger(0); + + query.findEach(new QueryEachConsumer() { + + public void accept(Customer customer) { + counter.incrementAndGet(); + customer.getName(); + } + }); + + Assert.assertEquals(2, counter.get()); + } + + /** + * Test the behaviour when an exception is thrown inside the findVisit(). + */ + @Test(expected=IllegalStateException.class) + public void testVisitThrowingException() { + + ResetBasicData.reset(); + + EbeanServer server = Ebean.getServer(null); + + Query query = server.find(Customer.class).setAutofetch(false) + .fetch("contacts", new FetchConfig().query(2)).where().gt("id", 0).orderBy("id") + .setMaxRows(2); + + final AtomicInteger counter = new AtomicInteger(0); + + query.findEach(new QueryEachConsumer() { + + public void accept(Customer customer) { + counter.incrementAndGet(); + if (counter.intValue() > 0) { + throw new IllegalStateException("cause a failure"); + } + } + }); + + Assert.assertFalse("Never get here - exception thrown", true); + } +} diff --git a/src/test/java/com/avaje/tests/query/TestQueryFindEachWhile.java b/src/test/java/com/avaje/tests/query/TestQueryFindEachWhile.java new file mode 100644 index 000000000..a305fc974 --- /dev/null +++ b/src/test/java/com/avaje/tests/query/TestQueryFindEachWhile.java @@ -0,0 +1,69 @@ +package com.avaje.tests.query; + +import com.avaje.ebean.*; +import com.avaje.tests.model.basic.Customer; +import com.avaje.tests.model.basic.ResetBasicData; +import org.junit.Assert; +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicInteger; + +public class TestQueryFindEachWhile extends BaseTestCase { + + @Test + public void test() { + + ResetBasicData.reset(); + + EbeanServer server = Ebean.getServer(null); + + Query query + = server.find(Customer.class) + .setAutofetch(false) + .fetch("contacts", new FetchConfig().query(2)).where().gt("id", 0).orderBy("id") + .setMaxRows(2); + + final AtomicInteger counter = new AtomicInteger(0); + + query.findEachWhile(new QueryEachWhileConsumer< Customer > () { + + public boolean accept(Customer customer) { + counter.incrementAndGet(); + customer.getName(); + return true; + } + }); + + Assert.assertEquals(2, counter.get()); + } + + /** + * Test the behaviour when an exception is thrown inside the findVisit(). + */ + @Test(expected=IllegalStateException.class) + public void testVisitThrowingException() { + + ResetBasicData.reset(); + + EbeanServer server = Ebean.getServer(null); + + Query query = server.find(Customer.class).setAutofetch(false) + .fetch("contacts", new FetchConfig().query(2)).where().gt("id", 0).orderBy("id") + .setMaxRows(2); + + final AtomicInteger counter = new AtomicInteger(0); + + query.findEachWhile(new QueryEachWhileConsumer() { + + public boolean accept(Customer customer) { + counter.incrementAndGet(); + if (counter.intValue() > 0) { + throw new IllegalStateException("cause a failure"); + } + return true; + } + }); + + Assert.assertFalse("Never get here - exception thrown", true); + } +}