lhs 5.3.0 → 5.4.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.
- checksums.yaml +4 -4
- data/README.md +36 -3
- data/lib/lhs/concerns/record/all.rb +1 -3
- data/lib/lhs/concerns/record/batch.rb +1 -1
- data/lib/lhs/concerns/record/chainable.rb +61 -1
- data/lib/lhs/concerns/record/pagination.rb +9 -5
- data/lib/lhs/pagination.rb +17 -6
- data/lib/lhs/version.rb +1 -1
- data/spec/pagination/pages_left_spec.rb +1 -1
- data/spec/record/pagination_chain_spec.rb +92 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 80529532ef8aaafcbe7822abac42c0082f2b2b32
|
4
|
+
data.tar.gz: f3b872fa678981d24ccfdcc24af642a397cffac4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bbfea24429cac66bfc5684d31411ed975456d52be8110df299dcd762b2771205e4827b9fcb183305e9444cd0f3e3165fc8b3cf055c5352504f485fbb45cd890a
|
7
|
+
data.tar.gz: 47678b919459a2a896995a01588d1c29876982324872d889dbef21297ff57dc76674561fae8d1f98062ab6dc6e93058c9e9cd608b1cb373c89db4a23b1c3a3c0
|
data/README.md
CHANGED
@@ -449,7 +449,7 @@ unless user.valid?
|
|
449
449
|
end
|
450
450
|
```
|
451
451
|
|
452
|
-
##
|
452
|
+
## Pagination
|
453
453
|
|
454
454
|
LHS supports paginated APIs and it also supports various pagination strategies and by providing configuration possibilities.
|
455
455
|
|
@@ -520,6 +520,40 @@ end
|
|
520
520
|
|
521
521
|
In case of paginated resources it's important to know the difference between [count vs. length](#count-vs-length)
|
522
522
|
|
523
|
+
### Pagination Chains
|
524
|
+
|
525
|
+
You can use chainable pagination in combination with query chains:
|
526
|
+
|
527
|
+
```ruby
|
528
|
+
class Record < LHS::Record
|
529
|
+
endpoint 'http://local.ch/records'
|
530
|
+
end
|
531
|
+
Record.page(3).per(20).where(color: 'blue')
|
532
|
+
# http://local.ch/records?offset=40&limit=20&color=blue
|
533
|
+
```
|
534
|
+
|
535
|
+
The applied pagination strategy depends on the actual configured pagination, so the interface is the same for all strategies:
|
536
|
+
|
537
|
+
```ruby
|
538
|
+
class Record < LHS::Record
|
539
|
+
endpoint 'http://local.ch/records'
|
540
|
+
configuration pagination_strategy: 'page'
|
541
|
+
end
|
542
|
+
Record.page(3).per(20).where(color: 'blue')
|
543
|
+
# http://local.ch/records?page=3&limit=20&color=blue
|
544
|
+
```
|
545
|
+
|
546
|
+
```ruby
|
547
|
+
class Record < LHS::Record
|
548
|
+
endpoint 'http://local.ch/records'
|
549
|
+
configuration pagination_strategy: 'start'
|
550
|
+
end
|
551
|
+
Record.page(3).per(20).where(color: 'blue')
|
552
|
+
# http://local.ch/records?start=41&limit=20&color=blue
|
553
|
+
```
|
554
|
+
|
555
|
+
`limit(argument)` is an alias for `per(argument)`. Take notice that `limit` without argument instead, makes the query resolve and provides the current limit from the responds.
|
556
|
+
|
523
557
|
### Partial Kaminari support
|
524
558
|
|
525
559
|
LHS implements an interface that makes it partially working with Kaminari.
|
@@ -531,8 +565,7 @@ The kaminari’s page parameter is in params[:page]. For example, you can use ka
|
|
531
565
|
params[:page] = 0 if params[:page].nil?
|
532
566
|
page = params[:page].to_i
|
533
567
|
limit = 100
|
534
|
-
|
535
|
-
@items = Record.where({ limit: limit, offset: offset }))
|
568
|
+
@items = Record.page(page).per(limit)
|
536
569
|
```
|
537
570
|
|
538
571
|
```ruby
|
@@ -5,8 +5,6 @@ class LHS::Record
|
|
5
5
|
module All
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
|
-
DEFAULT_LIMIT = 100
|
9
|
-
|
10
8
|
module ClassMethods
|
11
9
|
# Should be an edge case but sometimes all objects from a certain resource
|
12
10
|
# are required. In this case we load the first page with the default max limit,
|
@@ -14,7 +12,7 @@ class LHS::Record
|
|
14
12
|
# for the following pages and concatenate all the results in order to return
|
15
13
|
# all the objects for a given resource.
|
16
14
|
def all(params = {})
|
17
|
-
limit = params[limit_key] || DEFAULT_LIMIT
|
15
|
+
limit = params[limit_key] || LHS::Pagination::DEFAULT_LIMIT
|
18
16
|
data = request(params: params.merge(limit_key => limit))
|
19
17
|
request_all_the_rest(data, params) if paginated?(data._raw)
|
20
18
|
data._record.new(LHS::Data.new(data, nil, self))
|
@@ -20,7 +20,7 @@ class LHS::Record
|
|
20
20
|
def find_in_batches(options = {})
|
21
21
|
fail 'No block given' unless block_given?
|
22
22
|
start = options[:start] || 1
|
23
|
-
batch_size = options[:batch_size] ||
|
23
|
+
batch_size = options[:batch_size] || LHS::Pagination::DEFAULT_LIMIT
|
24
24
|
params = options[:params] || {}
|
25
25
|
loop do # as suggested by Matz
|
26
26
|
data = request(params: params.merge(limit: batch_size, offset: start))
|
@@ -18,6 +18,18 @@ class LHS::Record
|
|
18
18
|
def options(hash = nil)
|
19
19
|
Chain.new(self, Option.new(hash))
|
20
20
|
end
|
21
|
+
|
22
|
+
def page(page)
|
23
|
+
Chain.new(self, Pagination.new(page: page))
|
24
|
+
end
|
25
|
+
|
26
|
+
def per(limit)
|
27
|
+
Chain.new(self, Pagination.new(per: limit))
|
28
|
+
end
|
29
|
+
|
30
|
+
def limit(argument = nil)
|
31
|
+
Chain.new(self, Pagination.new(per: argument))
|
32
|
+
end
|
21
33
|
end
|
22
34
|
|
23
35
|
# Link: A part of a chain
|
@@ -26,6 +38,10 @@ class LHS::Record
|
|
26
38
|
@hash = hash
|
27
39
|
end
|
28
40
|
|
41
|
+
def [](parameter)
|
42
|
+
@hash[parameter]
|
43
|
+
end
|
44
|
+
|
29
45
|
def to_hash
|
30
46
|
@hash
|
31
47
|
end
|
@@ -39,6 +55,10 @@ class LHS::Record
|
|
39
55
|
class Option < Link
|
40
56
|
end
|
41
57
|
|
58
|
+
# Pagination: Part of the chain that will be used to controll pagination
|
59
|
+
class Pagination < Link
|
60
|
+
end
|
61
|
+
|
42
62
|
# A sequence of links
|
43
63
|
class Chain
|
44
64
|
|
@@ -99,6 +119,19 @@ class LHS::Record
|
|
99
119
|
push Option.new(hash)
|
100
120
|
end
|
101
121
|
|
122
|
+
def page(page)
|
123
|
+
push Pagination.new(page: page)
|
124
|
+
end
|
125
|
+
|
126
|
+
def per(per)
|
127
|
+
push Pagination.new(per: per)
|
128
|
+
end
|
129
|
+
|
130
|
+
def limit(argument = nil)
|
131
|
+
return resolve.limit if argument.blank?
|
132
|
+
push Pagination.new(per: argument)
|
133
|
+
end
|
134
|
+
|
102
135
|
def find(args)
|
103
136
|
@record_class.find(args, chain_options)
|
104
137
|
end
|
@@ -117,6 +150,11 @@ class LHS::Record
|
|
117
150
|
chain_options
|
118
151
|
end
|
119
152
|
|
153
|
+
# Returns a hash of pagination values
|
154
|
+
def pagination_values_hash
|
155
|
+
chain_pagination
|
156
|
+
end
|
157
|
+
|
120
158
|
protected
|
121
159
|
|
122
160
|
def method_missing(name, *args, &block)
|
@@ -132,7 +170,10 @@ class LHS::Record
|
|
132
170
|
|
133
171
|
def resolve
|
134
172
|
@resolved ||= @record_class.new(
|
135
|
-
@record_class.request(
|
173
|
+
@record_class.request(
|
174
|
+
chain_options
|
175
|
+
.merge(params: chain_parameters.merge(chain_pagination))
|
176
|
+
)
|
136
177
|
)
|
137
178
|
end
|
138
179
|
|
@@ -151,6 +192,25 @@ class LHS::Record
|
|
151
192
|
merge_links @chain.select { |link| link.is_a? Option }
|
152
193
|
end
|
153
194
|
|
195
|
+
def chain_pagination
|
196
|
+
resolve_pagination @chain.select { |link| link.is_a? Pagination }
|
197
|
+
end
|
198
|
+
|
199
|
+
def resolve_pagination(links)
|
200
|
+
return {} if links.empty?
|
201
|
+
page = 1
|
202
|
+
per = LHS::Pagination::DEFAULT_LIMIT
|
203
|
+
links.each do |link|
|
204
|
+
page = link[:page] if link[:page].present?
|
205
|
+
per = link[:per] if link[:per].present?
|
206
|
+
end
|
207
|
+
pagination = @record_class.pagination_class
|
208
|
+
{
|
209
|
+
@record_class.pagination_key => pagination.page_to_offset(page, per),
|
210
|
+
@record_class.limit_key => per
|
211
|
+
}
|
212
|
+
end
|
213
|
+
|
154
214
|
def merge_links(links)
|
155
215
|
hash = {}
|
156
216
|
links.each do |link|
|
@@ -12,16 +12,20 @@ class LHS::Record
|
|
12
12
|
end
|
13
13
|
|
14
14
|
module ClassMethods
|
15
|
-
def
|
16
|
-
case
|
15
|
+
def pagination_class
|
16
|
+
case pagination_strategy.to_sym
|
17
17
|
when :page
|
18
|
-
PagePagination
|
18
|
+
LHS::PagePagination
|
19
19
|
when :start
|
20
|
-
StartPagination
|
20
|
+
LHS::StartPagination
|
21
21
|
else
|
22
|
-
OffsetPagination
|
22
|
+
LHS::OffsetPagination
|
23
23
|
end
|
24
24
|
end
|
25
|
+
|
26
|
+
def pagination(data)
|
27
|
+
pagination_class.new(data)
|
28
|
+
end
|
25
29
|
end
|
26
30
|
end
|
27
31
|
end
|
data/lib/lhs/pagination.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Pagination is used to navigate paginateable collections
|
2
|
-
class Pagination
|
2
|
+
class LHS::Pagination
|
3
|
+
|
4
|
+
DEFAULT_LIMIT = 100
|
3
5
|
|
4
6
|
delegate :_record, to: :data
|
5
7
|
attr_accessor :data
|
@@ -18,7 +20,7 @@ class Pagination
|
|
18
20
|
end
|
19
21
|
|
20
22
|
def limit
|
21
|
-
data._raw[_record.limit_key.to_sym] || LHS::
|
23
|
+
data._raw[_record.limit_key.to_sym] || LHS::Pagination::DEFAULT_LIMIT
|
22
24
|
end
|
23
25
|
|
24
26
|
def offset
|
@@ -62,9 +64,13 @@ class Pagination
|
|
62
64
|
def total_pages
|
63
65
|
(total.to_f / limit).ceil
|
64
66
|
end
|
67
|
+
|
68
|
+
def self.page_to_offset(page, _limit)
|
69
|
+
page
|
70
|
+
end
|
65
71
|
end
|
66
72
|
|
67
|
-
class PagePagination < Pagination
|
73
|
+
class LHS::PagePagination < LHS::Pagination
|
68
74
|
|
69
75
|
def current_page
|
70
76
|
offset
|
@@ -73,10 +79,9 @@ class PagePagination < Pagination
|
|
73
79
|
def next_offset
|
74
80
|
current_page + 1
|
75
81
|
end
|
76
|
-
|
77
82
|
end
|
78
83
|
|
79
|
-
class StartPagination < Pagination
|
84
|
+
class LHS::StartPagination < LHS::Pagination
|
80
85
|
|
81
86
|
def current_page
|
82
87
|
(offset + limit - 1) / limit
|
@@ -86,9 +91,12 @@ class StartPagination < Pagination
|
|
86
91
|
offset + limit
|
87
92
|
end
|
88
93
|
|
94
|
+
def self.page_to_offset(page, limit = LHS::Pagination::DEFAULT_LIMIT)
|
95
|
+
(page - 1) * limit + 1
|
96
|
+
end
|
89
97
|
end
|
90
98
|
|
91
|
-
class OffsetPagination < Pagination
|
99
|
+
class LHS::OffsetPagination < LHS::Pagination
|
92
100
|
|
93
101
|
def current_page
|
94
102
|
(offset + limit) / limit
|
@@ -98,4 +106,7 @@ class OffsetPagination < Pagination
|
|
98
106
|
offset + limit
|
99
107
|
end
|
100
108
|
|
109
|
+
def self.page_to_offset(page, limit = LHS::Pagination::DEFAULT_LIMIT)
|
110
|
+
(page - 1) * limit
|
111
|
+
end
|
101
112
|
end
|
data/lib/lhs/version.rb
CHANGED
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe LHS::Record do
|
4
|
+
context 'pagination chain' do
|
5
|
+
context 'default pagination (offset)' do
|
6
|
+
before(:each) do
|
7
|
+
class Record < LHS::Record
|
8
|
+
endpoint 'http://local.ch/records'
|
9
|
+
endpoint 'http://local.ch/records/:id'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'allows to chain pagination methods' do
|
14
|
+
request = stub_request(:get, "http://local.ch/records?color=blue&offset=200&limit=100").to_return(body: [].to_json)
|
15
|
+
Record.where(color: 'blue').page(3).first
|
16
|
+
expect(request).to have_been_made.times(1)
|
17
|
+
request = stub_request(:get, "http://local.ch/records?color=blue&offset=20&limit=10").to_return(body: [].to_json)
|
18
|
+
Record.where(color: 'blue').page(3).per(10).first
|
19
|
+
Record.where(color: 'blue').per(10).page(3).first
|
20
|
+
Record.where(color: 'blue').per(20).page(5).per(10).page(3).first
|
21
|
+
expect(request).to have_been_made.times(3)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'allows to start chains with pagination methods' do
|
25
|
+
request = stub_request(:get, "http://local.ch/records?color=blue&offset=200&limit=100").to_return(body: [].to_json)
|
26
|
+
Record.page(3).where(color: 'blue').first
|
27
|
+
expect(request).to have_been_made.times(1)
|
28
|
+
request = stub_request(:get, "http://local.ch/records?color=blue&offset=20&limit=10").to_return(body: [].to_json)
|
29
|
+
Record.page(3).per(10).where(color: 'blue').first
|
30
|
+
Record.per(10).page(3).where(color: 'blue').first
|
31
|
+
Record.per(20).page(5).where(color: 'blue').per(10).page(3).first
|
32
|
+
expect(request).to have_been_made.times(3)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'defaults page to 1' do
|
36
|
+
request = stub_request(:get, "http://local.ch/records?limit=10&offset=0").to_return(body: [].to_json)
|
37
|
+
Record.per(10).first
|
38
|
+
Record.per(10).page("").first
|
39
|
+
expect(request).to have_been_made.times(2)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'provides limit as alias for per' do
|
43
|
+
request = stub_request(:get, "http://local.ch/records?limit=10&offset=0").to_return(body: [].to_json)
|
44
|
+
Record.limit(10).first
|
45
|
+
Record.page("").limit(10).first
|
46
|
+
expect(request).to have_been_made.times(2)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'start pagination' do
|
51
|
+
before(:each) do
|
52
|
+
class Record < LHS::Record
|
53
|
+
configuration pagination_strategy: 'start', pagination_key: 'start'
|
54
|
+
endpoint 'http://local.ch/records'
|
55
|
+
endpoint 'http://local.ch/records/:id'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'allows to chain pagination methods' do
|
60
|
+
request = stub_request(:get, "http://local.ch/records?color=blue&start=201&limit=100").to_return(body: [].to_json)
|
61
|
+
Record.where(color: 'blue').page(3).first
|
62
|
+
expect(request).to have_been_made.times(1)
|
63
|
+
request = stub_request(:get, "http://local.ch/records?color=blue&start=21&limit=10").to_return(body: [].to_json)
|
64
|
+
Record.where(color: 'blue').page(3).per(10).first
|
65
|
+
Record.where(color: 'blue').per(10).page(3).first
|
66
|
+
Record.where(color: 'blue').per(20).page(5).per(10).page(3).first
|
67
|
+
expect(request).to have_been_made.times(3)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'page pagination' do
|
72
|
+
before(:each) do
|
73
|
+
class Record < LHS::Record
|
74
|
+
configuration pagination_strategy: 'page', pagination_key: 'page'
|
75
|
+
endpoint 'http://local.ch/records'
|
76
|
+
endpoint 'http://local.ch/records/:id'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'allows to chain pagination methods' do
|
81
|
+
request = stub_request(:get, "http://local.ch/records?color=blue&page=3&limit=100").to_return(body: [].to_json)
|
82
|
+
Record.where(color: 'blue').page(3).first
|
83
|
+
expect(request).to have_been_made.times(1)
|
84
|
+
request = stub_request(:get, "http://local.ch/records?color=blue&page=3&limit=10").to_return(body: [].to_json)
|
85
|
+
Record.where(color: 'blue').page(3).per(10).first
|
86
|
+
Record.where(color: 'blue').per(10).page(3).first
|
87
|
+
Record.where(color: 'blue').per(20).page(5).per(10).page(3).first
|
88
|
+
expect(request).to have_been_made.times(3)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lhs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- https://github.com/local-ch/lhs/graphs/contributors
|
@@ -304,6 +304,7 @@ files:
|
|
304
304
|
- spec/record/new_spec.rb
|
305
305
|
- spec/record/options_spec.rb
|
306
306
|
- spec/record/paginatable_collection_spec.rb
|
307
|
+
- spec/record/pagination_chain_spec.rb
|
307
308
|
- spec/record/pagination_spec.rb
|
308
309
|
- spec/record/persisted_spec.rb
|
309
310
|
- spec/record/request_spec.rb
|
@@ -343,7 +344,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
343
344
|
requirements:
|
344
345
|
- Ruby >= 1.9.2
|
345
346
|
rubyforge_project:
|
346
|
-
rubygems_version: 2.
|
347
|
+
rubygems_version: 2.2.2
|
347
348
|
signing_key:
|
348
349
|
specification_version: 4
|
349
350
|
summary: Rails gem providing an easy, active-record-like interface for http json services
|
@@ -441,6 +442,7 @@ test_files:
|
|
441
442
|
- spec/record/new_spec.rb
|
442
443
|
- spec/record/options_spec.rb
|
443
444
|
- spec/record/paginatable_collection_spec.rb
|
445
|
+
- spec/record/pagination_chain_spec.rb
|
444
446
|
- spec/record/pagination_spec.rb
|
445
447
|
- spec/record/persisted_spec.rb
|
446
448
|
- spec/record/request_spec.rb
|