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