api-pagination 4.8.1 → 4.8.2

Sign up to get free protection for your applications and to get access to all the features.
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