QueryOptionState state = (QueryOptionState)query.option(QueryOptionState.ID);
QueryOptionFetchType fetchType = (QueryOptionFetchType)query.option(QueryOptionFetchType.ID);
FetchOptions fetchOptions = FetchOptions.Builder.withDefaults();
QueryOptionPage pag = (QueryOptionPage)query.option(QueryOptionPage.ID);
if(!pag.isPaginating()){
// no pagination but pageOption active
if(pag.isActive()){
// if local limit is set, it overrides the pageOption.pageSize
if(limit!=Integer.MAX_VALUE){
gaeCtx.realPageSize = limit;
fetchOptions.limit(gaeCtx.realPageSize);
// pageOption is passivated to be sure it is not reused
pag.passivate();
}
// using pageOption.pageSize
else {
gaeCtx.realPageSize = pag.pageSize;
fetchOptions.limit(gaeCtx.realPageSize);
// passivates the pageOption in stateless mode not to keep anything between 2 requests
if(state.isStateless()){
pag.passivate();
}
}
}
else {
if(limit != Integer.MAX_VALUE){
gaeCtx.realPageSize = limit;
fetchOptions.limit(gaeCtx.realPageSize);
}
}
}else {
// paginating so use the pagesize and don't passivate pageOption
// local limit is not taken into account
gaeCtx.realPageSize = pag.pageSize;
fetchOptions.limit(gaeCtx.realPageSize);
}
QueryOptionOffset off = (QueryOptionOffset)query.option(QueryOptionOffset.ID);
// if local offset has been set, uses it
if(offset!=0){
off.activate();
off.offset = offset;
}
// if previousPage has detected there is no more data, simply returns an empty list
if(gaeCtx.noMoreDataBefore){
return new ArrayList<T>();
}
if(state.isStateless()) {
if(pag.isPaginating()){
if(off.isActive()){
gaeCtx.realOffset+=off.offset;
fetchOptions.offset(gaeCtx.realOffset);
off.passivate();
}else {
fetchOptions.offset(gaeCtx.realOffset);
}
}else {
// if stateless and not paginating, resets the realoffset to 0
gaeCtx.realOffset = 0;
if(off.isActive()){
gaeCtx.realOffset=off.offset;
fetchOptions.offset(gaeCtx.realOffset);
off.passivate();
}
}
switch(fetchType.fetchType){
case KEYS_ONLY:
{
// uses iterable as it is the only async request for prepared query for the time being
List<Entity> entities = prepareKeysOnly(query).asList(fetchOptions);
// if paginating and 0 results then no more data else resets noMoreDataAfter
if(pag.isPaginating()){
if(entities.size() == 0){
gaeCtx.noMoreDataAfter = true;
}
else {
gaeCtx.noMoreDataAfter = false;
}
}
return mapKeysOnly(query, entities);
}
case NORMAL:
default:
{
// uses iterable as it is the only async request for prepared query for the time being
List<Entity> entities = prepare(query).asList(fetchOptions);
// if paginating and 0 results then no more data else resets noMoreDataAfter
if(pag.isPaginating()){
if(entities.size() == 0){
gaeCtx.noMoreDataAfter = true;
}
else {
gaeCtx.noMoreDataAfter = false;
}
}
return map(query, entities);
}
}
}else {
if(off.isActive()){
// by default, we add the offset but it can be added with the realoffset
// in case of cursor desactivated
fetchOptions.offset(off.offset);
gaeCtx.realOffset+=off.offset;
off.passivate();
}
// manages cursor limitations for IN and != operators with offsets
if(!gaeCtx.isActive()){
// cursor not yet created
switch(fetchType.fetchType){
case KEYS_ONLY:
{
PreparedQuery pq = prepareKeysOnly(query);
if(!gaeCtx.useCursor){
// then uses offset (in case of IN or != operators)
//if(offset.isActive()){
// fetchOptions.offset(gaeCtx.realOffset);
//}
fetchOptions.offset(gaeCtx.realOffset);
}
// we can't use real asynchronous function with cursors
// so the page is extracted at once and wrapped into a SienaFuture
QueryResultList<Entity> entities = pq.asQueryResultList(fetchOptions);
// activates the GaeCtx now that it is initialised
gaeCtx.activate();
// sets the current cursor (in stateful mode, cursor is always kept for further use)
if(pag.isPaginating()){
Cursor cursor = entities.getCursor();
if(cursor!=null){
gaeCtx.addCursor(cursor.toWebSafeString());
}
// if paginating and 0 results then no more data else resets noMoreDataAfter
if(entities.size()==0){
gaeCtx.noMoreDataAfter = true;
} else {
gaeCtx.noMoreDataAfter = false;
}
}else{
Cursor cursor = entities.getCursor();
if(cursor!=null){
gaeCtx.addAndMoveCursor(entities.getCursor().toWebSafeString());
}
// keeps track of the offset anyway if not paginating
gaeCtx.realOffset+=entities.size();
}
return mapKeysOnly(query, entities);
}
case NORMAL:
default:
{
PreparedQuery pq = prepare(query);
if(!gaeCtx.useCursor){
// then uses offset (in case of IN or != operators)
//if(offset.isActive()){
// fetchOptions.offset(gaeCtx.realOffset);
//}
fetchOptions.offset(gaeCtx.realOffset);
}
// we can't use real asynchronous function with cursors
// so the page is extracted at once and wrapped into a SienaFuture
QueryResultList<Entity> entities = pq.asQueryResultList(fetchOptions);
// activates the GaeCtx now that it is initialised
gaeCtx.activate();
// sets the current cursor (in stateful mode, cursor is always kept for further use)
if(pag.isPaginating()){
Cursor cursor = entities.getCursor();
if(cursor!=null){
gaeCtx.addCursor(cursor.toWebSafeString());
}
// if paginating and 0 results then no more data else resets noMoreDataAfter
if(entities.size()==0){
gaeCtx.noMoreDataAfter = true;
} else {
gaeCtx.noMoreDataAfter = false;
}
}else{
Cursor cursor = entities.getCursor();
if(cursor!=null){
gaeCtx.addAndMoveCursor(entities.getCursor().toWebSafeString());
}
// keeps track of the offset anyway if not paginating
gaeCtx.realOffset+=entities.size();
}
return map(query, entities);
}
}
}else {
switch(fetchType.fetchType){
case KEYS_ONLY:
{
// we prepare the query each time
PreparedQuery pq = prepareKeysOnly(query);
QueryResultList<Entity> entities;
if(!gaeCtx.useCursor){
// then uses offset (in case of IN or != operators)
//if(offset.isActive()){
// fetchOptions.offset(gaeCtx.realOffset);
//}
fetchOptions.offset(gaeCtx.realOffset);
// we can't use real asynchronous function with cursors
// so the page is extracted at once and wrapped into a SienaFuture
entities = pq.asQueryResultList(fetchOptions);
}else {
// we can't use real asynchronous function with cursors
// so the page is extracted at once and wrapped into a SienaFuture
String cursor = gaeCtx.currentCursor();
if(cursor!=null){
entities = pq.asQueryResultList(
fetchOptions.startCursor(Cursor.fromWebSafeString(cursor)));
}
else {
entities = pq.asQueryResultList(fetchOptions);
}
}
// sets the current cursor (in stateful mode, cursor is always kept for further use)
if(pag.isPaginating()){
Cursor cursor = entities.getCursor();
if(cursor!=null){
gaeCtx.addCursor(cursor.toWebSafeString());
}
// if paginating and 0 results then no more data else resets noMoreDataAfter
if(entities.size()==0){
gaeCtx.noMoreDataAfter = true;
} else {
gaeCtx.noMoreDataAfter = false;
}
}else{
Cursor cursor = entities.getCursor();
if(cursor!=null){
gaeCtx.addAndMoveCursor(entities.getCursor().toWebSafeString());
}
// keeps track of the offset anyway if not paginating
gaeCtx.realOffset+=entities.size();
}
//}
return mapKeysOnly(query, entities);
}
case NORMAL:
default:
{
PreparedQuery pq = prepare(query);
QueryResultList<Entity> entities;
if(!gaeCtx.useCursor){
// then uses offset (in case of IN or != operators)
//if(offset.isActive()){
// fetchOptions.offset(gaeCtx.realOffset);
//}
fetchOptions.offset(gaeCtx.realOffset);
// we can't use real asynchronous function with cursors
// so the page is extracted at once and wrapped into a SienaFuture
entities = pq.asQueryResultList(fetchOptions);
}else {
// we can't use real asynchronous function with cursors
// so the page is extracted at once and wrapped into a SienaFuture
String cursor = gaeCtx.currentCursor();
if(cursor!=null){
entities = pq.asQueryResultList(
fetchOptions.startCursor(Cursor.fromWebSafeString(gaeCtx.currentCursor())));
}else {
entities = pq.asQueryResultList(fetchOptions);
}
}
// sets the current cursor (in stateful mode, cursor is always kept for further use)
if(pag.isPaginating()){
Cursor cursor = entities.getCursor();
if(cursor!=null){
gaeCtx.addCursor(cursor.toWebSafeString());
}
// if paginating and 0 results then no more data else resets noMoreDataAfter