package siena.gae;
import java.lang.reflect.Field;
import java.util.Iterator;
import siena.ClassInfo;
import siena.core.async.QueryAsync;
import siena.core.options.QueryOptionPage;
import com.google.appengine.api.datastore.Cursor;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.QueryResultIterable;
import com.google.appengine.api.datastore.QueryResultIterator;
/**
* @author mandubian <pascal.voitot@mandubian.org>
*
* A Siena Iterable<Model> encapsulating a GAE Iterable<Entity> with its Iterator in asynchronous mode<Model>...
*/
public class GaeSienaIterableAsyncWithCursor<Model> implements Iterable<Model> {
QueryResultIterable<Entity> gaeIterable;
QueryAsync<Model> query;
GaePersistenceManagerAsync pm;
GaeSienaIterableAsyncWithCursor(GaePersistenceManagerAsync pm, QueryResultIterable<Entity> gaeIterable, QueryAsync<Model> query) {
this.gaeIterable = gaeIterable;
this.query = query;
this.pm = pm;
}
public Iterator<Model> iterator() {
return new SienaGaeIteratorAsyncWithCursor<Model>(query, gaeIterable);
}
public class SienaGaeIteratorAsyncWithCursor<T> implements Iterator<T> {
Field id;
QueryAsync<T> query;
QueryResultIterator<Entity> gaeIterator;
SienaGaeIteratorAsyncWithCursor(QueryAsync<T> query, QueryResultIterable<Entity> gaeIterable) {
this.query = query;
this.id = ClassInfo.getIdField(query.getQueriedClass());
this.gaeIterator = gaeIterable.iterator();
// if paginating and 0 results then no more data else resets noMoreDataAfter
QueryOptionPage pag = (QueryOptionPage)query.option(QueryOptionPage.ID);
QueryOptionGaeContext gaeCtx = (QueryOptionGaeContext)query.option(QueryOptionGaeContext.ID);
if(pag.isPaginating()){
if(!gaeIterator.hasNext()){
gaeCtx.noMoreDataAfter = true;
}else {
gaeCtx.noMoreDataAfter = false;
}
}
}
public boolean hasNext() {
return gaeIterator.hasNext();
}
public T next() {
Entity entity = gaeIterator.next();
QueryOptionGaeContext gaeCtx = (QueryOptionGaeContext)query.option(QueryOptionGaeContext.ID);
// overrides current cursor with the current iterator cursor
// sets the current cursor (in stateful mode, cursor is always kept for further use)
Cursor cursor = gaeIterator.getCursor();
if(cursor!=null) {
gaeCtx.setCurrentCursor(cursor.toWebSafeString());
}
// keeps track of the offset anyway if not paginating
//QueryOptionOffset offset = (QueryOptionOffset)query.option(QueryOptionOffset.ID);
gaeCtx.realOffset++;
T obj = pm.map(query, entity);
return obj;
}
public void remove() {
gaeIterator.remove();
}
}
}