api-pagination 4.8.1 → 4.8.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3bb99a6e4283fff7d5fa69b46f58e2b464817aa85a9377c0dee0712ec53e2966
4
- data.tar.gz: ea909de1558e7d1db8492b61cb6140acaf4b97431d77716995fd9878f4c47b1b
3
+ metadata.gz: e0006fcbe882c8a54820796eaf3d573d04b3dd2057cb9d6130b56389dff36790
4
+ data.tar.gz: b585330048fb81eb9b83c377af32ea85d3fd80afcc864b70a01426e0d51c1bf4
5
5
  SHA512:
6
- metadata.gz: 3d648ef5559a8200612186dac182f1fee3b8babb294c54762e241f41b9e7f4ffc673ba21aa51ece2dff4bfa39a17bf6b9f78d3a44bd52d2f581aba63e7a4051f
7
- data.tar.gz: 0c90a0cb15d533248f848fb590694a190b62eb13df4ddea426889740d848e9ed0d9eac64d7a5dc40b5aec222d995f91fac8070d60eea0ae3750cb6d0f48220ef
6
+ metadata.gz: e79b9e403a5a30834d9bd94e11687a79e08ac049463fe749b025dc98cd476ed11b98e0667b6e01f13315c9bf374d19fb500af6e0a98a1cecb1bf2753101be9ef
7
+ data.tar.gz: '0398d5cab6c18f426823f8d99ef02a3796380047f87c99864600cfd0ff52bb86246f4d3091f8b3d95decd1f34827323792eebe2d77502abe05bcc235a7993382'
@@ -30,7 +30,7 @@ module ApiPagination
30
30
  end
31
31
 
32
32
  unless collection.last_page? || (ApiPagination.config.paginator == :kaminari && collection.out_of_range?)
33
- pages[:last] = collection.total_pages
33
+ pages[:last] = collection.total_pages if ApiPagination.config.include_total
34
34
  pages[:next] = collection.current_page + 1
35
35
  end
36
36
  end
@@ -64,7 +64,12 @@ module ApiPagination
64
64
  end
65
65
 
66
66
  def pagy_from(collection, options)
67
- count = collection.is_a?(Array) ? collection.count : collection.count(:all)
67
+ if options[:count]
68
+ count = options[:count]
69
+ else
70
+ count = collection.is_a?(Array) ? collection.count : collection.count(:all)
71
+ end
72
+
68
73
  Pagy.new(count: count, items: options[:per_page], page: options[:page])
69
74
  end
70
75
 
@@ -76,7 +81,7 @@ module ApiPagination
76
81
  end
77
82
 
78
83
  unless pagy.page == pagy.pages
79
- pages[:last] = pagy.pages
84
+ pages[:last] = pagy.pages if ApiPagination.config.include_total
80
85
  pages[:next] = pagy.next
81
86
  end
82
87
  end
@@ -90,7 +95,9 @@ module ApiPagination
90
95
  end
91
96
 
92
97
  collection = Kaminari.paginate_array(collection, paginate_array_options) if collection.is_a?(Array)
93
- [collection.page(options[:page]).per(options[:per_page]), nil]
98
+ collection = collection.page(options[:page]).per(options[:per_page])
99
+ collection.without_count if !collection.is_a?(Array) && !ApiPagination.config.include_total
100
+ [collection, nil]
94
101
  end
95
102
 
96
103
  def paginate_with_will_paginate(collection, options)
@@ -111,24 +118,23 @@ module ApiPagination
111
118
 
112
119
  def get_default_per_page_for_kaminari(collection)
113
120
  default = Kaminari.config.default_per_page
114
- detect_model(collection).default_per_page || default
115
- rescue
116
- default
121
+ extract_per_page_from_model(collection, :default_per_page) || default
117
122
  end
118
123
 
119
124
  def default_per_page_for_will_paginate(collection)
120
125
  default = WillPaginate.per_page
121
- detect_model(collection).per_page || default
122
- rescue
123
- default
126
+ extract_per_page_from_model(collection, :per_page) || default
124
127
  end
125
128
 
126
- def detect_model(collection)
127
- if collection.respond_to?(:table_name)
128
- collection.table_name.classify.constantize
129
+ def extract_per_page_from_model(collection, accessor)
130
+ klass = if collection.respond_to?(:klass)
131
+ collection.klass
129
132
  else
130
133
  collection.first.class
131
134
  end
135
+
136
+ return unless klass.respond_to?(accessor)
137
+ klass.send(accessor)
132
138
  end
133
139
  end
134
140
  end
@@ -10,6 +10,8 @@ module ApiPagination
10
10
 
