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.
- data/.gitignore +2 -0
- data/.travis.yml +6 -0
- data/Gemfile +11 -0
- data/MIT-LICENSE +21 -0
- data/README.md +18 -0
- data/Rakefile +5 -0
- data/lib/mongoid-pagination.rb +2 -0
- data/lib/mongoid/pagination.rb +95 -0
- data/lib/mongoid/pagination/version.rb +5 -0
- data/mongoid-pagination.gemspec +23 -0
- data/spec/pagination_spec.rb +245 -0
- data/spec/spec_helper.rb +16 -0
- metadata +77 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -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
|
+
|
data/README.md
ADDED
@@ -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
|
+
```
|
data/Rakefile
ADDED
@@ -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,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
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -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
|