lhs 5.2.0 → 5.3.0

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
  SHA1:
3
- metadata.gz: 42f49d74b6cae3f84139b46895b5defb5454c184
4
- data.tar.gz: 9232b8df9672d9caa11e3f0a3a36f2474ba3386e
3
+ metadata.gz: b5e2d8c23fc37ece5d7b13aebd02f43df60aec96
4
+ data.tar.gz: 650560241439a1cb5b97c86894ef4a5e133d5bd4
5
5
  SHA512:
6
- metadata.gz: 7fbeecfceee4e4c6ebb5f125d427d98cbc1ece337469fb3ae8070de018616e33e5c8923df319863c835367cfcbda6581cc24f22512d3d3b11899bd8531aa801a
7
- data.tar.gz: 36520b86b942ac32f0c01191a7e6f418100122f18724b760a0d7f4c7ef630b8c32c3974fa49c714bf6631dc044b5e8448bf8a87ef6be26e7a6f1bb552537d059
6
+ metadata.gz: 7d086164639d3fd4b3a40a772c2c98360cf212f6b58e6d55a5debe7317daecb341e42aec62948783e79f3eb18f398a607a9cffc99a7828d73f9fc02c894cc36a
7
+ data.tar.gz: 329fbdb7a8edc677a156588061af8e99e9a15db6bec9684f50e057157f6c4489fd1eb71d5c58c8378bb7e194682b2679e77b58c0ada1f3fc2b012bdfc70c2e9d
data/README.md CHANGED
@@ -293,7 +293,7 @@ feedback.ratings # {:quality=>3}
293
293
 
294
294
  ## Include linked resources
295
295
 
296
- When fetching records, you can specify in advance all the linked resources that you want to include in the results. With `includes`, LHS ensures that all matching and explicitly linked resources are loaded and merged.
296
+ When fetching records, you can specify in advance all the linked resources that you want to include in the results. With `includes`, LHS ensures that all matching and explicitly linked resources are loaded and merged, if they're included in the server response.
297
297
 
