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