slim3(GAE/J)で検索条件で絞り込んだ結果に対してのページング

問題

gaeではページングをしようとしてoffsetに1000以上の値をセットすると、以下のようなエラーになってしまう。

 java.lang.IllegalArgumentException: offset may not be above 1000

当然gae上のフレームワークであるslim3で以下のように書いても同じこと。

Datastore.query(meta)
  .offset(1000)

以下のページでやり方を紹介しているが、この方法は全件検索の結果に対してしか有効ではない。
http://code.google.com/intl/ja/appengine/articles/paging.html

また、カーソルを使ったやり方も紹介されているが、それって「次へ」っていうナビゲーションしかないページングでは使えるけど、それ以外のページングにも使えるのか?
http://sites.google.com/site/slim3documentja/documents/slim3-datastore/queries-and-indexes#TOC-20

ちなみに環境は下記

  • gaeは1.3.2
  • slim3は1.0.1

というわけで

というわけで、slim3のModelQueryを拡張したクラスと、それを返す以下のようなクラスを作った。
これでアプリ側では以下のような形で1000を超えたoffsetでも気にせずページングをさせることができる。

MyDatastore.query(meta)
  .offset(1000)
  .limit(50)
package nanzokore.datastore;

import org.slim3.datastore.ModelMeta;
import org.slim3.datastore.ModelQuery;

public class MyDatastore {
    public static <M> ModelQuery<M> query(ModelMeta<M> modelMeta){
        return new MyModelQuery<M>(modelMeta);
    }
}
package nanzokore.datastore;

import java.util.List;

import org.slim3.datastore.ModelMeta;
import org.slim3.datastore.ModelQuery;

import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Transaction;

public class MyModelQuery<M> extends ModelQuery<M>{

    protected static final int MAXIMUM = 1000;
    
    protected Integer offset = 0;
    
    protected Integer limit = 0;
    
    public MyModelQuery(ModelMeta<M> modelMeta) throws NullPointerException {
        super(modelMeta);
    }

    public MyModelQuery(ModelMeta<M> modelMeta, Key ancestorKey)
            throws NullPointerException {
        super(modelMeta, ancestorKey);
    }

    public MyModelQuery(Transaction tx, ModelMeta<M> modelMeta, Key ancestorKey)
            throws NullPointerException {
        super(tx, modelMeta, ancestorKey);
    }
    
    @Override
    public ModelQuery<M> offset(int offset) {
        this.offset = offset;
        return this; 
    }
    
    @Override
    public ModelQuery<M> limit(int limit) {
        this.limit = limit;
        return this;   
    }
    
    @Override
    public List<M> asList() {
      super.offset(0);
      super.limit(Integer.MAX_VALUE);
      List<M> entries = super.asList();
      int lastIndex = entries.size();
      int fromIndex = Math.min(this.offset, lastIndex);
      int toIndex = (limit == 0) ? 
          lastIndex : Math.min(offset + limit, lastIndex);
      return new ArrayList<M>(entries.subList(fromIndex, toIndex));
  }
}

備考

バグってたらすいません。教えていただけるとうれしいです。
(2010/04/25)InMemorySortができていなかったので、修正した。