mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#494 - ENH: Support findPagingList() ... that uses firstRow & maxRows (rather than pageIndex, pageSize)
This commit is contained in:
@@ -1020,7 +1020,7 @@ public interface EbeanServer {
|
||||
SqlFutureList findFutureList(SqlQuery query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Return a PagedList for this query.
|
||||
* Return a PagedList for this query using pageIndex and pageSize.
|
||||
* <p>
|
||||
* The benefit of using this over just using the normal {@link Query#setFirstRow(int)} and
|
||||
* {@link Query#setMaxRows(int)} is that it additionally wraps an optional call to
|
||||
@@ -1042,6 +1042,38 @@ public interface EbeanServer {
|
||||
*/
|
||||
<T> PagedList<T> findPagedList(Query<T> query, Transaction transaction, int pageIndex, int pageSize);
|
||||
|
||||
/**
|
||||
* Return a PagedList for this query using firstRow and maxRows.
|
||||
* <p>
|
||||
* The benefit of using this over findList() is that it provides functionality to get the
|
||||
* total row count etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* If maxRows is not set on the query prior to calling findPagedList() then a
|
||||
* PersistenceException is thrown.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* PagedList<Order> pagedList = Ebean.find(Order.class)
|
||||
* .setFirstRow(50)
|
||||
* .setMaxRows(20)
|
||||
* .findPagedList();
|
||||
*
|
||||
* // fetch the total row count in the background
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* List<Order> orders = pagedList.getList();
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @return The PagedList
|
||||
*
|
||||
* @see Query#findPagedList()
|
||||
*/
|
||||
<T> PagedList<T> findPagedList(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query returning a set of entity beans.
|
||||
* <p>
|
||||
|
||||
@@ -245,7 +245,7 @@ public interface ExpressionList<T> extends Serializable {
|
||||
FutureList<T> findFutureList();
|
||||
|
||||
/**
|
||||
* Return a PagedList for this query.
|
||||
* Return a PagedList for this query using pageIndex and pageSize.
|
||||
* <p>
|
||||
* The benefit of using this over just using the normal {@link Query#setFirstRow(int)} and
|
||||
* {@link Query#setMaxRows(int)} is that it additionally wraps an optional call to
|
||||
@@ -265,6 +265,38 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
PagedList<T> findPagedList(int pageIndex, int pageSize);
|
||||
|
||||
/**
|
||||
* Return a PagedList for this query using firstRow and maxRows.
|
||||
* <p>
|
||||
* The benefit of using this over findList() is that it provides functionality to get the
|
||||
* total row count etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* If maxRows is not set on the query prior to calling findPagedList() then a
|
||||
* PersistenceException is thrown.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* PagedList<Order> pagedList = Ebean.find(Order.class)
|
||||
* .setFirstRow(50)
|
||||
* .setMaxRows(20)
|
||||
* .findPagedList();
|
||||
*
|
||||
* // fetch the total row count in the background
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* List<Order> orders = pagedList.getList();
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @return The PagedList
|
||||
*
|
||||
* @see Query#findPagedList()
|
||||
*/
|
||||
PagedList<T> findPagedList();
|
||||
|
||||
/**
|
||||
* Return versions of a @History entity bean.
|
||||
* <p>
|
||||
|
||||
@@ -17,6 +17,33 @@ import java.util.concurrent.Future;
|
||||
* limit the result set.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <h4>Example: typical use including total row count</h4>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // We want to find the first 50 new orders
|
||||
* // ... so we don't really need setFirstRow(0)
|
||||
*
|
||||
* PagedList<Order> pagedList
|
||||
* = ebeanServer.find(Order.class)
|
||||
* .where().eq("status", Order.Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .setFirstRow(0)
|
||||
* .setMaxRows(50)
|
||||
* .findPagedList();
|
||||
*
|
||||
* // Optional: initiate the loading of the total
|
||||
* // row count in a background thread
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* // get the total row count (from the future)
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h4>Example: typical use including total row count</h4>
|
||||
* <pre>{@code
|
||||
*
|
||||
@@ -156,11 +183,15 @@ public interface PagedList<T> {
|
||||
|
||||
/**
|
||||
* Return the index position of this page. Zero based.
|
||||
* <p>
|
||||
* Note that if firstRows/maxRows is used rather than pageIndex/pageSize then
|
||||
* this always returns 0.
|
||||
* </p>
|
||||
*/
|
||||
int getPageIndex();
|
||||
|
||||
/**
|
||||
* Return the page size used for this query.
|
||||
* Return the page size used for this query. This is the same value as maxRows used by the query.
|
||||
*/
|
||||
int getPageSize();
|
||||
|
||||
|
||||
@@ -822,7 +822,7 @@ public interface Query<T> extends Serializable {
|
||||
FutureList<T> findFutureList();
|
||||
|
||||
/**
|
||||
* Return a PagedList for this query.
|
||||
* Return a PagedList for this query using pageIndex and pageSize.
|
||||
* <p>
|
||||
* The benefit of using this over just using the normal {@link Query#setFirstRow(int)} and
|
||||
* {@link Query#setMaxRows(int)} is that it additionally wraps an optional call to
|
||||
@@ -867,6 +867,36 @@ public interface Query<T> extends Serializable {
|
||||
*/
|
||||
PagedList<T> findPagedList(int pageIndex, int pageSize);
|
||||
|
||||
/**
|
||||
* Return a PagedList for this query using firstRow and maxRows.
|
||||
* <p>
|
||||
* The benefit of using this over findList() is that it provides functionality to get the
|
||||
* total row count etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* If maxRows is not set on the query prior to calling findPagedList() then a
|
||||
* PersistenceException is thrown.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* PagedList<Order> pagedList = Ebean.find(Order.class)
|
||||
* .setFirstRow(50)
|
||||
* .setMaxRows(20)
|
||||
* .findPagedList();
|
||||
*
|
||||
* // fetch the total row count in the background
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* List<Order> orders = pagedList.getList();
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @return The PagedList
|
||||
*/
|
||||
PagedList<T> findPagedList();
|
||||
|
||||
/**
|
||||
* Set a named bind parameter. Named parameters have a colon to prefix the name.
|
||||
*
|
||||
|
||||
@@ -1384,6 +1384,18 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return new LimitOffsetPagedList<T>(this, (SpiQuery<T>)query, pageIndex, pageSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> PagedList<T> findPagedList(Query<T> query, Transaction transaction) {
|
||||
|
||||
SpiQuery<T> spiQuery = (SpiQuery<T>)query;
|
||||
int maxRows = spiQuery.getMaxRows();
|
||||
if (maxRows == 0) {
|
||||
throw new PersistenceException("maxRows must be specified for findPagedList() query");
|
||||
}
|
||||
|
||||
return new LimitOffsetPagedList<T>(this, spiQuery);
|
||||
}
|
||||
|
||||
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
|
||||
|
||||
@@ -314,6 +314,11 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
|
||||
return exprList.findPagedList(pageIndex, pageSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PagedList<T> findPagedList() {
|
||||
return exprList.findPagedList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findRowCount() {
|
||||
return exprList.findRowCount();
|
||||
|
||||
@@ -21,7 +21,9 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
|
||||
private final SpiQuery<T> query;
|
||||
|
||||
private final int pageSize;
|
||||
private final int firstRow;
|
||||
|
||||
private final int maxRows;
|
||||
|
||||
private final int pageIndex;
|
||||
|
||||
@@ -33,11 +35,29 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
|
||||
private List<T> list;
|
||||
|
||||
/**
|
||||
* Construct with pageIndex/pageSize.
|
||||
*/
|
||||
public LimitOffsetPagedList(EbeanServer server, SpiQuery<T> query, int pageIndex, int pageSize) {
|
||||
this.server = server;
|
||||
this.query = query;
|
||||
this.pageSize = pageSize;
|
||||
this.maxRows = pageSize;
|
||||
this.firstRow = pageIndex * pageSize;
|
||||
this.pageIndex = pageIndex;
|
||||
|
||||
query.setFirstRow(firstRow);
|
||||
query.setMaxRows(pageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with firstRow/maxRows.
|
||||
*/
|
||||
public LimitOffsetPagedList(EbeanServer server, SpiQuery<T> query) {
|
||||
this.server = server;
|
||||
this.query = query;
|
||||
this.maxRows = query.getMaxRows();
|
||||
this.firstRow = query.getFirstRow();
|
||||
this.pageIndex = 0;
|
||||
}
|
||||
|
||||
public void loadRowCount() {
|
||||
@@ -56,8 +76,6 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
public List<T> getList() {
|
||||
synchronized (monitor) {
|
||||
if (list == null) {
|
||||
query.setFirstRow(pageIndex * pageSize);
|
||||
query.setMaxRows(pageSize);
|
||||
list = server.findList(query, null);
|
||||
}
|
||||
return list;
|
||||
@@ -70,7 +88,7 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
if (rowCount == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return ((rowCount - 1) / pageSize) + 1;
|
||||
return ((rowCount - 1) / maxRows) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,11 +112,11 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return pageIndex < (getTotalPageCount() - 1);
|
||||
return (firstRow + maxRows) < getTotalRowCount();
|
||||
}
|
||||
|
||||
public boolean hasPrev() {
|
||||
return pageIndex > 0;
|
||||
return firstRow > 0;
|
||||
}
|
||||
|
||||
public int getPageIndex() {
|
||||
@@ -106,13 +124,13 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
}
|
||||
|
||||
public int getPageSize() {
|
||||
return pageSize;
|
||||
return maxRows;
|
||||
}
|
||||
|
||||
public String getDisplayXtoYofZ(String to, String of) {
|
||||
|
||||
int first = pageIndex * pageSize + 1;
|
||||
int last = first + getList().size() - 1;
|
||||
int first = firstRow + 1;
|
||||
int last = firstRow + getList().size();
|
||||
int total = getTotalRowCount();
|
||||
|
||||
return first + to + last + of + total;
|
||||
|
||||
@@ -1094,6 +1094,11 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return server.findPagedList(this, null, pageIndex, pageSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PagedList<T> findPagedList() {
|
||||
return server.findPagedList(this, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an ordered bind parameter according to its position. Note that the position starts at 1 to
|
||||
* be consistent with JDBC PreparedStatement. You need to set a parameter value for each ? you
|
||||
|
||||
@@ -201,6 +201,11 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return query.findPagedList(pageIndex, pageSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PagedList<T> findPagedList() {
|
||||
return query.findPagedList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findRowCount() {
|
||||
return query.findRowCount();
|
||||
|
||||
@@ -512,6 +512,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> PagedList<T> findPagedList(Query<T> query, Transaction transaction) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Set<T> findSet(Query<T> query, Transaction transaction) {
|
||||
return null;
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.avaje.tests.model.basic.ResetBasicData;
|
||||
import org.avaje.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
@@ -16,10 +17,126 @@ import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class TestQueryFindPagedList extends BaseTestCase {
|
||||
|
||||
|
||||
@Test(expected = PersistenceException.class)
|
||||
public void test_noMaxRows() throws ExecutionException, InterruptedException {
|
||||
|
||||
Ebean.find(Order.class).findPagedList();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_maxRows_NoCount() throws ExecutionException, InterruptedException {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
PagedList<Order> pagedList = Ebean.find(Order.class)
|
||||
.setMaxRows(4)
|
||||
.findPagedList();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
List<Order> orders = pagedList.getList();
|
||||
|
||||
assertTrue(!orders.isEmpty());
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
|
||||
assertEquals("Only 1 SQL statement, no count query",1, loggedSql.size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test_maxRows_countInBackground() throws ExecutionException, InterruptedException, TimeoutException {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
PagedList<Order> pagedList = Ebean.find(Order.class)
|
||||
.setMaxRows(3)
|
||||
.findPagedList();
|
||||
|
||||
Future<Integer> rowCount = pagedList.getFutureRowCount();
|
||||
List<Order> orders = pagedList.getList();
|
||||
|
||||
// these are each getting the total row count
|
||||
int totalRowCount = pagedList.getTotalRowCount();
|
||||
Integer totalRowCountWithTimeout = rowCount.get(30, TimeUnit.SECONDS);
|
||||
Integer totalRowCountViaFuture = rowCount.get();
|
||||
|
||||
assertTrue(orders.size() < totalRowCount);
|
||||
assertEquals(Integer.valueOf(totalRowCount), totalRowCountViaFuture);
|
||||
assertEquals(Integer.valueOf(totalRowCount), totalRowCountWithTimeout);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_maxRows_countInBackground_withLoadRowCount() throws InterruptedException {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
// fetch less that total orders (page size 3)
|
||||
PagedList<Order> pagedList = Ebean.find(Order.class)
|
||||
.setMaxRows(3)
|
||||
.findPagedList();
|
||||
|
||||
pagedList.loadRowCount();
|
||||
List<Order> orders = pagedList.getList();
|
||||
int totalRowCount = pagedList.getTotalRowCount();
|
||||
|
||||
assertThat(orders.size()).isLessThan(totalRowCount);
|
||||
assertTrue(pagedList.hasNext());
|
||||
assertFalse(pagedList.hasPrev());
|
||||
|
||||
|
||||
// fetch less that total orders (page size 3)
|
||||
PagedList<Order> pagedList2 = Ebean.find(Order.class)
|
||||
.setFirstRow(1)
|
||||
.setMaxRows(3)
|
||||
.findPagedList();
|
||||
|
||||
pagedList2.loadRowCount();
|
||||
List<Order> orders2 = pagedList2.getList();
|
||||
int totalRowCount2 = pagedList2.getTotalRowCount();
|
||||
assertTrue(pagedList2.hasNext());
|
||||
assertTrue(pagedList2.hasPrev());
|
||||
|
||||
assertThat(totalRowCount).isEqualTo(totalRowCount2);
|
||||
assertThat(orders2.size()).isLessThan(totalRowCount);
|
||||
|
||||
|
||||
PagedList<Order> pagedList3 = Ebean.find(Order.class)
|
||||
.setFirstRow(2)
|
||||
.setMaxRows(150)
|
||||
.findPagedList();
|
||||
|
||||
assertFalse(pagedList3.hasNext());
|
||||
assertTrue(pagedList3.hasPrev());
|
||||
|
||||
List<Order> list3 = pagedList3.getList();
|
||||
String xtoYofZ = pagedList3.getDisplayXtoYofZ(" to ", " of ");
|
||||
assertThat(xtoYofZ).isEqualTo("3 to "+totalRowCount+" of "+totalRowCount);
|
||||
assertThat(list3.size()).isEqualTo(totalRowCount - 2);
|
||||
|
||||
PagedList<Order> pagedList4 = Ebean.find(Order.class)
|
||||
.setFirstRow(0)
|
||||
.setMaxRows(totalRowCount)
|
||||
.findPagedList();
|
||||
|
||||
assertFalse(pagedList4.hasNext());
|
||||
assertFalse(pagedList4.hasPrev());
|
||||
assertThat(pagedList4.getDisplayXtoYofZ(" to ", "of ")).isEqualTo("1 to "+totalRowCount+" of "+totalRowCount);
|
||||
|
||||
PagedList<Order> pagedList5 = Ebean.find(Order.class)
|
||||
.setFirstRow(0)
|
||||
.setMaxRows(totalRowCount - 1)
|
||||
.findPagedList();
|
||||
|
||||
assertTrue(pagedList5.hasNext());
|
||||
assertFalse(pagedList5.hasPrev());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_noCount() throws ExecutionException, InterruptedException {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user