lhs 14.2.0 → 14.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|