lhs 23.0.2 → 24.1.1
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 +53 -5
- data/lhs.gemspec +1 -1
- data/lib/lhs/concerns/collection/internal_collection.rb +28 -4
- data/lib/lhs/concerns/data/extend.rb +83 -0
- data/lib/lhs/concerns/record/chainable.rb +4 -4
- data/lib/lhs/concerns/record/request.rb +3 -71
- data/lib/lhs/data.rb +15 -0
- data/lib/lhs/version.rb +1 -1
- data/spec/dummy/app/controllers/error_handling_with_chains_controller.rb +2 -2
- data/spec/record/compact_spec.rb +90 -0
- data/spec/record/error_handling_spec.rb +4 -4
- data/spec/record/find_in_parallel_spec.rb +1 -1
- data/spec/record/handle_includes_errors_spec.rb +1 -1
- data/spec/record/includes_first_page_spec.rb +1 -1
- data/spec/record/references_spec.rb +43 -0
- metadata +13 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00243f3b3ea3dd2e97864c126dc7b8177c3f6e38cd217aba7c1a2843d9215d4c
|
4
|
+
data.tar.gz: 2c63934cbc1752513d1336997d2c9743c40b518d31b177d30f18a6ffe00ea99a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 492a78447b6b7985bed8a82025a95551f94943f6e712d09863ca99d3952bb16a26da46a88d6fc1edc5cb744dae230eab22319a038c3a0e67e76747e406afd2aa
|
7
|
+
data.tar.gz: 274eacd3f4815d81514b7273d6613851be0eb6427cd7c9fca1c0a8105cd5a28e62e1f5b740ad31331446a10d2cfe6fdc13c64808fb957511cbcf6b4e7790dc99
|
data/README.md
CHANGED
@@ -979,7 +979,7 @@ If you need to render some different view in Rails based on an LHS error raised
|
|
979
979
|
|
980
980
|
def show
|
981
981
|
@records = Record
|
982
|
-
.
|
982
|
+
.rescue(LHC::Error, ->(error){ rescue_from(error) })
|
983
983
|
.where(color: 'blue')
|
984
984
|
render 'show'
|
985
985
|
render_error if @error
|
@@ -987,7 +987,7 @@ end
|
|
987
987
|
|
988
988
|
private
|
989
989
|
|
990
|
-
def
|
990
|
+
def rescue_from(error)
|
991
991
|
@error = error
|
992
992
|
nil
|
993
993
|
end
|
@@ -1012,7 +1012,7 @@ If you want to inject values for the failing records, that might not have been f
|
|
1012
1012
|
# app/controllers/some_controller.rb
|
1013
1013
|
|
1014
1014
|
data = Record
|
1015
|
-
.
|
1015
|
+
.rescue(LHC::Unauthorized, ->(response) { Record.new(name: 'unknown') })
|
1016
1016
|
.find(1, 2, 3)
|
1017
1017
|
|
1018
1018
|
data[1].name # 'unknown'
|
@@ -1698,7 +1698,7 @@ record.partial_update(recommended: true)
|
|
1698
1698
|
|
1699
1699
|
```
|
1700
1700
|
```
|
1701
|
-
POST https://service.example.com/records/1z-5r1fkaj { body: "{ '
|
1701
|
+
POST https://service.example.com/records/1z-5r1fkaj { body: "{ 'recommended': true }" }
|
1702
1702
|
```
|
1703
1703
|
|
1704
1704
|
-> See [record validation](#record-validation) for how to handle validation errors when updating records.
|
@@ -2286,10 +2286,58 @@ Here is another example, if you want to ignore errors, that occure while you fet
|
|
2286
2286
|
|
2287
2287
|
feedback = Feedback
|
2288
2288
|
.includes(campaign: :entry)
|
2289
|
-
.references(campaign: {
|
2289
|
+
.references(campaign: { ignore: LHC::NotFound })
|
2290
2290
|
.find(12345)
|
2291
2291
|
```
|
2292
2292
|
|
2293
|
+
#### compact: Remove included resources that didn't return any records
|
2294
|
+
|
2295
|
+
In case you include nested data and ignored errors while including, it can happen that you get back a collection that contains data based on response errors:
|
2296
|
+
|
2297
|
+
```ruby
|
2298
|
+
# app/controllers/some_controller.rb
|
2299
|
+
|
2300
|
+
user = User
|
2301
|
+
.includes(:places)
|
2302
|
+
.references(places: { ignore: LHC::NotFound })
|
2303
|
+
.find(123)
|
2304
|
+
```
|
2305
|
+
|
2306
|
+
```
|
2307
|
+
GET http://service/users/123
|
2308
|
+
{ "places": { "href": "http://service/users/123/places" } }
|
2309
|
+
|
2310
|
+
GET http://service/users/123/places
|
2311
|
+
{ "items": [
|
2312
|
+
{ "href": "http://service/places/1" },
|
2313
|
+
{ "href": "http://service/places/2" }
|
2314
|
+
] }
|
2315
|
+
|
2316
|
+
GET http://service/places/1
|
2317
|
+
200 { "name": "Casa Ferlin" }
|
2318
|
+
|
2319
|
+
GET http://service/places/2
|
2320
|
+
404 { "status": 404, "error": "not found" }
|
2321
|
+
```
|
2322
|
+
|
2323
|
+
```ruby
|
2324
|
+
user.places[1] # { "status": 404, "error": "not found" }
|
2325
|
+
```
|
2326
|
+
|
2327
|
+
In order to exclude items from a collection which where not based on successful responses, use `.compact` or `.compact!`:
|
2328
|
+
|
2329
|
+
```ruby
|
2330
|
+
# app/controllers/some_controller.rb
|
2331
|
+
|
2332
|
+
user = User
|
2333
|
+
.includes(:places)
|
2334
|
+
.references(places: { ignore: LHC::NotFound })
|
2335
|
+
.find(123)
|
2336
|
+
places = user.places.compact
|
2337
|
+
|
2338
|
+
places # { "items": [ { "href": "http://service/places/1", "name": "Casa Ferlin" } ] }
|
2339
|
+
```
|
2340
|
+
|
2293
2341
|
### Record batch processing
|
2294
2342
|
|
2295
2343
|
**Be careful using methods for batch processing. They could result in a lot of HTTP requests!**
|
data/lhs.gemspec
CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
|
25
25
|
s.add_dependency 'activemodel'
|
26
26
|
s.add_dependency 'activesupport', '>= 4.2.11'
|
27
|
-
s.add_dependency 'lhc', '>=
|
27
|
+
s.add_dependency 'lhc', '>= 12.1.1', '< 13'
|
28
28
|
s.add_dependency 'local_uri'
|
29
29
|
|
30
30
|
s.add_development_dependency 'capybara'
|
@@ -14,7 +14,7 @@ class LHS::Collection < LHS::Proxy
|
|
14
14
|
|
15
15
|
attr_accessor :raw
|
16
16
|
delegate :length, :size, :first, :last, :sample, :[], :present?, :blank?, :empty?,
|
17
|
-
:<<, :push,
|
17
|
+
:<<, :push, to: :raw
|
18
18
|
|
19
19
|
def initialize(raw, parent, record)
|
20
20
|
self.raw = raw
|
@@ -36,13 +36,37 @@ class LHS::Collection < LHS::Proxy
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
+
def compact
|
40
|
+
dup.tap do |collection|
|
41
|
+
collection.compact! if collection.raw.present?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def compact!
|
46
|
+
self.raw = raw.map do |item|
|
47
|
+
if item.is_a?(LHS::Data) && item._request && !item._request.response.success?
|
48
|
+
nil
|
49
|
+
else
|
50
|
+
cast_item(item)
|
51
|
+
end
|
52
|
+
end.compact
|
53
|
+
end
|
54
|
+
|
39
55
|
private
|
40
56
|
|
41
57
|
def cast_item(item)
|
42
|
-
record_by_href = LHS::Record.for_url(item[:href]) if item[:href]
|
43
58
|
data = LHS::Data.new(item, @parent, @record)
|
44
|
-
|
45
|
-
|
59
|
+
(record_by_href(item) || @record)&.new(data) || data
|
60
|
+
end
|
61
|
+
|
62
|
+
def record_by_href(item)
|
63
|
+
return if plain_value?(item) || item[:href].blank?
|
64
|
+
|
65
|
+
LHS::Record.for_url(item[:href])
|
66
|
+
end
|
67
|
+
|
68
|
+
def plain_value?(item)
|
69
|
+
item.is_a?(String) || item.is_a?(Numeric) || item.is_a?(TrueClass) || item.is_a?(FalseClass)
|
46
70
|
end
|
47
71
|
end
|
48
72
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support'
|
4
|
+
|
5
|
+
class LHS::Data
|
6
|
+
|
7
|
+
module Extend
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
# Extends already fetched data (self) with additionally
|
11
|
+
# fetched data (addition) using the given key
|
12
|
+
def extend!(addition, key)
|
13
|
+
addition = cast_relation_class_for_extension(addition, key)
|
14
|
+
if collection?
|
15
|
+
extend_collection!(addition, key)
|
16
|
+
elsif self[key]._raw.is_a? Array
|
17
|
+
extend_array!(addition, key)
|
18
|
+
elsif item?
|
19
|
+
extend_item!(addition, key)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def cast_relation_class_for_extension(addition, key)
|
26
|
+
return addition if _record.nil? || _record._relations.nil? || _record._relations[key].nil?
|
27
|
+
addition.becomes(_record._relations[key][:record_class_name].constantize, errors: addition.errors, warnings: addition.warnings)
|
28
|
+
end
|
29
|
+
|
30
|
+
def extend_collection!(addition, key)
|
31
|
+
map do |item|
|
32
|
+
item_raw = item._raw[key]
|
33
|
+
item_raw.blank? ? [nil] : item_raw
|
34
|
+
end
|
35
|
+
.flatten
|
36
|
+
.each_with_index do |item, index|
|
37
|
+
item_addition = addition[index]
|
38
|
+
next if item_addition.nil? || item.nil?
|
39
|
+
if item_addition._raw.is_a?(Array)
|
40
|
+
item[items_key] ||= []
|
41
|
+
item[items_key].concat(item_addition._raw)
|
42
|
+
else
|
43
|
+
item.merge! item_addition._raw
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def extend_array!(addition, key)
|
49
|
+
self[key].zip(addition) do |item, additional_item|
|
50
|
+
item._raw.merge!(additional_item._raw) if additional_item.present?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def extend_item!(addition, key)
|
55
|
+
return if addition.nil?
|
56
|
+
if addition.collection?
|
57
|
+
extend_item_with_collection!(addition, key)
|
58
|
+
else # simple case merges hash into hash
|
59
|
+
_raw[key.to_sym].merge!(addition._raw)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def extend_item_with_collection!(addition, key)
|
64
|
+
target = self[key]
|
65
|
+
if target._raw.is_a? Array
|
66
|
+
self[key] = addition.map(&:_raw)
|
67
|
+
else # hash with items
|
68
|
+
extend_item_with_hash_containing_items!(target, addition)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def extend_item_with_hash_containing_items!(target, addition)
|
73
|
+
LHS::Collection.nest(input: target._raw, value: [], record: self) # inits the nested collection
|
74
|
+
if LHS::Collection.access(input: target._raw, record: self).empty?
|
75
|
+
LHS::Collection.nest(input: target._raw, value: addition.reject { |item| item.nil? }, record: self)
|
76
|
+
else
|
77
|
+
LHS::Collection.access(input: target._raw, record: self).each_with_index do |item, index|
|
78
|
+
item.merge!(addition[index])
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -52,7 +52,7 @@ class LHS::Record
|
|
52
52
|
Chain.new(self, Pagination.new(per: argument))
|
53
53
|
end
|
54
54
|
|
55
|
-
def
|
55
|
+
def rescue(error_class, handler)
|
56
56
|
Chain.new(self, ErrorHandling.new(error_class => handler))
|
57
57
|
end
|
58
58
|
|
@@ -255,7 +255,7 @@ class LHS::Record
|
|
255
255
|
push(Pagination.new(per: argument))
|
256
256
|
end
|
257
257
|
|
258
|
-
def
|
258
|
+
def rescue(error_class, handler)
|
259
259
|
push(ErrorHandling.new(error_class => handler))
|
260
260
|
end
|
261
261
|
|
@@ -348,8 +348,8 @@ class LHS::Record
|
|
348
348
|
def resolved_options
|
349
349
|
options = chain_options
|
350
350
|
options = options.deep_merge(params: chain_parameters.merge(chain_pagination))
|
351
|
-
options = options.merge(
|
352
|
-
options = options.merge(
|
351
|
+
options = options.merge(rescue: chain_error_handler) if chain_error_handler.present?
|
352
|
+
options = options.merge(ignore: chain_ignored_errors) if chain_ignored_errors.present?
|
353
353
|
options = options.merge(including: chain_includes) if chain_includes.present?
|
354
354
|
options = options.merge(referencing: chain_references) if chain_references.present?
|
355
355
|
options
|
@@ -98,74 +98,6 @@ class LHS::Record
|
|
98
98
|
)
|
99
99
|
end
|
100
100
|
|
101
|
-
# Extends existing raw data with additionaly fetched data
|
102
|
-
def extend_raw_data!(data, addition, key)
|
103
|
-
if data.collection?
|
104
|
-
extend_base_collection!(data, addition, key)
|
105
|
-
elsif data[key]._raw.is_a? Array
|
106
|
-
extend_base_array!(data, addition, key)
|
107
|
-
elsif data.item?
|
108
|
-
extend_base_item!(data, addition, key)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def extend_base_collection!(data, addition, key)
|
113
|
-
data.map do |item|
|
114
|
-
item_raw = item._raw[key]
|
115
|
-
item_raw.blank? ? [nil] : item_raw
|
116
|
-
end
|
117
|
-
.flatten
|
118
|
-
.each_with_index do |item, index|
|
119
|
-
item_addition = addition[index]
|
120
|
-
next if item_addition.nil? || item.nil?
|
121
|
-
if item_addition._raw.is_a?(Array)
|
122
|
-
extend_base_collection_with_array!(item, item_addition._raw)
|
123
|
-
else
|
124
|
-
item.merge! item_addition._raw
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
def extend_base_collection_with_array!(item, addition)
|
130
|
-
item[items_key] ||= []
|
131
|
-
item[items_key].concat(addition)
|
132
|
-
end
|
133
|
-
|
134
|
-
def extend_base_array!(data, addition, key)
|
135
|
-
data[key].zip(addition) do |item, additional_item|
|
136
|
-
item._raw.merge!(additional_item._raw) if additional_item.present?
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
def extend_base_item!(data, addition, key)
|
141
|
-
return if addition.nil?
|
142
|
-
if addition.collection?
|
143
|
-
extend_base_item_with_collection!(data, addition, key)
|
144
|
-
else # simple case merges hash into hash
|
145
|
-
data._raw[key.to_sym].merge!(addition._raw)
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def extend_base_item_with_collection!(data, addition, key)
|
150
|
-
target = data[key]
|
151
|
-
if target._raw.is_a? Array
|
152
|
-
data[key] = addition.map(&:_raw)
|
153
|
-
else # hash with items
|
154
|
-
extend_base_item_with_hash_of_items!(target, addition)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
def extend_base_item_with_hash_of_items!(target, addition)
|
159
|
-
LHS::Collection.nest(input: target._raw, value: [], record: self)
|
160
|
-
if LHS::Collection.access(input: target._raw, record: self).empty?
|
161
|
-
LHS::Collection.nest(input: target._raw, value: addition.compact.map(&:_raw), record: self)
|
162
|
-
else
|
163
|
-
LHS::Collection.access(input: target._raw, record: self).each_with_index do |item, index|
|
164
|
-
item.merge!(addition[index])
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
101
|
def handle_includes(includes, data, references = {})
|
170
102
|
references ||= {}
|
171
103
|
if includes.is_a? Hash
|
@@ -187,7 +119,7 @@ class LHS::Record
|
|
187
119
|
options = options_for_data(data, included)
|
188
120
|
options = extend_with_reference(options, reference)
|
189
121
|
addition = load_include(options, data, sub_includes, reference)
|
190
|
-
|
122
|
+
data.extend!(addition, included)
|
191
123
|
expand_addition!(data, included, options) unless expanded_data?(addition)
|
192
124
|
end
|
193
125
|
end
|
@@ -210,7 +142,7 @@ class LHS::Record
|
|
210
142
|
record = record_for_options(options) || self
|
211
143
|
options = convert_options_to_endpoints(options) if record_for_options(options)
|
212
144
|
expanded_data = record.request(options)
|
213
|
-
|
145
|
+
data.extend!(expanded_data, included)
|
214
146
|
end
|
215
147
|
|
216
148
|
def expanded_data?(addition)
|
@@ -504,7 +436,7 @@ class LHS::Record
|
|
504
436
|
options = options.deep_dup
|
505
437
|
options[:ignored_errors] = ignored_errors if ignored_errors.present?
|
506
438
|
options[:params]&.deep_symbolize_keys!
|
507
|
-
options[:
|
439
|
+
options[:rescue] = merge_error_handlers(options[:rescue]) if options[:rescue]
|
508
440
|
options = (provider_options || {})
|
509
441
|
.deep_merge(endpoint.options || {})
|
510
442
|
.deep_merge(options)
|
data/lib/lhs/data.rb
CHANGED
@@ -6,6 +6,8 @@ class LHS::Data
|
|
6
6
|
'lhs/concerns/data/becomes'
|
7
7
|
autoload :Equality,
|
8
8
|
'lhs/concerns/data/equality'
|
9
|
+
autoload :Extend,
|
10
|
+
'lhs/concerns/data/extend'
|
9
11
|
autoload :Json,
|
10
12
|
'lhs/concerns/data/json'
|
11
13
|
autoload :ToHash,
|
@@ -13,6 +15,7 @@ class LHS::Data
|
|
13
15
|
|
14
16
|
include Becomes
|
15
17
|
include Equality
|
18
|
+
include Extend
|
16
19
|
include Json
|
17
20
|
include ToHash
|
18
21
|
include LHS::Inspect
|
@@ -30,6 +33,7 @@ class LHS::Data
|
|
30
33
|
self._proxy = proxy_from_input(input)
|
31
34
|
self._request = request
|
32
35
|
self._endpoint = endpoint
|
36
|
+
preserve_input_requests!(input)
|
33
37
|
end
|
34
38
|
|
35
39
|
# merging data
|
@@ -97,6 +101,17 @@ class LHS::Data
|
|
97
101
|
|
98
102
|
private
|
99
103
|
|
104
|
+
def preserve_input_requests!(input)
|
105
|
+
if input.is_a?(LHS::Data)
|
106
|
+
_request = input._request if _request.nil?
|
107
|
+
elsif input.is_a?(Array) && input.first.is_a?(LHS::Data)
|
108
|
+
input.each_with_index do |item, index|
|
109
|
+
next if item.nil?
|
110
|
+
self[index]._request = item._request
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
100
115
|
def collection_proxy?(input)
|
101
116
|
(input.is_a?(Hash) && LHS::Collection.access(input: input, record: _record)) ||
|
102
117
|
input.is_a?(Array) ||
|
data/lib/lhs/version.rb
CHANGED
@@ -6,7 +6,7 @@ class ErrorHandlingWithChainsController < ApplicationController
|
|
6
6
|
# in the view (during render 'show')
|
7
7
|
def fetch_in_view
|
8
8
|
@records = DummyRecord
|
9
|
-
.
|
9
|
+
.rescue(LHC::Error, ->(error) { handle_error(error) })
|
10
10
|
.where(color: 'blue')
|
11
11
|
render 'show'
|
12
12
|
render_error if @error
|
@@ -16,7 +16,7 @@ class ErrorHandlingWithChainsController < ApplicationController
|
|
16
16
|
# before the view is rendered
|
17
17
|
def fetch_in_controller
|
18
18
|
@records = DummyRecord
|
19
|
-
.
|
19
|
+
.rescue(LHC::Error, ->(error) { handle_error(error) })
|
20
20
|
.where(color: 'blue').fetch
|
21
21
|
render 'show'
|
22
22
|
render_error if @error
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe LHS::Record do
|
6
|
+
before do
|
7
|
+
class Place < LHS::Record
|
8
|
+
endpoint 'http://datastore/places/{id}'
|
9
|
+
endpoint 'http://datastore/users/{user_id}/places/{id}'
|
10
|
+
|
11
|
+
def display_name
|
12
|
+
"*#{name}*"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class User < LHS::Record
|
17
|
+
endpoint 'http://datastore/users/{id}'
|
18
|
+
end
|
19
|
+
|
20
|
+
stub_request(:get, 'http://datastore/users/123')
|
21
|
+
.to_return(status: 200, body: {
|
22
|
+
href: 'http://datastore/users/123',
|
23
|
+
places: { href: 'http://datastore/users/123/places' }
|
24
|
+
}.to_json)
|
25
|
+
|
26
|
+
stub_request(:get, 'http://datastore/users/123/places?limit=100')
|
27
|
+
.to_return(status: 200, body: {
|
28
|
+
href: 'http://datastore/users/123/places?offset=0&limit=100',
|
29
|
+
items: [
|
30
|
+
{
|
31
|
+
href: 'http://datastore/users/123/places/789'
|
32
|
+
}, {
|
33
|
+
href: 'http://datastore/users/123/places/790'
|
34
|
+
}
|
35
|
+
],
|
36
|
+
total: 2,
|
37
|
+
offset: 0,
|
38
|
+
limit: 10
|
39
|
+
}.to_json)
|
40
|
+
|
41
|
+
stub_request(:get, 'http://datastore/users/123/places/789?limit=100')
|
42
|
+
.to_return(
|
43
|
+
body: {
|
44
|
+
href: 'http://datastore/users/123/places/789?limit=100',
|
45
|
+
name: 'Mc Donalds'
|
46
|
+
}.to_json
|
47
|
+
)
|
48
|
+
|
49
|
+
stub_request(:get, 'http://datastore/users/123/places/790?limit=100')
|
50
|
+
.to_return(
|
51
|
+
status: 404,
|
52
|
+
body: {
|
53
|
+
status: 404,
|
54
|
+
message: 'The requested resource does not exist.'
|
55
|
+
}.to_json
|
56
|
+
)
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
let(:places) do
|
61
|
+
User
|
62
|
+
.includes(:places)
|
63
|
+
.references(places: { ignore: LHC::NotFound })
|
64
|
+
.find('123')
|
65
|
+
.places
|
66
|
+
end
|
67
|
+
|
68
|
+
context '.compact' do
|
69
|
+
it 'removes linked resouces which could not get fetched' do
|
70
|
+
expect(places.compact.length).to eq 1
|
71
|
+
expect(places.length).not_to eq 1 # leaves the original intact
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'record casting' do
|
76
|
+
let(:expected_display_name) { '*Mc Donalds*' }
|
77
|
+
|
78
|
+
it 'finds the right record class' do
|
79
|
+
expect(places.first.display_name).to eq expected_display_name
|
80
|
+
expect(places.compact.map(&:display_name)).to eq [expected_display_name]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context '.compact!' do
|
85
|
+
it 'removes linked resouces which could not get fetched' do
|
86
|
+
expect(places.compact!.length).to eq 1
|
87
|
+
expect(places.length).to eq 1 # and changes the original intact
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -15,14 +15,14 @@ describe LHS::Record do
|
|
15
15
|
|
16
16
|
it 'allows to chain error handling' do
|
17
17
|
expect {
|
18
|
-
Record.where(color: 'blue').
|
18
|
+
Record.where(color: 'blue').rescue(LHC::Error, ->(_error) { handler.handle }).first
|
19
19
|
}.not_to raise_error
|
20
20
|
expect(handler).to have_received(:handle)
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'reraises in case chained error is not matched' do
|
24
24
|
expect {
|
25
|
-
Record.where(color: 'blue').
|
25
|
+
Record.where(color: 'blue').rescue(LHC::Conflict, ->(_error) { handler.handle }).first
|
26
26
|
}.to raise_error(LHC::Error)
|
27
27
|
expect(handler).not_to have_received(:handle)
|
28
28
|
end
|
@@ -30,8 +30,8 @@ describe LHS::Record do
|
|
30
30
|
it 'calls all the handlers' do
|
31
31
|
expect {
|
32
32
|
Record.where(color: 'blue')
|
33
|
-
.
|
34
|
-
.
|
33
|
+
.rescue(LHC::Error, ->(_error) { handler.handle_1 })
|
34
|
+
.rescue(LHC::Error, ->(_error) { handler.handle_2 })
|
35
35
|
.first
|
36
36
|
}.not_to raise_error
|
37
37
|
expect(handler).to have_received(:handle_1)
|
@@ -33,7 +33,7 @@ describe LHS::Record do
|
|
33
33
|
it 'applies error handlers from the chain and returns whatever the error handler returns' do
|
34
34
|
stub_request(:get, "http://datastore/records/2").to_return(status: 401)
|
35
35
|
data = Record
|
36
|
-
.
|
36
|
+
.rescue(LHC::Unauthorized, ->(_response) { Record.new(name: 'unknown') })
|
37
37
|
.find(1, 2, 3)
|
38
38
|
expect(data[1].name).to eq 'unknown'
|
39
39
|
end
|
@@ -25,7 +25,7 @@ describe LHS::Record do
|
|
25
25
|
|
26
26
|
it 'allows to pass error_handling for includes to LHC' do
|
27
27
|
handler = ->(_) { return { deleted: true } }
|
28
|
-
record = Record.includes_first_page(:other).references(other: {
|
28
|
+
record = Record.includes_first_page(:other).references(other: { rescue: { LHC::NotFound => handler } }).find(id: 1)
|
29
29
|
|
30
30
|
expect(record.other.deleted).to be(true)
|
31
31
|
end
|
@@ -249,7 +249,7 @@ describe LHS::Record do
|
|
249
249
|
it 'ignores LHC::NotFound for links that cannot be included if configured so with reference options' do
|
250
250
|
feedback = Feedback
|
251
251
|
.includes_first_page(campaign: :entry)
|
252
|
-
.references(campaign: {
|
252
|
+
.references(campaign: { ignore: [LHC::NotFound] })
|
253
253
|
.find(123)
|
254
254
|
expect(feedback.campaign._raw.keys.length).to eq 1
|
255
255
|
end
|
@@ -8,6 +8,14 @@ describe LHS::Record do
|
|
8
8
|
class Customer < LHS::Record
|
9
9
|
endpoint 'http://datastore/customers/{id}'
|
10
10
|
end
|
11
|
+
|
12
|
+
class User < LHS::Record
|
13
|
+
endpoint 'http://datastore/users/{id}'
|
14
|
+
endpoint 'http://datastore/customers/{customer_id}/users/{id}'
|
15
|
+
def reversed_name
|
16
|
+
name.split.reverse.join(' ')
|
17
|
+
end
|
18
|
+
end
|
11
19
|
end
|
12
20
|
|
13
21
|
let!(:customer_request) do
|
@@ -18,6 +26,9 @@ describe LHS::Record do
|
|
18
26
|
},
|
19
27
|
'contact_addresses' => {
|
20
28
|
'href' => "http://datastore/contact_addresses"
|
29
|
+
},
|
30
|
+
'users' => {
|
31
|
+
'href' => 'http://datastore/customers/1/users'
|
21
32
|
}
|
22
33
|
}.to_json)
|
23
34
|
end
|
@@ -49,5 +60,37 @@ describe LHS::Record do
|
|
49
60
|
assert_requested(electronic_addresses_request)
|
50
61
|
assert_requested(contact_addresses_request)
|
51
62
|
end
|
63
|
+
|
64
|
+
describe 'mapping related classes correctly' do
|
65
|
+
before do
|
66
|
+
stub_request(:get, 'http://datastore/customers/1/users?limit=100').to_return(
|
67
|
+
status: 200,
|
68
|
+
body: {
|
69
|
+
href: 'http://datastore/customers/1/users?offset=0&limit=100',
|
70
|
+
items: [
|
71
|
+
{ href: 'http://datastore/customers/1/users/1' }
|
72
|
+
],
|
73
|
+
total: 1,
|
74
|
+
offset: 0,
|
75
|
+
limit: 10
|
76
|
+
}.to_json
|
77
|
+
)
|
78
|
+
|
79
|
+
stub_request(:get, 'http://datastore/customers/1/users/1?limit=100')
|
80
|
+
.with(headers: { 'Authentication' => 'Bearer 123' })
|
81
|
+
.to_return(body: { href: 'http://datastore/users/1', name: 'Elizabeth Baker' }.to_json)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'maps correctly' do
|
85
|
+
users = Customer
|
86
|
+
.includes(:users)
|
87
|
+
.references(users: referencing_options)
|
88
|
+
.find(1)
|
89
|
+
.users
|
90
|
+
|
91
|
+
expect(users.first.reversed_name).to be_present
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
52
95
|
end
|
53
96
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lhs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 24.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- https://github.com/local-ch/lhs/graphs/contributors
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -44,20 +44,20 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 12.1.1
|
48
48
|
- - "<"
|
49
49
|
- !ruby/object:Gem::Version
|
50
|
-
version: '
|
50
|
+
version: '13'
|
51
51
|
type: :runtime
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
54
54
|
requirements:
|
55
55
|
- - ">="
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version:
|
57
|
+
version: 12.1.1
|
58
58
|
- - "<"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: '
|
60
|
+
version: '13'
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: local_uri
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -274,6 +274,7 @@ files:
|
|
274
274
|
- lib/lhs/concerns/configuration.rb
|
275
275
|
- lib/lhs/concerns/data/becomes.rb
|
276
276
|
- lib/lhs/concerns/data/equality.rb
|
277
|
+
- lib/lhs/concerns/data/extend.rb
|
277
278
|
- lib/lhs/concerns/data/json.rb
|
278
279
|
- lib/lhs/concerns/data/to_hash.rb
|
279
280
|
- lib/lhs/concerns/inspect.rb
|
@@ -471,6 +472,7 @@ files:
|
|
471
472
|
- spec/record/attribute_assignment_spec.rb
|
472
473
|
- spec/record/build_spec.rb
|
473
474
|
- spec/record/cast_nested_data_spec.rb
|
475
|
+
- spec/record/compact_spec.rb
|
474
476
|
- spec/record/create_spec.rb
|
475
477
|
- spec/record/creation_failed_spec.rb
|
476
478
|
- spec/record/custom_setters_spec.rb
|
@@ -550,7 +552,7 @@ homepage: https://github.com/local-ch/lhs
|
|
550
552
|
licenses:
|
551
553
|
- GPL-3.0
|
552
554
|
metadata: {}
|
553
|
-
post_install_message:
|
555
|
+
post_install_message:
|
554
556
|
rdoc_options: []
|
555
557
|
require_paths:
|
556
558
|
- lib
|
@@ -566,8 +568,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
566
568
|
version: '0'
|
567
569
|
requirements:
|
568
570
|
- Ruby >= 2.3.0
|
569
|
-
rubygems_version: 3.0.
|
570
|
-
signing_key:
|
571
|
+
rubygems_version: 3.0.3
|
572
|
+
signing_key:
|
571
573
|
specification_version: 4
|
572
574
|
summary: 'REST services accelerator: Rails gem providing an easy, active-record-like
|
573
575
|
interface for http (hypermedia) json services'
|
@@ -699,6 +701,7 @@ test_files:
|
|
699
701
|
- spec/record/attribute_assignment_spec.rb
|
700
702
|
- spec/record/build_spec.rb
|
701
703
|
- spec/record/cast_nested_data_spec.rb
|
704
|
+
- spec/record/compact_spec.rb
|
702
705
|
- spec/record/create_spec.rb
|
703
706
|
- spec/record/creation_failed_spec.rb
|
704
707
|
- spec/record/custom_setters_spec.rb
|