banjo-mongoid-pagination 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ .rspec
2
+ Gemfile.lock
@@ -0,0 +1,6 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - ree
5
+ - ruby-head
6
+ - rbx
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ gem 'bson_ext'
6
+ gem 'rake'
7
+
8
+ group :test do
9
+ gem 'rspec'
10
+ gem 'rspec-rails-mocha'
11
+ end
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2012 Alex Sharp
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
@@ -0,0 +1,18 @@
1
+ ## What
2
+
3
+ Adds pagination scopes to your mongoid models.
4
+
5
+ ## Usage
6
+
7
+ ```ruby
8
+ class Person
9
+ include Mongoid::Document
10
+ include Mongoid::Pagination
11
+
12
+ default_page_size 20
13
+ end
14
+
15
+ Person.paginate(:page => 2, :limit => 25) # limit and page
16
+ Person.paginate(:offset => 20, :limit => 25) # limit and offset
17
+ Person.per_page(25) # just does a limit
18
+ ```
@@ -0,0 +1,5 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ RSpec::Core::RakeTask.new(:spec)
4
+
5
+ task :default => :spec
@@ -0,0 +1,2 @@
1
+ require 'mongoid'
2
+ require 'mongoid/pagination'
@@ -0,0 +1,95 @@
1
+ module Mongoid
2
+ module Pagination
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+
7
+ def page_size
8
+ @page_size || 25
9
+ end
10
+
11
+ def page_size=(page_size)
12
+ @page_size = page_size
13
+ end
14
+
15
+ # Paginate the results
16
+ #
17
+ # @param [Hash] opts
18
+ # @option [Integer] :page (default: 1)
19
+ # @option [Integer] :offset (default: 0)
20
+ # @option [Integer] :limit (default: 25)
21
+ #
22
+ # @return [Mongoid::Criteria]
23
+ def paginated_criteria(opts = {})
24
+ limit = (opts[:limit] || page_size).to_i
25
+ offset = paginate_offset(opts)
26
+
27
+ per_page(limit).offset(offset)
28
+ end
29
+
30
+ def paginate(opts = {})
31
+
32
+ criteria = paginated_criteria(opts)
33
+ limit = criteria.options[:limit]
34
+ criteria.options[:limit] += 1
35
+
36
+ over_fetched_collection = criteria.to_a
37
+ has_more_results = over_fetched_collection.size > limit
38
+
39
+ over_fetched_collection.pop if has_more_results
40
+
41
+ @paginated_collection = ::Mongoid::Pagination::Collection.new(over_fetched_collection)
42
+ @paginated_collection.current_offset = criteria.options[:skip]
43
+ @paginated_collection.current_page_size = limit
44
+ @paginated_collection.has_more_results = has_more_results
45
+
46
+ preload(opts[:eager_load]) if opts[:eager_load].present?
47
+
48
+ @paginated_collection
49
+ end
50
+
51
+ def preload(args)
52
+ return unless args.present? && @paginated_collection.present?
53
+
54
+ relations.select { |k,v| args.map(&:to_s).include?(k) }.each_pair do |name,meta|
55
+ field_key = meta.key
56
+ ids = @paginated_collection.map { |c| c.send(field_key.to_sym) }.compact
57
+ meta.class_name.constantize.any_in(_id: ids).to_a if ids.present?
58
+ end
59
+ end
60
+
61
+ # Limit the result set
62
+ #
63
+ # @param [Integer] page_limit the max number of results to return
64
+ # @return [Mongoid::Criteria]
65
+ def per_page(page_limit = page_size)
66
+ limit(page_limit.to_i)
67
+ end
68
+
69
+ def paginate_offset(opts = {})
70
+ case
71
+ when opts[:page] && (page = opts[:page].to_i) > 0 then (page - 1) * (opts[:limit] || page_size).to_i
72
+ when opts[:offset] && (offset = opts[:offset].to_i) >= 0 then offset
73
+ else 0
74
+ end
75
+ end
76
+
77
+ def paginated_collection
78
+ @paginated_collection
79
+ end
80
+ end
81
+
82
+ class Collection < Array
83
+ attr_accessor :current_offset, :current_page_size, :has_more_results
84
+
85
+ def next_offset_at
86
+ current_offset + current_page_size
87
+ end
88
+
89
+ def next_offset
90
+ has_more_results ? next_offset_at : nil
91
+ end
92
+ end
93
+ end
94
+ end
95
+
@@ -0,0 +1,5 @@
1
+ module Mongoid
2
+ module Pagination
3
+ VERSION = '1.0.0'
4
+ end
5
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "mongoid/pagination/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "banjo-mongoid-pagination"
7
+ s.version = Mongoid::Pagination::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Alex Sharp", "KW Justin Leung"]
10
+ s.email = ["ajsharp@gmail.com", "justin@teambanjo.com"]
11
+ s.homepage = "https://github.com/BanjoInc/mongoid-pagination"
12
+ s.summary = %q{A simple pagination module for Mongoid}
13
+ s.description = %q{A simple pagination module for Mongoid}
14
+
15
+ s.rubyforge_project = s.name
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency 'mongoid'
23
+ end
@@ -0,0 +1,245 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::Pagination do
4
+ class Group
5
+ include Mongoid::Document
6
+
7
+ has_many :persons
8
+ end
9
+
10
+ class Person
11
+ include Mongoid::Document
12
+ include Mongoid::Pagination
13
+
14
+ belongs_to :group
15
+ end
16
+
17
+ describe ".page_size" do
18
+ class Person_50
19
+ include Mongoid::Document
20
+ include Mongoid::Pagination
21
+
22
+ self.page_size = 50
23
+ end
24
+
25
+ it 'returns configured default page size' do
26
+ Person.page_size.should == 25
27
+ Person_50.page_size.should == 50
28
+ end
29
+ end
30
+
31
+ describe ".paginate" do
32
+ let!(:group) { Group.create! }
33
+ let!(:one) { Person.create!(group: group) }
34
+ let!(:two) { Person.create!(group: group) }
35
+
36
+ context 'without eager loading' do
37
+ subject { Person.paginate(offset: 0, limit: 2) }
38
+
39
+ it 'is an paginated array' do
40
+ subject.should be_kind_of(Mongoid::Pagination::Collection)
41
+ end
42
+
43
+ context 'for less than a page' do
44
+ it 'returns page size' do
45
+ subject.size.should == 2
46
+ subject.has_more_results.should == false
47
+ subject.next_offset.should be_nil
48
+ subject.next_offset_at.should == 2
49
+ end
50
+ end
51
+ end
52
+
53
+ context 'with eager loading' do
54
+ subject { Person.paginate(offset: 0, limit: 2, eager_load: [ :group ]) }
55
+
56
+ it 'is an paginated array' do
57
+ subject.should be_kind_of(Mongoid::Pagination::Collection)
58
+ end
59
+
60
+ context 'for less than a page' do
61
+ it 'returns page size' do
62
+ Group.expects(:any_in).once.returns([group])
63
+ subject.size.should == 2
64
+ subject.has_more_results.should == false
65
+ subject.next_offset.should be_nil
66
+ subject.next_offset_at.should == 2
67
+ end
68
+ end
69
+
70
+ context 'for more than a page' do
71
+ let!(:three) { Person.create!(group: group) }
72
+ let!(:four) { Person.create!(group: group) }
73
+
74
+ it 'overfetched by 1' do
75
+ Group.expects(:any_in).once.returns([group])
76
+ subject.size.should == 2
77
+ subject.has_more_results.should == true
78
+ subject.next_offset.should == 2
79
+ subject.next_offset_at.should == 2
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ describe ".paginated_criteria" do
86
+ let!(:one) { Person.create! }
87
+ let!(:two) { Person.create! }
88
+ let!(:three) { Person.create! }
89
+ let!(:four) { Person.create! }
90
+
91
+ context "parameter defaults and massaging" do
92
+ describe "when no params are passed in" do
93
+ subject { Person.paginated_criteria }
94
+
95
+ it "does not set the skip param by default" do
96
+ subject.options[:skip].should == 0
97
+ end
98
+
99
+ it "defaults the limit param to 25" do
100
+ subject.options[:limit].should == 25
101
+ end
102
+
103
+ it "returns the criteria unmodified if the limit param is not passed in" do
104
+ criteria = Person.where(:name => 'someone')
105
+ expect {
106
+ criteria.paginated_criteria
107
+ }.not_to change { criteria.options }
108
+ end
109
+ end
110
+
111
+ describe "when passed a page param but no limit" do
112
+ subject { Person.paginated_criteria(:page => 1) }
113
+
114
+ it "defaults the limit to 25" do
115
+ subject.options[:limit].should == 25
116
+ end
117
+
118
+ it "sets the offset to 0" do
119
+ subject.options[:skip].should == 0
120
+ end
121
+ end
122
+
123
+ describe "when passed an offset param but no limit" do
124
+ subject { Person.paginated_criteria(:offset => 0) }
125
+
126
+ it "defaults the limit to 25" do
127
+ subject.options[:limit].should == 25
128
+ end
129
+
130
+ it "sets the offset to 0" do
131
+ subject.options[:skip].should == 0
132
+ end
133
+ end
134
+
135
+ describe "when passed a limit param but no page nor offset" do
136
+ subject { Person.paginated_criteria(:limit => 100) }
137
+
138
+ it "defaults the offset to 0" do
139
+ subject.options[:skip].should == 0
140
+ end
141
+
142
+ it "sets the limit to 100" do
143
+ subject.options[:limit].should == 100
144
+ end
145
+ end
146
+
147
+ describe "when passed both page and offset, offset is ignored" do
148
+ subject { Person.paginated_criteria(:page => 2, :offset => 1) }
149
+
150
+ it "sets the skip to 25" do
151
+ subject.options[:skip].should == 25
152
+ end
153
+ end
154
+
155
+ context 'with page param' do
156
+ it "sets the skip param to 0 if passed 0" do
157
+ Person.paginated_criteria(:page => 0).options[:skip].should == 0
158
+ end
159
+
160
+ it "sets the skip param to 0 if passed a string of 0" do
161
+ Person.paginated_criteria(:page => '0').options[:skip].should == 0
162
+ end
163
+
164
+ it "sets the skip param to 0 if the passed a string of 1" do
165
+ Person.paginated_criteria(:page => '1').options[:skip].should == 0
166
+ end
167
+
168
+ it "limits when passed a string param" do
169
+ Person.paginated_criteria(:limit => '1').to_a.size.should == 1
170
+ end
171
+
172
+ it "correctly sets criteria options" do
173
+ Person.paginated_criteria(:limit => 10, :page => 3).options.should == {:limit => 10, :skip => 20}
174
+ end
175
+ end
176
+
177
+ context 'with offset param' do
178
+ it "sets the skip param to 0 if passed 0" do
179
+ Person.paginated_criteria(:offset => 0).options[:skip].should == 0
180
+ end
181
+
182
+ it "sets the skip param to 0 if passed a string of 0" do
183
+ Person.paginated_criteria(:offset=> '0').options[:skip].should == 0
184
+ end
185
+
186
+ it "sets the skip param to 1 if the passed a string of 1" do
187
+ Person.paginated_criteria(:offset => '1').options[:skip].should == 1
188
+ end
189
+
190
+ it "sets the skip param with page even if offset is passed as 1" do
191
+ Person.paginated_criteria(:offset => '1', :page => '2').options[:skip].should == 25
192
+ end
193
+
194
+ it "correctly sets criteria options" do
195
+ Person.paginated_criteria(:limit => 10, :offset => 3).options.should == {:limit => 10, :skip => 3}
196
+ end
197
+ end
198
+ end
199
+
200
+ context "results" do
201
+ context "with page param" do
202
+ it "paginates correctly on the first page" do
203
+ Person.paginated_criteria(:page => 1, :limit => 2).to_a.should == [one, two]
204
+ end
205
+
206
+ it "paginates correctly on the second page" do
207
+ Person.paginated_criteria(:page => 2, :limit => 2).to_a.should == [three, four]
208
+ end
209
+ end
210
+
211
+ context "with offset param" do
212
+ it "paginates correctly on the first page" do
213
+ Person.paginated_criteria(:offset => 0, :limit => 2).to_a.should == [one, two]
214
+ end
215
+
216
+ it "paginates correctly on the second page" do
217
+ Person.paginated_criteria(:offset => 2, :limit => 2).to_a.should == [three, four]
218
+ end
219
+ end
220
+ end
221
+
222
+ it "paginates the result set based on the limit and page params" do
223
+ # Person.
224
+ end
225
+ end
226
+
227
+ describe ".per_page" do
228
+ before do
229
+ 2.times { Person.create! }
230
+ end
231
+
232
+ it "limits the results by the per page param" do
233
+ Person.per_page(1).to_a.size.should == 1
234
+ end
235
+
236
+ it "works for string params" do
237
+ Person.per_page('1').to_a.size.should == 1
238
+ end
239
+
240
+ it "defaults to 25" do
241
+ Person.per_page.options[:limit].should == 25
242
+ end
243
+ end
244
+ end
245
+
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.setup :default, :test
5
+ Bundler.require :default, :test
6
+
7
+ $:.push(File.expand_path(File.dirname(__FILE__)))
8
+ require './lib/mongoid-pagination'
9
+
10
+ Mongoid.database = Mongo::Connection.new.db('mongoid-pagination_test')
11
+
12
+ RSpec.configure do |c|
13
+ c.before(:each) do
14
+ Mongoid.database.collections.each { |c| c.drop unless c.name =~ /system\.indexes$/}
15
+ end
16
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: banjo-mongoid-pagination
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Alex Sharp
9
+ - KW Justin Leung
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2013-04-26 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: mongoid
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ description: A simple pagination module for Mongoid
32
+ email:
33
+ - ajsharp@gmail.com
34
+ - justin@teambanjo.com
35
+ executables: []
36
+ extensions: []
37
+ extra_rdoc_files: []
38
+ files:
39
+ - .gitignore
40
+ - .travis.yml
41
+ - Gemfile
42
+ - MIT-LICENSE
43
+ - README.md
44
+ - Rakefile
45
+ - lib/mongoid-pagination.rb
46
+ - lib/mongoid/pagination.rb
47
+ - lib/mongoid/pagination/version.rb
48
+ - mongoid-pagination.gemspec
49
+ - spec/pagination_spec.rb
50
+ - spec/spec_helper.rb
51
+ homepage: https://github.com/BanjoInc/mongoid-pagination
52
+ licenses: []
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ requirements: []
70
+ rubyforge_project: banjo-mongoid-pagination
71
+ rubygems_version: 1.8.23
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: A simple pagination module for Mongoid
75
+ test_files:
76
+ - spec/pagination_spec.rb
77
+ - spec/spec_helper.rb