Skip to content

Instantly share code, notes, and snippets.

@karmi
Created July 29, 2010 13:54
Show Gist options
  • Select an option

  • Save karmi/498177 to your computer and use it in GitHub Desktop.

Select an option

Save karmi/498177 to your computer and use it in GitHub Desktop.
WillPaginate adapter for paginating CouchPotato views
# = WillPaginate adapter for CouchPotato views
#
# Pagination for CouchPotato[http://github.com/langalex/couch_potato] views
# compatible with the will_paginate[http://github.com/mislav/will_paginate] gem.
#
# See http://github.com/mislav/will_paginate/blob/rails3/lib/will_paginate/finders/data_mapper.rb
# for example adapter.
#
# Just `require` this file in your code and you'll have the `paginate` method available.
#
# TODO: Research if pagination can be done via "fast pagination" as described in
# http://books.couchdb.org/relax/reference/recipes#Pagination.
# We need the "Jump to Page" functionality for WillPaginate.
#
# TODO: Make ordering work (descending=true, have to flip startkey/endkey etc)
#
require 'rubygems'
require 'will_paginate/finders/base'
require 'couch_potato'
module CouchPotato
module View
class BaseViewSpec
# Allow manipulation of view_parameters
attr_writer :view_parameters
end
end
end
module WillPaginate::Finders
module CouchPotato
include WillPaginate::Finders::Base
# Return WillPaginate collection for the passed CouchPotato view, so you can use the
# fine-tuned view helper with automatic CSS classes, pagination links, etc.
#
# Example:
# --------
#
# In the controller:
#
# @articles = CouchPotato.database.paginate Article.all, :page => params[:page], :per_page => 50
#
# In the view:
#
# <%= will_paginate @articles %>
#
def paginate(spec, options={}, &block)
options[:page] ||= 1
page, per_page, total_entries = wp_parse_options(options)
WillPaginate::Collection.create(page, per_page, total_entries) do |pager|
query_options = options.except :page, :per_page, :total_entries, :page_params
wp_query(spec, query_options, pager, &block)
end
end
# Return count of all documents for the passed view.
#
# Example:
# --------
#
# @CouchPotato.database.count Article.all
#
def count(spec)
# FIXME: Why `view_parameters.update ...` does not work?
spec.view_parameters = spec.view_parameters.merge({ :reduce => true, :include_docs => false })
view(spec) || 0
end
protected
def wp_query(spec, options, pager, &block) #:nodoc
query_options = { :limit => pager.per_page,
:skip => pager.offset }
paginated_spec = spec.dup
paginated_spec.view_parameters = paginated_spec.view_parameters.merge(query_options)
collection = view(paginated_spec)
pager.replace collection
pager.total_entries = collection.total_rows
end
end
end
CouchPotato::Database.send(:include, WillPaginate::Finders::CouchPotato)
if $0 == __FILE__ # Launch `ruby couch_potato_pagination.rb` to run test suite
require 'test/unit'
require 'shoulda'
class CouchPotato::PaginationWithWillPaginate < Test::Unit::TestCase
class ::Article
include CouchPotato::Persistence
property :title
property :author
view :all, :key => :title
end
def setup
CouchPotato::Config.database_name = 'couchpotato-pagination-test'
CouchPotato.couchrest_database.recreate!
50.times do |i|
CouchPotato.database.save_document Article.new(:title => "Article #{ '%.3d' % (i+1) }", :author => 'John Smith')
end
end
def teardown
CouchPotato.couchrest_database.delete!
end
context "CouchPotato database" do
should "have the paginate method" do
assert_respond_to CouchPotato.database, :paginate
end
should "return the count of documents" do
assert_respond_to CouchPotato.database, :count
assert_equal 50, CouchPotato.database.count(Article.all)
end
should "return zero count when there are no documents" do
CouchPotato.couchrest_database.recreate!
assert_equal 0, CouchPotato.database.count(Article.all)
end
should "return paginated collection of records" do
collection = CouchPotato.database.paginate Article.all, :per_page => 20
assert_respond_to collection, :each
assert_equal 20, collection.size
end
should "raise NoMethodError when paginate method is called with non-existing view" do
assert_raise(NoMethodError) { CouchPotato.database.paginate Article.krupitzowka }
end
should "return default WillPaginate::Collection from paginate method" do
collection = CouchPotato.database.paginate Article.all
assert_instance_of WillPaginate::Collection, collection
assert_equal 30, collection.size
assert_equal 50, collection.total_entries
end
should "allow to set options for paginate method" do
collection = CouchPotato.database.paginate Article.all, :per_page => 5
assert_equal 5, collection.size
assert_equal 50, collection.total_entries
end
end
context "When paginating articles, it" do
should "allow to move in paginated collection" do
collection = CouchPotato.database.paginate Article.all, :per_page => 5
assert_equal 'Article 001', collection.first.title
collection = CouchPotato.database.paginate Article.all, :page => collection.next_page, :per_page => 5
assert_equal 'Article 006', collection.first.title
collection = CouchPotato.database.paginate Article.all, :page => collection.next_page, :per_page => 5
assert_equal 'Article 011', collection.first.title
collection = CouchPotato.database.paginate Article.all, :page => collection.previous_page, :per_page => 5
assert_equal 'Article 006', collection.first.title
collection = CouchPotato.database.paginate Article.all, :page => 5, :per_page => 5
assert_equal 'Article 021', collection.first.title
collection = CouchPotato.database.paginate Article.all, :page => 11, :per_page => 5
assert collection.empty?, "#{collection.inspect} should be empty"
assert collection.out_of_bounds?, "Should be out of bounds"
end
should "give total entries" do
collection = CouchPotato.database.paginate Article.all, :page => 2, :per_page => 5
assert_equal 50, collection.total_entries
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment