lhs 24.0.0 → 24.1.0.pre.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 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