lhs 23.0.2 → 24.1.1

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: 4598d2f5041bf799a481dd7fb9ddbe6767acfdc799de851a7592228023d70f96
4
- data.tar.gz: 3688dabba7d80461e187b93107ba785d081bedb8be8b008eadebe00c43513e72
3
+ metadata.gz: 00243f3b3ea3dd2e97864c126dc7b8177c3f6e38cd217aba7c1a2843d9215d4c
4
+ data.tar.gz: 2c63934cbc1752513d1336997d2c9743c40b518d31b177d30f18a6ffe00ea99a
5
5
  SHA512:
6
- metadata.gz: 73d23712b3ee30c3e55fb11f95be384144ff521580ddb1afd7c3e70694aa3c57778f6a5bf751576e9a633e53720419147aadb249c4d076b0428caa0d30617829
7
- data.tar.gz: 95f2eb1975d019b0f5ea57e20225552c459c6784a9584f5a79d6c45a0e92d3fd42eebfdbd010d6f00350ab750bb447ae6b50133537cec002d3aa9f6ff3d8ac73
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
- .handle(LHC::Error, ->(error){ handle_error(error) })
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 handle_error(error)
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
- .handle(LHC::Unauthorized, ->(response) { Record.new(name: 'unknown') })
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: "{ 'name': 'Starbucks', 'recommended': true }" }
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: { ignored_errors: [LHC::NotFound] })
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!**
@@ -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', '>= 11.2.0', '< 12'
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, :compact, to: :raw
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
- return (record_by_href || @record).new(data) if record_by_href || @record
45
- data
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 handle(error_class, handler)
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 handle(error_class, handler)
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(error_handler: chain_error_handler) if chain_error_handler.present?
352
- options = options.merge(ignored_errors: chain_ignored_errors) if chain_ignored_errors.present?
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
- extend_raw_data!(data, addition, included)
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
- extend_raw_data!(data, expanded_data, included)
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[:error_handler] = merge_error_handlers(options[:error_handler]) if options[:error_handler]
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)
@@ -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) ||
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LHS
4
- VERSION = '23.0.2'
4
+ VERSION = '24.1.1'
5
5
  end
@@ -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
- .handle(LHC::Error, ->(error) { handle_error(error) })
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
- .handle(LHC::Error, ->(error) { handle_error(error) })
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').handle(LHC::Error, ->(_error) { handler.handle }).first
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').handle(LHC::Conflict, ->(_error) { handler.handle }).first
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
- .handle(LHC::Error, ->(_error) { handler.handle_1 })
34
- .handle(LHC::Error, ->(_error) { handler.handle_2 })
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
- .handle(LHC::Unauthorized, ->(_response) { Record.new(name: 'unknown') })
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: { error_handler: { LHC::NotFound => handler } }).find(id: 1)
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: { ignored_errors: [LHC::NotFound] })
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: 23.0.2
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-07-13 00:00:00.000000000 Z
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: 11.2.0
47
+ version: 12.1.1
48
48
  - - "<"
49
49
  - !ruby/object:Gem::Version
50
- version: '12'
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: 11.2.0
57
+ version: 12.1.1
58
58
  - - "<"
59
59
  - !ruby/object:Gem::Version
60
- version: '12'
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.6
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