[開発][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 にあがっているような感じで、どうもオフセット値で正しくない値を返す場合があるらしい。。。