1 /* 2 Copyright (c) 2013 James Ahlborn 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package com.healthmarketscience.jackcess; 18 19 import java.io.IOException; 20 import java.util.Collection; 21 import java.util.Iterator; 22 import java.util.Map; 23 import java.util.stream.Stream; 24 import java.util.stream.StreamSupport; 25 26 import com.healthmarketscience.jackcess.util.ColumnMatcher; 27 import com.healthmarketscience.jackcess.util.ErrorHandler; 28 import com.healthmarketscience.jackcess.util.IterableBuilder; 29 30 /** 31 * Manages iteration for a {@link Table}. Different cursors provide different 32 * methods of traversing a table. Cursors should be fairly robust in the face 33 * of table modification during traversal (although depending on how the table 34 * is traversed, row updates may or may not be seen). Multiple cursors may 35 * traverse the same table simultaneously. 36 * <p> 37 * Basic cursors will generally iterate table data in the order it appears in 38 * the database and searches will require scanning the entire table. 39 * Additional features are available when utilizing an {@link Index} backed 40 * {@link IndexCursor}. 41 * <p> 42 * The {@link CursorBuilder} provides a variety of static utility methods to 43 * construct cursors with given characteristics or easily search for specific 44 * values as well as friendly and flexible construction options. 45 * <p> 46 * A Cursor instance is not thread-safe (see {@link Database} for more 47 * thread-safety details). 48 * 49 * @author James Ahlborn 50 * @usage _general_class_ 51 */ 52 public interface Cursor extends Iterable<Row> 53 { 54 55 public Id getId(); 56 57 public Table getTable(); 58 59 /** 60 * Gets the currently configured ErrorHandler (always non-{@code null}). 61 * This will be used to handle all errors. 62 */ 63 public ErrorHandler getErrorHandler(); 64 65 /** 66 * Sets a new ErrorHandler. If {@code null}, resets to using the 67 * ErrorHandler configured at the Table level. 68 */ 69 public void setErrorHandler(ErrorHandler newErrorHandler); 70 71 /** 72 * Returns the currently configured ColumnMatcher, always non-{@code null}. 73 */ 74 public ColumnMatcher getColumnMatcher(); 75 76 /** 77 * Sets a new ColumnMatcher. If {@code null}, resets to using the default 78 * matcher (default depends on Cursor type). 79 */ 80 public void setColumnMatcher(ColumnMatcher columnMatcher); 81 82 /** 83 * Returns the current state of the cursor which can be restored at a future 84 * point in time by a call to {@link #restoreSavepoint}. 85 * <p> 86 * Savepoints may be used across different cursor instances for the same 87 * table, but they must have the same {@link Id}. 88 */ 89 public Savepoint getSavepoint(); 90 91 /** 92 * Moves the cursor to a savepoint previously returned from 93 * {@link #getSavepoint}. 94 * @throws IllegalArgumentException if the given savepoint does not have a 95 * cursorId equal to this cursor's id 96 */ 97 public void restoreSavepoint(Savepoint savepoint) 98 throws IOException; 99 100 /** 101 * Resets this cursor for forward traversal. Calls {@link #beforeFirst}. 102 */ 103 public void reset(); 104 105 /** 106 * Resets this cursor for forward traversal (sets cursor to before the first 107 * row). 108 */ 109 public void beforeFirst(); 110 111 /** 112 * Resets this cursor for reverse traversal (sets cursor to after the last 113 * row). 114 */ 115 public void afterLast(); 116 117 /** 118 * Returns {@code true} if the cursor is currently positioned before the 119 * first row, {@code false} otherwise. 120 */ 121 public boolean isBeforeFirst() throws IOException; 122 123 /** 124 * Returns {@code true} if the cursor is currently positioned after the 125 * last row, {@code false} otherwise. 126 */ 127 public boolean isAfterLast() throws IOException; 128 129 /** 130 * Returns {@code true} if the row at which the cursor is currently 131 * positioned is deleted, {@code false} otherwise (including invalid rows). 132 */ 133 public boolean isCurrentRowDeleted() throws IOException; 134 135 /** 136 * Calls {@link #beforeFirst} on this cursor and returns a modifiable 137 * Iterator which will iterate through all the rows of this table. Use of 138 * the Iterator follows the same restrictions as a call to 139 * {@link #getNextRow}. 140 * <p> 141 * For more flexible iteration see {@link #newIterable}. 142 * @throws RuntimeIOException if an IOException is thrown by one of the 143 * operations, the actual exception will be contained within 144 */ 145 @Override 146 public Iterator<Row> iterator(); 147 148 /** 149 * @return a Stream using the default Iterator. 150 */ 151 default public Stream<Row> stream() { 152 return StreamSupport.stream(spliterator(), false); 153 } 154 155 /** 156 * Convenience method for constructing a new IterableBuilder for this 157 * cursor. An IterableBuilder provides a variety of options for more 158 * flexible iteration. 159 */ 160 public IterableBuilder newIterable(); 161 162 /** 163 * Delete the current row. 164 * <p> 165 * Note, re-deleting an already deleted row is allowed (it does nothing). 166 * @throws IllegalStateException if the current row is not valid (at 167 * beginning or end of table) 168 */ 169 public void deleteCurrentRow() throws IOException; 170 171 /** 172 * Update the current row. 173 * @return the given row values if long enough, otherwise a new array, 174 * updated with the current row values 175 * @throws IllegalStateException if the current row is not valid (at 176 * beginning or end of table), or deleted. 177 */ 178 public Object[] updateCurrentRow(Object... row) throws IOException; 179 180 /** 181 * Update the current row. 182 * @return the given row, updated with the current row values 183 * @throws IllegalStateException if the current row is not valid (at 184 * beginning or end of table), or deleted. 185 */ 186 public <M extends Map<String,Object>> M updateCurrentRowFromMap(M row) 187 throws IOException; 188 189 /** 190 * Moves to the next row in the table and returns it. 191 * @return The next row in this table (Column name -> Column value), or 192 * {@code null} if no next row is found 193 */ 194 public Row getNextRow() throws IOException; 195 196 /** 197 * Moves to the next row in the table and returns it. 198 * @param columnNames Only column names in this collection will be returned 199 * @return The next row in this table (Column name -> Column value), or 200 * {@code null} if no next row is found 201 */ 202 public Row getNextRow(Collection<String> columnNames) 203 throws IOException; 204 205 /** 206 * Moves to the previous row in the table and returns it. 207 * @return The previous row in this table (Column name -> Column value), or 208 * {@code null} if no previous row is found 209 */ 210 public Row getPreviousRow() throws IOException; 211 212 /** 213 * Moves to the previous row in the table and returns it. 214 * @param columnNames Only column names in this collection will be returned 215 * @return The previous row in this table (Column name -> Column value), or 216 * {@code null} if no previous row is found 217 */ 218 public Row getPreviousRow(Collection<String> columnNames) 219 throws IOException; 220 221 /** 222 * Moves to the next row as defined by this cursor. 223 * @return {@code true} if a valid next row was found, {@code false} 224 * otherwise 225 */ 226 public boolean moveToNextRow() throws IOException; 227 228 /** 229 * Moves to the previous row as defined by this cursor. 230 * @return {@code true} if a valid previous row was found, {@code false} 231 * otherwise 232 */ 233 public boolean moveToPreviousRow() throws IOException; 234 235 /** 236 * Moves to the row with the given rowId. If the row is not found (or an 237 * exception is thrown), the cursor is restored to its previous state. 238 * 239 * @return {@code true} if a valid row was found with the given id, 240 * {@code false} if no row was found 241 */ 242 public boolean findRow(RowId rowId) throws IOException; 243 244 /** 245 * Moves to the first row (as defined by the cursor) where the given column 246 * has the given value. This may be more efficient on some cursors than 247 * others. If a match is not found (or an exception is thrown), the cursor 248 * is restored to its previous state. 249 * <p> 250 * Warning, this method <i>always</i> starts searching from the beginning of 251 * the Table (you cannot use it to find successive matches). 252 * 253 * @param columnPattern column from the table for this cursor which is being 254 * matched by the valuePattern 255 * @param valuePattern value which is equal to the corresponding value in 256 * the matched row. If this object is an instance of 257 * {@link java.util.function.Predicate}, it will be 258 * applied to the potential row value instead 259 * (overriding any configured ColumnMatcher) 260 * @return {@code true} if a valid row was found with the given value, 261 * {@code false} if no row was found 262 */ 263 public boolean findFirstRow(Column columnPattern, Object valuePattern) 264 throws IOException; 265 266 /** 267 * Moves to the next row (as defined by the cursor) where the given column 268 * has the given value. This may be more efficient on some cursors than 269 * others. If a match is not found (or an exception is thrown), the cursor 270 * is restored to its previous state. 271 * 272 * @param columnPattern column from the table for this cursor which is being 273 * matched by the valuePattern 274 * @param valuePattern value which is equal to the corresponding value in 275 * the matched row. If this object is an instance of 276 * {@link java.util.function.Predicate}, it will be 277 * applied to the potential row value instead 278 * (overriding any configured ColumnMatcher) 279 * @return {@code true} if a valid row was found with the given value, 280 * {@code false} if no row was found 281 */ 282 public boolean findNextRow(Column columnPattern, Object valuePattern) 283 throws IOException; 284 285 /** 286 * Moves to the first row (as defined by the cursor) where the given columns 287 * have the given values. This may be more efficient on some cursors than 288 * others. If a match is not found (or an exception is thrown), the cursor 289 * is restored to its previous state. 290 * <p> 291 * Warning, this method <i>always</i> starts searching from the beginning of 292 * the Table (you cannot use it to find successive matches). 293 * 294 * @param rowPattern column names and values which must be equal to the 295 * corresponding values in the matched row. If a value is 296 * an instance of {@link java.util.function.Predicate}, it 297 * will be applied to the potential row value instead 298 * (overriding any configured ColumnMatcher) 299 * @return {@code true} if a valid row was found with the given values, 300 * {@code false} if no row was found 301 */ 302 public boolean findFirstRow(Map<String,?> rowPattern) throws IOException; 303 304 /** 305 * Moves to the next row (as defined by the cursor) where the given columns 306 * have the given values. This may be more efficient on some cursors than 307 * others. If a match is not found (or an exception is thrown), the cursor 308 * is restored to its previous state. 309 * 310 * @param rowPattern column names and values which must be equal to the 311 * corresponding values in the matched row. If a value is 312 * an instance of {@link java.util.function.Predicate}, it 313 * will be applied to the potential row value instead 314 * (overriding any configured ColumnMatcher) 315 * @return {@code true} if a valid row was found with the given values, 316 * {@code false} if no row was found 317 */ 318 public boolean findNextRow(Map<String,?> rowPattern) throws IOException; 319 320 /** 321 * Returns {@code true} if the current row matches the given pattern. 322 * @param columnPattern column from the table for this cursor which is being 323 * matched by the valuePattern 324 * @param valuePattern value which is equal to the corresponding value in 325 * the matched row. If this object is an instance of 326 * {@link java.util.function.Predicate}, it will be 327 * applied to the potential row value instead 328 * (overriding any configured ColumnMatcher) 329 */ 330 public boolean currentRowMatches(Column columnPattern, Object valuePattern) 331 throws IOException; 332 333 /** 334 * Returns {@code true} if the current row matches the given pattern. 335 * @param rowPattern column names and values which must be equal to the 336 * corresponding values in the matched row. If a value is 337 * an instance of {@link java.util.function.Predicate}, it 338 * will be applied to the potential row value instead 339 * (overriding any configured ColumnMatcher) 340 */ 341 public boolean currentRowMatches(Map<String,?> rowPattern) throws IOException; 342 343 /** 344 * Moves forward as many rows as possible up to the given number of rows. 345 * @return the number of rows moved. 346 */ 347 public int moveNextRows(int numRows) throws IOException; 348 349 /** 350 * Moves backward as many rows as possible up to the given number of rows. 351 * @return the number of rows moved. 352 */ 353 public int movePreviousRows(int numRows) throws IOException; 354 355 /** 356 * Returns the current row in this cursor (Column name -> Column value). 357 */ 358 public Row getCurrentRow() throws IOException; 359 360 /** 361 * Returns the current row in this cursor (Column name -> Column value). 362 * @param columnNames Only column names in this collection will be returned 363 */ 364 public Row getCurrentRow(Collection<String> columnNames) 365 throws IOException; 366 367 /** 368 * Returns the given column from the current row. 369 */ 370 public Object getCurrentRowValue(Column column) throws IOException; 371 372 /** 373 * Updates a single value in the current row. 374 * @throws IllegalStateException if the current row is not valid (at 375 * beginning or end of table), or deleted. 376 */ 377 public void setCurrentRowValue(Column column, Object value) 378 throws IOException; 379 380 /** 381 * Identifier for a cursor. Will be equal to any other cursor of the same 382 * type for the same table. Primarily used to check the validity of a 383 * Savepoint. 384 */ 385 public interface Id 386 { 387 } 388 389 /** 390 * Value object which maintains the current position of the cursor. 391 */ 392 public interface Position 393 { 394 /** 395 * Returns the unique RowId of the position of the cursor. 396 */ 397 public RowId getRowId(); 398 } 399 400 /** 401 * Value object which represents a complete save state of the cursor. 402 * Savepoints are created by calling {@link Cursor#getSavepoint} and used by 403 * calling {@link Cursor#restoreSavepoint} to return the the cursor state at 404 * the time the Savepoint was created. 405 */ 406 public interface Savepoint 407 { 408 public Id getCursorId(); 409 410 public Position getCurrentPosition(); 411 } 412 413 }