11
11
  attr_accessor :base_url
12
12
 
13
+ attr_accessor :response_formats
14
+
13
15
  def configure(&block)
14
16
  yield self
15
17
  end
@@ -20,6 +22,7 @@ module ApiPagination
20
22
  @page_header = nil
21
23
  @include_total = true
22
24
  @base_url = nil
25
+ @response_formats = [:json, :xml]
23
26
  end
24
27
 
25
28
  ['page', 'per_page'].each do |param_name|
@@ -50,7 +53,11 @@ module ApiPagination
50
53
  end
51
54
 
52
55
  def paginator
53
- @paginator || set_paginator
56
+ if instance_variable_defined? :@paginator
57
+ @paginator
58
+ else
59
+ set_paginator
60
+ end
54
61
  end
55
62
 
56
63
  def paginator=(paginator)
@@ -1,7 +1,14 @@
1
1
  begin; require 'grape'; rescue LoadError; end
2
2
  if defined?(Grape::API)
3
3
  require 'grape/pagination'
4
- Grape::API.send(:include, Grape::Pagination)
4
+
5
+ klass = if Grape::VERSION >= '1.2.0' || defined?(Grape::API::Instance)
6
+ Grape::API::Instance
7
+ else
8
+ Grape::API
9
+ end
10
+
11
+ klass.send(:include, Grape::Pagination)
5
12
  end
6
13
 
7
14
  begin; require 'pagy'; rescue LoadError; end
@@ -2,7 +2,7 @@ module ApiPagination
2
2
  class Version
3
3
  MAJOR = 4
4
4
  MINOR = 8
5
- PATCH = 1
5
+ PATCH = 2
6
6
 
7
7
  def self.to_s
8
8
  [MAJOR, MINOR, PATCH].join('.')
@@ -46,7 +46,7 @@ module Grape
46
46
  params do
47
47
  optional :page, :type => Integer, :default => 1,
48
48
  :desc => 'Page of results to fetch.'
49
- optional :per_page, :type => Integer,
49
+ optional :per_page, :type => Integer, :default => options[:per_page],
50
50
  :desc => 'Number of results to return per page.',
51
51
  :values => per_page_values
52
52
  end
@@ -8,11 +8,12 @@ module Rails
8
8
 
9
9
  return _paginate_collection(collection, options) if collection
10
10
 
11
- collection = options[:json] || options[:xml]
11
+ response_format = _discover_format(options)
12
+
13
+ collection = options[response_format]
12
14
  collection = _paginate_collection(collection, options)
13
15
 
14
- options[:json] = collection if options[:json]
15
- options[:xml] = collection if options[:xml]
16
+ options[response_format] = collection if options[response_format]
16
17
 
17
18
  render options
18
19
  end
@@ -23,6 +24,12 @@ module Rails
23
24
 
24
25
  private
25
26
 
27
+ def _discover_format(options)
28
+ for response_format in ApiPagination.config.response_formats
29
+ return response_format if options.key?(response_format)
30
+ end
31
+ end
32
+
26
33
  def _paginate_collection(collection, options={})
27
34
  options[:page] = ApiPagination.config.page_param(params)
28
35
  options[:per_page] ||= ApiPagination.config.per_page_param(params)
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+ require 'support/active_record/foo'
3
+ require 'nulldb_rspec'
4
+
5
+ ActiveRecord::Base.establish_connection(
6
+ adapter: :nulldb,
7
+ schema: 'spec/support/active_record/schema.rb'
8
+ )
9
+
10
+ NullDB.configure { |ndb| def ndb.project_root; Dir.pwd; end; }
11
+
12
+ shared_examples 'produces_correct_sql' do
13
+ it 'produces correct sql for first page' do
14
+ allow(collection).to receive(:count).and_return(collection_size)
15
+ paginated_sql, _ = ApiPagination.paginate(collection, per_page: per_page)
16
+ expect(paginated_sql.to_sql).to eql(Foo.limit(per_page).offset(0).to_sql)
17
+ end
18
+ end
19
+
20
+ describe 'ActiveRecord Support' do
21
+ let(:collection) { Foo.all }
22
+ let(:collection_size) { 50 }
23
+ let(:per_page) { 5 }
24
+
25
+ if ApiPagination.config.paginator == :will_paginate
26
+ require 'will_paginate/active_record'
27
+ end
28
+
29
+ context "pagination with #{ApiPagination.config.paginator}" do
30
+ include_examples 'produces_correct_sql'
31
+ end
32
+
33
+
34
+ if ApiPagination.config.paginator != :pagy
35
+ context 'reflections' do
36
+ it 'invokes the correct methods to determine type' do
37
+ expect(collection).to receive(:klass).at_least(:once)
38
+ .and_call_original
39
+ ApiPagination.paginate(collection)
40
+ end
41
+
42
+ it 'does not fail if table name is not snake cased class name' do
43
+ allow(collection).to receive(:table_name).and_return(SecureRandom.uuid)
44
+ expect { ApiPagination.paginate(collection) }.to_not raise_error
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+
@@ -2,23 +2,45 @@ require 'spec_helper'
2
2
 
