lhs 21.2.3 → 22.0.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +249 -116
  3. data/lhs.gemspec +1 -1
  4. data/lib/lhs.rb +8 -0
  5. data/lib/lhs/concerns/o_auth.rb +25 -0
  6. data/lib/lhs/concerns/record/chainable.rb +4 -4
  7. data/lib/lhs/concerns/record/configuration.rb +28 -11
  8. data/lib/lhs/concerns/record/request.rb +29 -8
  9. data/lib/lhs/config.rb +1 -1
  10. data/lib/lhs/interceptors/auto_oauth/interceptor.rb +33 -0
  11. data/lib/lhs/interceptors/auto_oauth/thread_registry.rb +18 -0
  12. data/lib/lhs/version.rb +1 -1
  13. data/spec/auto_oauth_spec.rb +169 -0
  14. data/spec/dummy/app/controllers/application_controller.rb +15 -0
  15. data/spec/dummy/app/controllers/automatic_authentication_controller.rb +29 -0
  16. data/spec/dummy/app/models/dummy_record_with_auto_oauth_provider.rb +6 -0
  17. data/spec/dummy/app/models/dummy_record_with_multiple_oauth_providers1.rb +7 -0
  18. data/spec/dummy/app/models/dummy_record_with_multiple_oauth_providers2.rb +7 -0
  19. data/spec/dummy/app/models/dummy_record_with_multiple_providers_per_endpoint.rb +6 -0
  20. data/spec/dummy/app/models/dummy_record_with_oauth.rb +7 -0
  21. data/spec/dummy/app/models/providers/internal_services.rb +7 -0
  22. data/spec/dummy/config/routes.rb +5 -0
  23. data/spec/item/destroy_spec.rb +1 -1
  24. data/spec/proxy/record_identification_spec.rb +1 -1
  25. data/spec/record/all_spec.rb +1 -1
  26. data/spec/record/endpoints_spec.rb +1 -1
  27. data/spec/record/error_handling_integration_spec.rb +1 -1
  28. data/spec/record/handle_includes_errors_spec.rb +1 -1
  29. data/spec/record/has_many_spec.rb +1 -1
  30. data/spec/record/has_one_spec.rb +1 -1
  31. data/spec/record/includes_first_page_spec.rb +727 -0
  32. data/spec/record/includes_spec.rb +546 -561
  33. data/spec/record/includes_warning_spec.rb +1 -1
  34. data/spec/record/mapping_spec.rb +2 -2
  35. data/spec/record/references_spec.rb +1 -1
  36. data/spec/record/relation_caching_spec.rb +3 -3
  37. data/spec/request_cycle_cache_spec.rb +3 -3
  38. metadata +27 -8
  39. 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
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rails_helper'
4
- require 'lhc/test/cache_helper.rb'
4
+ require 'lhc/rspec'
5
5
 
6
6
  describe 'Request Cycle Cache', type: :request do
7
7
  let!(:request) do
