dhs 1.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 (301) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/rubocop.yml +27 -0
  3. data/.github/workflows/test.yml +27 -0
  4. data/.gitignore +39 -0
  5. data/.rubocop.yml +186 -0
  6. data/.ruby-version +1 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE +674 -0
  9. data/README.md +2807 -0
  10. data/Rakefile +26 -0
  11. data/dhs.gemspec +44 -0
  12. data/docs/accessing-data.png +0 -0
  13. data/lib/dhs.rb +67 -0
  14. data/lib/dhs/collection.rb +84 -0
  15. data/lib/dhs/complex.rb +158 -0
  16. data/lib/dhs/concerns/autoload_records.rb +57 -0
  17. data/lib/dhs/concerns/collection/handle_nested.rb +43 -0
  18. data/lib/dhs/concerns/collection/internal_collection.rb +74 -0
  19. data/lib/dhs/concerns/configuration.rb +20 -0
  20. data/lib/dhs/concerns/data/becomes.rb +18 -0
  21. data/lib/dhs/concerns/data/equality.rb +14 -0
  22. data/lib/dhs/concerns/data/extend.rb +87 -0
  23. data/lib/dhs/concerns/data/json.rb +14 -0
  24. data/lib/dhs/concerns/data/to_hash.rb +14 -0
  25. data/lib/dhs/concerns/inspect.rb +70 -0
  26. data/lib/dhs/concerns/is_href.rb +15 -0
  27. data/lib/dhs/concerns/item/destroy.rb +38 -0
  28. data/lib/dhs/concerns/item/endpoint_lookup.rb +27 -0
  29. data/lib/dhs/concerns/item/save.rb +55 -0
  30. data/lib/dhs/concerns/item/update.rb +50 -0
  31. data/lib/dhs/concerns/item/validation.rb +61 -0
  32. data/lib/dhs/concerns/o_auth.rb +25 -0
  33. data/lib/dhs/concerns/option_blocks.rb +26 -0
  34. data/lib/dhs/concerns/proxy/accessors.rb +132 -0
  35. data/lib/dhs/concerns/proxy/create.rb +45 -0
  36. data/lib/dhs/concerns/proxy/link.rb +25 -0
  37. data/lib/dhs/concerns/proxy/problems.rb +27 -0
  38. data/lib/dhs/concerns/record/attribute_assignment.rb +25 -0
  39. data/lib/dhs/concerns/record/batch.rb +40 -0
  40. data/lib/dhs/concerns/record/chainable.rb +465 -0
  41. data/lib/dhs/concerns/record/configuration.rb +103 -0
  42. data/lib/dhs/concerns/record/create.rb +24 -0
  43. data/lib/dhs/concerns/record/custom_setters.rb +22 -0
  44. data/lib/dhs/concerns/record/destroy.rb +18 -0
  45. data/lib/dhs/concerns/record/endpoints.rb +108 -0
  46. data/lib/dhs/concerns/record/equality.rb +14 -0
  47. data/lib/dhs/concerns/record/find.rb +86 -0
  48. data/lib/dhs/concerns/record/find_by.rb +38 -0
  49. data/lib/dhs/concerns/record/first.rb +20 -0
  50. data/lib/dhs/concerns/record/href_for.rb +19 -0
  51. data/lib/dhs/concerns/record/last.rb +27 -0
  52. data/lib/dhs/concerns/record/mapping.rb +25 -0
  53. data/lib/dhs/concerns/record/merge.rb +26 -0
  54. data/lib/dhs/concerns/record/model.rb +23 -0
  55. data/lib/dhs/concerns/record/pagination.rb +49 -0
  56. data/lib/dhs/concerns/record/provider.rb +23 -0
  57. data/lib/dhs/concerns/record/relations.rb +26 -0
  58. data/lib/dhs/concerns/record/request.rb +581 -0
  59. data/lib/dhs/concerns/record/scope.rb +25 -0
  60. data/lib/dhs/concerns/record/tracing.rb +24 -0
  61. data/lib/dhs/concerns/record/update.rb +17 -0
  62. data/lib/dhs/config.rb +24 -0
  63. data/lib/dhs/data.rb +180 -0
  64. data/lib/dhs/endpoint.rb +12 -0
  65. data/lib/dhs/interceptors/auto_oauth/interceptor.rb +33 -0
  66. data/lib/dhs/interceptors/auto_oauth/thread_registry.rb +18 -0
  67. data/lib/dhs/interceptors/extended_rollbar/handler.rb +40 -0
  68. data/lib/dhs/interceptors/extended_rollbar/interceptor.rb +20 -0
  69. data/lib/dhs/interceptors/extended_rollbar/thread_registry.rb +19 -0
  70. data/lib/dhs/interceptors/request_cycle_cache/interceptor.rb +41 -0
  71. data/lib/dhs/interceptors/request_cycle_cache/thread_registry.rb +18 -0
  72. data/lib/dhs/item.rb +59 -0
  73. data/lib/dhs/pagination/base.rb +90 -0
  74. data/lib/dhs/pagination/link.rb +21 -0
  75. data/lib/dhs/pagination/offset.rb +22 -0
  76. data/lib/dhs/pagination/page.rb +18 -0
  77. data/lib/dhs/pagination/start.rb +22 -0
  78. data/lib/dhs/pagination/total_pages.rb +9 -0
  79. data/lib/dhs/problems/base.rb +113 -0
  80. data/lib/dhs/problems/errors.rb +69 -0
  81. data/lib/dhs/problems/nested/base.rb +54 -0
  82. data/lib/dhs/problems/nested/errors.rb +16 -0
  83. data/lib/dhs/problems/nested/warnings.rb +15 -0
  84. data/lib/dhs/problems/warnings.rb +24 -0
  85. data/lib/dhs/proxy.rb +69 -0
  86. data/lib/dhs/railtie.rb +34 -0
  87. data/lib/dhs/record.rb +112 -0
  88. data/lib/dhs/rspec.rb +10 -0
  89. data/lib/dhs/test/stubbable_records.rb +34 -0
  90. data/lib/dhs/unprocessable.rb +6 -0
  91. data/lib/dhs/version.rb +5 -0
  92. data/script/ci/build.sh +18 -0
  93. data/spec/auto_oauth_spec.rb +163 -0
  94. data/spec/autoloading_spec.rb +45 -0
  95. data/spec/collection/accessors_spec.rb +31 -0
  96. data/spec/collection/collection_items_spec.rb +44 -0
  97. data/spec/collection/configurable_spec.rb +43 -0
  98. data/spec/collection/delegate_spec.rb +21 -0
  99. data/spec/collection/enumerable_spec.rb +27 -0
  100. data/spec/collection/href_spec.rb +17 -0
  101. data/spec/collection/meta_data_spec.rb +58 -0
  102. data/spec/collection/respond_to_spec.rb +20 -0
  103. data/spec/collection/to_a_spec.rb +34 -0
  104. data/spec/collection/to_ary_spec.rb +40 -0
  105. data/spec/collection/without_object_items_spec.rb +27 -0
  106. data/spec/complex/reduce_spec.rb +202 -0
  107. data/spec/concerns/record/request_spec.rb +78 -0
  108. data/spec/data/collection_spec.rb +56 -0
  109. data/spec/data/equality_spec.rb +23 -0
  110. data/spec/data/inspect_spec.rb +88 -0
  111. data/spec/data/is_item_or_collection_spec.rb +40 -0
  112. data/spec/data/item_spec.rb +106 -0
  113. data/spec/data/merge_spec.rb +27 -0
  114. data/spec/data/parent_spec.rb +39 -0
  115. data/spec/data/raw_spec.rb +48 -0
  116. data/spec/data/respond_to_spec.rb +26 -0
  117. data/spec/data/root_spec.rb +25 -0
  118. data/spec/data/select_spec.rb +27 -0
  119. data/spec/data/to_ary_spec.rb +28 -0
  120. data/spec/data/to_json_spec.rb +68 -0
  121. data/spec/dummy/Rakefile +8 -0
  122. data/spec/dummy/app/assets/images/.keep +0 -0
  123. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  124. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  125. data/spec/dummy/app/controllers/application_controller.rb +26 -0
  126. data/spec/dummy/app/controllers/automatic_authentication_controller.rb +29 -0
  127. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  128. data/spec/dummy/app/controllers/error_handling_with_chains_controller.rb +36 -0
  129. data/spec/dummy/app/controllers/extended_rollbar_controller.rb +10 -0
  130. data/spec/dummy/app/controllers/option_blocks_controller.rb +15 -0
  131. data/spec/dummy/app/controllers/request_cycle_cache_controller.rb +27 -0
  132. data/spec/dummy/app/helpers/application_helper.rb +4 -0
  133. data/spec/dummy/app/mailers/.keep +0 -0
  134. data/spec/dummy/app/models/.keep +0 -0
  135. data/spec/dummy/app/models/concerns/.keep +0 -0
  136. data/spec/dummy/app/models/concerns/dummy_customer/some_concern.rb +9 -0
  137. data/spec/dummy/app/models/dummy_customer.rb +7 -0
  138. data/spec/dummy/app/models/dummy_record.rb +6 -0
  139. data/spec/dummy/app/models/dummy_record_with_auto_oauth_provider.rb +6 -0
  140. data/spec/dummy/app/models/dummy_record_with_multiple_oauth_providers1.rb +7 -0
  141. data/spec/dummy/app/models/dummy_record_with_multiple_oauth_providers2.rb +7 -0
  142. data/spec/dummy/app/models/dummy_record_with_multiple_providers_per_endpoint.rb +6 -0
  143. data/spec/dummy/app/models/dummy_record_with_oauth.rb +7 -0
  144. data/spec/dummy/app/models/dummy_user.rb +6 -0
  145. data/spec/dummy/app/models/providers/customer_system.rb +7 -0
  146. data/spec/dummy/app/models/providers/internal_services.rb +7 -0
  147. data/spec/dummy/app/views/error_handling_with_chains/error.html.erb +1 -0
  148. data/spec/dummy/app/views/error_handling_with_chains/show.html.erb +3 -0
  149. data/spec/dummy/app/views/form_for.html.erb +5 -0
  150. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  151. data/spec/dummy/bin/bundle +5 -0
  152. data/spec/dummy/bin/rails +6 -0
  153. data/spec/dummy/bin/rake +6 -0
  154. data/spec/dummy/config.ru +6 -0
  155. data/spec/dummy/config/application.rb +16 -0
  156. data/spec/dummy/config/boot.rb +7 -0
  157. data/spec/dummy/config/environment.rb +7 -0
  158. data/spec/dummy/config/environments/development.rb +36 -0
  159. data/spec/dummy/config/environments/production.rb +77 -0
  160. data/spec/dummy/config/environments/test.rb +40 -0
  161. data/spec/dummy/config/initializers/assets.rb +10 -0
  162. data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
  163. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  164. data/spec/dummy/config/initializers/dhs.rb +5 -0
  165. data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  166. data/spec/dummy/config/initializers/inflections.rb +18 -0
  167. data/spec/dummy/config/initializers/mime_types.rb +6 -0
  168. data/spec/dummy/config/initializers/rollbar.rb +9 -0
  169. data/spec/dummy/config/initializers/session_store.rb +5 -0
  170. data/spec/dummy/config/initializers/wrap_parameters.rb +11 -0
  171. data/spec/dummy/config/locales/en.yml +23 -0
  172. data/spec/dummy/config/routes.rb +27 -0
  173. data/spec/dummy/config/secrets.yml +22 -0
  174. data/spec/dummy/lib/assets/.keep +0 -0
  175. data/spec/dummy/public/404.html +67 -0
  176. data/spec/dummy/public/422.html +67 -0
  177. data/spec/dummy/public/500.html +66 -0
  178. data/spec/dummy/public/favicon.ico +0 -0
  179. data/spec/endpoint/for_url_spec.rb +27 -0
  180. data/spec/extended_rollbar_spec.rb +67 -0
  181. data/spec/item/access_errors_spec.rb +31 -0
  182. data/spec/item/accessors_spec.rb +21 -0
  183. data/spec/item/add_error_spec.rb +21 -0
  184. data/spec/item/becomes_spec.rb +38 -0
  185. data/spec/item/blacklisted_keywords_spec.rb +28 -0
  186. data/spec/item/delegate_spec.rb +32 -0
  187. data/spec/item/destroy_spec.rb +113 -0
  188. data/spec/item/dig_spec.rb +29 -0
  189. data/spec/item/error_codes_spec.rb +55 -0
  190. data/spec/item/errors_spec.rb +324 -0
  191. data/spec/item/fetch_spec.rb +39 -0
  192. data/spec/item/getter_spec.rb +24 -0
  193. data/spec/item/internal_data_structure_spec.rb +37 -0
  194. data/spec/item/map_spec.rb +46 -0
  195. data/spec/item/nested_errors_spec.rb +27 -0
  196. data/spec/item/partial_update_spec.rb +168 -0
  197. data/spec/item/respond_to_spec.rb +31 -0
  198. data/spec/item/save_spec.rb +115 -0
  199. data/spec/item/setter_spec.rb +44 -0
  200. data/spec/item/translate_errors_spec.rb +257 -0
  201. data/spec/item/update_spec.rb +161 -0
  202. data/spec/item/validation_spec.rb +131 -0
  203. data/spec/item/warning_codes_spec.rb +55 -0
  204. data/spec/item/warnings_spec.rb +51 -0
  205. data/spec/option_blocks/ensure_reset_between_requests_spec.rb +23 -0
  206. data/spec/option_blocks/main_spec.rb +54 -0
  207. data/spec/pagination/link/current_page_spec.rb +19 -0
  208. data/spec/pagination/link/pages_left_spec.rb +36 -0
  209. data/spec/pagination/link/parallel_spec.rb +19 -0
  210. data/spec/pagination/link/total_spec.rb +45 -0
  211. data/spec/pagination/offset/pages_left_spec.rb +26 -0
  212. data/spec/pagination/parameters_spec.rb +59 -0
  213. data/spec/pagination/total_pages_spec.rb +51 -0
  214. data/spec/proxy/create_sub_resource_spec.rb +182 -0
  215. data/spec/proxy/load_spec.rb +75 -0
  216. data/spec/proxy/record_identification_spec.rb +35 -0
  217. data/spec/rails_helper.rb +13 -0
  218. data/spec/record/all_spec.rb +133 -0
  219. data/spec/record/attribute_assignment_spec.rb +28 -0
  220. data/spec/record/build_spec.rb +26 -0
  221. data/spec/record/cast_nested_data_spec.rb +80 -0
  222. data/spec/record/compact_spec.rb +93 -0
  223. data/spec/record/create_spec.rb +160 -0
  224. data/spec/record/creation_failed_spec.rb +55 -0
  225. data/spec/record/custom_setters_spec.rb +42 -0
  226. data/spec/record/definitions_spec.rb +29 -0
  227. data/spec/record/destroy_spec.rb +38 -0
  228. data/spec/record/dig_configuration_spec.rb +75 -0
  229. data/spec/record/dup_spec.rb +20 -0
  230. data/spec/record/endpoint_inheritance_spec.rb +65 -0
  231. data/spec/record/endpoint_options_spec.rb +51 -0
  232. data/spec/record/endpoint_priorities_spec.rb +24 -0
  233. data/spec/record/endpoints_spec.rb +96 -0
  234. data/spec/record/equality_spec.rb +27 -0
  235. data/spec/record/error_handling_integration_spec.rb +25 -0
  236. data/spec/record/error_handling_spec.rb +40 -0
  237. data/spec/record/expanded_spec.rb +69 -0
  238. data/spec/record/fetch_spec.rb +40 -0
  239. data/spec/record/find_by_chains_spec.rb +21 -0
  240. data/spec/record/find_by_spec.rb +76 -0
  241. data/spec/record/find_each_spec.rb +57 -0
  242. data/spec/record/find_in_batches_spec.rb +122 -0
  243. data/spec/record/find_in_parallel_spec.rb +67 -0
  244. data/spec/record/find_spec.rb +103 -0
  245. data/spec/record/first_spec.rb +39 -0
  246. data/spec/record/force_merge_spec.rb +55 -0
  247. data/spec/record/handle_includes_errors_spec.rb +33 -0
  248. data/spec/record/has_many_spec.rb +118 -0
  249. data/spec/record/has_one_spec.rb +114 -0
  250. data/spec/record/href_for_spec.rb +24 -0
  251. data/spec/record/ignore_errors_spec.rb +137 -0
  252. data/spec/record/immutable_chains_spec.rb +22 -0
  253. data/spec/record/includes_after_expansion_spec.rb +70 -0
  254. data/spec/record/includes_expanded_spec.rb +37 -0
  255. data/spec/record/includes_first_page_spec.rb +738 -0
  256. data/spec/record/includes_missing_spec.rb +57 -0
  257. data/spec/record/includes_spec.rb +690 -0
  258. data/spec/record/includes_warning_spec.rb +46 -0
  259. data/spec/record/item_key_spec.rb +81 -0
  260. data/spec/record/items_created_key_configuration_spec.rb +37 -0
  261. data/spec/record/last_spec.rb +64 -0
  262. data/spec/record/loading_twice_spec.rb +19 -0
  263. data/spec/record/mapping_spec.rb +103 -0
  264. data/spec/record/model_name_spec.rb +17 -0
  265. data/spec/record/new_spec.rb +106 -0
  266. data/spec/record/options_getter_spec.rb +25 -0
  267. data/spec/record/options_spec.rb +164 -0
  268. data/spec/record/paginatable_collection_spec.rb +360 -0
  269. data/spec/record/pagination_chain_spec.rb +101 -0
  270. data/spec/record/pagination_links_spec.rb +72 -0
  271. data/spec/record/pagination_spec.rb +71 -0
  272. data/spec/record/persisted_spec.rb +52 -0
  273. data/spec/record/provider_spec.rb +40 -0
  274. data/spec/record/references_spec.rb +95 -0
  275. data/spec/record/relation_caching_spec.rb +120 -0
  276. data/spec/record/reload_by_id_spec.rb +43 -0
  277. data/spec/record/reload_spec.rb +64 -0
  278. data/spec/record/request_spec.rb +90 -0
  279. data/spec/record/save_spec.rb +40 -0
  280. data/spec/record/scope_chains_spec.rb +39 -0
  281. data/spec/record/select_spec.rb +17 -0
  282. data/spec/record/to_ary_spec.rb +65 -0
  283. data/spec/record/to_hash_spec.rb +22 -0
  284. data/spec/record/to_json_spec.rb +22 -0
  285. data/spec/record/tracing_spec.rb +149 -0
  286. data/spec/record/update_spec.rb +61 -0
  287. data/spec/record/where_chains_spec.rb +57 -0
  288. data/spec/record/where_spec.rb +62 -0
  289. data/spec/record/where_values_hash_spec.rb +32 -0
  290. data/spec/request_cycle_cache_spec.rb +106 -0
  291. data/spec/require_dhs_spec.rb +9 -0
  292. data/spec/spec_helper.rb +6 -0
  293. data/spec/stubs/all_spec.rb +69 -0
  294. data/spec/support/fixtures/json/feedback.json +11 -0
  295. data/spec/support/fixtures/json/feedbacks.json +174 -0
  296. data/spec/support/fixtures/json/localina_content_ad.json +23 -0
  297. data/spec/support/load_json.rb +5 -0
  298. data/spec/support/request_cycle_cache.rb +10 -0
  299. data/spec/support/reset.rb +67 -0
  300. data/spec/views/form_for_spec.rb +20 -0
  301. metadata +783 -0
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ before do
7
+ class Record < DHS::Record
8
+ endpoint 'http://datastore/records/{id}'
9
+ end
10
+ end
11
+
12
+ context 'find in parallel' do
13
+ before do
14
+ stub_request(:get, 'http://datastore/records/1').to_return(status: 200, body: { id: 1 }.to_json)
15
+ stub_request(:get, 'http://datastore/records/3').to_return(status: 200, body: { id: 3 }.to_json)
16
+ end
17
+
18
+ it 'finds records in parallel' do
19
+ stub_request(:get, 'http://datastore/records/2').to_return(status: 200, body: { id: 2 }.to_json)
20
+ allow(Record).to receive(:request).and_call_original
21
+ data = Record.find([1, 2, 3])
22
+ expect(Record).to have_received(:request).once
23
+ expect(data[0].id).to eq 1
24
+ expect(data[1].id).to eq 2
25
+ expect(data[2].id).to eq 3
26
+ end
27
+
28
+ it 'raises an exeption if one of the parallel request fails' do
29
+ stub_request(:get, 'http://datastore/records/2').to_return(status: 401)
30
+ expect(-> { Record.find([1, 2, 3]) }).to raise_error(DHC::Unauthorized)
31
+ end
32
+
33
+ it 'applies error handlers from the chain and returns whatever the error handler returns' do
34
+ stub_request(:get, 'http://datastore/records/2').to_return(status: 401)
35
+ data = Record
36
+ .rescue(DHC::Unauthorized, ->(_response) { Record.new(name: 'unknown') })
37
+ .find(1, 2, 3)
38
+ expect(data[1].name).to eq 'unknown'
39
+ end
40
+ end
41
+
42
+ context 'find in parallel with extra methods' do
43
+ before do
44
+ class Record < DHS::Record
45
+ endpoint 'http://datastore/records/{id}'
46
+
47
+ def identifier
48
+ 123456
49
+ end
50
+ end
51
+
52
+ stub_request(:get, 'http://datastore/records/1').to_return(status: 200, body: { id: 1 }.to_json)
53
+ stub_request(:get, 'http://datastore/records/2').to_return(status: 200, body: { id: 2 }.to_json)
54
+ stub_request(:get, 'http://datastore/records/3').to_return(status: 200, body: { id: 3 }.to_json)
55
+ end
56
+
57
+ it 'finds single record in parallel' do
58
+ data = Record.find([1])
59
+ expect(data[0].identifier).to eq 123456
60
+ end
61
+
62
+ it 'finds records in parallel' do
63
+ data = Record.find([1, 2, 3])
64
+ expect(data[0].identifier).to eq 123456
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ let(:datastore) { 'http://depay.fi/v2' }
7
+
8
+ before do
9
+ DHC.config.placeholder(:datastore, datastore)
10
+ class Record < DHS::Record
11
+ endpoint '{+datastore}/content-ads/{campaign_id}/feedbacks'
12
+ endpoint '{+datastore}/content-ads/{campaign_id}/feedbacks/{id}'
13
+ endpoint '{+datastore}/feedbacks'
14
+ endpoint '{+datastore}/feedbacks/{id}'
15
+ end
16
+ end
17
+
18
+ context 'find' do
19
+ context 'finds a single unique record' do
20
+ before do
21
+ stub_request(:get, "#{datastore}/feedbacks/z12f-3asm3ngals")
22
+ .to_return(status: 200, body: load_json(:feedback))
23
+ end
24
+
25
+ it 'by id' do
26
+ record = Record.find('z12f-3asm3ngals')
27
+ expect(record).to be_kind_of Record
28
+ expect(record.source_id).to be_kind_of String
29
+ end
30
+
31
+ it 'by href' do
32
+ record = Record.find("#{datastore}/feedbacks/z12f-3asm3ngals")
33
+ expect(record).to be_kind_of Record
34
+ expect(record.source_id).to be_kind_of String
35
+ end
36
+ end
37
+
38
+ context 'endpoint without identifier' do
39
+ before do
40
+ class LatestAGB < DHS::Record
41
+ endpoint 'agbs/latest'
42
+ end
43
+ end
44
+
45
+ it 'finds a single unique record' do
46
+ stub_request(:get, 'http://agbs/latest')
47
+ .to_return(body: { pdf: 'http://depay.fi/1.pdf' }.to_json)
48
+
49
+ expect(LatestAGB.find.pdf).to eq 'http://depay.fi/1.pdf'
50
+ end
51
+ end
52
+ end
53
+
54
+ it 'raises if empty id' do
55
+ expect { Record.find('') }.to raise_error DHS::Unprocessable
56
+ end
57
+
58
+ it 'raises if nothing was found' do
59
+ stub_request(:get, "#{datastore}/feedbacks/not-existing")
60
+ .to_return(status: 404)
61
+ expect { Record.find('not-existing') }.to raise_error DHC::NotFound
62
+ end
63
+
64
+ it 'finds unique item by providing parameters' do
65
+ stub_request(:get, "#{datastore}/content-ads/123/feedbacks/123")
66
+ .to_return(body: '{}')
67
+ data = Record.find(campaign_id: '123', id: '123')
68
+ expect(data._proxy).to be_kind_of DHS::Item
69
+ end
70
+
71
+ it 'returns item in case of backend returning collection' do
72
+ data = JSON.parse(load_json(:feedbacks))
73
+ data['items'] = [data['items'].first]
74
+ stub_request(:get, "#{datastore}/content-ads/123/feedbacks/123")
75
+ .to_return(body: data.to_json)
76
+ data = Record.find(campaign_id: '123', id: '123')
77
+ expect(data._proxy).to be_kind_of DHS::Item
78
+ end
79
+
80
+ it 'fails when multiple items where found by parameters' do
81
+ stub_request(:get, "#{datastore}/content-ads/123/feedbacks/123")
82
+ .to_return(body: load_json(:feedbacks))
83
+ expect(lambda {
84
+ Record.find(campaign_id: '123', id: '123')
85
+ }).to raise_error DHC::NotFound
86
+ end
87
+
88
+ it 'fails when no item as found by parameters' do
89
+ data = JSON.parse(load_json(:feedbacks))
90
+ data['items'] = []
91
+ stub_request(:get, "#{datastore}/content-ads/123/feedbacks/123")
92
+ .to_return(body: data.to_json)
93
+ expect(lambda {
94
+ Record.find(campaign_id: '123', id: '123')
95
+ }).to raise_error DHC::NotFound
96
+ end
97
+
98
+ it 'raises if nothing was found with parameters' do
99
+ stub_request(:get, "#{datastore}/content-ads/123/feedbacks/123")
100
+ .to_return(status: 404)
101
+ expect { Record.find(campaign_id: '123', id: '123') }.to raise_error DHC::NotFound
102
+ end
103
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ let(:datastore) { 'http://depay.fi/v2' }
7
+
8
+ before do
9
+ DHC.config.placeholder(:datastore, datastore)
10
+ class Record < DHS::Record
11
+ endpoint '{+datastore}/content-ads/{campaign_id}/feedbacks'
12
+ endpoint '{+datastore}/feedbacks'
13
+ end
14
+ end
15
+
16
+ context 'first' do
17
+ it 'finds a single record' do
18
+ stub_request(:get, "#{datastore}/feedbacks?limit=1")
19
+ .to_return(status: 200, body: load_json(:feedback))
20
+ record = Record.first
21
+ expect(record).to be_kind_of Record
22
+ expect(record.source_id).to be_present
23
+ end
24
+
25
+ it 'returns nil if no record was found' do
26
+ stub_request(:get, "#{datastore}/feedbacks?limit=1")
27
+ .to_return(status: 404)
28
+ expect(Record.first).to be_nil
29
+ end
30
+ end
31
+
32
+ context 'first!' do
33
+ it 'raises if nothing was found with parameters' do
34
+ stub_request(:get, "#{datastore}/feedbacks?limit=1")
35
+ .to_return(status: 404)
36
+ expect { Record.first! }.to raise_error DHC::NotFound
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ context 'merge' do
7
+ before do
8
+ class Change < DHS::Record
9
+ endpoint 'https://onboarding/places/{id}/change'
10
+ end
11
+ end
12
+
13
+ it 'merges a given hash' do
14
+ stub_request(:get, 'https://onboarding/places/1/change')
15
+ .to_return(body: { entry: { name: 'Steve', address: 'Zurich' }, products: ['LBP'] }.to_json)
16
+ record = Change.find(1)
17
+ record.merge!(entry: { name: 'Paul' })
18
+ expect(record.entry.name).to eq 'Paul'
19
+ expect(record.entry.address).to eq nil
20
+ expect(record.products.to_a).to eq ['LBP']
21
+ end
22
+
23
+ it 'merges! a given hash' do
24
+ stub_request(:get, 'https://onboarding/places/1/change')
25
+ .to_return(body: { entry: { name: 'Steve', address: 'Zurich' }, products: ['LBP'] }.to_json)
26
+ record = Change.find(1)
27
+ new_record = record.merge(entry: { name: 'Paul' })
28
+ expect(new_record.entry.name).to eq 'Paul'
29
+ expect(new_record.entry.address).to eq nil
30
+ expect(new_record.products.to_a).to eq ['LBP']
31
+ expect(record.entry.name).to eq 'Steve'
32
+ expect(record.entry.address).to eq 'Zurich'
33
+ expect(record.products.to_a).to eq ['LBP']
34
+ end
35
+
36
+ it 'deep_merge! a given hash' do
37
+ stub_request(:get, 'https://onboarding/places/1/change')
38
+ .to_return(body: { entry: { name: 'Steve', address: 'Zurich' } }.to_json)
39
+ record = Change.find(1)
40
+ record.deep_merge!(entry: { name: 'Paul' })
41
+ expect(record.entry.name).to eq 'Paul'
42
+ expect(record.entry.address).to eq 'Zurich'
43
+ end
44
+
45
+ it 'deep_merge a given hash' do
46
+ stub_request(:get, 'https://onboarding/places/1/change')
47
+ .to_return(body: { entry: { name: 'Steve', address: 'Zurich' } }.to_json)
48
+ record = Change.find(1)
49
+ new_record = record.deep_merge(entry: { name: 'Paul' })
50
+ expect(new_record.entry.name).to eq 'Paul'
51
+ expect(new_record.entry.address).to eq 'Zurich'
52
+ expect(record.entry.name).to eq 'Steve'
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ let(:handler) { spy('handler') }
7
+
8
+ before do
9
+ class Record < DHS::Record
10
+ endpoint 'http://depay.fi/v2/records/{id}'
11
+ end
12
+
13
+ class NestedRecord < DHS::Record
14
+ endpoint 'http://depay.fi/v2/other_records/{id}'
15
+ end
16
+ stub_request(:get, 'http://depay.fi/v2/records/1')
17
+ .to_return(body: {
18
+ href: 'http://depay.fi/v2/records/1',
19
+ other: {
20
+ href: 'http://depay.fi/v2/other_records/2'
21
+ }
22
+ }.to_json)
23
+ stub_request(:get, 'http://depay.fi/v2/other_records/2')
24
+ .to_return(status: 404)
25
+ end
26
+
27
+ it 'allows to pass error_handling for includes to DHC' do
28
+ handler = ->(_) { return { deleted: true } }
29
+ record = Record.includes_first_page(:other).references(other: { rescue: { DHC::NotFound => handler } }).find(id: 1)
30
+
31
+ expect(record.other.deleted).to be(true)
32
+ end
33
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ let(:listing) { location.listings.first }
7
+
8
+ before do
9
+ stub_request(:get, 'http://uberall/locations/1')
10
+ .to_return(body: {
11
+ listings: [{
12
+ directory: { name: 'Instagram' }
13
+ }]
14
+ }.to_json)
15
+ end
16
+
17
+ context 'has_many' do
18
+ before do
19
+ class Location < DHS::Record
20
+ endpoint 'http://uberall/locations'
21
+ endpoint 'http://uberall/locations/{id}'
22
+ has_many :listings
23
+ end
24
+
25
+ class Listing < DHS::Record
26
+
27
+ def supported?
28
+ true
29
+ end
30
+ end
31
+ end
32
+
33
+ let(:location) { Location.find(1) }
34
+
35
+ it 'casts the relation into the correct type' do
36
+ expect(listing).to be_kind_of(Listing)
37
+ expect(listing.supported?).to eq true
38
+ end
39
+
40
+ it 'keeps hirachy when casting it to another class on access' do
41
+ expect(listing._root._raw).to eq location._raw
42
+ expect(listing.parent.parent._raw).to eq location._raw
43
+ end
44
+ end
45
+
46
+ context 'custom class_name' do
47
+ before do
48
+ module Uberall
49
+ class Location < DHS::Record
50
+ endpoint 'http://uberall/locations'
51
+ endpoint 'http://uberall/locations/{id}'
52
+ has_many :listings, class_name: 'Uberall::Listing'
53
+ end
54
+ end
55
+
56
+ module Uberall
57
+ class Listing < DHS::Record
58
+
59
+ def supported?
60
+ true
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ let(:location) { Uberall::Location.find(1) }
67
+
68
+ it 'casts the relation into the correct type' do
69
+ expect(listing).to be_kind_of(Uberall::Listing)
70
+ expect(listing.supported?).to eq true
71
+ end
72
+
73
+ it 'keeps hirachy when casting it to another class on access' do
74
+ expect(listing._root._raw).to eq location._raw
75
+ expect(listing.parent.parent._raw).to eq location._raw
76
+ end
77
+ end
78
+
79
+ context 'explicit association class configuration overrules href class casting' do
80
+ before do
81
+ class Place < DHS::Record
82
+ endpoint 'http://places/places/{id}'
83
+ has_many :categories, class_name: 'NewCategory'
84
+ end
85
+
86
+ class NewCategory < DHS::Record
87
+ endpoint 'http://newcategories/newcategories/{id}'
88
+
89
+ def name
90
+ self['category_name']
91
+ end
92
+ end
93
+
94
+ class Category < DHS::Record
95
+ endpoint 'http://categories/categories/{id}'
96
+ end
97
+
98
+ stub_request(:get, 'http://places/places/1')
99
+ .to_return(body: {
100
+ categories: [{
101
+ href: 'https://categories/categories/1'
102
+ }]
103
+ }.to_json)
104
+
105
+ stub_request(:get, 'https://categories/categories/1')
106
+ .to_return(body: {
107
+ href: 'https://categories/categories/1',
108
+ category_name: 'Pizza'
109
+ }.to_json)
110
+ end
111
+
112
+ it 'explicit association configuration overrules href class casting' do
113
+ place = Place.includes_first_page(:categories).find(1)
114
+ expect(place.categories.first).to be_kind_of NewCategory
115
+ expect(place.categories.first.name).to eq('Pizza')
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ let(:transaction) { Transaction.find(1) }
7
+ let(:user) { transaction.user }
8
+
9
+ before do
10
+ [1, 2].each do |id|
11
+ stub_request(:get, "http://myservice/transactions/#{id}")
12
+ .to_return(body: {
13
+ user: {
14
+ email_address: 'steve@depay.fi',
15
+ comments: []
16
+ }
17
+ }.to_json)
18
+ end
19
+ end
20
+
21
+ context 'has_one' do
22
+ before do
23
+ class Transaction < DHS::Record
24
+ endpoint 'http://myservice/transactions'
25
+ endpoint 'http://myservice/transactions/{id}'
26
+ has_one :user
27
+ end
28
+
29
+ class User < DHS::Record
30
+ has_many :comments
31
+
32
+ def email
33
+ self[:email_address]
34
+ end
35
+ end
36
+
37
+ class Comment < DHS::Record
38
+ end
39
+ end
40
+
41
+ it 'casts the relation into the correct type' do
42
+ expect(user).to be_kind_of(User)
43
+ expect(user.email).to eq 'steve@depay.fi'
44
+ end
45
+
46
+ it 'keeps hirachy when casting it to another class on access' do
47
+ expect(user._root._raw).to eq transaction._raw
48
+ expect(user.parent._raw).to eq transaction._raw
49
+ end
50
+ end
51
+
52
+ context 'custom class_name' do
53
+ before do
54
+ class Transaction < DHS::Record
55
+ endpoint 'http://myservice/transactions'
56
+ endpoint 'http://myservice/transactions/{id}'
57
+ has_one :user, class_name: 'Custom::User'
58
+ end
59
+
60
+ module Custom
61
+ class User < DHS::Record
62
+ def email
63
+ self[:email_address]
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ it 'casts the relation into the correct type' do
70
+ expect(user).to be_kind_of(Custom::User)
71
+ expect(user.email).to eq 'steve@depay.fi'
72
+ end
73
+ end
74
+
75
+ context 'explicit association class configuration overrules href class casting' do
76
+ before do
77
+ class Place < DHS::Record
78
+ endpoint 'http://places/places/{id}'
79
+ has_one :category, class_name: 'NewCategory'
80
+ end
81
+
82
+ class NewCategory < DHS::Record
83
+ endpoint 'http://newcategories/newcategories/{id}'
84
+
85
+ def name
86
+ self['category_name']
87
+ end
88
+ end
89
+
90
+ class Category < DHS::Record
91
+ endpoint 'http://categories/categories/{id}'
92
+ end
93
+
94
+ stub_request(:get, 'http://places/places/1')
95
+ .to_return(body: {
96
+ category: {
97
+ href: 'https://categories/categories/1'
98
+ }
99
+ }.to_json)
100
+
101
+ stub_request(:get, 'https://categories/categories/1')
102
+ .to_return(body: {
103
+ href: 'https://categories/categories/1',
104
+ category_name: 'Pizza'
105
+ }.to_json)
106
+ end
107
+
108
+ it 'explicit association configuration overrules href class casting' do
109
+ place = Place.includes_first_page(:category).find(1)
110
+ expect(place.category).to be_kind_of NewCategory
111
+ expect(place.category.name).to eq('Pizza')
112
+ end
113
+ end
114
+ end