001package io.ebean; 002 003import javax.annotation.Nonnull; 004import java.util.List; 005import java.util.concurrent.Future; 006 007/** 008 * Represents a page of results. 009 * <p> 010 * The benefit of using PagedList over just using the normal Query with 011 * {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} is that it additionally wraps 012 * functionality that can call {@link Query#findFutureCount()} to determine total row count, 013 * total page count etc. 014 * </p> 015 * <p> 016 * Internally this works using {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} on 017 * the query. This translates into SQL that uses limit offset, rownum or row_number function to 018 * limit the result set. 019 * </p> 020 * <p> 021 * <h4>Example: typical use including total row count</h4> 022 * <pre>{@code 023 * 024 * // We want to find the first 50 new orders 025 * // ... so we don't really need setFirstRow(0) 026 * 027 * PagedList<Order> pagedList = DB.find(Order.class) 028 * .where().eq("status", Order.Status.NEW) 029 * .order().asc("id") 030 * .setFirstRow(0) 031 * .setMaxRows(50) 032 * .findPagedList(); 033 * 034 * // Optional: initiate the loading of the total 035 * // row count in a background thread 036 * pagedList.loadRowCount(); 037 * 038 * // fetch and return the list in the foreground thread 039 * List<Order> orders = pagedList.getList(); 040 * 041 * // get the total row count (from the future) 042 * int totalRowCount = pagedList.getTotalRowCount(); 043 * 044 * }</pre> 045 * <p> 046 * <h4>Example: No total row count required</h4> 047 * <pre>{@code 048 * 049 * // If you are not getting the 'first page' often 050 * // you do not bother getting the total row count again 051 * // so instead just get the page list of data 052 * 053 * // fetch and return the list in the foreground thread 054 * List<Order> orders = pagedList.getList(); 055 * 056 * }</pre> 057 * 058 * @param <T> the entity bean type 059 * @see Query#findPagedList() 060 */ 061public interface PagedList<T> { 062 063 /** 064 * Initiate the loading of the total row count in the background. 065 * <pre>{@code 066 * 067 * // initiate the loading of the total row count 068 * // in a background thread 069 * pagedList.loadRowCount(); 070 * 071 * // fetch and return the list in the foreground thread 072 * List<Order> orders = pagedList.getList(); 073 * 074 * // get the total row count (from the future) 075 * int totalRowCount = pagedList.getTotalRowCount(); 076 * 077 * }</pre> 078 * <p> 079 * Also note that using loadRowCount() and getTotalRowCount() rather than getFutureRowCount() 080 * means that exceptions ExecutionException, InterruptedException, TimeoutException are instead 081 * wrapped in the unchecked PersistenceException (which might be preferrable). 082 * </p> 083 */ 084 void loadCount(); 085 086 /** 087 * Return the Future row count. You might get this if you wish to cancel the total row count query 088 * or specify a timeout for the row count query. 089 * <p> 090 * The loadRowCount() & getTotalRowCount() methods internally make use of this getFutureRowCount() method. 091 * Generally I expect people to prefer loadRowCount() & getTotalRowCount() over getFutureRowCount(). 092 * </p> 093 * <pre>{@code 094 * 095 * // initiate the row count query in the background thread 096 * Future<Integer> rowCount = pagedList.getFutureRowCount(); 097 * 098 * // fetch and return the list in the foreground thread 099 * List<Order> orders = pagedList.getList(); 100 * 101 * // now get the total count with a timeout 102 * Integer totalRowCount = rowCount.get(30, TimeUnit.SECONDS); 103 * 104 * // or ge the total count without a timeout 105 * Integer totalRowCountViaFuture = rowCount.get(); 106 * 107 * // which is actually the same as ... 108 * int totalRowCount = pagedList.getTotalRowCount(); 109 * 110 * }</pre> 111 */ 112 @Nonnull 113 Future<Integer> getFutureCount(); 114 115 /** 116 * Return the list of entities for this page. 117 */ 118 @Nonnull 119 List<T> getList(); 120 121 /** 122 * Return the total row count for all pages. 123 * <p> 124 * If loadRowCount() has already been called then the row count query is already executing in a background thread 125 * and this gets the associated Future and gets the value waiting for the future to finish. 126 * </p> 127 * <p> 128 * If loadRowCount() has not been called then this executes the find row count query and returns the result and this 129 * will just occur in the current thread and not use a background thread. 130 * </p> 131 * <pre>{@code 132 * 133 * // Optional: initiate the loading of the total 134 * // row count in a background thread 135 * pagedList.loadRowCount(); 136 * 137 * // fetch and return the list in the foreground thread 138 * List<Order> orders = pagedList.getList(); 139 * 140 * // get the total row count (which was being executed 141 * // in a background thread if loadRowCount() was used) 142 * int totalRowCount = pagedList.getTotalRowCount(); 143 * 144 * }</pre> 145 */ 146 int getTotalCount(); 147 148 /** 149 * Return the total number of pages based on the page size and total row count. 150 * <p> 151 * This method requires that the total row count has been fetched and will invoke 152 * the total row count query if it has not already been invoked. 153 * </p> 154 */ 155 int getTotalPageCount(); 156 157 /** 158 * Return the page size used for this query. This is the same value as maxRows used by the query. 159 */ 160 int getPageSize(); 161 162 /** 163 * Return the index position of this page (Zero based). 164 * <p> 165 * This is a calculated value based on firstRow/maxRows. 166 * </p> 167 */ 168 int getPageIndex(); 169 170 /** 171 * Return true if there is a next page. 172 * <p> 173 * This method requires that the total row count has been fetched and will invoke 174 * the total row count query if it has not already been invoked. 175 * </p> 176 */ 177 boolean hasNext(); 178 179 /** 180 * Return true if there is a previous page. 181 */ 182 boolean hasPrev(); 183 184 /** 185 * Helper method to return a "X to Y of Z" string for this page where X is the first row, Y the 186 * last row and Z the total row count. 187 * <p> 188 * This method requires that the total row count has been fetched and will invoke 189 * the total row count query if it has not already been invoked. 190 * </p> 191 * 192 * @param to String to put between the first and last row 193 * @param of String to put between the last row and the total row count 194 * @return String of the format XtoYofZ. 195 */ 196 String getDisplayXtoYofZ(String to, String of); 197}