lhs 21.3.0.pre.autoauth.1 → 22.1.1.pre

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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +205 -117
  3. data/lhs.gemspec +1 -1
  4. data/lib/lhs/concerns/record/chainable.rb +4 -4
  5. data/lib/lhs/concerns/record/configuration.rb +23 -14
  6. data/lib/lhs/concerns/record/request.rb +29 -32
  7. data/lib/lhs/concerns/record/update.rb +17 -0
  8. data/lib/lhs/interceptors/auto_oauth/interceptor.rb +16 -1
  9. data/lib/lhs/record.rb +6 -3
  10. data/lib/lhs/version.rb +1 -1
  11. data/spec/auto_oauth_spec.rb +141 -23
  12. data/spec/dummy/app/controllers/application_controller.rb +9 -1
  13. data/spec/dummy/app/controllers/automatic_authentication_controller.rb +18 -0
  14. data/spec/dummy/app/models/dummy_record_with_auto_oauth_provider.rb +6 -0
  15. data/spec/dummy/app/models/dummy_record_with_multiple_oauth_providers1.rb +7 -0
  16. data/spec/dummy/app/models/dummy_record_with_multiple_oauth_providers2.rb +7 -0
  17. data/spec/dummy/app/models/dummy_record_with_multiple_providers_per_endpoint.rb +6 -0
  18. data/spec/dummy/app/models/providers/internal_services.rb +7 -0
  19. data/spec/dummy/config/routes.rb +2 -0
  20. data/spec/item/destroy_spec.rb +1 -1
  21. data/spec/proxy/record_identification_spec.rb +1 -1
  22. data/spec/record/all_spec.rb +1 -1
  23. data/spec/record/endpoints_spec.rb +1 -1
  24. data/spec/record/handle_includes_errors_spec.rb +1 -1
  25. data/spec/record/has_many_spec.rb +1 -1
  26. data/spec/record/has_one_spec.rb +1 -1
  27. data/spec/record/includes_first_page_spec.rb +727 -0
  28. data/spec/record/includes_spec.rb +545 -579
  29. data/spec/record/includes_warning_spec.rb +1 -1
  30. data/spec/record/mapping_spec.rb +2 -2
  31. data/spec/record/references_spec.rb +1 -1
  32. data/spec/record/relation_caching_spec.rb +3 -3
  33. data/spec/record/update_spec.rb +62 -0
  34. metadata +21 -10
  35. data/spec/dummy/config/initializers/lhs.rb +0 -3
  36. data/spec/record/includes_all_spec.rb +0 -693
@@ -37,7 +37,7 @@ describe LHS::Record do
37
37
 
38
38
  it 'warns if linked data was simply included but is paginated' do
