lhs 24.0.0 → 24.1.0.pre.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: e31a9b37f1bc0f12b3a6c87933b145781ed3054e08ea4ea347d5b27d00a069ea
4
- data.tar.gz: d67f414e70fdcae5567dcf5c81c2e2dec93237026e829c9dc9522df5eb778480
3
+ metadata.gz: '0098eb4147ef54ee7e80bb67e1a466c39165ef4b65ad2ac18f6a2c024ee2e9f7'
4
+ data.tar.gz: 853bd4e9697debd6c559d24d295019473793c3c5bcf4c1a3f5cdba3d966a743c
5
5
  SHA512:
6
- metadata.gz: f39832a96aa989660bfbaf051c53bd53c647d4e75f7b9fa3ca81ab1243ec94bd17828da931207f80fd57a9f98f38188cca659143912a01a4ffc5e197090f6b3a
7
- data.tar.gz: 19ea228303da96f4f4e831825c19c98ea9a81c15b76ad645b3ecbe23532f0a7336eb87d815f432f2d25ee5d6f0c07d98963ed0ba5388022cd79521cd0ae04424
6
+ metadata.gz: d3db0060e2155188d1697ec6e9c9000d05b13592d6a8ec7c5f952a28b25d1162f72c009f5f70375e06e67637a8d4e488e1946a161bda24513cbb1ea17fe626a3
7
+ data.tar.gz: aa448eeb65c3b13ba529040d79b4a3cb6ac31f3961cf407e6d72d6f69bdc3dfc5f543c8d02cd1a3d4932b6a57e0c26fabbd91f365f7629676445cbc328e93e42
data/README.md CHANGED
@@ -2290,6 +2290,54 @@ feedback = Feedback
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!**
@@ -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,6 +36,22 @@ 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
+ item
51
+ end
52
+ end.compact
53
+ end
54
+
39
55
  private
40
56
 
41
57
  def cast_item(item)
@@ -0,0 +1,77 @@
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
+ if collection?
14
+ extend_collection!(addition, key)
15
+ elsif self[key]._raw.is_a? Array
16
+ extend_array!(addition, key)
17
+ elsif item?
18
+ extend_item!(addition, key)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def extend_collection!(addition, key)
25
+ map do |item|
26
+ item_raw = item._raw[key]
27
+ item_raw.blank? ? [nil] : item_raw
28
+ end
29
+ .flatten
30
+ .each_with_index do |item, index|
31
+ item_addition = addition[index]
32
+ next if item_addition.nil? || item.nil?
33
+ if item_addition._raw.is_a?(Array)
34
+ item[items_key] ||= []
35
+ item[items_key].concat(item_addition._raw)
36
+ else
37
+ item.merge! item_addition._raw
38
+ end
39
+ end
40
+ end
41
+
42
+ def extend_array!(addition, key)
43
+ self[key].zip(addition) do |item, additional_item|
44
+ item._raw.merge!(additional_item._raw) if additional_item.present?
45
+ end
46
+ end
47
+
48
+ def extend_item!(addition, key)
49
+ return if addition.nil?
50
+ if addition.collection?
51
+ extend_item_with_collection!(addition, key)
52
+ else # simple case merges hash into hash
53
+ _raw[key.to_sym].merge!(addition._raw)
54
+ end
55
+ end
56
+
57
+ def extend_item_with_collection!(addition, key)
58
+ target = self[key]
59
+ if target._raw.is_a? Array
60
+ self[key] = addition.map(&:_raw)
61
+ else # hash with items
62
+ extend_item_with_hash_containing_items!(target, addition)
63
+ end
64
+ end
65
+
66
+ def extend_item_with_hash_containing_items!(target, addition)
67
+ LHS::Collection.nest(input: target._raw, value: [], record: self) # inits the nested collection
68
+ if LHS::Collection.access(input: target._raw, record: self).empty?
69
+ LHS::Collection.nest(input: target._raw, value: addition.reject { |item| item.nil? }, record: self)
70
+ else
71
+ LHS::Collection.access(input: target._raw, record: self).each_with_index do |item, index|
72
+ item.merge!(addition[index])
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -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)
@@ -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 = '24.0.0'
4
+ VERSION = '24.1.0.pre.1'
5
5
  end
@@ -0,0 +1,67 @@
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
+ end
10
+
11
+ class User < LHS::Record
12
+ endpoint 'http://datastore/users/{id}'
13
+ end
14
+
15
+ stub_request(:get, 'http://datastore/users/123')
16
+ .to_return(status: 200, body: {
17
+ href: 'http://datastore/users/123',
18
+ places: { href: 'http://datastore/users/123/places' }
19
+ }.to_json)
20
+
21
+ stub_request(:get, 'http://datastore/users/123/places?limit=100')
22
+ .to_return(status: 200, body: {
23
+ href: 'http://datastore/users/123/places?offset=0&limit=100',
24
+ items: [
25
+ {
26
+ href: 'http://datastore/users/123/places/789'
27
+ }
28
+ ],
29
+ total: 4,
30
+ offset: 0,
31
+ limit: 10
32
+ }.to_json)
33
+
34
+ stub_request(:get, 'http://datastore/users/123/places/789?limit=100')
35
+ .to_return(
36
+ status: 404,
37
+ body: {
38
+ status: 404,
39
+ message: 'The requested resource does not exist.'
40
+ }.to_json
41
+ )
42
+
43
+ end
44
+
45
+ let(:places) do
46
+ User
47
+ .includes(:places)
48
+ .references(places: { ignore: LHC::NotFound })
49
+ .find('123')
50
+ .places
51
+ end
52
+
53
+ context '.compact' do
54
+
55
+ it 'removes linked resouces which could not get fetched' do
56
+ expect(places.compact.length).to eq 0
57
+ expect(places.length).not_to eq 0 # leaves the original intact
58
+ end
59
+ end
60
+
61
+ context '.compact!' do
62
+ it 'removes linked resouces which could not get fetched' do
63
+ expect(places.compact!.length).to eq 0
64
+ expect(places.length).to eq 0 # and changes the original intact
65
+ end
66
+ end
67
+ 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: 24.0.0
4
+ version: 24.1.0.pre.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - https://github.com/local-ch/lhs/graphs/contributors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-30 00:00:00.000000000 Z
11
+ date: 2020-08-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -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
@@ -561,9 +563,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
561
563
  version: 2.3.0
562
564
  required_rubygems_version: !ruby/object:Gem::Requirement
563
565
  requirements:
564
- - - ">="
566
+ - - ">"
565
567
  - !ruby/object:Gem::Version
566
- version: '0'
568
+ version: 1.3.1
567
569
  requirements:
568
570
  - Ruby >= 2.3.0
569
571
  rubygems_version: 3.0.6
@@ -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