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