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.

CursorBuilder.java 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /*
  2. Copyright (c) 2007 Health Market Science, Inc.
  3. This library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. This library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with this library; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  14. USA
  15. You can contact Health Market Science at info@healthmarketscience.com
  16. or at the following address:
  17. Health Market Science
  18. 2700 Horizon Drive
  19. Suite 200
  20. King of Prussia, PA 19406
  21. */
  22. package com.healthmarketscience.jackcess;
  23. import java.io.IOException;
  24. import java.util.ArrayList;
  25. import java.util.Arrays;
  26. import java.util.Collection;
  27. import java.util.Iterator;
  28. import java.util.List;
  29. /**
  30. * Builder style class for constructing a Cursor. By default, a cursor is
  31. * created at the beginning of the table, and any start/end rows are
  32. * inclusive.
  33. *
  34. * @author James Ahlborn
  35. */
  36. public class CursorBuilder {
  37. /** the table which the cursor will traverse */
  38. private final Table _table;
  39. /** optional index to use in traversal */
  40. private Index _index;
  41. /** optional start row for an index cursor */
  42. private Object[] _startRow;
  43. /** whether or not start row for an index cursor is inclusive */
  44. private boolean _startRowInclusive = true;
  45. /** optional end row for an index cursor */
  46. private Object[] _endRow;
  47. /** whether or not end row for an index cursor is inclusive */
  48. private boolean _endRowInclusive = true;
  49. /** whether to start at beginning or end of cursor */
  50. private boolean _beforeFirst = true;
  51. /** optional save point to restore to the cursor */
  52. private Cursor.Savepoint _savepoint;
  53. /** ColumnMatcher to be used when matching column values */
  54. private ColumnMatcher _columnMatcher;
  55. public CursorBuilder(Table table) {
  56. _table = table;
  57. }
  58. /**
  59. * Sets the cursor so that it will start at the beginning (unless a
  60. * savepoint is given).
  61. */
  62. public CursorBuilder beforeFirst() {
  63. _beforeFirst = true;
  64. return this;
  65. }
  66. /**
  67. * Sets the cursor so that it will start at the end (unless a savepoint is
  68. * given).
  69. */
  70. public CursorBuilder afterLast() {
  71. _beforeFirst = false;
  72. return this;
  73. }
  74. /**
  75. * Sets a savepoint to restore for the initial position of the cursor.
  76. */
  77. public CursorBuilder restoreSavepoint(Cursor.Savepoint savepoint) {
  78. _savepoint = savepoint;
  79. return this;
  80. }
  81. /**
  82. * Sets an index to use for the cursor.
  83. */
  84. public CursorBuilder setIndex(Index index) {
  85. _index = index;
  86. return this;
  87. }
  88. /**
  89. * Sets an index to use for the cursor by searching the table for an index
  90. * with the given name.
  91. * @throws IllegalArgumentException if no index can be found on the table
  92. * with the given name
  93. */
  94. public CursorBuilder setIndexByName(String indexName) {
  95. return setIndex(_table.getIndex(indexName));
  96. }
  97. /**
  98. * Sets an index to use for the cursor by searching the table for an index
  99. * with exactly the given columns.
  100. * @throws IllegalArgumentException if no index can be found on the table
  101. * with the given columns
  102. */
  103. public CursorBuilder setIndexByColumnNames(String... columnNames) {
  104. return setIndexByColumns(Arrays.asList(columnNames));
  105. }
  106. /**
  107. * Sets an index to use for the cursor by searching the table for an index
  108. * with exactly the given columns.
  109. * @throws IllegalArgumentException if no index can be found on the table
  110. * with the given columns
  111. */
  112. public CursorBuilder setIndexByColumns(Column... columns) {
  113. List<String> colNames = new ArrayList<String>();
  114. for(Column col : columns) {
  115. colNames.add(col.getName());
  116. }
  117. return setIndexByColumns(colNames);
  118. }
  119. /**
  120. * Searches for an index with the given column names.
  121. */
  122. private CursorBuilder setIndexByColumns(List<String> searchColumns) {
  123. boolean found = false;
  124. for(Index index : _table.getIndexes()) {
  125. Collection<IndexData.ColumnDescriptor> indexColumns = index.getColumns();
  126. if(indexColumns.size() != searchColumns.size()) {
  127. continue;
  128. }
  129. Iterator<String> sIter = searchColumns.iterator();
  130. Iterator<IndexData.ColumnDescriptor> iIter = indexColumns.iterator();
  131. boolean matches = true;
  132. while(sIter.hasNext()) {
  133. String sColName = sIter.next();
  134. String iColName = iIter.next().getName();
  135. if((sColName != iColName) &&
  136. ((sColName == null) || !sColName.equalsIgnoreCase(iColName))) {
  137. matches = false;
  138. break;
  139. }
  140. }
  141. if(matches) {
  142. _index = index;
  143. found = true;
  144. break;
  145. }
  146. }
  147. if(!found) {
  148. throw new IllegalArgumentException("Index with columns " +
  149. searchColumns +
  150. " does not exist in table " + _table);
  151. }
  152. return this;
  153. }
  154. /**
  155. * Sets the starting and ending row for a range based index cursor.
  156. * <p>
  157. * A valid index must be specified before calling this method.
  158. */
  159. public CursorBuilder setSpecificRow(Object[] specificRow) {
  160. setStartRow(specificRow);
  161. setEndRow(specificRow);
  162. return this;
  163. }
  164. /**
  165. * Sets the starting and ending row for a range based index cursor to the
  166. * given entry (where the given values correspond to the index's columns).
  167. * <p>
  168. * A valid index must be specified before calling this method.
  169. */
  170. public CursorBuilder setSpecificEntry(Object... specificEntry) {
  171. if(specificEntry != null) {
  172. setSpecificRow(_index.constructIndexRowFromEntry(specificEntry));
  173. }
  174. return this;
  175. }
  176. /**
  177. * Sets the starting row for a range based index cursor.
  178. * <p>
  179. * A valid index must be specified before calling this method.
  180. */
  181. public CursorBuilder setStartRow(Object[] startRow) {
  182. _startRow = startRow;
  183. return this;
  184. }
  185. /**
  186. * Sets the starting row for a range based index cursor to the given entry
  187. * (where the given values correspond to the index's columns).
  188. * <p>
  189. * A valid index must be specified before calling this method.
  190. */
  191. public CursorBuilder setStartEntry(Object... startEntry) {
  192. if(startEntry != null) {
  193. setStartRow(_index.constructIndexRowFromEntry(startEntry));
  194. }
  195. return this;
  196. }
  197. /**
  198. * Sets whether the starting row for a range based index cursor is inclusive
  199. * or exclusive.
  200. */
  201. public CursorBuilder setStartRowInclusive(boolean inclusive) {
  202. _startRowInclusive = inclusive;
  203. return this;
  204. }
  205. /**
  206. * Sets the ending row for a range based index cursor.
  207. * <p>
  208. * A valid index must be specified before calling this method.
  209. */
  210. public CursorBuilder setEndRow(Object[] endRow) {
  211. _endRow = endRow;
  212. return this;
  213. }
  214. /**
  215. * Sets the ending row for a range based index cursor to the given entry
  216. * (where the given values correspond to the index's columns).
  217. * <p>
  218. * A valid index must be specified before calling this method.
  219. */
  220. public CursorBuilder setEndEntry(Object... endEntry) {
  221. if(endEntry != null) {
  222. setEndRow(_index.constructIndexRowFromEntry(endEntry));
  223. }
  224. return this;
  225. }
  226. /**
  227. * Sets whether the ending row for a range based index cursor is inclusive
  228. * or exclusive.
  229. */
  230. public CursorBuilder setEndRowInclusive(boolean inclusive) {
  231. _endRowInclusive = inclusive;
  232. return this;
  233. }
  234. /**
  235. * Sets the ColumnMatcher to use for matching row patterns.
  236. */
  237. public CursorBuilder setColumnMatcher(ColumnMatcher columnMatcher) {
  238. _columnMatcher = columnMatcher;
  239. return this;
  240. }
  241. /**
  242. * Returns a new cursor for the table, constructed to the given
  243. * specifications.
  244. */
  245. public Cursor toCursor()
  246. throws IOException
  247. {
  248. Cursor cursor = null;
  249. if(_index == null) {
  250. cursor = Cursor.createCursor(_table);
  251. } else {
  252. cursor = Cursor.createIndexCursor(_table, _index,
  253. _startRow, _startRowInclusive,
  254. _endRow, _endRowInclusive);
  255. }
  256. cursor.setColumnMatcher(_columnMatcher);
  257. if(_savepoint == null) {
  258. if(!_beforeFirst) {
  259. cursor.afterLast();
  260. }
  261. } else {
  262. cursor.restoreSavepoint(_savepoint);
  263. }
  264. return cursor;
  265. }
  266. /**
  267. * Returns a new index cursor for the table, constructed to the given
  268. * specifications.
  269. */
  270. public IndexCursor toIndexCursor()
  271. throws IOException
  272. {
  273. return (IndexCursor)toCursor();
  274. }
  275. }