298
298
  The implementation is heavily influenced by [http://guides.rubyonrails.org/active_record_class_querying](http://guides.rubyonrails.org/active_record_class_querying.html#eager-loading-associations) and you should read it to understand this feature in all its glory.
299
299
 
@@ -26,6 +26,7 @@ class LHS::Record
26
26
  end
27
27
 
28
28
  def convert_option_to_endpoints(option)
29
+ return unless option.present?
29
30
  new_options = option.dup
30
31
  url = option[:url]
31
32
  endpoint = LHS::Endpoint.for_url(url)
@@ -38,10 +39,12 @@ class LHS::Record
38
39
 
39
40
  # Extends existing raw data with additionaly fetched data
40
41
  def extend_raw_data(data, addition, key)
41
- if data._proxy.is_a? LHS::Collection
42
+ return if addition.empty?
43
+ if data.collection?
42
44
  data.each_with_index do |item, i|
43
45
  item = item[i] if item.is_a? LHS::Collection
44
- item._raw[key.to_sym].merge!(addition[i]._raw)
46
+ link = item[key.to_sym]
47
+ link.merge_raw!(addition[i]) if link.present?
45
48
  end
46
49
  elsif data._proxy.is_a? LHS::Item
47
50
  data._raw[key.to_sym].merge!(addition._raw)
@@ -59,19 +62,25 @@ class LHS::Record
59
62
  end
60
63
 
61
64
  def handle_include(included, data, sub_includes = nil)
62
- return unless data.present?
65
+ return if data.blank? || skip_loading_includes?(data, included)
63
66
  options =
64
- if data._proxy.is_a? LHS::Collection
65
- options_for_multiple(data, included)
67
+ if data.collection?
66
68
  options_for_multiple(data, included)
67
69
  else
68
70
  url_option_for(data, included)
69
- url_option_for(data, included)
70
71
  end
71
72
  addition = load_include(options, data, sub_includes)
72
73
  extend_raw_data(data, addition, included)
73
74
  end
74
75
 
76
+ def skip_loading_includes?(data, included)
77
+ if data.collection?
78
+ data.to_a.none? { |item| item[included].present? }
79
+ else
80
+ !data._raw.key?(included)
81
+ end
82
+ end
83
+
75
84
  # Load additional resources that are requested with include
76
85
  def load_include(options, data, sub_includes)
77
86
  record = record_for_options(options) || self
@@ -92,14 +101,31 @@ class LHS::Record
92
101
  end
93
102
 
94
103
  def multiple_requests(options)
95
- options = options.map { |option| process_options(option, find_endpoint(option[:params])) }
96
- responses = LHC.request(options)
97
- data = responses.map { |response| LHS::Data.new(response.body, nil, self, response.request) }
98
- data = LHS::Data.new(data, nil, self)
99
- handle_includes(including, data) if including
104
+ options = options.map do |option|
105
+ next unless option.present?
106
+ process_options(option, find_endpoint(option[:params]))
107
+ end
108
+ data = LHC.request(options.compact).map { |response| LHS::Data.new(response.body, nil, self, response.request) }
109
+ data = restore_with_nils(data, locate_nils(options)) # nil objects in data provide location information for mapping
110
+ unless data.empty?
111
+ data = LHS::Data.new(data, nil, self)
112
+ handle_includes(including, data) if including
113
+ end
100
114
  data
101
115
  end
102
116
 
117
+ def locate_nils(array)
118
+ nils = []
119
+ array.each_with_index { |value, index| nils << index if value.nil? }
120
+ nils
121
+ end
122
+
123
+ def restore_with_nils(array, nils)
124
+ array = array.dup
125
+ nils.sort.each { |index| array.insert(index, nil) }
126
+ array
127
+ end
128
+
103
129
  def options_for_multiple(data, key)
104
130
  data.map do |item|
105
131
  url_option_for(item, key)
@@ -119,7 +145,7 @@ class LHS::Record
119
145
  def record_for_options(options)
120
146
  records = []
121
147
  if options.is_a?(Array)
122
- options.each do |option|
148
+ options.compact.each do |option|
123
149
  record = LHS::Record.for_url(option[:url])
124
150
  next unless record
125
151
  records.push(record)
@@ -143,7 +169,7 @@ class LHS::Record
143
169
 
144
170
  def url_option_for(item, key)
145
171
  link = item[key]
146
- { url: link.href }
172
+ return { url: link.href } if link.present? && link.href.present?
147
173
  end
148
174
  end
149
175
  end
@@ -23,7 +23,7 @@ class LHS::Data
23
23
  # merging data
24
24
  # e.g. when loading remote data via link
25
25
  def merge_raw!(data)
26
- return false unless data._raw.is_a?(Hash)
26
+ return false if data.blank? || !data._raw.is_a?(Hash)
27
27
  _raw.merge! data._raw
28
28
  end
29
29
 
@@ -18,9 +18,7 @@ class LHS::Record
18
18
  include Request
19
19
  include Scope
20
20
 
21
- delegate :_proxy, to: :_data
22
- delegate :_endpoint, to: :_data
23
- delegate :select, to: :_data
21
+ delegate :_proxy, :_endpoint, :merge_raw!, :select, to: :_data
24
22
 
25
23
  def initialize(data = nil)
26
24
  data = LHS::Data.new({}, nil, self.class) unless data
@@ -1,3 +1,3 @@
1
1
  module LHS
2
- VERSION = "5.2.0"
2
+ VERSION = "5.3.0"
3
3
  end
@@ -170,6 +170,59 @@ describe LHS::Record do
170
170
  # rubocop:enable RSpec/InstanceVariable
171
171
  end
172
172
  end
173
+
174
+ context 'includes not present in response' do
175
+ before :each do
176
+ class Parent < LHS::Record
177
+ endpoint ':datastore/local-parents'
178
+ endpoint ':datastore/local-parents/:id'
179
+ end
180
+
181
+ class OptionalChild < LHS::Record
182
+ endpoint ':datastore/local-children/:id'
183
+ end
184
+ end
185
+
186
+ it 'handles missing but included fields in single object response' do
187
+ stub_request(:get, "#{datastore}/local-parents/1")
188
+ .to_return(status: 200, body: {
189
+ 'href' => "#{datastore}/local-parents/1",
190
+ 'name' => 'RspecName'
191
+ }.to_json)
192
+
193
+ parent = Parent.includes(:optional_children).find(1)
194
+ expect(parent).not_to be nil
195
+ expect(parent.name).to eq 'RspecName'
196
+ expect(parent.optional_children).to be nil
197
+ end
198
+
199
+ it 'handles missing but included fields in collection response' do
200
+ stub_request(:get, "#{datastore}/local-parents")
201
+ .to_return(status: 200, body: {
202
+ items: [
203
+ {
204
+ 'href' => "#{datastore}/local-parents/1",
205
+ 'name' => 'RspecParent'
206
+ }, {
207
+ 'href' => "#{datastore}/local-parents/2",
208
+ 'name' => 'RspecParent2',
209
+ 'optional_child' => {
210
+ 'href' => "#{datastore}/local-children/1"
211
+ }
212
+ }]
213
+ }.to_json)
214
+
215
+ stub_request(:get, "#{datastore}/local-children/1")
216
+ .to_return(status: 200, body: {
217
+ href: "#{datastore}/local_children/1",
218
+ name: 'RspecOptionalChild1'
219
+ }.to_json)
220
+
221
+ child = Parent.includes(:optional_child).where[1].optional_child
222
+ expect(child).not_to be nil
223
+ expect(child.name).to eq 'RspecOptionalChild1'
224
+ end
225
+ end
173
226
  end
174
227
 
175
228
  context 'links pointing to nowhere' do
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.2.0
4
+ version: 5.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - https://github.com/local-ch/lhs/graphs/contributors
@@ -343,7 +343,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
343
343
  requirements:
344
344
  - Ruby >= 1.9.2
345
345
  rubyforge_project:
346
- rubygems_version: 2.2.2
346
+ rubygems_version: 2.5.1
347
347
  signing_key:
348
348
  specification_version: 4
349
349
  summary: Rails gem providing an easy, active-record-like interface for http json services