package io.ebean; import java.util.List; import java.util.concurrent.Future; /** * Represents a page of results. * <p> * The benefit of using PagedList over just using the normal Query with * {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} is that it additionally wraps * functionality that can call {@link Query#findFutureCount()} to determine total row count, * total page count etc. * </p> * <p> * Internally this works using {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} on * the query. This translates into SQL that uses limit offset, rownum or row_number function to * limit the result set. * </p> * <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> * <p> * <h4>Example: No total row count required</h4> * <pre>{@code * * // If you are not getting the 'first page' often * // you do not bother getting the total row count again * // so instead just get the page list of data * * // fetch and return the list in the foreground thread * List<Order> orders = pagedList.getList(); * * }</pre> * * @param <T> the entity bean type * @see Query#findPagedList() */ public interface PagedList<T> { /** * Initiate the loading of the total row count in the background. * <pre>{@code * * // 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> * <p> * Also note that using loadRowCount() and getTotalRowCount() rather than getFutureRowCount() * means that exceptions ExecutionException, InterruptedException, TimeoutException are instead * wrapped in the unchecked PersistenceException (which might be preferrable). * </p> */ void loadCount(); /** * Return the Future row count. You might get this if you wish to cancel the total row count query * or specify a timeout for the row count query. * <p> * The loadRowCount() & getTotalRowCount() methods internally make use of this getFutureRowCount() method. * Generally I expect people to prefer loadRowCount() & getTotalRowCount() over getFutureRowCount(). * </p> * <pre>{@code * * // initiate the row count query in the background thread * Future<Integer> rowCount = pagedList.getFutureRowCount(); * * // fetch and return the list in the foreground thread * List<Order> orders = pagedList.getList(); * * // now get the total count with a timeout * Integer totalRowCount = rowCount.get(30, TimeUnit.SECONDS); * * // or ge the total count without a timeout * Integer totalRowCountViaFuture = rowCount.get(); * * // which is actually the same as ... * int totalRowCount = pagedList.getTotalRowCount(); * * }</pre> */ Future<Integer> getFutureCount(); /** * Return the list of entities for this page. */ List<T> getList(); /** * Return the total row count for all pages. * <p> * If loadRowCount() has already been called then the row count query is already executing in a background thread * and this gets the associated Future and gets the value waiting for the future to finish. * </p> * <p> * If loadRowCount() has not been called then this executes the find row count query and returns the result and this * will just occur in the current thread and not use a background thread. * </p> * <pre>{@code * * // 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 (which was being executed * // in a background thread if loadRowCount() was used) * int totalRowCount = pagedList.getTotalRowCount(); * * }</pre> */ int getTotalCount(); /** * Return the total number of pages based on the page size and total row count. * <p> * This method requires that the total row count has been fetched and will invoke * the total row count query if it has not already been invoked. * </p> */ int getTotalPageCount(); /** * Return the page size used for this query. This is the same value as maxRows used by the query. */ int getPageSize(); /** * Return the index position of this page (Zero based). * <p> * This is a calculated value based on firstRow/maxRows. * </p> */ int getPageIndex(); /** * Return true if there is a next page. * <p> * This method requires that the total row count has been fetched and will invoke * the total row count query if it has not already been invoked. * </p> */ boolean hasNext(); /** * Return true if there is a previous page. */ boolean hasPrev(); /** * Helper method to return a "X to Y of Z" string for this page where X is the first row, Y the * last row and Z the total row count. * <p> * This method requires that the total row count has been fetched and will invoke * the total row count query if it has not already been invoked. * </p> * * @param to String to put between the first and last row * @param of String to put between the last row and the total row count * @return String of the format XtoYofZ. */ String getDisplayXtoYofZ(String to, String of); }