banjo-mongoid-pagination 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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