39
39
  expect(lambda {
40
- Customer.includes(:contracts).find(1)
40
+ Customer.includes_first_page(:contracts).find(1)
41
41
  }).to output(
42
42
  %r{\[WARNING\] You included `http://datastore/customers/1/contracts`, but this endpoint is paginated. You might want to use `includes_all` instead of `includes` \(https://github.com/local-ch/lhs#includes_all-for-paginated-endpoints\)\.}
43
43
  ).to_stderr
@@ -75,7 +75,7 @@ describe LHS::Record do
75
75
  status: 200, body: { 'href' => preceding_agb_url }.to_json, headers: {}
76
76
  )
77
77
 
78
- agb = Agb.includes(:preceding_agb).first!
78
+ agb = Agb.includes_first_page(:preceding_agb).first!
79
79
  expect(agb.pdf_url).to be == 'de'
80
80
  end
81
81
 
@@ -94,7 +94,7 @@ describe LHS::Record do
94
94
  stub_request(:get, "#{datastore}/favorites/1")
95
95
  .to_return(body: { local_entry: { href: "#{datastore}/local-entries/1" } }.to_json)
96
96
 
97
- favorite = Favorite.includes(:local_entry).find(1)
97
+ favorite = Favorite.includes_first_page(:local_entry).find(1)
98
98
  expect(favorite.local_entry).to be_kind_of LocalEntry
99
99
  expect(favorite.local_entry.name).to eq 'local.ch'
100
100
  end
@@ -40,7 +40,7 @@ describe LHS::Record do
40
40
 
41
41
  it 'uses the "references" hash for all symbols of the "including" array' do
42
42
  Customer
43
- .includes(:electronic_addresses, :contact_addresses)
43
+ .includes_first_page(:electronic_addresses, :contact_addresses)
44
44
  .references(
45
45
  electronic_addresses: referencing_options,
46
46
  contact_addresses: referencing_options
@@ -92,7 +92,7 @@ describe LHS::Record do
92
92
  .to_return(body: place_hash.to_json)
93
93
  place = Place
94
94
  .options(auth: { bearer: 'XYZ' })
95
- .includes_all(:available_assets)
95
+ .includes(:available_assets)
96
96
  .find(place_id)
97
97
  expect(place.available_assets.first).to be_a(AvailableAsset)
98
98
  end
@@ -102,7 +102,7 @@ describe LHS::Record do
102
102
  .to_return(body: place_hash.to_json)
103
103
  place = Place
104
104
  .options(auth: { bearer: 'XYZ' })
105
- .includes_all(:available_assets)
105
+ .includes(:available_assets)
106
106
  .where(id: place_id)
107
107
  expect(place.available_assets.first).to be_a(AvailableAsset)
108
108
  end
@@ -112,7 +112,7 @@ describe LHS::Record do
112
112
  .to_return(body: place_hash.to_json)
113
113
  place = Place
114
114
  .options(auth: { bearer: 'XYZ' })
115
- .includes_all(:available_assets)
115
+ .includes(:available_assets)
116
116
  .find_by(id: place_id)
117
117
  expect(place.available_assets.first).to be_a(AvailableAsset)
118
118
  end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHS::Record do
6
+ context 'update' do
7
+
8
+ before do
9
+ class Record < LHS::Record
10
+ endpoint 'http://datastore/records/{id}'
11
+ end
12
+ end
13
+
14
+ it 'allows to directly update a record without fetching it first' do
15
+ stub_request(:post, "http://datastore/records/123")
16
+ .with(body: { name: 'Steve' }.to_json)
17
+ .to_return(status: 200, body: {}.to_json)
18
+
19
+ Record.update(
20
+ id: '123',
21
+ name: 'Steve'
22
+ )
23
+ end
24
+
25
+ it 'does not fail during an error with update' do
26
+ stub_request(:post, "http://datastore/records/123")
27
+ .with(body: { name: 'Steve' }.to_json)
28
+ .to_return(status: 404, body: {}.to_json)
29
+
30
+ record = Record.update(
31
+ id: '123',
32
+ name: 'Steve'
33
+ )
34
+
35
+ expect(record.errors.status_code).to eq 404
36
+ end
37
+
38
+ it 'allows to directly update! a record without fetching it first' do
39
+ stub_request(:post, "http://datastore/records/123")
40
+ .with(body: { name: 'Steve' }.to_json)
41
+ .to_return(status: 200)
42
+
43
+ Record.update!(
44
+ id: '123',
45
+ name: 'Steve'
46
+ )
47
+ end
48
+
49
+ it 'raises an error when trying to update! but retrieving an error status' do
50
+ stub_request(:post, "http://datastore/records/123")
51
+ .with(body: { name: 'Steve' }.to_json)
52
+ .to_return(status: 404)
53
+
54
+ expect(-> {
55
+ Record.update!(
56
+ id: '123',
57
+ name: 'Steve'
58
+ )
59
+ }).to raise_error(LHC::NotFound)
60
+ end
61
+ end
62
+ 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: 21.3.0.pre.autoauth.1
4
+ version: 22.1.1.pre
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-06-15 00:00:00.000000000 Z
11
+ date: 2020-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -146,16 +146,16 @@ dependencies:
146
146
  name: rollbar
147
147
  requirement: !ruby/object:Gem::Requirement
148
148
  requirements:
149
- - - ">="
149
+ - - "<="
150
150
  - !ruby/object:Gem::Version
151
- version: '0'
151
+ version: 2.24.0
152
152
  type: :development
153
153
  prerelease: false
154
154
  version_requirements: !ruby/object:Gem::Requirement
155
155
  requirements:
156
- - - ">="
156
+ - - "<="
157
157
  - !ruby/object:Gem::Version
158
- version: '0'
158
+ version: 2.24.0
159
159
  - !ruby/object:Gem::Dependency
160
160
  name: rspec-rails
161
161
  requirement: !ruby/object:Gem::Requirement
@@ -312,6 +312,7 @@ files:
312
312
  - lib/lhs/concerns/record/request.rb
313
313
  - lib/lhs/concerns/record/scope.rb
314
314
  - lib/lhs/concerns/record/tracing.rb
315
+ - lib/lhs/concerns/record/update.rb
315
316
  - lib/lhs/config.rb
316
317
  - lib/lhs/data.rb
317
318
  - lib/lhs/endpoint.rb
@@ -388,9 +389,14 @@ files:
388
389
  - spec/dummy/app/models/concerns/.keep
389
390
  - spec/dummy/app/models/dummy_customer.rb
390
391
  - spec/dummy/app/models/dummy_record.rb
392
+ - spec/dummy/app/models/dummy_record_with_auto_oauth_provider.rb
393
+ - spec/dummy/app/models/dummy_record_with_multiple_oauth_providers1.rb
394
+ - spec/dummy/app/models/dummy_record_with_multiple_oauth_providers2.rb
395
+ - spec/dummy/app/models/dummy_record_with_multiple_providers_per_endpoint.rb
391
396
  - spec/dummy/app/models/dummy_record_with_oauth.rb
392
397
  - spec/dummy/app/models/dummy_user.rb
393
398
  - spec/dummy/app/models/providers/customer_system.rb
399
+ - spec/dummy/app/models/providers/internal_services.rb
394
400
  - spec/dummy/app/views/error_handling_with_chains/error.html.erb
395
401
  - spec/dummy/app/views/error_handling_with_chains/show.html.erb
396
402
  - spec/dummy/app/views/form_for.html.erb
@@ -410,7 +416,6 @@ files:
410
416
  - spec/dummy/config/initializers/cookies_serializer.rb
411
417
  - spec/dummy/config/initializers/filter_parameter_logging.rb
412
418
  - spec/dummy/config/initializers/inflections.rb
413
- - spec/dummy/config/initializers/lhs.rb
414
419
  - spec/dummy/config/initializers/mime_types.rb
415
420
  - spec/dummy/config/initializers/rollbar.rb
416
421
  - spec/dummy/config/initializers/session_store.rb
@@ -496,7 +501,7 @@ files:
496
501
  - spec/record/href_for_spec.rb
497
502
  - spec/record/ignore_errors_spec.rb
498
503
  - spec/record/immutable_chains_spec.rb
499
- - spec/record/includes_all_spec.rb
504
+ - spec/record/includes_first_page_spec.rb
500
505
  - spec/record/includes_spec.rb
501
506
  - spec/record/includes_warning_spec.rb
502
507
  - spec/record/item_key_spec.rb
@@ -526,6 +531,7 @@ files:
526
531
  - spec/record/to_hash_spec.rb
527
532
  - spec/record/to_json_spec.rb
528
533
  - spec/record/tracing_spec.rb
534
+ - spec/record/update_spec.rb
529
535
  - spec/record/where_chains_spec.rb
530
536
  - spec/record/where_spec.rb
531
537
  - spec/record/where_values_hash_spec.rb
@@ -611,9 +617,14 @@ test_files:
611
617
  - spec/dummy/app/models/concerns/.keep
612
618
  - spec/dummy/app/models/dummy_customer.rb
613
619
  - spec/dummy/app/models/dummy_record.rb
620
+ - spec/dummy/app/models/dummy_record_with_auto_oauth_provider.rb
621
+ - spec/dummy/app/models/dummy_record_with_multiple_oauth_providers1.rb
622
+ - spec/dummy/app/models/dummy_record_with_multiple_oauth_providers2.rb
623
+ - spec/dummy/app/models/dummy_record_with_multiple_providers_per_endpoint.rb
614
624
  - spec/dummy/app/models/dummy_record_with_oauth.rb
615
625
  - spec/dummy/app/models/dummy_user.rb
616
626
  - spec/dummy/app/models/providers/customer_system.rb
627
+ - spec/dummy/app/models/providers/internal_services.rb
617
628
  - spec/dummy/app/views/error_handling_with_chains/error.html.erb
618
629
  - spec/dummy/app/views/error_handling_with_chains/show.html.erb
619
630
  - spec/dummy/app/views/form_for.html.erb
@@ -633,7 +644,6 @@ test_files:
633
644
  - spec/dummy/config/initializers/cookies_serializer.rb
634
645
  - spec/dummy/config/initializers/filter_parameter_logging.rb
635
646
  - spec/dummy/config/initializers/inflections.rb
636
- - spec/dummy/config/initializers/lhs.rb
637
647
  - spec/dummy/config/initializers/mime_types.rb
638
648
  - spec/dummy/config/initializers/rollbar.rb
639
649
  - spec/dummy/config/initializers/session_store.rb
@@ -719,7 +729,7 @@ test_files:
719
729
  - spec/record/href_for_spec.rb
720
730
  - spec/record/ignore_errors_spec.rb
721
731
  - spec/record/immutable_chains_spec.rb
722
- - spec/record/includes_all_spec.rb
732
+ - spec/record/includes_first_page_spec.rb
723
733
  - spec/record/includes_spec.rb
724
734
  - spec/record/includes_warning_spec.rb
725
735
  - spec/record/item_key_spec.rb
@@ -749,6 +759,7 @@ test_files:
749
759
  - spec/record/to_hash_spec.rb
750
760
  - spec/record/to_json_spec.rb
751
761
  - spec/record/tracing_spec.rb
762
+ - spec/record/update_spec.rb
752
763
  - spec/record/where_chains_spec.rb
753
764
  - spec/record/where_spec.rb
754
765
  - spec/record/where_values_hash_spec.rb
@@ -1,3 +0,0 @@
1
- LHS.configure do |config|
2
- config.auto_oauth = -> { access_token }
3
- end
@@ -1,693 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rails_helper'
4
-
5
- describe LHS::Record do
6
- context 'includes all' do
7
- before do
8
- class Customer < LHS::Record
9
- endpoint 'http://datastore/customers/{id}'
10
- end
11
-
12
- class User < LHS::Record
13
- configuration pagination_strategy: 'link'
14
- endpoint 'http://datastore/users'
15
- end
16
- end
17
-
18
- let(:amount_of_contracts) { 33 }
19
- let(:amount_of_products) { 22 }
20
- let(:amount_of_users_1st_page) { 10 }
21
- let(:amount_of_users_2nd_page) { 3 }
22
- let(:amount_of_users) { amount_of_users_1st_page + amount_of_users_2nd_page }
23
-
24
- let!(:customer_request) do
25
- stub_request(:get, 'http://datastore/customers/1')
26
- .to_return(
27
- body: {
28
- contracts: { href: 'http://datastore/customers/1/contracts' },
29
- users: { href: 'http://datastore/users?limit=10' }
30
- }.to_json
31
- )
32
- end
33
-
34
- #
35
- # Contracts
36
- #
37
-
38
- let!(:contracts_request) do
39
- stub_request(:get, "http://datastore/customers/1/contracts?limit=100")
40
- .to_return(
41
- body: {
42
- items: 10.times.map do
43
- {
44
- products: { href: 'http://datastore/products' }
45
- }
46
- end,
47
- limit: 10,
48
- offset: 0,
49
- total: amount_of_contracts
50
- }.to_json
51
- )
52
- end
53
-
54
- def additional_contracts_request(offset, amount)
55
- stub_request(:get, "http://datastore/customers/1/contracts?limit=10&offset=#{offset}")
56
- .to_return(
57
- body: {
58
- items: amount.times.map do
59
- {
60
- products: { href: 'http://datastore/products' }
61
- }
62
- end,
63
- limit: 10,
64
- offset: offset,
65
- total: amount_of_contracts
66
- }.to_json
67
- )
68
- end
69
-
70
- let!(:contracts_request_page_2) do
71
- additional_contracts_request(10, 10)
72
- end
73
-
74
- let!(:contracts_request_page_3) do
75
- additional_contracts_request(20, 10)
76
- end
77
-
78
- let!(:contracts_request_page_4) do
79
- additional_contracts_request(30, 3)
80
- end
81
-
82
- #
83
- # Products
84
- #
85
-
86
- let!(:products_request) do
87
- stub_request(:get, "http://datastore/products?limit=100")
88
- .to_return(
89
- body: {
90
- items: 10.times.map do
91
- { name: 'LBC' }
92
- end,
93
- limit: 10,
94
- offset: 0,
95
- total: amount_of_products
96
- }.to_json
97
- )
98
- end
99
-
100
- def additional_products_request(offset, amount)
101
- stub_request(:get, "http://datastore/products?limit=10&offset=#{offset}")
102
- .to_return(
103
- body: {
104
- items: amount.times.map do
105
- { name: 'LBC' }
106
- end,
107
- limit: 10,
108
- offset: offset,
109
- total: amount_of_products
110
- }.to_json
111
- )
112
- end
113
-
114
- let!(:products_request_page_2) do
115
- additional_products_request(10, 10)
116
- end
117
-
118
- let!(:products_request_page_3) do
119
- additional_products_request(20, 2)
120
- end
121
-
122
- #
123
- # Users
124
- #
125
-
126
- let!(:users_request) do
127
- stub_request(:get, 'http://datastore/users?limit=10')
128
- .to_return(
129
- body: {
130
- items: amount_of_users_1st_page.times.map do
131
- { name: 'Hans Muster' }
132
- end,
133
- limit: 10,
134
- next: { href: 'http://datastore/users?for_user_id=10&limit=10' }
135
- }.to_json
136
- )
137
- end
138
-
139
- let!(:users_request_page_2) do
140
- stub_request(:get, 'http://datastore/users?for_user_id=10&limit=10')
141
- .to_return(
142
- body: {
143
- items: amount_of_users_2nd_page.times.map do
144
- { name: 'Lisa Müller' }
145
- end,
146
- limit: 10,
147
- next: { href: 'http://datastore/users?for_user_id=13&limit=10' }
148
- }.to_json
149
- )
150
- end
151
-
152
- let!(:users_request_page_3) do
153
- stub_request(:get, 'http://datastore/users?for_user_id=13&limit=10')
154
- .to_return(
155
- body: {
156
- items: [],
157
- limit: 10
158
- }.to_json
159
- )
160
- end
161
-
162
- it 'includes all linked business objects no matter pagination' do
163
- customer = nil
164
-
165
- expect(lambda do
166
- customer = Customer
167
- .includes_all(:users, contracts: :products)
168
- .find(1)
169
- end).to output(
170
- %r{\[WARNING\] You are loading all pages from a resource paginated with links only. As this is performed sequentially, it can result in very poor performance! \(https://github.com/local-ch/lhs#pagination-strategy-link\).}
171
- ).to_stderr
172
-
173
- expect(customer.users.length).to eq amount_of_users
174
- expect(customer.contracts.length).to eq amount_of_contracts
175
- expect(customer.contracts.first.products.length).to eq amount_of_products
176
- expect(customer_request).to have_been_requested.at_least_once
177
- expect(contracts_request).to have_been_requested.at_least_once
178
- expect(contracts_request_page_2).to have_been_requested.at_least_once
179
- expect(contracts_request_page_3).to have_been_requested.at_least_once
180
- expect(contracts_request_page_4).to have_been_requested.at_least_once
181
- expect(products_request).to have_been_requested.at_least_once
182
- expect(products_request_page_2).to have_been_requested.at_least_once
183
- expect(products_request_page_3).to have_been_requested.at_least_once
184
- expect(users_request).to have_been_requested.at_least_once
185
- expect(users_request_page_2).to have_been_requested.at_least_once
186
- expect(users_request_page_3).to have_been_requested.at_least_once
187
- end
188
-
189
- context 'links already contain pagination parameters' do
190
- let!(:customer_request) do
191
- stub_request(:get, 'http://datastore/customers/1')
192
- .to_return(
193
- body: {
194
- contracts: { href: 'http://datastore/customers/1/contracts?limit=5&offset=0' }
195
- }.to_json
196
- )
197
- end
198
-
199
- let!(:contracts_request) do
200
- stub_request(:get, "http://datastore/customers/1/contracts?limit=100")
201
- .to_return(
202
- body: {
203
- items: 10.times.map do
204
- {
205
- products: { href: 'http://datastore/products' }
206
- }
207
- end,
208
- limit: 10,
209
- offset: 0,
210
- total: amount_of_contracts
211
- }.to_json
212
- )
213
- end
214
-
215
- it 'overwrites existing pagination paramters if they are already contained in a string' do
216
- expect(LHC).to receive(:request)
217
- .with(url: "http://datastore/customers/1").and_call_original
218
-
219
- expect(LHC).to receive(:request)
220
- .with(url: "http://datastore/customers/1/contracts",
221
- all: true,
222
- params: { limit: 100 }).and_call_original
223
-
224
- expect(LHC).to receive(:request)
225
- .with([{ url: "http://datastore/customers/1/contracts",
226
- all: true,
227
- params: { limit: 10, offset: 10 } },
228
- { url: "http://datastore/customers/1/contracts",
229
- all: true,
230
- params: { limit: 10, offset: 20 } },
231
- { url: "http://datastore/customers/1/contracts",
232
- all: true,
233
- params: { limit: 10, offset: 30 } }]).and_call_original
234
-
235
- customer = Customer
236
- .includes_all(:contracts)
237
- .find(1)
238
- expect(customer.contracts.length).to eq amount_of_contracts
239
- end
240
- end
241
-
242
- context 'includes for an empty array' do
243
- before do
244
- class Contract < LHS::Record
245
- endpoint 'http://datastore/contracts/{id}'
246
- end
247
- stub_request(:get, %r{http://datastore/contracts/\d})
248
- .to_return(body: {
249
- options: nested_resources
250
- }.to_json)
251
- end
252
-
253
- context 'empty array' do
254
- let(:nested_resources) { [] }
255
-
256
- it 'includes_all in case of an empty array' do
257
- expect(
258
- -> { Contract.includes(:product).includes_all(:options).find(1) }
259
- ).not_to raise_error
260
- expect(
261
- -> { Contract.includes(:product).includes_all(:options).find(1, 2) }
262
- ).not_to raise_error
263
- end
264
- end
265
-
266
- context 'weird array without hrefs' do
267
- before do
268
- stub_request(:get, "http://datastore/options/1?limit=100")
269
- .to_return(body: { type: 'REACH_EXT' }.to_json)
270
- end
271
-
272
- let(:nested_resources) { [{ href: 'http://datastore/options/1' }, { type: 'E_COMMERCE' }] }
273
-
274
- it 'includes_all in case of an unexpect objects within array' do
275
- expect(
276
- -> { Contract.includes(:product).includes_all(:options).find(1) }
277
- ).not_to raise_error
278
- expect(
279
- -> { Contract.includes(:product).includes_all(:options).find(1, 2) }
280
- ).not_to raise_error
281
- end
282
- end
283
- end
284
-
285
- context 'include a known/identifiable record' do
286
- before do
287
- class Contract < LHS::Record
288
- endpoint 'http://datastore/contracts/{id}'
289
- end
290
-
291
- class Entry < LHS::Record
292
- endpoint '{+datastore}/entry/v1/{id}.json'
293
- end
294
-
295
- LHC.config.placeholder(:datastore, 'http://datastore')
296
- end
297
-
298
- let!(:customer_request) do
299
- stub_request(:get, %r{http://datastore/customers/\d+})
300
- .to_return(
301
- body: {
302
- contracts: [{ href: 'http://datastore/contracts/1' }, { href: 'http://datastore/contracts/2' }]
303
- }.to_json
304
- )
305
- end
306
-
307
- let!(:contracts_request) do
308
- stub_request(:get, %r{http://datastore/contracts/\d+})
309
- .to_return(
310
- body: {
311
- type: 'contract',
312
- entry: { href: 'http://datastore/entry/v1/1.json' }
313
- }.to_json
314
- )
315
- end
316
-
317
- let!(:entry_request) do
318
- stub_request(:get, %r{http://datastore/entry/v1/\d+.json})
319
- .to_return(
320
- body: {
321
- name: 'Casa Ferlin'
322
- }.to_json
323
- )
324
- end
325
-
326
- it 'loads included identifiable records without raising exceptions' do
327
- customer = Customer.includes_all(contracts: :entry).find(1, 2).first
328
- expect(customer.contracts.first.href).to eq 'http://datastore/contracts/1'
329
- expect(customer.contracts.first.type).to eq 'contract'
330
- expect(customer.contracts.first.entry.name).to eq 'Casa Ferlin'
331
- end
332
- end
333
-
334
- context 'includes all for parallel loaded ids' do
335
- before do
336
- class Place < LHS::Record
337
- endpoint 'http://datastore/places/{id}'
338
- end
339
- end
340
-
341
- let!(:place_request_1) do
342
- stub_request(:get, %r{http://datastore/places/1})
343
- .to_return(
344
- body: {
345
- category_relations: [
346
- { href: 'http://datastore/category_relations/1' },
347
- { href: 'http://datastore/category_relations/2' }
348
- ]
349
- }.to_json
350
- )
351
- end
352
-
353
- let!(:place_request_2) do
354
- stub_request(:get, %r{http://datastore/places/2})
355
- .to_return(
356
- body: {
357
- category_relations: []
358
- }.to_json
359
- )
360
- end
361
-
362
- let!(:place_request_3) do
363
- stub_request(:get, %r{http://datastore/places/3})
364
- .to_return(
365
- body: {
366
- category_relations: [
367
- { href: 'http://datastore/category_relations/1' },
368
- { href: 'http://datastore/category_relations/3' }
369
- ]
370
- }.to_json
371
- )
372
- end
373
-
374
- let!(:category_relation_request_1) do
375
- stub_request(:get, %r{http://datastore/category_relations/1})
376
- .to_return(
377
- body: {
378
- name: "Category 1"
379
- }.to_json
380
- )
381
- end
382
-
383
- let!(:category_relation_request_2) do
384
- stub_request(:get, %r{http://datastore/category_relations/2})
385
- .to_return(
386
- body: {
387
- name: "Category 2"
388
- }.to_json
389
- )
390
- end
391
-
392
- let!(:category_relation_request_3) do
393
- stub_request(:get, %r{http://datastore/category_relations/3})
394
- .to_return(
395
- body: {
396
- name: "Category 3"
397
- }.to_json
398
- )
399
- end
400
-
401
- let(:category_name) { 'Category Relation' }
402
-
403
- it 'requests places in parallel and includes category relation' do
404
- places = Place.includes_all(:category_relations).find(1, 2, 3)
405
- expect(places[0].category_relations[0].name).to eq 'Category 1'
406
- expect(places[0].category_relations[1].name).to eq 'Category 2'
407
- expect(places[2].category_relations[0].name).to eq 'Category 1'
408
- expect(places[2].category_relations[1].name).to eq 'Category 3'
409
- end
410
- end
411
- end
412
-
413
- context 'Linked resources' do
414
- before do
415
- stub_request(:get, 'http://datastore/places/1/contracts?offset=0&limit=10')
416
- .to_return(
417
- body: {
418
- href: "http://datastore/v2/places/1/contracts?offset=0&limit=10",
419
- items: [{ href: "http://datastore/v2/contracts/1" }],
420
- offset: 0,
421
- limit: 10,
422
- total: 10
423
- }.to_json
424
- )
425
-
426
- stub_request(:get, "http://datastore/v2/contracts/1")
427
- .to_return(
428
- body: {
429
- customer: { name: 'Swisscom Directories AG' }
430
- }.to_json
431
- )
432
-
433
- stub_request(:get, 'http://datastore/places/1?limit=1')
434
- .to_return(
435
- body: { href: 'http://datastore/places/1', contracts: { href: 'http://datastore/places/1/contracts?offset=0&limit=10' } }.to_json
436
- )
437
-
438
- class Place < LHS::Record
439
- endpoint 'http://datastore/places/{id}'
440
- end
441
-
442
- class Contract < LHS::Record
443
- endpoint 'http://datastore/places/{place_id}/contracts'
444
- end
445
- end
446
-
447
- it 'does not use the root record endpoints when including nested records' do
448
- place = Place
449
- .includes_all(:contracts)
450
- .find_by(id: 1)
451
- expect(place.contracts.first.customer.name).to eq 'Swisscom Directories AG'
452
- end
453
- end
454
-
455
- context 'nested includes_all' do
456
- context 'with optional children' do
457
-
458
- let(:favorites_request_stub) do
459
- stub_request(:get, %r{http://datastore/favorites})
460
- .to_return(
461
- body: {
462
- items: [{
463
- href: "http://datastore/favorites/1",
464
- place: {
465
- href: "http://datastore/places/1"
466
- }
467
- }, {
468
- href: "http://datastore/favorite/2",
469
- place: {
470
- href: "http://datastore/places/2"
471
- }
472
- }, {
473
- href: "http://datastore/favorite/3",
474
- place: {
475
- href: "http://datastore/places/3"
476
- }
477
- }],
478
- total: 3,
479
- offset: 0,
480
- limit: 100
481
- }.to_json
482
- )
483
- end
484
-
485
- let(:place1_request_stub) do
486
- stub_request(:get, %r{http://datastore/places/1})
487
- .to_return(
488
- body: {
489
- href: "http://datastore/places/1",
490
- name: 'Place 1',
491
- contracts: {
492
- href: "http://datastore/places/1/contracts"
493
- }
494
- }.to_json
495
- )
496
- end
497
-
498
- let(:place2_request_stub) do
499
- stub_request(:get, %r{http://datastore/places/2})
500
- .to_return(
501
- body: {
502
- href: "http://datastore/places/2",
503
- name: 'Place 2'
504
- }.to_json
505
- )
506
- end
507
-
508
- let(:place3_request_stub) do
509
- stub_request(:get, %r{http://datastore/places/3})
510
- .to_return(
511
- body: {
512
- href: "http://datastore/places/3",
513
- name: 'Place 3',
514
- contracts: {
515
- href: "http://datastore/places/3/contracts"
516
- }
517
- }.to_json
518
- )
519
- end
520
-
521
- let(:contracts_request_for_place1_stub) do
522
- stub_request(:get, %r{http://datastore/places/1/contracts})
523
- .to_return(
524
- body: {
525
- items: [{
526
- href: "http://datastore/places/1/contracts/1",
527
- name: 'Contract 1'
528
- }],
529
- total: 1,
530
- offset: 0,
531
- limit: 10
532
- }.to_json
533
- )
534
- end
535
-
536
- let(:contracts_request_for_place3_stub) do
537
- stub_request(:get, %r{http://datastore/places/3/contracts})
538
- .to_return(
539
- body: {
540
- items: [{
541
- href: "http://datastore/places/3/contracts/1",
542
- name: 'Contract 3'
543
- }],
544
- total: 1,
545
- offset: 0,
546
- limit: 10
547
- }.to_json
548
- )
549
- end
550
-
551
- before do
552
- class Favorite < LHS::Record
553
- endpoint 'http://datastore/favorites'
554
- end
555
-
556
- class Place < LHS::Record
557
- endpoint 'http://datastore/places/{id}'
558
- end
559
-
560
- class Contract < LHS::Record
561
- endpoint 'http://datastore/places/{place_id}/contracts'
562
- end
563
-
564
- favorites_request_stub
565
- place1_request_stub
566
- place2_request_stub
567
- place3_request_stub
568
- contracts_request_for_place1_stub
569
- contracts_request_for_place3_stub
570
- end
571
-
572
- it 'includes nested objects when they exist' do
573
- favorites = Favorite.includes(:place).includes_all(place: :contracts).all
574
-
575
- expect(favorites.first.place.name).to eq('Place 1')
576
- expect(favorites.first.place.contracts.first.name).to eq('Contract 1')
577
- end
578
-
579
- it 'does not include nested objects when they are not there' do
580
- favorites = Favorite.includes(:place).includes_all(place: :contracts).all
581
-
582
- expect(favorites[1].place.name).to eq('Place 2')
583
- expect(favorites[1].place.contracts).to be(nil)
584
- end
585
-
586
- it 'does include and merges objects after nil objects in collections' do
587
- favorites = Favorite.includes(:place).includes_all(place: :contracts).all
588
-
589
- expect(favorites.last.place.name).to eq('Place 3')
590
- expect(favorites.last.place.contracts.first.name).to eq('Contract 3')
591
- end
592
- end
593
- end
594
-
595
- context 'includes collection trough single item' do
596
-
597
- before do
598
- class Place < LHS::Record
599
- endpoint 'https://places/{id}'
600
- end
601
-
602
- stub_request(:get, 'https://places/1')
603
- .to_return(
604
- body: {
605
- customer: { href: 'https://customers/1' }
606
- }.to_json
607
- )
608
-
609
- stub_request(:get, 'https://customers/1?limit=100')
610
- .to_return(
611
- body: {
612
- addresses: { 'href': 'https://customer/1/addresses' }
613
- }.to_json
614
- )
615
-
616
- stub_request(:get, 'https://customer/1/addresses?limit=100')
617
- .to_return(
618
- body: {
619
- items: [
620
- { city: 'Zurich', no: 1 },
621
- { city: 'Zurich', no: 2 }
622
- ],
623
- total: 2
624
- }.to_json
625
- )
626
- end
627
-
628
- it 'includes a collection trough a single item without exceptions' do
629
- place = Place
630
- .includes_all(customer: :addresses)
631
- .find(1)
632
- expect(place.customer.addresses.map(&:no)).to eq [1, 2]
633
- end
634
- end
635
-
636
- context 'does not fail including all linked resources' do
637
-
638
- before do
639
- class CustomerOnboardingToken < LHS::Record
640
- endpoint 'https://token/{id}'
641
- end
642
-
643
- class Place < LHS::Record
644
- endpoint 'https://places/{id}'
645
- end
646
-
647
- class AvailableAsset < LHS::Record
648
- endpoint 'https://assets'
649
- end
650
-
651
- stub_request(:get, 'https://token/1')
652
- .to_return(
653
- body: {
654
- places: [{ href: 'https://places/1' }]
655
- }.to_json
656
- )
657
-
658
- stub_request(:get, 'https://places/1?limit=100')
659
- .to_return(
660
- body: {
661
- available_assets: { 'href': 'https://assets?limit=10&offset=0' }
662
- }.to_json
663
- )
664
-
665
- stub_request(:get, 'https://assets?limit=10&offset=0')
666
- .to_return(
667
- body: {
668
- items: 10.times.map { { asset_code: 'CATEGORIES' } },
669
- total: 17,
670
- offset: 0,
671
- limit: 10
672
- }.to_json
673
- )
674
-
675
- stub_request(:get, 'https://assets?limit=10&offset=10')
676
- .to_return(
677
- body: {
678
- items: 7.times.map { { asset_code: 'CATEGORIES' } },
679
- total: 17,
680
- offset: 0,
681
- limit: 10
682
- }.to_json
683
- )
684
- end
685
-
686
- it 'includes a collection trough a single item without exceptions' do
687
- token = CustomerOnboardingToken
688
- .includes_all(places: :available_assets)
689
- .find(1)
690
- expect(token.places.first.available_assets.length).to eq 17
691
- end
692
- end
693
- end