@@ -37,7 +37,7 @@ describe 'Request Cycle Cache', type: :request do
37
37
  expect(lambda do
38
38
  get '/request_cycle_cache/no_caching_interceptor'
39
39
  end).to output(
40
- %r{\[WARNING\] Can't enable request cycle cache as LHC::Caching interceptor is not enabled/configured \(see https://github.com/local-ch/lhc/blob/master/docs/interceptors/caching.md#caching-interceptor\)!}
40
+ %r{\[WARNING\] Can't enable request cycle cache as LHC::Caching interceptor is not enabled/configured \(see https://github.com/local-ch/lhc/blob/master/README.md#caching-interceptor\)!}
41
41
  ).to_stderr
42
42
  expect(request).to have_been_made.times(2)
43
43
  end
@@ -70,7 +70,7 @@ describe 'Request Cycle Cache', type: :request do
70
70
  expect(lambda do
71
71
  get '/request_cycle_cache/no_caching_interceptor'
72
72
  end).not_to output(
73
- %r{\[WARNING\] Can't enable request cycle cache as LHC::Caching interceptor is not enabled/configured \(see https://github.com/local-ch/lhc/blob/master/docs/interceptors/caching.md#caching-interceptor\)!}
73
+ %r{\[WARNING\] Can't enable request cycle cache as LHC::Caching interceptor is not enabled/configured \(see https://github.com/local-ch/lhc/blob/master/README.md#caching-interceptor\)!}
74
74
  ).to_stderr
75
75
  expect(request).to have_been_made.times(2)
76
76
  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.2.3
4
+ version: 22.0.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: 2020-03-24 00:00:00.000000000 Z
11
+ date: 2020-06-29 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
@@ -283,6 +283,7 @@ files:
283
283
  - lib/lhs/concerns/item/save.rb
284
284
  - lib/lhs/concerns/item/update.rb
285
285
  - lib/lhs/concerns/item/validation.rb
286
+ - lib/lhs/concerns/o_auth.rb
286
287
  - lib/lhs/concerns/option_blocks.rb
287
288
  - lib/lhs/concerns/proxy/accessors.rb
288
289
  - lib/lhs/concerns/proxy/create.rb
@@ -314,6 +315,8 @@ files:
314
315
  - lib/lhs/config.rb
315
316
  - lib/lhs/data.rb
316
317
  - lib/lhs/endpoint.rb
318
+ - lib/lhs/interceptors/auto_oauth/interceptor.rb
319
+ - lib/lhs/interceptors/auto_oauth/thread_registry.rb
317
320
  - lib/lhs/interceptors/extended_rollbar/handler.rb
318
321
  - lib/lhs/interceptors/extended_rollbar/interceptor.rb
319
322
  - lib/lhs/interceptors/extended_rollbar/thread_registry.rb
@@ -340,6 +343,7 @@ files:
340
343
  - lib/lhs/version.rb
341
344
  - script/ci/build.sh
342
345
  - spec/.DS_Store
346
+ - spec/auto_oauth_spec.rb
343
347
  - spec/autoloading_spec.rb
344
348
  - spec/collection/accessors_spec.rb
345
349
  - spec/collection/collection_items_spec.rb
@@ -372,6 +376,7 @@ files:
372
376
  - spec/dummy/app/assets/javascripts/application.js
373
377
  - spec/dummy/app/assets/stylesheets/application.css
374
378
  - spec/dummy/app/controllers/application_controller.rb
379
+ - spec/dummy/app/controllers/automatic_authentication_controller.rb
375
380
  - spec/dummy/app/controllers/concerns/.keep
376
381
  - spec/dummy/app/controllers/error_handling_with_chains_controller.rb
377
382
  - spec/dummy/app/controllers/extended_rollbar_controller.rb
@@ -383,8 +388,14 @@ files:
383
388
  - spec/dummy/app/models/concerns/.keep
384
389
  - spec/dummy/app/models/dummy_customer.rb
385
390
  - spec/dummy/app/models/dummy_record.rb
391
+ - spec/dummy/app/models/dummy_record_with_auto_oauth_provider.rb
392
+ - spec/dummy/app/models/dummy_record_with_multiple_oauth_providers1.rb
393
+ - spec/dummy/app/models/dummy_record_with_multiple_oauth_providers2.rb
394
+ - spec/dummy/app/models/dummy_record_with_multiple_providers_per_endpoint.rb
395
+ - spec/dummy/app/models/dummy_record_with_oauth.rb
386
396
  - spec/dummy/app/models/dummy_user.rb
387
397
  - spec/dummy/app/models/providers/customer_system.rb
398
+ - spec/dummy/app/models/providers/internal_services.rb
388
399
  - spec/dummy/app/views/error_handling_with_chains/error.html.erb
389
400
  - spec/dummy/app/views/error_handling_with_chains/show.html.erb
390
401
  - spec/dummy/app/views/form_for.html.erb
@@ -489,7 +500,7 @@ files:
489
500
  - spec/record/href_for_spec.rb
490
501
  - spec/record/ignore_errors_spec.rb
491
502
  - spec/record/immutable_chains_spec.rb
492
- - spec/record/includes_all_spec.rb
503
+ - spec/record/includes_first_page_spec.rb
493
504
  - spec/record/includes_spec.rb
494
505
  - spec/record/includes_warning_spec.rb
495
506
  - spec/record/item_key_spec.rb
@@ -559,6 +570,7 @@ specification_version: 4
559
570
  summary: 'REST services accelerator: Rails gem providing an easy, active-record-like
560
571
  interface for http (hypermedia) json services'
561
572
  test_files:
573
+ - spec/auto_oauth_spec.rb
562
574
  - spec/autoloading_spec.rb
563
575
  - spec/collection/accessors_spec.rb
564
576
  - spec/collection/collection_items_spec.rb
@@ -591,6 +603,7 @@ test_files:
591
603
  - spec/dummy/app/assets/javascripts/application.js
592
604
  - spec/dummy/app/assets/stylesheets/application.css
593
605
  - spec/dummy/app/controllers/application_controller.rb
606
+ - spec/dummy/app/controllers/automatic_authentication_controller.rb
594
607
  - spec/dummy/app/controllers/concerns/.keep
595
608
  - spec/dummy/app/controllers/error_handling_with_chains_controller.rb
596
609
  - spec/dummy/app/controllers/extended_rollbar_controller.rb
@@ -602,8 +615,14 @@ test_files:
602
615
  - spec/dummy/app/models/concerns/.keep
603
616
  - spec/dummy/app/models/dummy_customer.rb
604
617
  - spec/dummy/app/models/dummy_record.rb
618
+ - spec/dummy/app/models/dummy_record_with_auto_oauth_provider.rb
619
+ - spec/dummy/app/models/dummy_record_with_multiple_oauth_providers1.rb
620
+ - spec/dummy/app/models/dummy_record_with_multiple_oauth_providers2.rb
621
+ - spec/dummy/app/models/dummy_record_with_multiple_providers_per_endpoint.rb
622
+ - spec/dummy/app/models/dummy_record_with_oauth.rb
605
623
  - spec/dummy/app/models/dummy_user.rb
606
624
  - spec/dummy/app/models/providers/customer_system.rb
625
+ - spec/dummy/app/models/providers/internal_services.rb
607
626
  - spec/dummy/app/views/error_handling_with_chains/error.html.erb
608
627
  - spec/dummy/app/views/error_handling_with_chains/show.html.erb
609
628
  - spec/dummy/app/views/form_for.html.erb
@@ -708,7 +727,7 @@ test_files:
708
727
  - spec/record/href_for_spec.rb
709
728
  - spec/record/ignore_errors_spec.rb
710
729
  - spec/record/immutable_chains_spec.rb
711
- - spec/record/includes_all_spec.rb
730
+ - spec/record/includes_first_page_spec.rb
712
731
  - spec/record/includes_spec.rb
713
732
  - spec/record/includes_warning_spec.rb
714
733
  - spec/record/item_key_spec.rb
@@ -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