3
3
  describe ApiPagination do
4
4
  let(:collection) {(1..100).to_a}
5
+ let(:active_record_relation) {double("ActiveRecord_Relation").as_null_object}
5
6
  let(:paginate_array_options) {{ total_count: 1000 }}
6
7
 
7
8
  describe "#paginate" do
8
9
  if ENV['PAGINATOR'].to_sym == :kaminari
9
10
  context 'Using kaminari' do
10
- it 'should accept paginate_array_options option' do
11
- expect(Kaminari).to receive(:paginate_array)
12
- .with(collection, paginate_array_options)
13
- .and_call_original
14
-
15
- ApiPagination.paginate(
16
- collection,
17
- {
18
- per_page: 30,
19
- paginate_array_options: paginate_array_options
20
- }
21
- )
11
+ describe '.paginate' do
12
+ it 'should accept paginate_array_options option' do
13
+ expect(Kaminari).to receive(:paginate_array)
14
+ .with(collection, paginate_array_options)
15
+ .and_call_original
16
+
17
+ ApiPagination.paginate(
18
+ collection,
19
+ {
20
+ per_page: 30,
21
+ paginate_array_options: paginate_array_options
22
+ }
23
+ )
24
+ end
25
+
26
+ context 'configured not to include the total' do
27
+ before { ApiPagination.config.include_total = false }
28
+
29
+ context 'and paginating an array' do
30
+ it 'should not call without_count on the collection' do
31
+ expect(collection).to_not receive :without_count
32
+ ApiPagination.paginate(collection)
33
+ end
34
+ end
35
+ context 'and paginating an active record relation' do
36
+ it 'should call without_count on the relation' do
37
+ expect(active_record_relation).to receive :without_count
38
+ ApiPagination.paginate(active_record_relation)
39
+ end
40
+ end
41
+
42
+ after { ApiPagination.config.include_total = true }
43
+ end
22
44
  end
23
45
 
24
46
  describe '.pages_from' do
@@ -5,8 +5,11 @@ require 'support/shared_examples/middle_page'
5
5
  require 'support/shared_examples/last_page'
6
6
 
7
7
  describe NumbersAPI do
8
+ it { is_expected.to be_kind_of(Grape::Pagination) }
9
+
8
10
  describe 'GET #index' do
9
- let(:links) { last_response.headers['Link'].split(', ') }
11
+ let(:link) { last_response.headers['Link'] }
12
+ let(:links) { link.split(', ') }
10
13
  let(:total) { last_response.headers['Total'].to_i }
11
14
  let(:per_page) { last_response.headers['Per-Page'].to_i }
12
15
 
@@ -139,6 +142,12 @@ describe NumbersAPI do
139
142
  expect(last_response.header['Total']).to be_nil
140
143
  end
141
144
 
145
+ it 'should not include a link with rel "last"' do
146
+ get '/numbers', count: 100
147
+
148
+ expect(link).to_not include('rel="last"')
149
+ end
150
+
142
151
  after { ApiPagination.config.include_total = true }
143
152
  end
144
153
 
@@ -8,7 +8,8 @@ describe NumbersController, :type => :controller do
8
8
  before { request.host = 'example.org' }
9
9
 
10
10
  describe 'GET #index' do
11
- let(:links) { response.headers['Link'].split(', ') }
11
+ let(:link) { response.headers['Link'] }
12
+ let(:links) { link.split(', ') }
12
13
  let(:total) { response.headers['Total'].to_i }
13
14
  let(:per_page) { response.headers['Per-Page'].to_i }
14
15
 
@@ -134,6 +135,12 @@ describe NumbersController, :type => :controller do
134
135
  expect(response.header['Total']).to be_nil
135
136
  end
136
137
 
138
+ it 'should not include a link with rel "last"' do
139
+ get :index, params: { count: 100 }
140
+
141
+ expect(link).to_not include('rel="last"')
142
+ end
143
+
137
144
  after { ApiPagination.config.include_total = true }
138
145
  end
139
146
 
@@ -255,13 +262,21 @@ describe NumbersController, :type => :controller do
255
262
  end
256
263
  end
