lhs 14.2.0 → 14.3.0
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 +19 -2
- data/lib/lhs/concerns/item/save.rb +3 -2
- data/lib/lhs/concerns/item/update.rb +22 -6
- data/lib/lhs/data.rb +4 -6
- data/lib/lhs/version.rb +1 -1
- data/spec/item/errors_spec.rb +1 -1
- data/spec/item/partial_update_spec.rb +110 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6435e1ce72c8bd918fc9a4b1f5fde544c47ba90
|
4
|
+
data.tar.gz: f12a4d30361c30793c3a79b182be4acf9bd213f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c40a3b2b6d1f0942837fae1e2e0ee44794708b51a4927e4b52c8d0771f05f442ebf8313d0658053cb8ee7114f23ffaf8c6f0cb780d44da1e5e6bea271c7b46cb
|
7
|
+
data.tar.gz: ab234e491cf9e16141610dc9f3d8bda6423757b96daf2ba992b68f91e972d053409adcf3cb15b90a15a41b6f7cfe8ea0eb0149b9f2cb4fad25b6ecc138ef9720
|
data/README.md
CHANGED
@@ -696,6 +696,23 @@ record = Record.find('1z-5r1fkaj')
|
|
696
696
|
record.update(recommended: false)
|
697
697
|
```
|
698
698
|
|
699
|
+
## Partial Update
|
700
|
+
|
701
|
+
Often you just want to update a single attribute on an existing record. As ActiveRecord's `update_attribute` skips validation, which is unlikely with api services, and `update_attributes` is just an alias for `update`, LHS introduces `partial_update` for that matter.
|
702
|
+
|
703
|
+
`partial_update` will return false if persisting fails. `partial_update!` instead will an raise exception.
|
704
|
+
|
705
|
+
`partial_update` always updates the data of the local object first, before it tries to sync with an endpoint. So even if persisting fails, the local object is updated.
|
706
|
+
|
707
|
+
```ruby
|
708
|
+
record = Record.find('1z-5r1fkaj')
|
709
|
+
record.partial_update(recommended: false)
|
710
|
+
# POST /records/1z-5r1fkaj
|
711
|
+
{
|
712
|
+
recommended: true
|
713
|
+
}
|
714
|
+
```
|
715
|
+
|
699
716
|
## Becomes
|
700
717
|
|
701
718
|
Based on [ActiveRecord's implementation](http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-becomes), LHS implements `becomes`, too.
|
@@ -978,7 +995,7 @@ location = Location.find(123)
|
|
978
995
|
location.id # 123
|
979
996
|
```
|
980
997
|
|
981
|
-
### Configure complex accessors for nested data
|
998
|
+
### Configure complex accessors for nested data
|
982
999
|
|
983
1000
|
If items, limit, pagination, total etc. is nested in the responding objects, use complex data structures for configuring a record.
|
984
1001
|
|
@@ -1171,7 +1188,7 @@ end
|
|
1171
1188
|
Add to your spec_helper.rb:
|
1172
1189
|
|
1173
1190
|
```ruby
|
1174
|
-
require 'lhs/test/
|
1191
|
+
require 'lhs/test/request_cycle_cache_helper'
|
1175
1192
|
```
|
1176
1193
|
|
1177
1194
|
This will initialize a MemoryStore cache for LHC::Caching interceptor and resets the cache before every test.
|
@@ -34,11 +34,12 @@ class LHS::Item < LHS::Proxy
|
|
34
34
|
|
35
35
|
def create_and_merge_data!(options)
|
36
36
|
direct_response_data = record.request(options)
|
37
|
-
|
37
|
+
nested_path = record.item_created_key ? record.item_created_key : nil
|
38
|
+
_data.merge_raw!(direct_response_data, nested_path)
|
38
39
|
response_headers = direct_response_data._request.response.headers
|
39
40
|
if response_headers && response_headers['Location']
|
40
41
|
location_data = record.request(options.merge(url: response_headers['Location'], method: :get, body: nil))
|
41
|
-
_data.merge_raw!(location_data)
|
42
|
+
_data.merge_raw!(location_data, nested_path)
|
42
43
|
end
|
43
44
|
true
|
44
45
|
end
|
@@ -12,18 +12,34 @@ class LHS::Item < LHS::Proxy
|
|
12
12
|
false
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
15
|
+
def partial_update(params, options = nil)
|
16
|
+
update!(params, options, true)
|
17
|
+
rescue LHC::Error => e
|
18
|
+
self.errors = LHS::Problems::Errors.new(e.response, record)
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
def partial_update!(params, options = nil)
|
23
|
+
update!(params, options, true)
|
24
|
+
end
|
25
|
+
|
26
|
+
def update!(params, options = {}, partial_update = false)
|
16
27
|
options ||= {}
|
17
|
-
|
28
|
+
partial_data = LHS::Data.new(params, _data.parent, record)
|
29
|
+
nested_path = record.item_created_key ? record.item_created_key : nil
|
30
|
+
_data.merge_raw!(partial_data, nested_path)
|
31
|
+
data_sent = partial_update ? partial_data : _data
|
32
|
+
url = href || record.find_endpoint(id: id).compile(id: id)
|
18
33
|
response_data = record.request(
|
19
34
|
options.merge(
|
20
|
-
method: :post,
|
21
|
-
url:
|
22
|
-
body:
|
35
|
+
method: options.fetch(:method, :post),
|
36
|
+
url: url,
|
37
|
+
body: data_sent.to_json,
|
23
38
|
headers: { 'Content-Type' => 'application/json' }
|
24
39
|
)
|
25
40
|
)
|
26
|
-
|
41
|
+
nested_path = record.item_created_key ? record.item_created_key : nil
|
42
|
+
_data.merge_raw!(response_data, nested_path)
|
27
43
|
true
|
28
44
|
end
|
29
45
|
end
|
data/lib/lhs/data.rb
CHANGED
@@ -28,13 +28,11 @@ class LHS::Data
|
|
28
28
|
|
29
29
|
# merging data
|
30
30
|
# e.g. when loading remote data via link
|
31
|
-
def merge_raw!(data)
|
31
|
+
def merge_raw!(data, nested_path = nil)
|
32
32
|
return false if data.blank? || !data._raw.is_a?(Hash)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
_raw.merge! data._raw
|
37
|
-
end
|
33
|
+
raw = data._raw.dig(*nested_path) if nested_path
|
34
|
+
raw ||= data._raw
|
35
|
+
_raw.merge! raw
|
38
36
|
end
|
39
37
|
|
40
38
|
def _root
|
data/lib/lhs/version.rb
CHANGED
data/spec/item/errors_spec.rb
CHANGED
@@ -241,7 +241,7 @@ describe LHS::Item do
|
|
241
241
|
it 'does not raise an error when trying to find error record model name' do
|
242
242
|
expect(lambda do
|
243
243
|
record.reviews.first.errors[:name]
|
244
|
-
end).not_to raise_error
|
244
|
+
end).not_to raise_error
|
245
245
|
end
|
246
246
|
end
|
247
247
|
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe LHS::Item do
|
4
|
+
before(:each) do
|
5
|
+
class Record < LHS::Record
|
6
|
+
endpoint ':datastore/v2/:campaign_id/feedbacks'
|
7
|
+
endpoint ':datastore/v2/feedbacks'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:json) do
|
12
|
+
load_json(:feedbacks)
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:data) do
|
16
|
+
LHS::Data.new(json, nil, Record)
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:item) do
|
20
|
+
data[0]
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'update' do
|
24
|
+
it 'persists changes on the backend' do
|
25
|
+
stub_request(:post, item.href)
|
26
|
+
.with(body: { name: 'Steve' }.to_json)
|
27
|
+
result = item.partial_update(name: 'Steve')
|
28
|
+
expect(result).to eq true
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns false if persisting went wrong' do
|
32
|
+
stub_request(:post, item.href).to_return(status: 500)
|
33
|
+
result = item.partial_update(name: 'Steve')
|
34
|
+
expect(result).to eq false
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'merges reponse data with object' do
|
38
|
+
stub_request(:post, item.href)
|
39
|
+
.to_return(status: 200, body: item._raw.merge(likes: 'Banana').to_json)
|
40
|
+
item.partial_update(name: 'Steve')
|
41
|
+
expect(item.name).to eq 'Steve'
|
42
|
+
expect(item.likes).to eq 'Banana'
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'updates local version of an object even if BE request fails' do
|
46
|
+
stub_request(:post, item.href)
|
47
|
+
.to_return(status: 400, body: item._raw.merge(likes: 'Banana').to_json)
|
48
|
+
item.update(name: 'Andrea')
|
49
|
+
expect(item.name).to eq 'Andrea'
|
50
|
+
expect(item.likes).not_to eq 'Banana'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'update!' do
|
55
|
+
it 'raises if something goes wrong' do
|
56
|
+
stub_request(:post, item.href)
|
57
|
+
.with(body: { name: 'Steve' }.to_json)
|
58
|
+
.to_return(status: 500)
|
59
|
+
expect(-> { item.partial_update!(name: 'Steve') }).to raise_error LHC::ServerError
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'records without hrefs and nested items' do
|
64
|
+
|
65
|
+
before(:each) do
|
66
|
+
class Location < LHS::Record
|
67
|
+
endpoint 'http://uberall/locations'
|
68
|
+
endpoint 'http://uberall/locations/:id'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'finds and compiles existing endpoints to determine update url' do
|
73
|
+
stub_request(:get, "http://uberall/locations/1").to_return(body: { id: 1 }.to_json)
|
74
|
+
stub_request(:post, "http://uberall/locations/1").to_return(body: { id: 1, listings: [{ directory: 'facebook' }] }.to_json)
|
75
|
+
location = Location.find(1)
|
76
|
+
location.partial_update(autoSync: true)
|
77
|
+
expect(location.autoSync).to eq true
|
78
|
+
expect(location.listings.first.directory).to eq 'facebook'
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'records with nested items' do
|
82
|
+
|
83
|
+
before(:each) do
|
84
|
+
class Location < LHS::Record
|
85
|
+
endpoint 'http://uberall/locations'
|
86
|
+
endpoint 'http://uberall/locations/:id'
|
87
|
+
configuration item_created_key: [:response, :location], item_key: [:response, :location]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'finds and compiles existing endpoints to determine update url' do
|
92
|
+
stub_request(:get, "http://uberall/locations/1").to_return(body: { response: { location: { id: 1 } } }.to_json)
|
93
|
+
stub_request(:post, "http://uberall/locations/1").to_return(body: { response: { location: { id: 1, listings: [{ directory: 'facebook' }] } } }.to_json)
|
94
|
+
location = Location.find(1)
|
95
|
+
location.partial_update(autoSync: true)
|
96
|
+
expect(location.autoSync).to eq true
|
97
|
+
expect(location.listings.first.directory).to eq 'facebook'
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'use given update http method' do
|
101
|
+
stub_request(:get, "http://uberall/locations/1").to_return(body: { response: { location: { id: 1 } } }.to_json)
|
102
|
+
stub_request(:patch, "http://uberall/locations/1").to_return(body: { response: { location: { id: 1, listings: [{ directory: 'facebook' }] } } }.to_json)
|
103
|
+
location = Location.find(1)
|
104
|
+
location.partial_update({ autoSync: true }, { method: :patch })
|
105
|
+
expect(location.autoSync).to eq true
|
106
|
+
expect(location.listings.first.directory).to eq 'facebook'
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
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: 14.
|
4
|
+
version: 14.3.0
|
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: 2017-
|
11
|
+
date: 2017-10-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: lhc
|
@@ -331,6 +331,7 @@ files:
|
|
331
331
|
- spec/item/getter_spec.rb
|
332
332
|
- spec/item/internal_data_structure_spec.rb
|
333
333
|
- spec/item/map_spec.rb
|
334
|
+
- spec/item/partial_update_spec.rb
|
334
335
|
- spec/item/respond_to_spec.rb
|
335
336
|
- spec/item/save_spec.rb
|
336
337
|
- spec/item/setter_spec.rb
|
@@ -508,6 +509,7 @@ test_files:
|
|
508
509
|
- spec/item/getter_spec.rb
|
509
510
|
- spec/item/internal_data_structure_spec.rb
|
510
511
|
- spec/item/map_spec.rb
|
512
|
+
- spec/item/partial_update_spec.rb
|
511
513
|
- spec/item/respond_to_spec.rb
|
512
514
|
- spec/item/save_spec.rb
|
513
515
|
- spec/item/setter_spec.rb
|