lhs 13.2.3 → 14.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.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/lib/lhs/concerns/record/request.rb +34 -4
- data/lib/lhs/pagination/base.rb +1 -1
- data/lib/lhs/pagination/offset.rb +7 -1
- data/lib/lhs/pagination/page.rb +7 -1
- data/lib/lhs/pagination/start.rb +7 -1
- data/lib/lhs/version.rb +1 -1
- data/spec/record/all_spec.rb +49 -5
- data/spec/record/endpoints_spec.rb +2 -0
- data/spec/record/includes_all_spec.rb +4 -1
- data/spec/record/paginatable_collection_spec.rb +4 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2844d363e539a18b08de95cd58f510dcaa101651
|
|
4
|
+
data.tar.gz: 0e4fc872e5730d30b8ead542f1b135cb28c96d81
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4ecde150a77ea8c199abc608331f35b854e546714f20e155003fa52b8cca63e6088128cec7d6ae0466bc9432124650d26d86fe16bc4bf840d8824bf1a44482ac
|
|
7
|
+
data.tar.gz: dd4f3cee3b961267307ca3a3f40cfa1bebffa53baa5b958255ac3594a6437095f00c1944e3f5dc4f68a97993ed0e90ea3c3e6c30a36e27d03063eb268b03aaab
|
data/README.md
CHANGED
|
@@ -336,6 +336,8 @@ Record.all(color: 'blue')
|
|
|
336
336
|
# All three are doing the same thing: fetching all records with the color 'blue' from the endpoint while resolving pagingation if endpoint is paginated
|
|
337
337
|
```
|
|
338
338
|
|
|
339
|
+
In case an API does not provide pagination information (limit, offset and total), LHS keeps on loading pages when requesting `all` until the first empty page responds.
|
|
340
|
+
|
|
339
341
|
[Count vs. Length](#count-vs-length)
|
|
340
342
|
|
|
341
343
|
`find_each` is a more fine grained way to process single records that are fetched in batches.
|
|
@@ -21,6 +21,15 @@ class LHS::Record
|
|
|
21
21
|
|
|
22
22
|
private
|
|
23
23
|
|
|
24
|
+
def single_request_load_and_merge_remaining_objects!(data, options, endpoint)
|
|
25
|
+
return unless options[:all]
|
|
26
|
+
load_and_merge_remaining_objects!(
|
|
27
|
+
data: data,
|
|
28
|
+
options: process_options(options, endpoint),
|
|
29
|
+
load_not_paginated_collection: true
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
|
|
24
33
|
def filter_empty_request_options(options)
|
|
25
34
|
options.map do |option|
|
|
26
35
|
option if !option || !option.key?(:url) || !option[:url].nil?
|
|
@@ -208,15 +217,36 @@ class LHS::Record
|
|
|
208
217
|
# we can evaluate if there are further remote objects remaining
|
|
209
218
|
# and after preparing all the requests that have to be made in order to fetch all
|
|
210
219
|
# remote items during this batch, they are fetched in parallel
|
|
211
|
-
def load_and_merge_remaining_objects!(data
|
|
220
|
+
def load_and_merge_remaining_objects!(data:, options:, load_not_paginated_collection: false)
|
|
212
221
|
if paginated?(data._raw)
|
|
213
222
|
load_and_merge_paginated_collection!(data, options)
|
|
214
223
|
elsif data.collection? && paginated?(data.first.try(:_raw))
|
|
215
224
|
load_and_merge_set_of_paginated_collections!(data, options)
|
|
225
|
+
elsif load_not_paginated_collection
|
|
226
|
+
load_and_merge_not_paginated_collection!(data, options)
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def load_and_merge_not_paginated_collection!(data, options)
|
|
231
|
+
return if data.length.zero?
|
|
232
|
+
options = options.is_a?(Hash) ? options : {}
|
|
233
|
+
limit = options.dig(:params, limit_key) || pagination_class::DEFAULT_LIMIT
|
|
234
|
+
offset = options.dig(:params, pagination_key) || pagination_class::DEFAULT_OFFSET
|
|
235
|
+
options[:params] = options.fetch(:params, {}).merge(
|
|
236
|
+
limit_key => limit,
|
|
237
|
+
pagination_key => pagination_class.next_offset(
|
|
238
|
+
offset,
|
|
239
|
+
limit
|
|
240
|
+
)
|
|
241
|
+
)
|
|
242
|
+
additional_data = data._record.request(options)
|
|
243
|
+
additional_data.each do |item_data|
|
|
244
|
+
data.concat(input: data._raw, items: [item_data], record: self)
|
|
216
245
|
end
|
|
217
246
|
end
|
|
218
247
|
|
|
219
248
|
def load_and_merge_paginated_collection!(data, options)
|
|
249
|
+
data._raw[limit_key] = data.length if data._raw[limit_key].blank? && !data.length.zero?
|
|
220
250
|
pagination = data._record.pagination(data)
|
|
221
251
|
return data if pagination.pages_left.zero?
|
|
222
252
|
record = data._record
|
|
@@ -279,13 +309,13 @@ class LHS::Record
|
|
|
279
309
|
# paginates itself to ensure all records are fetched
|
|
280
310
|
def load_all_included!(record, options)
|
|
281
311
|
data = record.request(options)
|
|
282
|
-
load_and_merge_remaining_objects!(data, options)
|
|
312
|
+
load_and_merge_remaining_objects!(data: data, options: options)
|
|
283
313
|
data
|
|
284
314
|
end
|
|
285
315
|
|
|
286
316
|
# Checks if given raw is paginated or not
|
|
287
317
|
def paginated?(raw)
|
|
288
|
-
!!(raw.is_a?(Hash) && raw[total_key]
|
|
318
|
+
!!(raw.is_a?(Hash) && raw[total_key])
|
|
289
319
|
end
|
|
290
320
|
|
|
291
321
|
def prepare_options_for_include_all_request!(options)
|
|
@@ -466,7 +496,7 @@ class LHS::Record
|
|
|
466
496
|
apply_limit!(options) if options[:all]
|
|
467
497
|
response = LHC.request(process_options(options, endpoint))
|
|
468
498
|
data = LHS::Data.new(response.body, nil, self, response.request, endpoint)
|
|
469
|
-
|
|
499
|
+
single_request_load_and_merge_remaining_objects!(data, options, endpoint)
|
|
470
500
|
expand_items(data, options[:expanded]) if data.collection? && options[:expanded]
|
|
471
501
|
handle_includes(including, data, referencing) if including.present? && data.present?
|
|
472
502
|
data
|
data/lib/lhs/pagination/base.rb
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
class LHS::Pagination::Offset < LHS::Pagination::Base
|
|
2
2
|
|
|
3
|
+
DEFAULT_OFFSET = 0
|
|
4
|
+
|
|
3
5
|
def current_page
|
|
4
6
|
(offset + limit) / limit
|
|
5
7
|
end
|
|
6
8
|
|
|
7
9
|
def next_offset(step = 1)
|
|
8
|
-
offset
|
|
10
|
+
self.class.next_offset(offset, limit, step)
|
|
9
11
|
end
|
|
10
12
|
|
|
11
13
|
def self.page_to_offset(page, limit = DEFAULT_LIMIT)
|
|
12
14
|
(page.to_i - 1) * limit.to_i
|
|
13
15
|
end
|
|
16
|
+
|
|
17
|
+
def self.next_offset(offset, limit, step = 1)
|
|
18
|
+
offset.to_i + limit.to_i * step.to_i
|
|
19
|
+
end
|
|
14
20
|
end
|
data/lib/lhs/pagination/page.rb
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
class LHS::Pagination::Page < LHS::Pagination::Base
|
|
2
2
|
|
|
3
|
+
DEFAULT_OFFSET = 1
|
|
4
|
+
|
|
3
5
|
def current_page
|
|
4
6
|
offset
|
|
5
7
|
end
|
|
6
8
|
|
|
7
9
|
def next_offset(step = 1)
|
|
8
|
-
current_page
|
|
10
|
+
self.class.next_offset(current_page, limit, step)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.next_offset(current_page, _limit, step = 1)
|
|
14
|
+
current_page.to_i + step.to_i
|
|
9
15
|
end
|
|
10
16
|
end
|
data/lib/lhs/pagination/start.rb
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
class LHS::Pagination::Start < LHS::Pagination::Base
|
|
2
2
|
|
|
3
|
+
DEFAULT_OFFSET = 1
|
|
4
|
+
|
|
3
5
|
def current_page
|
|
4
6
|
(offset + limit - 1) / limit
|
|
5
7
|
end
|
|
6
8
|
|
|
7
9
|
def next_offset(step = 1)
|
|
8
|
-
offset
|
|
10
|
+
self.class.next_offset(offset, limit, step)
|
|
9
11
|
end
|
|
10
12
|
|
|
11
13
|
def self.page_to_offset(page, limit = DEFAULT_LIMIT)
|
|
12
14
|
(page.to_i - 1) * limit.to_i + 1
|
|
13
15
|
end
|
|
16
|
+
|
|
17
|
+
def self.next_offset(offset, limit, step = 1)
|
|
18
|
+
offset.to_i + limit.to_i * step.to_i
|
|
19
|
+
end
|
|
14
20
|
end
|
data/lib/lhs/version.rb
CHANGED
data/spec/record/all_spec.rb
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
require 'rails_helper'
|
|
2
2
|
|
|
3
3
|
describe LHS::Record do
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
context 'all' do
|
|
5
|
+
before(:each) do
|
|
6
|
+
class Record < LHS::Record
|
|
7
|
+
endpoint 'http://datastore/feedbacks'
|
|
8
|
+
end
|
|
7
9
|
end
|
|
8
|
-
end
|
|
9
10
|
|
|
10
|
-
context 'all' do
|
|
11
11
|
it 'is querying endpoint without pagination when using all' do
|
|
12
12
|
stub_request(:get, "http://datastore/feedbacks?limit=100").to_return(body: { items: 300.times.map { { foo: 'bar' } }, total: 300 }.to_json)
|
|
13
13
|
records = Record.all
|
|
@@ -58,4 +58,48 @@ describe LHS::Record do
|
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
|
+
|
|
62
|
+
context 'all without current page indicator' do
|
|
63
|
+
before(:each) do
|
|
64
|
+
class Category < LHS::Record
|
|
65
|
+
configuration(
|
|
66
|
+
items_key: %i(response results),
|
|
67
|
+
limit_key: :max,
|
|
68
|
+
pagination_key: :offset,
|
|
69
|
+
pagination_strategy: :offset
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
endpoint 'http://store/categories'
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def stub_batch(url, items = 10)
|
|
77
|
+
stub_request(:get, url)
|
|
78
|
+
.to_return(
|
|
79
|
+
body: {
|
|
80
|
+
response: {
|
|
81
|
+
results: items.times.map { { name: 'category' } }
|
|
82
|
+
}
|
|
83
|
+
}.to_json
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'is able to fetch all remote objects without any current page indicator by simply increasing the offset until response is empty' do
|
|
88
|
+
stub_batch('http://store/categories?language=en&max=10&offset=0')
|
|
89
|
+
stub_batch('http://store/categories?language=en&max=10&offset=10')
|
|
90
|
+
stub_batch('http://store/categories?language=en&max=10&offset=20')
|
|
91
|
+
stub_batch('http://store/categories?language=en&max=10&offset=30', 0)
|
|
92
|
+
records = Category.limit(10).all(language: 'en').fetch
|
|
93
|
+
expect(records.length).to eq 30
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'is able to fetch all remote objects without any current page indicator by simply increasing the offset until response is empty' do
|
|
97
|
+
stub_batch('http://store/categories?language=en&max=100', 100)
|
|
98
|
+
stub_batch('http://store/categories?language=en&max=100&offset=100', 100)
|
|
99
|
+
stub_batch('http://store/categories?language=en&max=100&offset=200', 100)
|
|
100
|
+
stub_batch('http://store/categories?language=en&max=100&offset=300', 0)
|
|
101
|
+
records = Category.all(language: 'en').fetch
|
|
102
|
+
expect(records.length).to eq 300
|
|
103
|
+
end
|
|
104
|
+
end
|
|
61
105
|
end
|
|
@@ -81,6 +81,8 @@ describe LHS::Record do
|
|
|
81
81
|
it 'uses urls instead of trying to find base endpoint of parent class' do
|
|
82
82
|
stub_request(:get, "#{datastore}/entry/123/contracts?limit=100")
|
|
83
83
|
.to_return(body: [{ product: { href: "#{datastore}/products/LBC" } }].to_json)
|
|
84
|
+
stub_request(:get, "#{datastore}/entry/123/contracts?limit=100&offset=100")
|
|
85
|
+
.to_return(body: [].to_json)
|
|
84
86
|
stub_request(:get, "#{datastore}/products/LBC")
|
|
85
87
|
.to_return(body: { name: 'Local Business Card' }.to_json)
|
|
86
88
|
expect(lambda {
|
|
@@ -346,7 +346,10 @@ describe LHS::Record do
|
|
|
346
346
|
.to_return(
|
|
347
347
|
body: {
|
|
348
348
|
href: "http://datastore/v2/places/1/contracts?offset=0&limit=10",
|
|
349
|
-
items: [{ href: "http://datastore/v2/contracts/1" }]
|
|
349
|
+
items: [{ href: "http://datastore/v2/contracts/1" }],
|
|
350
|
+
offset: 0,
|
|
351
|
+
limit: 10,
|
|
352
|
+
total: 10
|
|
350
353
|
}.to_json
|
|
351
354
|
)
|
|
352
355
|
|
|
@@ -30,7 +30,8 @@ describe LHS::Record do
|
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
it 'also works when there is no total in the stubbing' do
|
|
33
|
-
stub_request(:get,
|
|
33
|
+
stub_request(:get, "http://local.ch/v2/feedbacks?limit=100").to_return(body: { items: (1..100).to_a }.to_json)
|
|
34
|
+
stub_request(:get, "http://local.ch/v2/feedbacks?limit=100&offset=100").to_return(body: { items: [] }.to_json)
|
|
34
35
|
all = Record.all
|
|
35
36
|
expect(all).to be_kind_of Record
|
|
36
37
|
expect(all._proxy).to be_kind_of LHS::Collection
|
|
@@ -38,7 +39,8 @@ describe LHS::Record do
|
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
it 'also works when there is no key "items" in the stubbing' do
|
|
41
|
-
stub_request(:get,
|
|
42
|
+
stub_request(:get, "http://local.ch/v2/feedbacks?limit=100").to_return(body: (1..100).to_a.to_json)
|
|
43
|
+
stub_request(:get, "http://local.ch/v2/feedbacks?limit=100&offset=100").to_return(body: [].to_json)
|
|
42
44
|
all = Record.all
|
|
43
45
|
expect(all).to be_kind_of Record
|
|
44
46
|
expect(all._proxy).to be_kind_of LHS::Collection
|