257
264
 
265
+ after :all do
266
+ class Fixnum
267
+ class << self
268
+ undef_method :default_per_page, :per_page
269
+ end
270
+ end
271
+ end
272
+
258
273
  it 'should use default per page from model' do
259
274
  get :index_with_no_per_page, params: {count: 100}
260
275
 
261
276
  expect(response.header['Per-Page']).to eq('6')
262
277
  end
263
278
 
264
- it 'should not fail if model does not respond to per page' do
279
+ it 'should not fail if the model yields nil for per page' do
265
280
  class Fixnum
266
281
  @default_per_page = nil
267
282
  @per_page = nil
@@ -279,5 +294,19 @@ describe NumbersController, :type => :controller do
279
294
  end
280
295
  end
281
296
  end
297
+
298
+ context 'default per page in objects without paginator defaults' do
299
+ it 'should not fail if model does not respond to per page' do
300
+ get :index_with_no_per_page, params: {count: 100}
301
+
302
+ expect(response.header['Per-Page']).to eq(
303
+ case ApiPagination.config.paginator
304
+ when :pagy then Pagy::VARS[:items].to_s
305
+ when :kaminari then Kaminari.config.default_per_page.to_s
306
+ when :will_paginate then WillPaginate.per_page.to_s
307
+ end
308
+ )
309
+ end
310
+ end
282
311
  end
283
- end
312
+ end
@@ -0,0 +1,3 @@
1
+ require 'active_record'
2
+
3
+ class Foo < ActiveRecord::Base; end
@@ -0,0 +1,5 @@
1
+ ActiveRecord::Schema.define(version: 0) do
2
+ create_table "foos", :force => true do |t|
3
+ t.string "foo"
4
+ end
5
+ end
@@ -1,10 +1,10 @@
1
1
  shared_examples 'an endpoint with a first page' do
2
2
  it 'should not give a link with rel "first"' do
3
- expect(links).not_to include('rel="first"')
3
+ expect(link).not_to include('rel="first"')
4
4
  end
5
5
 
6
6
  it 'should not give a link with rel "prev"' do
7
- expect(links).not_to include('rel="prev"')
7
+ expect(link).not_to include('rel="prev"')
8
8
  end
9
9
 
10
10
  it 'should give a link with rel "last"' do
@@ -1,10 +1,10 @@
1
1
  shared_examples 'an endpoint with a last page' do
2
2
  it 'should not give a link with rel "last"' do
3
- expect(links).not_to include('rel="last"')
3
+ expect(link).not_to include('rel="last"')
4
4
  end
5
5
 
6
6
  it 'should not give a link with rel "next"' do
7
- expect(links).not_to include('rel="next"')
7
+ expect(link).not_to include('rel="next"')
8
8
  end
9
9
 
10
10
  it 'should give a link with rel "first"' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api-pagination
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.8.1
4
+ version: 4.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Celis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-25 00:00:00.000000000 Z
11
+ date: 2018-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: 4.9.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: activerecord-nulldb-adapter
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 0.3.9
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 0.3.9
83
97
  description: Link header pagination for Rails and Grape APIs
84
98
  email:
85
99
  - me@davidcel.is
@@ -94,11 +108,14 @@ files:
94
108
  - lib/api-pagination/version.rb
95
109
  - lib/grape/pagination.rb
96
110
  - lib/rails/pagination.rb
111
+ - spec/active_record_spec.rb
97
112
  - spec/api-pagination_spec.rb
98
113
  - spec/grape_spec.rb
99
114
  - spec/rails_spec.rb
100
115
  - spec/sequel_spec.rb
101
116
  - spec/spec_helper.rb
117
+ - spec/support/active_record/foo.rb
118
+ - spec/support/active_record/schema.rb
102
119
  - spec/support/numbers_api.rb
103
120
  - spec/support/numbers_controller.rb
104
121
  - spec/support/shared_examples/existing_headers.rb
@@ -132,9 +149,12 @@ summary: Link header pagination for Rails and Grape APIs. Don't use the request
132
149
  test_files:
133
150
  - spec/spec_helper.rb
134
151
  - spec/api-pagination_spec.rb
152
+ - spec/active_record_spec.rb
135
153
  - spec/sequel_spec.rb
136
154
  - spec/support/numbers_api.rb
137
155
  - spec/support/numbers_controller.rb
156
+ - spec/support/active_record/foo.rb
157
+ - spec/support/active_record/schema.rb
138
158
  - spec/support/shared_examples/first_page.rb
139
159
  - spec/support/shared_examples/middle_page.rb
140
160
  - spec/support/shared_examples/last_page.rb