View Javadoc
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 -&gt; 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 -&gt; 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 -&gt; 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 -&gt; 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 -&gt; Column value).
358    */
359   public Row getCurrentRow() throws IOException;
360 
361   /**
362    * Returns the current row in this cursor (Column name -&gt; 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 }