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,43 @@
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'
9
+ endpoint 'http://datastore/records/{id}'
10
+ end
11
+
12
+ class AnotherRecord < DHS::Record
13
+ endpoint 'http://datastore/otherrecords'
14
+ endpoint 'http://datastore/otherrecords/{id}'
15
+
16
+ def id
17
+ another_id
18
+ end
19
+ end
20
+ end
21
+
22
+ context 'reload!' do
23
+ it 'reloads the record by id' do
24
+ stub_request(:post, 'http://datastore/records')
25
+ .to_return(body: { id: 1, name: 'Steve' }.to_json)
26
+ record = Record.create!(name: 'Steve')
27
+ stub_request(:get, 'http://datastore/records/1')
28
+ .to_return(body: { id: 1, name: 'Steve', async: 'data' }.to_json)
29
+ record.reload!
30
+ expect(record.async).to eq 'data'
31
+ end
32
+
33
+ it 'reloads the record by id if a record method defines the actual id' do
34
+ stub_request(:post, 'http://datastore/otherrecords')
35
+ .to_return(body: { another_id: 2, name: 'Can' }.to_json)
36
+ record = AnotherRecord.create!(name: 'Can')
37
+ stub_request(:get, 'http://datastore/otherrecords/2')
38
+ .to_return(body: { id: 2, name: 'Can', async: 'data' }.to_json)
39
+ record.reload!
40
+ expect(record.async).to eq 'data'
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,64 @@
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'
9
+ endpoint 'http://datastore/records/{id}'
10
+ end
11
+ end
12
+
13
+ let(:json) do
14
+ { id: 1, name: 'Steve' }.to_json
15
+ end
16
+
17
+ context 'reload!' do
18
+ it 'returns an instance of the record, not an DHS::Item' do
19
+ stub_request(:post, 'http://datastore/records').to_return(body: json)
20
+ stub_request(:get, 'http://datastore/records/1').to_return(body: json)
21
+ record = Record.create!(name: 'Steve')
22
+ expect(record).to be_kind_of Record
23
+ expect(record.reload!).to be_kind_of Record
24
+ end
25
+ end
26
+
27
+ context 'nested items' do
28
+ before do
29
+ class Location < DHS::Record
30
+ endpoint 'http://uberall/locations'
31
+ endpoint 'http://uberall/locations/{id}'
32
+
33
+ configuration item_key: %i[response location], items_key: %i[response locations]
34
+ end
35
+ end
36
+
37
+ it 'merges reloads properly' do
38
+ stub_request(:get, 'http://uberall/locations?identifier=http://places/1&limit=1')
39
+ .to_return(
40
+ body: {
41
+ response: {
42
+ locations: [{
43
+ id: 1,
44
+ name: 'Fridolin'
45
+ }]
46
+ }
47
+ }.to_json
48
+ )
49
+ location = Location.find_by(identifier: 'http://places/1')
50
+ stub_request(:get, 'http://uberall/locations/1')
51
+ .to_return(
52
+ body: {
53
+ response: {
54
+ location: {
55
+ normalizationStatus: 'NORMALIZED'
56
+ }
57
+ }
58
+ }.to_json
59
+ )
60
+ location.reload!
61
+ expect(location.normalizationStatus).to eq 'NORMALIZED'
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,90 @@
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/feedbacks/{id}'
9
+ end
10
+ end
11
+
12
+ context 'url pattern' do
13
+ let(:datastore) { 'http://depay.fi/v2' }
14
+
15
+ before do
16
+ DHC.config.placeholder(:datastore, datastore)
17
+ class Record < DHS::Record
18
+ endpoint '{+datastore}/content-ads/{campaign_id}/feedbacks'
19
+ endpoint '{+datastore}/feedbacks'
20
+ end
21
+ end
22
+
23
+ it 'is using params as query params explicitly when provided in params namespace' do
24
+ request = stub_request(:get, "#{datastore}/content-ads/123/feedbacks?campaign_id=456").to_return(status: 200)
25
+ Record.where(campaign_id: 123, params: { campaign_id: '456' }).to_a
26
+ assert_requested(request)
27
+ end
28
+ end
29
+
30
+ context '#convert_options_to_endpoint' do
31
+ before do
32
+ class Record < DHS::Record
33
+ endpoint 'http://datastore/feedbacks/{id}', params: { tracking: 123 }
34
+ end
35
+ end
36
+
37
+ it 'identifies endpoint by given url and merges back endpoint template parameters' do
38
+ options = DHS::Record.send(:convert_options_to_endpoints, url: 'http://datastore/feedbacks/1')
39
+ expect(options[:params][:id]).to eq '1'
40
+ expect(options[:url]).to eq 'http://datastore/feedbacks/{id}'
41
+ end
42
+
43
+ it 'identifies endpoint by given url and merges back endpoint template parameters into an array, if array was given' do
44
+ options = DHS::Record.send(:convert_options_to_endpoints, [{ url: 'http://datastore/feedbacks/1' }])
45
+ expect(options[0][:params][:id]).to eq '1'
46
+ expect(options[0][:url]).to eq 'http://datastore/feedbacks/{id}'
47
+ end
48
+
49
+ it 'returnes nil if endpoint was not found for the given url' do
50
+ options = DHS::Record.send(:convert_options_to_endpoints, url: 'http://datastore/reviews/1')
51
+ expect(options).to eq nil
52
+ end
53
+ end
54
+
55
+ context '#extend_with_reference' do
56
+ it 'extends given options with the one for the refernce' do
57
+ options = DHS::Record.send(:extend_with_reference, { url: 'http://datastore/feedbacks/1' }, { auth: { bearer: '123' } })
58
+ expect(options[:auth][:bearer]).to eq '123'
59
+ end
60
+
61
+ it 'extends given list of options with the one for the refernce' do
62
+ options = DHS::Record.send(:extend_with_reference, [{ url: 'http://datastore/feedbacks/1' }], auth: { bearer: '123' })
63
+ expect(options[0][:auth][:bearer]).to eq '123'
64
+ end
65
+ end
66
+
67
+ context '#options_for_data' do
68
+ it 'extract request options from raw data' do
69
+ options = DHS::Record.send(:url_option_for, DHS::Data.new({ href: 'http://datastore/feedbacks/1' }, nil, Record))
70
+ expect(options[:url]).to eq 'http://datastore/feedbacks/1'
71
+ end
72
+
73
+ it 'extract a list of request options from raw data if data is a collection' do
74
+ options = DHS::Record.send(:url_option_for, DHS::Data.new({ items: [{ href: 'http://datastore/feedbacks/1' }] }, nil, Record))
75
+ expect(options[0][:url]).to eq 'http://datastore/feedbacks/1'
76
+ end
77
+
78
+ it 'extract request options from raw nested data' do
79
+ options = DHS::Record.send(:url_option_for, DHS::Data.new({ reviews: { href: 'http://datastore/reviews/1' } }, nil, Record), :reviews)
80
+ expect(options[:url]).to eq 'http://datastore/reviews/1'
81
+ end
82
+ end
83
+
84
+ context '#record_for_options' do
85
+ it 'identifies dhs record from given options, as all request have to be done through DHS Records' do
86
+ record = DHS::Record.send(:record_for_options, url: 'http://datastore/feedbacks/1')
87
+ expect(record).to eq Record
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ context 'save!' do
7
+ context 'without href' do
8
+ before do
9
+ DHC.config.placeholder('datastore', datastore)
10
+ class Feedback < DHS::Record
11
+ endpoint '{+datastore}/content-ads/{campaign_id}/feedbacks'
12
+ end
13
+ end
14
+
15
+ let(:datastore) { 'http://depay.fi/v2' }
16
+ let(:campaign_id) { 12345 }
17
+ let(:object) { { recommended: true } }
18
+ let(:item) { Feedback.new(object.merge(campaign_id: campaign_id)) }
19
+ let!(:request) do
20
+ stub_request(:post, "#{datastore}/content-ads/#{campaign_id}/feedbacks")
21
+ .with(body: object.to_json)
22
+ .to_return(status: 200, body: object.to_json)
23
+ end
24
+
25
+ it 'removes params used to compute url from send data' do
26
+ item.save!
27
+ expect(request).to have_been_made.once
28
+ end
29
+
30
+ context 'item without data' do
31
+ let(:item) { Feedback.new(object) }
32
+
33
+ it 'takes params to find endpoint also from the options' do
34
+ item.save!(params: { campaign_id: campaign_id })
35
+ expect(request).to have_been_made.once
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,39 @@
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
+ let(:response) do
11
+ { body: [{ name: 'Steve' }] }
12
+ end
13
+
14
+ before do
15
+ DHC.config.placeholder('datastore', datastore)
16
+ class Record < DHS::Record
17
+ endpoint '{+datastore}/records/'
18
+ scope :blue, -> { where(color: 'blue') }
19
+ scope :available, -> { where(availalbe: 'true') }
20
+ scope :limited_to, ->(limit) { where(limit: limit) }
21
+ end
22
+ end
23
+
24
+ context 'scope chains' do
25
+ it 'allows chaining multiple scopes' do
26
+ stub_request(:get, 'http://datastore/v2/records/?availalbe=true&color=blue&limit=20').to_return(response)
27
+ expect(
28
+ Record.blue.available.limited_to(20).first.name
29
+ ).to eq 'Steve'
30
+ end
31
+
32
+ it 'allows to chain multiple scopes when first one has arguments' do
33
+ stub_request(:get, 'http://datastore/v2/records/?availalbe=true&color=blue&limit=20').to_return(response)
34
+ expect(
35
+ Record.limited_to(20).blue.available.first.name
36
+ ).to eq 'Steve'
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ let(:record) do
7
+ DHS::Record.new(DHS::Data.new(%w[cat dog]))
8
+ end
9
+
10
+ context 'select' do
11
+ it 'works with select' do
12
+ expect(
13
+ record.select { |x| x }.join
14
+ ).to eq 'catdog'
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ let(:user_item) do
7
+ {
8
+ email: 'someone@somewhe.re'
9
+ }
10
+ end
11
+
12
+ let(:item) do
13
+ {
14
+ href: 'http://datastore/records/1',
15
+ user: user_item
16
+ }
17
+ end
18
+
19
+ let(:record) { Record.find(1) }
20
+
21
+ before do
22
+ class User < DHS::Record
23
+ end
24
+
25
+ class Record < DHS::Record
26
+ endpoint 'http://datastore/records/{id}'
27
+
28
+ has_one :user, class_name: 'User'
29
+ end
30
+
31
+ stub_request(:get, 'http://datastore/records/1')
32
+ .to_return(body: item.to_json)
33
+ end
34
+
35
+ describe 'respond_to?(:to_ary)' do
36
+ context 'when creating item' do
37
+ let(:record) do
38
+ Record.new(user: User.new)
39
+ end
40
+
41
+ it 'does not respond to to_ary' do
42
+ expect(record.user.respond_to?(:to_ary)).to eq false
43
+ end
44
+ end
45
+
46
+ context 'when returning a single item' do
47
+ it 'does not respond to to_ary' do
48
+ expect(record.user.respond_to?(:to_ary)).to eq false
49
+ end
50
+ end
51
+
52
+ context 'when returning array of items' do
53
+ let(:user_item) do
54
+ [
55
+ { email: 'someone@somewhe.re' },
56
+ { email: 'someone.else@somewhe.re' }
57
+ ]
58
+ end
59
+
60
+ it 'responds to to_ary' do
61
+ expect(record.user.respond_to?(:to_ary)).to eq true
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,22 @@
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'
9
+ end
10
+ end
11
+
12
+ let(:item) { { name: 'Thomas' } }
13
+ let(:body) { [item] }
14
+
15
+ it 'converts itself to hash' do
16
+ stub_request(:get, 'http://datastore/records')
17
+ .to_return(body: body.to_json)
18
+ record = Record.where.first
19
+ expect(record.to_h).to eq item
20
+ expect(record.to_hash).to eq item
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ context 'to_json' do
7
+ let(:datastore) { 'http://depay.fi/v2' }
8
+
9
+ before do
10
+ DHC.config.placeholder('datastore', datastore)
11
+ class Feedback < DHS::Record
12
+ endpoint '{+datastore}/feedbacks'
13
+ end
14
+ end
15
+
16
+ it 'converts to json' do
17
+ feedback = Feedback.new recommended: true
18
+ expect(feedback.as_json).to eq('recommended' => true)
19
+ expect(feedback.to_json).to eq('{"recommended":true}')
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ context 'tracing' do
7
+ context 'with tracing enabled' do
8
+ before do
9
+ allow(DHS.config).to receive(:trace).and_return(true)
10
+ end
11
+
12
+ context 'with non-paginated methods' do
13
+ let(:request) do
14
+ stub_request(:get, 'https://records/3jg781')
15
+ .to_return(status: 204)
16
+ end
17
+
18
+ before do
19
+ class Record < DHS::Record
20
+ endpoint 'https://records'
21
+ end
22
+
23
+ expect(DHC).to receive(:request).with(anything) do |arguments|
24
+ expect(arguments[:source]).to include(__FILE__)
25
+ spy(:response)
26
+ end
27
+ end
28
+
29
+ %w[find find_by find_by! first first! last!].each do |method|
30
+ context method do
31
+ it 'forwards tracing options to dhc' do
32
+ Record.public_send(method, color: :blue)
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ context 'with paginated method last' do
39
+ before do
40
+ class Place < DHS::Record
41
+ endpoint 'http://datastore/places'
42
+ end
43
+
44
+ stub_request(:get, 'http://datastore/places?limit=1')
45
+ .to_return(
46
+ body: {
47
+ items: [
48
+ { id: 'first-1', company_name: 'Localsearch AG' }
49
+ ],
50
+ total: 500,
51
+ limit: 1,
52
+ offset: 0
53
+ }.to_json
54
+ )
55
+
56
+ stub_request(:get, 'http://datastore/places?limit=1&offset=499')
57
+ .to_return(
58
+ body: {
59
+ items: [
60
+ { id: 'last-500', company_name: 'Curious GmbH' }
61
+ ],
62
+ total: 500,
63
+ limit: 1,
64
+ offset: 0
65
+ }.to_json
66
+ )
67
+
68
+ expect(DHC).to receive(:request).and_call_original
69
+ expect(DHC).to receive(:request).with(hash_including(params: { offset: 499, limit: 1 })) do |arguments|
70
+ expect(arguments[:source]).to include(__FILE__)
71
+ spy(:response)
72
+ end
73
+ end
74
+
75
+ it 'forwards tracing options to dhc' do
76
+ Place.last
77
+ end
78
+ end
79
+ end
80
+
81
+ context 'tracing disabled (default)' do
82
+ context 'non-paginated methods' do
83
+ before do
84
+ class Record < DHS::Record
85
+ endpoint 'https://records'
86
+ end
87
+
88
+ expect(DHC).to receive(:request).with(anything) do |arguments|
89
+ expect(arguments).not_to include(:source)
90
+ spy(:response)
91
+ end
92
+ end
93
+
94
+ %w[find find_by find_by! first first! last!].each do |method|
95
+ context method do
96
+ it 'does not forward tracing options to dhc' do
97
+ Record.public_send(method, color: :blue)
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ context 'with paginated method last' do
104
+ before do
105
+ class Place < DHS::Record
106
+ endpoint 'http://datastore/places'
107
+ end
108
+
109
+ stub_request(:get, 'http://datastore/places?limit=1')
110
+ .to_return(
111
+ body: {
112
+ items: [
113
+ { id: 'first-1', company_name: 'Localsearch AG' }
114
+ ],
115
+ total: 500,
116
+ limit: 1,
117
+ offset: 0
118
+ }.to_json
119
+ )
120
+
121
+ stub_request(:get, 'http://datastore/places?limit=1&offset=499')
122
+ .to_return(
123
+ body: {
124
+ items: [
125
+ { id: 'last-500', company_name: 'Curious GmbH' }
126
+ ],
127
+ total: 500,
128
+ limit: 1,
129
+ offset: 0
130
+ }.to_json
131
+ )
132
+ end
133
+
134
+ it 'does not forward tracing options to dhc' do
135
+ # for first pagination requets (first-1)
136
+ expect(DHC).to receive(:request).and_call_original
137
+
138
+ # for second reques (last-500)
139
+ expect(DHC).to receive(:request).with(hash_including(params: { offset: 499, limit: 1 })) do |arguments|
140
+ expect(arguments).not_to include(:source)
141
+ spy(:response)
142
+ end
143
+
144
+ Place.last
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end