[開発][CouchDB] System::PageList ウィジェット実装完了、ただしCouchDB依存のバグ付き。

一覧系をCouchDBで実装する際のテストもかねてつくりました。とりあえず分かったのは、0.8.0から0.9.0への変更点で、クエリのoffsetにバグが混入されたっぽい。


CouchDBはクエリに対して、トータルのドキュメント数と、現在返したドキュメントのオフセットを返してくれるので、それを使えばクライアントサイドでページング処理がそこそこ難しいけれどもシンプルに(簡単にとはとてもいえない)実装できます。

なのでライブラリ自体にこのページング処理機能を持たせてしまおうと思って、自作Object Couch Mapperに実装した。@http://www.webjourney.org/svn/trunk/vendor/plugins/couch_resource/lib/couch_resource/base.rb

        path = view_path(design, view, options)
        logger.debug "CouchResource::Connection#get #{path}"
        result = self.connection.get(path)
        logger.debug result.to_json
        # set paginate infomation
        # [TODO] more complex case.
        if result[:rows].length > 0
          row_count   = result[:rows].length
          total_count = result[:total_rows]
          offset      = result[:offset]
          fetch_count = options[:count]
          #
          # if reduce is executed total_count and offset is not returned.
          #
          if !fetch_count.nil? && !total_count.nil? && !offset.nil?
            option_desc = options.has_key?(:descending) && options[:descending]
            more_previous, more_next = false, false
            # Direction handling
            # judge descending otpion
            # judge whether more resources exist or not.
            #
            # ** NOTES FOR THE CURRENT IMPLEMENTATION **
            # Sometimes paginate feature returns unexpected option.
            # It seems to be caused by CouchDB BUG (Couch-135)
            # keep watching on http://issues.apache.org/jira/browse/COUCHDB-135
            #
            if paginate_option[:previous]
              # if previous direction, then turn around the descending parameter
              result[:rows].reverse!
              option_desc = !option_desc
              more_previous = (total_count == row_count + offset) ? false : true
              more_next     = (offset == 0) ? false : true
            else
              more_previous = (offset == 0) ? false : true
              more_next     = (total_count == row_count + offset) ? false : true
            end

            if more_next
              result[:next] = {
                :startkey        => result[:rows].last["key"],
                :startkey_docid  => result[:rows].last["id"],
                :count           => options[:count] || result[:rows].length,
                :skip            => 1,
                :descending      => option_desc
              }
            end
            if more_previous
              result[:previous] = {
                :startkey        => result[:rows].first["key"],
                :startkey_docid  => result[:rows].first["id"],
                :count           => options[:count] || result[:rows].length,
                :skip            => 1,
                :descending      => !option_desc,
                :previous        => true
              }
            end

な具合に返されるハッシュに:next, :previous をくっつけて、「次のページ」を得る際にCouchDBに渡すべきオプションを自動的に計算してくれるようにしたかったわけです。

テストケースはこんな感じ。@http://www.webjourney.org/svn/trunk/vendor/plugins/couch_resource/test/test_base.rb

10件のドキュメントが登録されているとして、4件ずつページングするような場合、

    # retrive documents per 4 docs.
    # 0..3
    docs = SimpleDocument.simple_document_all( "all_by_title", :count => 4)
    # 4..7
    docs = SimpleDocument.simple_document_all( "all_by_title", docs[:next])
    # 8..9
    docs = SimpleDocument.simple_document_all( "all_by_title", docs[:next])
    # previous (should return 4 docs before title_8)
    # 4..7
    docs = SimpleDocument.simple_document_all( "all_by_title", docs[:previous])

このテストケースが、うまく通る場合とうまく通らない場合がある。いやいやおいおい、と思って、いろいろ確認しているのですが、http://issues.apache.org/jira/browse/COUCHDB-135 にあがっているような感じで、どうもオフセット値で正しくない値を返す場合があるらしい。。。

そんなぁ、て感じでCouch側のソースコード確認中ですが、これは正直、直るのを座して待ちたい。