package org.commcare.models.database;
import android.database.Cursor;
import org.commcare.modern.database.DatabaseHelper;
import org.javarosa.core.services.storage.IStorageIterator;
import org.javarosa.core.services.storage.Persistable;
import org.javarosa.core.services.storage.StorageModifiedException;
import java.util.Iterator;
/**
* @author ctsims
*/
public class SqlStorageIterator<T extends Persistable> implements IStorageIterator, Iterator<T> {
final Cursor c;
protected final SqlStorage<T> storage;
private boolean isClosedByProgress = false;
private final int count;
private final String primaryId;
/**
* only for use by subclasses which re-implement this behavior strategically (Note: Should be an interface pullout
* not a subclass)
*/
SqlStorageIterator(Cursor cursor) {
this.c = cursor;
storage = null;
primaryId = null;
count = -1;
}
public SqlStorageIterator(Cursor c, SqlStorage<T> storage) {
this(c, storage, null);
}
/**
* Creates an iterator into either a full or partial sql storage.
*
* @param c The uninitialized cursor for a query.
* @param storage The storage being queried
* @param primaryId An optional key index for a primary id that is part
* of the returned iterator
*/
public SqlStorageIterator(Cursor c, SqlStorage<T> storage, String primaryId) {
this.c = c;
this.storage = storage;
this.primaryId = primaryId;
count = c.getCount();
if (count == 0) {
c.close();
isClosedByProgress = true;
} else {
c.moveToFirst();
}
}
@Override
public boolean hasMore() {
if (!c.isClosed()) {
return !c.isAfterLast();
} else {
if (isClosedByProgress) {
return false;
} else {
//If we didn't close the cursor as part of the iterator, it means that it
//was forcibly invalidated externally, fail accordingly.
throw new StorageModifiedException("Storage Iterator [" + storage.table + "]" + " was invalidated");
}
}
}
@Override
public int nextID() {
int id = c.getInt(c.getColumnIndexOrThrow(DatabaseHelper.ID_COL));
c.moveToNext();
if (c.isAfterLast()) {
c.close();
isClosedByProgress = true;
}
return id;
}
@Override
public T nextRecord() {
byte[] data = c.getBlob(c.getColumnIndexOrThrow(DatabaseHelper.DATA_COL));
return storage.newObject(data, nextID());
}
@Override
public int numRecords() {
return count;
}
@Override
public boolean hasNext() {
return hasMore();
}
@Override
public T next() {
return nextRecord();
}
@Override
public void remove() {
//Unsupported for now
}
@Override
public int peekID() {
return c.getInt(c.getColumnIndexOrThrow(DatabaseHelper.ID_COL));
}
public String getPrimaryId() {
return c.getString(c.getColumnIndexOrThrow(primaryId));
}
}