Permalink
Browse files

add Mongoid support

  • Loading branch information...
1 parent a6caca5 commit ee44ac3f2ec332bdcce8c9ff856a8ac411b536a6 @dbackeus dbackeus committed with Oct 24, 2011
Showing with 187 additions and 0 deletions.
  1. +1 −0 Gemfile
  2. +8 −0 Gemfile.lock
  3. +46 −0 lib/will_paginate/mongoid.rb
  4. +132 −0 spec/finders/mongoid_spec.rb
View
1 Gemfile
@@ -15,6 +15,7 @@ gem 'dm-core'
gem 'dm-aggregates'
gem 'dm-migrations'
gem 'dm-sqlite-adapter'
+gem 'mongoid'
group :mysql do
gem 'mysql', '~> 2.8.1'
View
8 Gemfile.lock
@@ -25,6 +25,7 @@ GEM
addressable (2.2.6)
archive-tar-minitar (0.5.2)
arel (3.0.2)
+ bson (1.6.4)
builder (3.0.4)
columnize (0.3.5)
data_objects (0.10.7)
@@ -53,6 +54,12 @@ GEM
linecache19 (0.5.12)
ruby_core_source (>= 0.1.4)
mocha (0.9.12)
+ mongo (1.6.2)
+ bson (~> 1.6.2)
+ mongoid (2.4.11)
+ activemodel (~> 3.1)
+ mongo (<= 1.6.2)
+ tzinfo (~> 0.3.22)
multi_json (1.5.0)
mysql (2.8.1)
mysql2 (0.3.11)
@@ -111,6 +118,7 @@ DEPENDENCIES
dm-migrations
dm-sqlite-adapter
mocha (~> 0.9.8)
+ mongoid
mysql (~> 2.8.1)
mysql2 (>= 0.3.6)
pg (~> 0.11)
View
46 lib/will_paginate/mongoid.rb
@@ -0,0 +1,46 @@
+require 'mongoid'
+require 'will_paginate/collection'
+
+module WillPaginate
+ module Mongoid
+ module CriteriaMethods
+ def paginate(options = {})
+ extend CollectionMethods
+ @current_page = WillPaginate::PageNumber(options[:page] || @current_page || 1)
+ @page_multiplier = current_page - 1
+ pp = (options[:per_page] || per_page || WillPaginate.per_page).to_i
+ limit(pp).skip(@page_multiplier * pp)
+ end
+
+ def per_page(value = :non_given)
+ if value == :non_given
+ options[:limit] == 0 ? nil : options[:limit] # in new Mongoid versions a nil limit is saved as 0
+ else
+ limit(value)
+ end
+ end
+
+ def page(page)
+ paginate(:page => page)
+ end
+ end
+
+ module CollectionMethods
+ attr_reader :current_page
+
+ def total_entries
+ @total_entries ||= count
+ end
+
+ def total_pages
+ (total_entries / per_page.to_f).ceil
+ end
+
+ def offset
+ @page_multiplier * per_page
+ end
+ end
+
+ ::Mongoid::Criteria.send(:include, CriteriaMethods)
+ end
+end
View
132 spec/finders/mongoid_spec.rb
@@ -0,0 +1,132 @@
+require 'spec_helper'
+require 'will_paginate/mongoid'
+
+Mongoid.database = Mongo::Connection.new.db('will_paginate_test')
+
+class MongoidModel
+ include Mongoid::Document
+end
+
+describe WillPaginate::Mongoid do
+ before(:all) do
+ MongoidModel.delete_all
+ 4.times { MongoidModel.create! }
+ end
+
+ let(:criteria) { MongoidModel.criteria }
+
+ describe "#page" do
+ it "should forward to the paginate method" do
+ criteria.expects(:paginate).with(:page => 2).returns("itself")
+ criteria.page(2).should == "itself"
+ end
+
+ it "should not override per_page if set earlier in the chain" do
+ criteria.paginate(:per_page => 10).page(1).per_page.should == 10
+ criteria.paginate(:per_page => 20).page(1).per_page.should == 20
+ end
+ end
+
+ describe "#per_page" do
+ it "should set the limit if given an argument" do
+ criteria.per_page(10).options[:limit].should == 10
+ end
+
+ it "should return the current limit if no argument is given" do
+ criteria.per_page.should == nil
+ criteria.per_page(10).per_page.should == 10
+ end
+
+ it "should be interchangable with limit" do
+ criteria.limit(15).per_page.should == 15
+ end
+
+ it "should be nil'able" do
+ criteria.per_page(nil).per_page.should be_nil
+ end
+ end
+
+ describe "#paginate" do
+ it "should use criteria" do
+ criteria.paginate.should be_instance_of(::Mongoid::Criteria)
+ end
+
+ it "should not override page number if set earlier in the chain" do
+ criteria.page(3).paginate.current_page.should == 3
+ end
+
+ it "should limit according to per_page parameter" do
+ criteria.paginate(:per_page => 10).options.should include(:limit => 10)
+ end
+
+ it "should skip according to page and per_page parameters" do
+ criteria.paginate(:page => 2, :per_page => 5).options.should include(:skip => 5)
+ end
+
+ specify "first fallback value for per_page option is the current limit" do
+ criteria.limit(12).paginate.options.should include(:limit => 12)
+ end
+
+ specify "second fallback value for per_page option is WillPaginate.per_page" do
+ criteria.paginate.options.should include(:limit => WillPaginate.per_page)
+ end
+
+ specify "page should default to 1" do
+ criteria.paginate.options.should include(:skip => 0)
+ end
+
+ it "should convert strings to integers" do
+ criteria.paginate(:page => "2", :per_page => "3").options.should include(:limit => 3, :limit => 3)
+ end
+
+ describe "collection compatibility" do
+ describe "#total_count" do
+ it "should be calculated correctly" do
+ criteria.paginate(:per_page => 1).total_entries.should == 4
+ criteria.paginate(:per_page => 3).total_entries.should == 4
+ end
+
+ it "should be cached" do
+ criteria.expects(:count).once.returns(123)
+ criteria.paginate
+ 2.times { criteria.total_entries.should == 123 }
+ end
+ end
+
+ it "should calculate total_pages" do
+ criteria.paginate(:per_page => 1).total_pages.should == 4
+ criteria.paginate(:per_page => 3).total_pages.should == 2
+ criteria.paginate(:per_page => 10).total_pages.should == 1
+ end
+
+ it "should return per_page" do
+ criteria.paginate(:per_page => 1).per_page.should == 1
+ criteria.paginate(:per_page => 5).per_page.should == 5
+ end
+
+ describe "#current_page" do
+ it "should return current_page" do
+ criteria.paginate(:page => 1).current_page.should == 1
+ criteria.paginate(:page => 3).current_page.should == 3
+ end
+
+ it "should be casted to PageNumber" do
+ criteria.paginate(:page => 1).current_page.should be_instance_of(WillPaginate::PageNumber)
+ end
+ end
+
+ it "should return offset" do
+ criteria.paginate(:page => 1).offset.should == 0
+ criteria.paginate(:page => 2, :per_page => 5).offset.should == 5
+ criteria.paginate(:page => 3, :per_page => 10).offset.should == 20
+ end
+
+ it "should not pollute plain mongoid criterias" do
+ %w(total_entries total_pages current_page).each do |method|
+ criteria.should_not respond_to(method)
+ end
+ criteria.offset.should be_nil # this is already a criteria method
+ end
+ end
+ end
+end

0 comments on commit ee44ac3

Please sign in to comment.