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