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,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ context 'options' do
7
+ before do
8
+ class Record < DHS::Record
9
+ endpoint 'http://depay.fi/records'
10
+ end
11
+ end
12
+
13
+ let(:raw) do
14
+ { options: { criticality: :high } }
15
+ end
16
+
17
+ def record
18
+ DHS::Record.new DHS::Data.new(raw, nil, Record)
19
+ end
20
+
21
+ it 'is possible to fetch data from a key called options from an instance' do
22
+ expect(record.options.criticality).to eq :high
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ let(:datastore) do
7
+ 'http://datastore/v2'
8
+ end
9
+
10
+ before do
11
+ DHC.config.placeholder('datastore', datastore)
12
+ class Record < DHS::Record
13
+ endpoint '{+datastore}/records', validates: { persist: false }
14
+ end
15
+ end
16
+
17
+ let(:options) { { auth: { bearer: '123' }, validates: { persist: false } } }
18
+ let(:params) { { name: 'Steve' } }
19
+
20
+ context 'options' do
21
+ it 'is possible to pass options to the chain' do
22
+ expect(DHC).to receive(:request)
23
+ .with(options.merge(params: params).merge(url: 'http://datastore/v2/records'))
24
+ .and_call_original
25
+ stub_request(:get, 'http://datastore/v2/records?name=Steve')
26
+ .to_return(body: { name: 'Steve', is: 'awesome' }.to_json)
27
+ Record.options(options).where(params).first
28
+ end
29
+
30
+ it 'applies last one wins also to the options' do
31
+ stub_request(:get, 'http://datastore/v2/records')
32
+ .to_return(body: { name: 'Steve', is: 'awesome' }.to_json)
33
+ expect(DHC).to receive(:request)
34
+ .with(options.merge(url: 'http://datastore/v2/records'))
35
+ .and_call_original
36
+ Record.options(auth: 'basic').options(options).where.first
37
+ end
38
+
39
+ it 'is also applicable to find' do
40
+ stub_request(:get, 'http://datastore/v2/records?id=123').to_return(body: {}.to_json)
41
+ expect(DHC).to receive(:request)
42
+ .with(options.merge(params: { id: '123' }, url: 'http://datastore/v2/records'))
43
+ .and_call_original
44
+ Record.options(options).find('123')
45
+ end
46
+
47
+ it 'is also applicable to find_by' do
48
+ stub_request(:get, 'http://datastore/v2/records?id=123&limit=1').to_return(body: {}.to_json)
49
+ expect(DHC).to receive(:request)
50
+ .with(options.merge(params: { id: '123', limit: 1 }, url: 'http://datastore/v2/records'))
51
+ .and_call_original
52
+ Record.options(options).find_by(id: '123')
53
+ end
54
+
55
+ it 'is also applicable to first' do
56
+ stub_request(:get, 'http://datastore/v2/records').to_return(body: {}.to_json)
57
+ expect(DHC).to receive(:request)
58
+ .with(options.merge(url: 'http://datastore/v2/records'))
59
+ .and_call_original
60
+ Record.options(options).first
61
+ end
62
+
63
+ it 'is also applicable to create' do
64
+ stub_request(:post, 'http://datastore/v2/records').to_return(body: {}.to_json)
65
+ expect(DHC).to receive(:request)
66
+ .with(options.merge(method: :post, url: 'http://datastore/v2/records', body: { name: 'Steve' }, headers: {}))
67
+ .and_call_original
68
+ Record.options(options).create(name: 'Steve')
69
+ end
70
+
71
+ context 'actions on single records' do
72
+ let!(:record) do
73
+ stub_request(:get, 'http://datastore/v2/records?id=123').to_return(body: { href: 'http://datastore/v2/records/123' }.to_json)
74
+ Record.find(123)
75
+ end
76
+
77
+ context 'save' do
78
+ before do
79
+ stub_request(:post, 'http://datastore/v2/records/123').to_return(body: {}.to_json)
80
+ expect(DHC).to receive(:request)
81
+ .with(options.merge(method: :post, url: 'http://datastore/v2/records/123', body: { href: 'http://datastore/v2/records/123' }, headers: {}))
82
+ .and_call_original
83
+ end
84
+
85
+ it 'applies directly on save' do
86
+ record.save(options)
87
+ end
88
+
89
+ it 'applies directly on save!' do
90
+ record.save!(options)
91
+ end
92
+
93
+ it 'applies chaining them with save' do
94
+ record.options(options).save
95
+ end
96
+
97
+ it 'applies chaining them with save!' do
98
+ record.options(options).save!
99
+ end
100
+ end
101
+
102
+ context 'destroy' do
103
+ before do
104
+ stub_request(:delete, 'http://datastore/v2/records/123').to_return(body: {}.to_json)
105
+ expect(DHC).to receive(:request)
106
+ .with(options.merge(method: :delete, url: 'http://datastore/v2/records/123'))
107
+ .and_call_original
108
+ end
109
+
110
+ it 'applies directly on destroy' do
111
+ record.destroy(options)
112
+ end
113
+
114
+ it 'applies chaining them with destroy' do
115
+ record.options(options).destroy
116
+ end
117
+ end
118
+
119
+ context 'update' do
120
+ before do
121
+ stub_request(:post, 'http://datastore/v2/records/123').to_return(body: {}.to_json)
122
+ body = { href: 'http://datastore/v2/records/123', name: 'steve' }
123
+ expect(DHC).to receive(:request)
124
+ .with(options.merge(method: :post, url: 'http://datastore/v2/records/123', body: body))
125
+ .and_call_original
126
+ end
127
+
128
+ it 'applies directly on update' do
129
+ record.update({ name: 'steve' }, options)
130
+ end
131
+
132
+ it 'applies directly on update!' do
133
+ record.update!({ name: 'steve' }, options)
134
+ end
135
+
136
+ it 'applies chaining them with update' do
137
+ record.options(options).update(name: 'steve')
138
+ end
139
+
140
+ it 'applies chaining them with update!' do
141
+ record.options(options).update!(name: 'steve')
142
+ end
143
+ end
144
+
145
+ context 'valid' do
146
+ before do
147
+ stub_request(:post, 'http://datastore/v2/records?persist=false').to_return(body: {}.to_json)
148
+ body = DHS::Data.new({ href: 'http://datastore/v2/records/123' }, nil, Record)
149
+ expect(DHC).to receive(:request)
150
+ .with(options.merge(url: '{+datastore}/records', method: :post, params: { persist: false }, body: body))
151
+ .and_call_original
152
+ end
153
+
154
+ it 'applies directly on valid' do
155
+ record.valid?(options)
156
+ end
157
+
158
+ it 'applies chaining them with valid' do
159
+ record.options(options).valid?
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,360 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ before { DHC.config.placeholder('datastore', datastore) }
7
+ let(:datastore) { 'http://depay.fi/v2' }
8
+
9
+ context 'default pagination behaviour' do
10
+ before do
11
+ class Record < DHS::Record
12
+ endpoint '{+datastore}/feedbacks'
13
+ end
14
+ end
15
+
16
+ it 'also works when there is no item in the first response' do
17
+ stub_request(:get, "#{datastore}/feedbacks?limit=100")
18
+ .to_return(
19
+ status: 200,
20
+ body: { items: [], total: 200, offset: 0 }.to_json
21
+ )
22
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&offset=100")
23
+ .to_return(
24
+ status: 200,
25
+ body: { items: [], total: 200, offset: 0 }.to_json
26
+ )
27
+ all = Record.all
28
+ expect(all).to be_kind_of Record
29
+ expect(all._proxy).to be_kind_of DHS::Collection
30
+ expect(all.length).to eq 0
31
+ end
32
+
33
+ it 'also works when there is no total in the stubbing' do
34
+ stub_request(:get, 'http://depay.fi/v2/feedbacks?limit=100').to_return(body: { items: (1..100).to_a }.to_json)
35
+ stub_request(:get, 'http://depay.fi/v2/feedbacks?limit=100&offset=100').to_return(body: { items: [] }.to_json)
36
+ all = Record.all
37
+ expect(all).to be_kind_of Record
38
+ expect(all._proxy).to be_kind_of DHS::Collection
39
+ expect(all.length).to eq 100
40
+ end
41
+
42
+ it 'also works when there is no key "items" in the stubbing' do
43
+ stub_request(:get, 'http://depay.fi/v2/feedbacks?limit=100').to_return(body: (1..100).to_a.to_json)
44
+ stub_request(:get, 'http://depay.fi/v2/feedbacks?limit=100&offset=100').to_return(body: [].to_json)
45
+ all = Record.all
46
+ expect(all).to be_kind_of Record
47
+ expect(all._proxy).to be_kind_of DHS::Collection
48
+ expect(all.length).to eq 100
49
+ end
50
+ end
51
+
52
+ context 'pagination using offset(0,100,200,...)' do
53
+ before do
54
+ class Record < DHS::Record
55
+ configuration pagination_strategy: 'offset', pagination_key: 'offset'
56
+ endpoint '{+datastore}/feedbacks'
57
+ end
58
+ end
59
+
60
+ it 'fetches all records from the backend' do
61
+ stub_request(:get, "#{datastore}/feedbacks?limit=100")
62
+ .to_return(
63
+ status: 200,
64
+ body: { items: (1..100).to_a, limit: 100, total: 300, offset: 0 }.to_json
65
+ )
66
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&offset=100")
67
+ .to_return(
68
+ status: 200,
69
+ body: { items: (101..200).to_a, limit: 100, total: 300, offset: 100 }.to_json
70
+ )
71
+ last_request = stub_request(:get, "#{datastore}/feedbacks?limit=100&offset=200")
72
+ .to_return(
73
+ status: 200,
74
+ body: { items: (201..300).to_a, limit: 100, total: 300, offset: 200 }.to_json
75
+ )
76
+ all = Record.all
77
+ all.first # fetch/resolve
78
+ assert_requested last_request
79
+ expect(all).to be_kind_of Record
80
+ expect(all._data._proxy).to be_kind_of DHS::Collection
81
+ expect(all.count).to eq 300
82
+ expect(all.last).to eq 300
83
+ end
84
+
85
+ it 'fetches all, also if there is a rest and the total is not divideable trough the limit' do
86
+ stub_request(:get, "#{datastore}/feedbacks?limit=100")
87
+ .to_return(
88
+ status: 200,
89
+ body: { items: (1..100).to_a, limit: 100, total: 223, offset: 0 }.to_json
90
+ )
91
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&offset=100")
92
+ .to_return(
93
+ status: 200,
94
+ body: { items: (101..200).to_a, limit: 100, total: 223, offset: 100 }.to_json
95
+ )
96
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&offset=200")
97
+ .to_return(
98
+ status: 200,
99
+ body: { items: (201..223).to_a, limit: 100, total: 223, offset: 200 }.to_json
100
+ )
101
+ all = Record.all
102
+ expect(all).to be_kind_of Record
103
+ expect(all._data._proxy).to be_kind_of DHS::Collection
104
+ expect(all.count).to eq 223
105
+ expect(all.last).to eq 223
106
+ end
107
+
108
+ it 'also fetches all when there is no meta information for limit' do
109
+ stub_request(:get, "#{datastore}/feedbacks?limit=100")
110
+ .to_return(
111
+ status: 200,
112
+ body: { items: (1..100).to_a, total: 300, offset: 0 }.to_json
113
+ )
114
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&offset=100")
115
+ .to_return(
116
+ status: 200,
117
+ body: { items: (101..200).to_a, total: 300, offset: 100 }.to_json
118
+ )
119
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&offset=200")
120
+ .to_return(
121
+ status: 200,
122
+ body: { items: (201..300).to_a, total: 300, offset: 200 }.to_json
123
+ )
124
+ all = Record.all
125
+ expect(all).to be_kind_of Record
126
+ expect(all._proxy).to be_kind_of DHS::Collection
127
+ expect(all.count).to eq 300
128
+ expect(all.last).to eq 300
129
+ end
130
+ end
131
+
132
+ context 'pagination using page(1,2,3,...)' do
133
+ before do
134
+ class Record < DHS::Record
135
+ configuration pagination_strategy: 'page', pagination_key: 'page'
136
+ endpoint '{+datastore}/feedbacks'
137
+ end
138
+ end
139
+
140
+ it 'fetches all records from the backend' do
141
+ stub_request(:get, "#{datastore}/feedbacks?limit=100")
142
+ .to_return(
143
+ status: 200,
144
+ body: { items: (1..100).to_a, limit: 100, total: 300, page: 1 }.to_json
145
+ )
146
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&page=2")
147
+ .to_return(
148
+ status: 200,
149
+ body: { items: (101..200).to_a, limit: 100, total: 300, page: 2 }.to_json
150
+ )
151
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&page=3")
152
+ .to_return(
153
+ status: 200,
154
+ body: { items: (201..300).to_a, limit: 100, total: 300, page: 3 }.to_json
155
+ )
156
+ all = Record.all
157
+ expect(all).to be_kind_of Record
158
+ expect(all._data._proxy).to be_kind_of DHS::Collection
159
+ expect(all.count).to eq 300
160
+ expect(all.last).to eq 300
161
+ end
162
+
163
+ it 'also fetches all when there is no meta information for limit' do
164
+ stub_request(:get, "#{datastore}/feedbacks?limit=100")
165
+ .to_return(
166
+ status: 200,
167
+ body: { items: (1..100).to_a, total: 300, page: 1 }.to_json
168
+ )
169
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&page=2")
170
+ .to_return(
171
+ status: 200,
172
+ body: { items: (101..200).to_a, total: 300, page: 2 }.to_json
173
+ )
174
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&page=3")
175
+ .to_return(
176
+ status: 200,
177
+ body: { items: (201..300).to_a, total: 300, page: 3 }.to_json
178
+ )
179
+ all = Record.all
180
+ expect(all).to be_kind_of Record
181
+ expect(all._proxy).to be_kind_of DHS::Collection
182
+ expect(all.count).to eq 300
183
+ expect(all.last).to eq 300
184
+ end
185
+
186
+ it 'fetches all, also if there is a rest and the total is not divideable trough the limit' do
187
+ stub_request(:get, "#{datastore}/feedbacks?limit=100")
188
+ .to_return(
189
+ status: 200,
190
+ body: { items: (1..100).to_a, limit: 100, total: 223, page: 1 }.to_json
191
+ )
192
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&page=2")
193
+ .to_return(
194
+ status: 200,
195
+ body: { items: (101..200).to_a, limit: 100, total: 223, page: 2 }.to_json
196
+ )
197
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&page=3")
198
+ .to_return(
199
+ status: 200,
200
+ body: { items: (201..223).to_a, limit: 100, total: 223, page: 3 }.to_json
201
+ )
202
+ all = Record.all
203
+ expect(all).to be_kind_of Record
204
+ expect(all._data._proxy).to be_kind_of DHS::Collection
205
+ expect(all.count).to eq 223
206
+ expect(all.last).to eq 223
207
+ end
208
+ end
209
+
210
+ context 'pagination using start(1,101,201,...)' do
211
+ before do
212
+ class Record < DHS::Record
213
+ configuration pagination_strategy: 'start', pagination_key: 'start'
214
+ endpoint '{+datastore}/feedbacks'
215
+ end
216
+ end
217
+
218
+ it 'fetches all records from the backend' do
219
+ stub_request(:get, "#{datastore}/feedbacks?limit=100")
220
+ .to_return(
221
+ status: 200,
222
+ body: { items: (1..100).to_a, limit: 100, total: 300, start: 1 }.to_json
223
+ )
224
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&start=101")
225
+ .to_return(
226
+ status: 200,
227
+ body: { items: (101..200).to_a, limit: 100, total: 300, start: 101 }.to_json
228
+ )
229
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&start=201")
230
+ .to_return(
231
+ status: 200,
232
+ body: { items: (201..300).to_a, limit: 100, total: 300, start: 201 }.to_json
233
+ )
234
+ all = Record.all
235
+ expect(all).to be_kind_of Record
236
+ expect(all._data._proxy).to be_kind_of DHS::Collection
237
+ expect(all.count).to eq 300
238
+ expect(all.last).to eq 300
239
+ end
240
+
241
+ it 'also fetches all when there is no meta information for limit' do
242
+ stub_request(:get, "#{datastore}/feedbacks?limit=100")
243
+ .to_return(
244
+ status: 200,
245
+ body: { items: (1..100).to_a, total: 300, start: 1 }.to_json
246
+ )
247
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&start=101")
248
+ .to_return(
249
+ status: 200,
250
+ body: { items: (101..200).to_a, total: 300, start: 101 }.to_json
251
+ )
252
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&start=201")
253
+ .to_return(
254
+ status: 200,
255
+ body: { items: (201..300).to_a, total: 300, start: 201 }.to_json
256
+ )
257
+ all = Record.all
258
+ expect(all).to be_kind_of Record
259
+ expect(all._proxy).to be_kind_of DHS::Collection
260
+ expect(all.count).to eq 300
261
+ expect(all.last).to eq 300
262
+ end
263
+
264
+ it 'fetches all, also if there is a rest and the total is not divideable trough the limit' do
265
+ stub_request(:get, "#{datastore}/feedbacks?limit=100")
266
+ .to_return(
267
+ status: 200,
268
+ body: { items: (1..100).to_a, limit: 100, total: 223, start: 1 }.to_json
269
+ )
270
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&start=101")
271
+ .to_return(
272
+ status: 200,
273
+ body: { items: (101..200).to_a, limit: 100, total: 223, start: 101 }.to_json
274
+ )
275
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&start=201")
276
+ .to_return(
277
+ status: 200,
278
+ body: { items: (201..223).to_a, limit: 100, total: 223, start: 201 }.to_json
279
+ )
280
+ all = Record.all
281
+ expect(all).to be_kind_of Record
282
+ expect(all._data._proxy).to be_kind_of DHS::Collection
283
+ expect(all.count).to eq 223
284
+ expect(all.last).to eq 223
285
+ end
286
+ end
287
+
288
+ context 'pagination using links' do
289
+ before do
290
+ class Record < DHS::Record
291
+ configuration pagination_strategy: 'link'
292
+ endpoint '{+datastore}/feedbacks'
293
+ end
294
+ end
295
+
296
+ it 'fetches all records from the backend' do
297
+ stub_request(:get, "#{datastore}/feedbacks?limit=100")
298
+ .to_return(
299
+ status: 200,
300
+ body: { items: (1..100).to_a, limit: 100, next: { href: "#{datastore}/feedbacks?limit=100&cursor=x" } }.to_json
301
+ )
302
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&cursor=x")
303
+ .to_return(
304
+ status: 200,
305
+ body: { items: (101..200).to_a, limit: 100, next: { href: "#{datastore}/feedbacks?limit=100&cursor=y" } }.to_json
306
+ )
307
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&cursor=y")
308
+ .to_return(
309
+ status: 200,
310
+ body: { items: (201..300).to_a, limit: 100, next: { href: "#{datastore}/feedbacks?limit=100&cursor=z" } }.to_json
311
+ )
312
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&cursor=z")
313
+ .to_return(
314
+ status: 200,
315
+ body: { items: [], limit: 100 }.to_json
316
+ )
317
+ all = Record.all
318
+
319
+ expect(all).to be_kind_of Record
320
+ expect(all._data._proxy).to be_kind_of DHS::Collection
321
+ expect(all.count).to eq 300
322
+ expect(all.last).to eq 300
323
+ end
324
+
325
+ it 'fetches all, also if there is a rest and the total is not divideable trough the limit' do
326
+ stub_request(:get, "#{datastore}/feedbacks?limit=100")
327
+ .to_return(
328
+ status: 200,
329
+ body: { items: (1..100).to_a, limit: 100, next: { href: "#{datastore}/feedbacks?limit=100&cursor=x" } }.to_json
330
+ )
331
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&cursor=x")
332
+ .to_return(
333
+ status: 200,
334
+ body: { items: (101..200).to_a, limit: 100, next: { href: "#{datastore}/feedbacks?limit=100&cursor=y" } }.to_json
335
+ )
336
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&cursor=y")
337
+ .to_return(
338
+ status: 200,
339
+ body: { items: (201..300).to_a, limit: 100, next: { href: "#{datastore}/feedbacks?limit=100&cursor=z" } }.to_json
340
+ )
341
+ stub_request(:get, "#{datastore}/feedbacks?limit=100&cursor=z")
342
+ .to_return(
343
+ status: 200,
344
+ body: { items: [301], limit: 100 }.to_json
345
+ )
346
+
347
+ all = nil
348
+ expect(lambda do
349
+ all = Record.all.fetch
350
+ end).to output(
351
+ %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/DePayFi/dhs#pagination-strategy-link\).}
352
+ ).to_stderr
353
+
354
+ expect(all).to be_kind_of Record
355
+ expect(all._data._proxy).to be_kind_of DHS::Collection
356
+ expect(all.count).to eq 301
357
+ expect(all.last).to eq 301
358
+ end
359
+ end
360
+ end