]> source.dussan.org Git - jackcess.git/commitdiff
ditch builder-style methods on cursor impls, create CursorBuilder for simpler constru...
authorJames Ahlborn <jtahlborn@yahoo.com>
Mon, 3 Dec 2007 04:55:26 +0000 (04:55 +0000)
committerJames Ahlborn <jtahlborn@yahoo.com>
Mon, 3 Dec 2007 04:55:26 +0000 (04:55 +0000)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@196 f203690c-595d-4dc9-a70b-905162fa7fd2

src/java/com/healthmarketscience/jackcess/Cursor.java
src/java/com/healthmarketscience/jackcess/CursorBuilder.java [new file with mode: 0644]
src/java/com/healthmarketscience/jackcess/Index.java
src/java/com/healthmarketscience/jackcess/Table.java
src/java/com/healthmarketscience/jackcess/UsageMap.java
test/src/java/com/healthmarketscience/jackcess/CursorTest.java

index 520481a5086c2ebddfa06fe6ab3d84b21255f4c1..60fdf14a16bb4f06d4783be393db7ef4d21dd48a 100644 (file)
@@ -22,6 +22,11 @@ import org.apache.commons.logging.LogFactory;
  * traversed, row updates may or may not be seen).  Multiple cursors may
  * traverse the same table simultaneously.
  * <p>
+ * The Cursor provides a variety of static utility methods to construct
+ * cursors with given characteristics or easily search for specific values.
+ * For even friendlier and more flexible construction, see
+ * {@link CursorBuilder}.
+ * <p>
  * Is not thread-safe.
  *
  * @author james
