You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Cursor.java 15KB

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