low-level APIでTODOリストサービスを作ってみた。

昨日、low-level APIを試してみたんだけど。めちゃシンプルで分かりやすいってことがやってみて分かった。
low-level APIを使ったデータアクセス - ありの日記
そこで、low-level APIを使ったお得意のTODOリストサービスを作ってみた。あんまりむつかしいことはしてないんだけど、基本的な操作は一通りやってるはず。前回のTODOリストにはなかったページング機能を実装。と言っても、ユーザ管理とか何もないから。いや、みんなで共有して使えるというソーシャルなんとか的なアレがあるかも。

例によってSlim3で作って見ました。最初low-level APIを試すだけなら生のServletにそのまま書いてもいいかなと思ってたんだけど、やっぱりSlim3でやった方が色々はやそうなので、こっちにしました。やっぱりHOT reloadingが使えるのってメリット大きい。他にもControllerが使えること。web.xmlにURLマッピング書いたり、定義をしなくてもクラス名とパッケージからそのサービスにアクセスするURLに勝手にマッピングしてくれたり、
asStringやasIntegerとかのパラメータ取得用のメソッドやその他便利な機能が用意されてるってのって重要。余計なこと(余計ではないんだけど、あんまり生産的じゃなかったり、車輪の再発明だったり)になるべく気をとられずに色々出来るってことを考えると、やっぱ生ServletよりもSlim3で、ってなるよね。

そして、作ったTODOリストサービスはこんな感じ。

今回はページングの他にカテゴリもつけられるようにしました。CategoryというKindが親で、TodoというKindが子になっているEntity Groupを作っています。やっつけコードな所はスルーしてください。以下は、上記画面のTODOの一覧を取得する部分。

    private static final Integer PAGE_COUNT = 5;
    
    @Override
    public Navigation run() {
        DatastoreService datastoreService =
            DatastoreServiceFactory.getDatastoreService();
        // 検索
        Query q = new Query("Todo"); // KIND:Todoを検索
        q.addSort("done"); // doneでソートする
        PreparedQuery pq = datastoreService.prepare(q);
        // 総件数(このメソッドが返す結果件数は最大1000なのでそれを越える場合、
        // 別の方法を考える
        Integer count = pq.countEntities();
        
        // ページング処理
        Integer page = asInteger("page");
        if (page == null || page < 0) page = 0;
        if (page != null && page * PAGE_COUNT >= count) page = page - 1;
        Integer offset = page * PAGE_COUNT;
        
        requestScope("count", count);
        requestScope("page", page);
        
        // データの取得処理
        List<Entity> result = pq.asList(
                FetchOptions.Builder.withOffset(offset) // オフセットを指定
                .limit(PAGE_COUNT));                    // リミットを指定
        
        // JSPで使えるように結果をBeanMapに詰め替え
        List<BeanMap> list = new ArrayList<BeanMap>();
        for (Entity e : result) {
            Entity category = null;
            try {
                // 親Entity(カテゴリ)を取得
                // Enity#getParentで親のキーを取得
                category = datastoreService.get(e.getParent());
            } catch (EntityNotFoundException e1) {
                e1.printStackTrace();
            }
            
            BeanMap m = new BeanMap();
            m.put("key", KeyFactory.keyToString(e.getKey()));
            m.put("category", category.getProperty("name"));
            m.put("content", e.getProperty("content"));
            Boolean done = (Boolean) e.getProperty("done");
            if (done) {
                m.put("done", "完了済");
            } else {
                m.put("done", "未");
            }
            list.add(m);
        }
        requestScope("list", list);
        return forward("index.jsp");
    }

しかし、簡単に出来る。JDOを初めてやったときのはまりようを考えたら天と地ほどの差があるような。まぁ、当時はBigtableもよく分かってなかったっては大きいけど。

このサンプルのソースコードGoogle Codeのページからダウンロード出来ます。
Google Code Archive - Long-term storage for Google Code Project Hosting.

さて、Slim3がlow-level APIに対応したみたい。
Google グループ
ついにこの時がきた。よかった昨日low-level APIの勉強始めて!wこれで、Slim3の方もすぐに使えれば嬉しいな。
きっと、生のlow-level APIを使うときに気になるタイプセーフじゃないアレとかがタイプセーフなアレになるんだろうな。wktk