@@ -240,6 +245,10 @@ public abstract class Cursor implements Iterable<Map<String, Object>>
   /**
    * Returns the current state of the cursor which can be restored at a future
    * point in time by a call to {@link #restoreSavepoint}.
+   * <p>
+   * Savepoints may be used across different cursor instances for the same
+   * table, but they must be of the same type (index based vs. non-index
+   * based).
    */
   public Savepoint getSavepoint() {
     return new Savepoint(_curPos, _prevPos);
@@ -249,11 +258,11 @@ public abstract class Cursor implements Iterable<Map<String, Object>>
    * Moves the cursor to a savepoint previously returned from
    * {@link #getSavepoint}.
    */
-  public Cursor restoreSavepoint(Savepoint savepoint)
+  public void restoreSavepoint(Savepoint savepoint)
     throws IOException
   {
-    return restorePosition(savepoint.getCurrentPosition(),
-                           savepoint.getPreviousPosition());
+    restorePosition(savepoint.getCurrentPosition(),
+                    savepoint.getPreviousPosition());
   }
   
   /**
@@ -273,24 +282,24 @@ public abstract class Cursor implements Iterable<Map<String, Object>>
   /**
    * Resets this cursor for forward traversal.  Calls {@link #beforeFirst}.
    */
-  public Cursor reset() {
-    return beforeFirst();
+  public void reset() {
+    beforeFirst();
   }  
 
   /**
    * Resets this cursor for forward traversal (sets cursor to before the first
    * row).
    */
-  public Cursor beforeFirst() {
-    return reset(true);
+  public void beforeFirst() {
+    reset(true);
   }
   
   /**
    * Resets this cursor for reverse traversal (sets cursor to after the last
    * row).
    */
-  public Cursor afterLast() {
-    return reset(false);
+  public void afterLast() {
+    reset(false);
   }
 
   /**
@@ -335,11 +344,10 @@ public abstract class Cursor implements Iterable<Map<String, Object>>
   /**
    * Resets this cursor for traversing the given direction.
    */
-  protected Cursor reset(boolean moveForward) {
+  protected void reset(boolean moveForward) {
     _curPos = getDirHandler(moveForward).getBeginningPosition();
     _prevPos = _curPos;
     _rowState.reset();
-    return this;
   }  
 
   /**
@@ -511,23 +519,22 @@ public abstract class Cursor implements Iterable<Map<String, Object>>
    * Restores a current position for the cursor (current position becomes
    * previous position).
    */
-  protected Cursor restorePosition(Position curPos)
+  protected void restorePosition(Position curPos)
     throws IOException
   {
-    return restorePosition(curPos, _curPos);
+    restorePosition(curPos, _curPos);
   }
     
   /**
    * Restores a current and previous position for the cursor if the given
    * positions are different from the current positions.
    */
-  protected final Cursor restorePosition(Position curPos, Position prevPos)
+  protected final void restorePosition(Position curPos, Position prevPos)
     throws IOException
   {
     if(!curPos.equals(_curPos) || !prevPos.equals(_prevPos)) {
       restorePositionImpl(curPos, prevPos);
     }
-    return this;
   }
 
   /**
@@ -867,9 +874,9 @@ public abstract class Cursor implements Iterable<Map<String, Object>>
     }
     
     @Override
-    protected Cursor reset(boolean moveForward) {
+    protected void reset(boolean moveForward) {
       _ownedPagesCursor.reset(moveForward);
-      return super.reset(moveForward);
+      super.reset(moveForward);
     }
 
     @Override
@@ -1030,9 +1037,9 @@ public abstract class Cursor implements Iterable<Map<String, Object>>
     }
     
     @Override
-    protected Cursor reset(boolean moveForward) {
+    protected void reset(boolean moveForward) {
       _entryCursor.reset(moveForward);
-      return super.reset(moveForward);
+      super.reset(moveForward);
     }
 
     @Override
diff --git a/src/java/com/healthmarketscience/jackcess/CursorBuilder.java b/src/java/com/healthmarketscience/jackcess/CursorBuilder.java
new file mode 100644 (file)
index 0000000..9852b9e
--- /dev/null
@@ -0,0 +1,228 @@
+// Copyright (c) 2007 Health Market Science, Inc.
+
+package com.healthmarketscience.jackcess;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.lang.ObjectUtils;
+
+/**
+ * Builder style class for constructing a Cursor.  By default, a cursor is
+ * created at the beginning of the table, and any start/end rows are
+ * inclusive.
+ *
+ * @author james
+ */
+public class CursorBuilder {
+  /** the table which the cursor will traverse */
+  private final Table _table;
+  /** optional index to use in traversal */
+  private Index _index;
+  /** optional start row for an index cursor */
+  private Object[] _startRow;
+  /** whether or not start row for an index cursor is inclusive */
+  private boolean _startRowInclusive = true;
+  /** optional end row for an index cursor */
+  private Object[] _endRow;
+  /** whether or not end row for an index cursor is inclusive */
+  private boolean _endRowInclusive = true;
+  /** whether to start at beginning or end of cursor */
+  private boolean _beforeFirst = true;
+  /** optional save point to restore to the cursor */
+  private Cursor.Savepoint _savepoint;
+
+  public CursorBuilder(Table table) {
+    _table = table;
+  }
+
+  /**
+   * Sets the cursor so that it will start at the beginning (unless a
+   * savepoint is given).
+   */
+  public CursorBuilder beforeFirst() {
+    _beforeFirst = true;
+    return this;
+  }
+  
+  /**
+   * Sets the cursor so that it will start at the end (unless a savepoint is
+   * given).
+   */
+  public CursorBuilder afterLast() {
+    _beforeFirst = false;
+    return this;
+  }
+
+  /**
+   * Sets a savepoint to restore for the initial position of the cursor.
+   */
+  public CursorBuilder restoreSavepoint(Cursor.Savepoint savepoint) {
+    _savepoint = savepoint;
+    return this;
+  }
+
+  /**
+   * Sets an index to use for the cursor.
+   */
+  public CursorBuilder setIndex(Index index) {
+    _index = index;
+    return this;
+  }
+
+  /**
+   * Sets an index to use for the cursor by searching the table for an index
+   * with the given name.
+   * @throws IllegalArgumentException if no index can be found on the table
+   *         with the given name
+   */
+  public CursorBuilder setIndexByName(String indexName) {
+    boolean found = false;
+    for(Index index : _table.getIndexes()) {
+      if(ObjectUtils.equals(indexName, index.getName())) {
+        _index = index;
+        found = true;
+        break;
+      }
+    }
+    if(!found) {
+      throw new IllegalArgumentException("Index with name " + indexName +
+                                         " does not exist in table " + _table);
+    }
+    return this;
+  }
+
+  /**
+   * Sets an index to use for the cursor by searching the table for an index
+   * with exactly the given columns.
+   * @throws IllegalArgumentException if no index can be found on the table
+   *         with the given name
+   */
+  public CursorBuilder setIndexByColumns(Column... columns) {
+    List<Column> searchColumns = Arrays.asList(columns);
+    boolean found = false;
+    for(Index index : _table.getIndexes()) {
+      
+      Collection<Column> indexColumns = index.getColumns();
+      if(indexColumns.size() != searchColumns.size()) {
+        continue;
+      }
+      Iterator<Column> sIter = searchColumns.iterator();
+      Iterator<Column> iIter = indexColumns.iterator();
+      boolean matches = true;
+      while(sIter.hasNext()) {
+        Column sCol = sIter.next();
+        Column iCol = iIter.next();
+        if(!ObjectUtils.equals(sCol.getName(), iCol.getName())) {
+          matches = false;
+          break;
+        }
+      }
+
+      if(matches) {
+        _index = index;
+        found = true;
+        break;
+      }
+    }
+    if(!found) {
+      throw new IllegalArgumentException("Index with columns " +
+                                         searchColumns +
+                                         " does not exist in table " + _table);
+    }
+    return this;
+  }
+
+  /**
+   * Sets the starting row for a range based index cursor.
+   * <p>
+   * A valid index must be specified before calling this method.
+   */
+  public CursorBuilder setStartRow(Object[] startRow) {
+    _startRow = startRow;
+    return this;
+  }
+  
+  /**
+   * Sets the starting row for a range based index cursor to the given entry
+   * (where the given values correspond to the indexes columns).
+   * <p>
+   * A valid index must be specified before calling this method.
+   */
+  public CursorBuilder setStartEntry(Object... startEntry) {
+    if(startEntry != null) {
+      setStartRow(_index.constructIndexRowFromEntry(startEntry));
+    }
+    return this;
+  }
+
+  /**
+   * Sets whether the starting row for a range based index cursor is inclusive
+   * or exclusive.
+   */
+  public CursorBuilder setStartRowInclusive(boolean inclusive) {
+    _startRowInclusive = inclusive;
+    return this;
+  }
+
+  /**
+   * Sets the ending row for a range based index cursor.
+   * <p>
+   * A valid index must be specified before calling this method.
+   */
+  public CursorBuilder setEndRow(Object[] endRow) {
+    _endRow = endRow;
+    return this;
+  }
+  
+  /**
+   * Sets the ending row for a range based index cursor to the given entry
+   * (where the given values correspond to the indexes columns).
+   * <p>
+   * A valid index must be specified before calling this method.
+   */
+  public CursorBuilder setEndEntry(Object... endEntry) {
+    if(endEntry != null) {
+      setEndRow(_index.constructIndexRowFromEntry(endEntry));
+    }
+    return this;
+  }
+
+  /**
+   * Sets whether the ending row for a range based index cursor is inclusive
+   * or exclusive.
+   */
+  public CursorBuilder setEndRowInclusive(boolean inclusive) {
+    _endRowInclusive = inclusive;
+    return this;
+  }
+
+  /**
+   * Returns a new cursor for the table, constructed to the given
+   * specifications.
+   */
+  public Cursor toCursor()
+    throws IOException
+  {
+    Cursor cursor = null;
+    if(_index == null) {
+      cursor = Cursor.createCursor(_table);
+    } else {
+      cursor = Cursor.createIndexCursor(_table, _index,
+                                        _startRow, _startRowInclusive,
+                                        _endRow, _endRowInclusive);
+    }
+    if(_savepoint == null) {
+      if(!_beforeFirst) {
+        cursor.afterLast();
+      }
+    } else {
+      cursor.restoreSavepoint(_savepoint);
+    }
+    return cursor;
+  }
+  
+}
index fe128328e2a0c4e49b3a918864d99d661b71a652..5c26f6424875b5cd2d55a020f5ecf255ee2f796f 100644 (file)
@@ -705,7 +705,7 @@ public class Index implements Comparable<Index> {
    * @throws IllegalArgumentException if the wrong number of values are
    *         provided
    */
-  public Object[] constructIndexRow(Object... values)
+  public Object[] constructIndexRowFromEntry(Object... values)
   {
     if(values.length != _columns.size()) {
       throw new IllegalArgumentException(
@@ -1509,19 +1509,19 @@ public class Index implements Comparable<Index> {
       return(Index.this._modCount == _lastModCount);
     }
         
-    public EntryCursor reset() {
-      return beforeFirst();
+    public void reset() {
+      beforeFirst();
     }
 
-    public EntryCursor beforeFirst() {
-      return reset(true);
+    public void beforeFirst() {
+      reset(true);
     }
 
-    public EntryCursor afterLast() {
-      return reset(false);
+    public void afterLast() {
+      reset(false);
     }
 
-    protected EntryCursor reset(boolean moveForward) {
+    protected void reset(boolean moveForward) {
       _curPos = getDirHandler(moveForward).getBeginningPosition();
       _prevPos = _curPos;
       if(!isUpToDate()) {
@@ -1529,27 +1529,26 @@ public class Index implements Comparable<Index> {
         updateBounds();
         _lastModCount = Index.this._modCount;
       }
-      return this;
     }
 
     /**
      * Repositions the cursor so that the next row will be the first entry
      * >= the given row.
      */
-    public EntryCursor beforeEntry(Object[] row)
+    public void beforeEntry(Object[] row)
       throws IOException
     {
-      return restorePosition(new Entry(row, RowId.FIRST_ROW_ID, _columns));
+      restorePosition(new Entry(row, RowId.FIRST_ROW_ID, _columns));
     }
     
     /**
      * Repositions the cursor so that the previous row will be the first
      * entry <= the given row.
      */
-    public EntryCursor afterEntry(Object[] row)
+    public void afterEntry(Object[] row)
       throws IOException
     {
-      return restorePosition(new Entry(row, RowId.LAST_ROW_ID, _columns));
+      restorePosition(new Entry(row, RowId.LAST_ROW_ID, _columns));
     }
     
     /**
@@ -1572,14 +1571,14 @@ public class Index implements Comparable<Index> {
      * Restores a current position for the cursor (current position becomes
      * previous position).
      */
-    private EntryCursor restorePosition(Entry curEntry) {
-      return restorePosition(curEntry, _curPos.getEntry());
+    private void restorePosition(Entry curEntry) {
+      restorePosition(curEntry, _curPos.getEntry());
     }
     
     /**
      * Restores a current and previous position for the cursor.
      */
-    protected EntryCursor restorePosition(Entry curEntry, Entry prevEntry)
+    protected void restorePosition(Entry curEntry, Entry prevEntry)
     {
       if(!curEntry.equals(_curPos.getEntry()) ||
          !prevEntry.equals(_prevPos.getEntry()))
@@ -1593,7 +1592,6 @@ public class Index implements Comparable<Index> {
       } else {
         checkForModification();
       }
-      return this;
     }
 
     /**
index 830b17c27e3c717890a9609c798da128c419e952..d83c4b81d3c68fef000bb218cdf017c224866683 100644 (file)
@@ -1047,7 +1047,8 @@ public class Table
 
     // find last data page (Not bothering to check other pages for free
     // space.)
-    UsageMap.PageCursor revPageCursor = _ownedPages.cursor().afterLast();
+    UsageMap.PageCursor revPageCursor = _ownedPages.cursor();
+    revPageCursor.afterLast();
     while(true) {
       int tmpPageNumber = revPageCursor.getPreviousPage();
       if(tmpPageNumber < 0) {
index 79e772e142f29bab3116d19642f8aabf251365f9..00d87c745083fe76aa1446bd250352a047312859 100644 (file)
@@ -778,49 +778,48 @@ public class UsageMap
      * After calling this method, getNextPage will return the first page in
      * the map
      */
-    public PageCursor reset() {
-      return beforeFirst();
+    public void reset() {
+      beforeFirst();
     }
 
     /**
      * After calling this method, {@link #getNextPage} will return the first
      * page in the map
      */
-    public PageCursor beforeFirst() {
-      return reset(true);
+    public void beforeFirst() {
+      reset(true);
     }
 
     /**
      * After calling this method, {@link #getPreviousPage} will return the
      * last page in the map
      */
-    public PageCursor afterLast() {
-      return reset(false);
+    public void afterLast() {
+      reset(false);
     }
 
     /**
      * Resets this page cursor for traversing the given direction.
      */
-    protected PageCursor reset(boolean moveForward) {
+    protected void reset(boolean moveForward) {
       _curPageNumber = getDirHandler(moveForward).getBeginningPageNumber();
       _prevPageNumber = _curPageNumber;
       _lastModCount = UsageMap.this._modCount;
-      return this;
     }
 
     /**
      * Restores a current position for the cursor (current position becomes
      * previous position).
      */
-    private PageCursor restorePosition(int curPageNumber)
+    private void restorePosition(int curPageNumber)
     {
-      return restorePosition(curPageNumber, _curPageNumber);
+      restorePosition(curPageNumber, _curPageNumber);
     }
     
     /**
      * Restores a current and previous position for the cursor.
      */
-    protected PageCursor restorePosition(int curPageNumber, int prevPageNumber)
+    protected void restorePosition(int curPageNumber, int prevPageNumber)
     {
       if((curPageNumber != _curPageNumber) ||
          (prevPageNumber != _prevPageNumber))
@@ -831,7 +830,6 @@ public class UsageMap
       } else {
         checkForModification();
       }
-      return this;
     }
 
     /**
index 751c6cc8c7f51f445b80e8cb70d8879204cd1034..ad1a214de9d9089a85cc389c525e76a9b0204290 100644 (file)
@@ -101,10 +101,13 @@ public class CursorTest extends TestCase {
                                                   int type)
     throws Exception
   {
-    return Cursor.createIndexCursor(
-        table, idx,
-        idx.constructIndexRow(3 - type), (type == 0),
-        idx.constructIndexRow(8 + type), (type == 0));
+    return new CursorBuilder(table)
+      .setIndex(idx)
+      .setStartEntry(3 - type)
+      .setStartRowInclusive(type == 0)
+      .setEndEntry(8 + type)
+      .setEndRowInclusive(type == 0)
+      .toCursor();
   }
   
   public void testRowId() throws Exception {