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,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+
5
+ class DHS::Record
6
+
7
+ # Allows configuring endpoints
8
+ # like which keys are used for the items, offset, total etc.
9
+ module Configuration
10
+ extend ActiveSupport::Concern
11
+
12
+ mattr_accessor :configuration
13
+
14
+ module ClassMethods
15
+ def configuration(args = nil)
16
+ if !args.nil?
17
+ @configuration = args
18
+ else
19
+ @configuration || {}
20
+ end
21
+ end
22
+
23
+ def auto_oauth?
24
+ DHS.config.auto_oauth && configuration && auto_oauth
25
+ end
26
+
27
+ def auto_oauth
28
+ configuration.fetch(:auto_oauth, false)
29
+ end
30
+
31
+ def oauth(provider = nil)
32
+ value = provider || true
33
+ configuration.present? ? configuration.merge!(auto_oauth: value) : configuration(auto_oauth: value)
34
+ end
35
+
36
+ def item_key
37
+ symbolize_unless_complex(
38
+ configuration.dig(:item_key) || :item
39
+ )
40
+ end
41
+
42
+ def items_key
43
+ symbolize_unless_complex(
44
+ configuration.dig(:items_key) || :items
45
+ )
46
+ end
47
+
48
+ def item_created_key
49
+ symbolize_unless_complex(
50
+ configuration.dig(:item_created_key)
51
+ )
52
+ end
53
+
54
+ def limit_key(type = nil)
55
+ symbolize_unless_complex(
56
+ pagination_parameter(configuration.dig(:limit_key), type) ||
57
+ :limit
58
+ )
59
+ end
60
+
61
+ def total_key
62
+ symbolize_unless_complex(
63
+ configuration.dig(:total_key) || :total
64
+ )
65
+ end
66
+
67
+ # Key used for determine current page
68
+ def pagination_key(type = nil)
69
+ symbolize_unless_complex(
70
+ pagination_parameter(configuration.dig(:pagination_key), type) ||
71
+ :offset
72
+ )
73
+ end
74
+
75
+ # Strategy used for calculationg next pages and navigate pages
76
+ def pagination_strategy
77
+ symbolize_unless_complex(
78
+ configuration.dig(:pagination_strategy) || :offset
79
+ )
80
+ end
81
+
82
+ # Allows record to be configured as not paginated,
83
+ # as by default it's considered paginated
84
+ def paginated
85
+ return true if configuration.blank?
86
+ configuration.fetch(:paginated, true)
87
+ end
88
+
89
+ private
90
+
91
+ def symbolize_unless_complex(value)
92
+ return if value.blank?
93
+ return value.to_sym unless value.is_a?(Array)
94
+ value
95
+ end
96
+
97
+ def pagination_parameter(configuration, type)
98
+ return configuration unless configuration.is_a?(Hash)
99
+ configuration[type]
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+
5
+ class DHS::Record
6
+
7
+ module Create
8
+ extend ActiveSupport::Concern
9
+
10
+ module ClassMethods
11
+ def create(data = {}, options = nil)
12
+ record = new(data)
13
+ record.save(options)
14
+ record
15
+ end
16
+
17
+ def create!(data = {}, options = nil)
18
+ record = new(data)
19
+ record.save!(options)
20
+ record
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+
5
+ class DHS::Record
6
+
7
+ module CustomSetters
8
+ extend ActiveSupport::Concern
9
+
10
+ private
11
+
12
+ def apply_custom_setters!
13
+ return if !_data.item? || !_data._raw.respond_to?(:keys)
14
+ raw = _data._raw
15
+ custom_setters = raw.keys.find_all { |key| public_methods.include?("#{key}=".to_sym) }
16
+ custom_setters.each do |setter|
17
+ value = raw.delete(setter)
18
+ send("#{setter}=", value)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+
5
+ class DHS::Record
6
+
7
+ module Destroy
8
+ extend ActiveSupport::Concern
9
+
10
+ module ClassMethods
11
+ def destroy(args, options = nil)
12
+ options = {} if options.blank?
13
+ params = args.respond_to?(:to_h) ? args : { id: args }
14
+ request(options.merge(params: params, method: :delete))
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'active_support/core_ext'
5
+
6
+ class DHS::Record
7
+
8
+ # An endpoint is an url that leads to a backend resource.
9
+ # A record can contain multiple endpoints.
10
+ # The endpoint that is used to request data is choosen
11
+ # based on the provided parameters.
12
+ module Endpoints
13
+ extend ActiveSupport::Concern
14
+
15
+ mattr_accessor :all
16
+
17
+ included do
18
+ class_attribute :endpoints unless defined? endpoints
19
+ self.endpoints = []
20
+ end
21
+
22
+ module ClassMethods
23
+ # Adds the endpoint to the list of endpoints.
24
+ def endpoint(url, options = nil)
25
+ self.endpoints = endpoints.clone
26
+ validates_deprecation_check!(options)
27
+ endpoint = DHC::Endpoint.new(url, options)
28
+ endpoints.push(endpoint)
29
+ DHS::Record::Endpoints.all ||= {}
30
+ DHS::Record::Endpoints.all[url] ||= self
31
+ end
32
+
33
+ def for_url(url)
34
+ return unless url
35
+ _template, record = DHS::Record::Endpoints.all.dup.detect do |template, _|
36
+ DHC::Endpoint.match?(url, template)
37
+ end
38
+ record
39
+ end
40
+
41
+ # Find an endpoint based on the provided parameters.
42
+ # If no parameters are provided it finds the base endpoint
43
+ # otherwise it finds the endpoint that matches the parameters best.
44
+ def find_endpoint(params = {}, url = nil)
45
+ endpoint = find_best_endpoint(params) if params && params.keys.count > 0
46
+ endpoint ||= find_endpoint_by_url(url) if url.present?
47
+ endpoint ||= DHC::Endpoint.new(url) if url.present?
48
+ endpoint ||= find_base_endpoint
49
+ endpoint
50
+ end
51
+
52
+ # Computes the url from params
53
+ # by identifiying endpoint and compiles it if necessary.
54
+ def compute_url!(params)
55
+ endpoint = find_endpoint(params)
56
+ url = endpoint.compile(params)
57
+ endpoint.remove_interpolated_params!(params)
58
+ url
59
+ end
60
+
61
+ def compute_url(params, url = nil)
62
+ find_endpoint(params, url)
63
+ .compile(params)
64
+ end
65
+
66
+ private
67
+
68
+ def validates_deprecation_check!(options)
69
+ return if options.blank?
70
+ return if options[:validates].blank?
71
+ return if options[:validates].is_a?(Hash)
72
+ return if !options[:validates].is_a?(TrueClass) && options[:validates].match(%r{^\/})
73
+ raise 'Validates with either true or a simple string is deprecated! See here: https://github.com/DePayFi/dhs#validation'
74
+ end
75
+
76
+ # Finds the best endpoint.
77
+ # The best endpoint is the one where all placeholders are interpolated.
78
+ def find_best_endpoint(params)
79
+ sorted_endpoints.find do |endpoint|
80
+ endpoint.placeholders.all? { |match| endpoint.find_value(match, params).present? }
81
+ end
82
+ end
83
+
84
+ # Find endpoint by given URL
85
+ def find_endpoint_by_url(url)
86
+ sorted_endpoints.find do |endpoint|
87
+ DHC::Endpoint.match?(url, endpoint.url)
88
+ end
89
+ end
90
+
91
+ # Sort endpoints by number of placeholders, heighest first
92
+ def sorted_endpoints
93
+ endpoints.sort { |a, b| b.placeholders.count <=> a.placeholders.count }
94
+ end
95
+
96
+ # Finds the base endpoint.
97
+ # A base endpoint is the one thats has the least amont of placeholers.
98
+ # There cannot be multiple base endpoints.
99
+ def find_base_endpoint
100
+ endpoints = self.endpoints.group_by do |endpoint|
101
+ endpoint.placeholders.length
102
+ end
103
+ bases = endpoints[endpoints.keys.min]
104
+ bases.first
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+
5
+ class DHS::Record
6
+
7
+ module Equality
8
+ extend ActiveSupport::Concern
9
+
10
+ def ==(other)
11
+ _raw == other.try(:_raw)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+
5
+ class DHS::Record
6
+
7
+ module Find
8
+ extend ActiveSupport::Concern
9
+
10
+ module ClassMethods
11
+ # Find a single uniqe record
12
+ def find(*args)
13
+ args, options = process_args(args)
14
+ options = trace!(options)
15
+ raise(DHS::Unprocessable.new, 'Cannot find Record without an ID') if args.blank? && !args.is_a?(Array)
16
+ data =
17
+ if args.present? && args.is_a?(Array)
18
+ find_in_parallel(args, options)
19
+ elsif args.is_a? Hash
20
+ find_with_parameters(args, options)
21
+ else
22
+ find_by_id(args, options)
23
+ end
24
+ return nil if data.nil?
25
+ return data unless data._record
26
+ if data.collection?
27
+ data.map { |record| data._record.new(record.unwrap_nested_item) }
28
+ else
29
+ data._record.new(data.unwrap_nested_item)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def process_args(args)
36
+ if args.length == 1
37
+ args = args.first
38
+ elsif args.length == 2 && args.last.is_a?(Hash)
39
+ options = args.pop if args.last.is_a?(Hash)
40
+ args = args.first
41
+ elsif args.last.is_a?(Hash)
42
+ options = args.pop
43
+ end
44
+ options ||= nil
45
+ [args, options]
46
+ end
47
+
48
+ def get_unique_item!(data)
49
+ return if data.nil?
50
+ if data._proxy.is_a?(DHS::Collection)
51
+ raise DHC::NotFound.new('Requested unique item. Multiple were found.', data._request.response) if data.length > 1
52
+ data.first || raise(DHC::NotFound.new('No item was found.', data._request.response))
53
+ else
54
+ data
55
+ end
56
+ end
57
+
58
+ def find_with_parameters(args, options = {})
59
+ data = request(request_options(args, options))
60
+ get_unique_item!(data)
61
+ end
62
+
63
+ def find_by_id(args, options = {})
64
+ request(request_options(args, options))
65
+ end
66
+
67
+ def find_in_parallel(args, options)
68
+ options = args.map { |argument| request_options(argument, options) }
69
+ request(options)
70
+ end
71
+
72
+ def request_options(args, options)
73
+ options ||= {}
74
+ if args.is_a? Hash
75
+ options.merge(params: args)
76
+ elsif href?(args)
77
+ options.merge(url: args)
78
+ elsif args.present?
79
+ options.merge(params: { id: args })
80
+ else
81
+ options
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+
5
+ class DHS::Record
6
+
7
+ module FindBy
8
+ extend ActiveSupport::Concern
9
+
10
+ module ClassMethods
11
+ # Fetch some record by parameters
12
+ def find_by(params = {}, options = nil)
13
+ _find_by(params, trace!(options))
14
+ rescue DHC::NotFound
15
+ nil
16
+ end
17
+
18
+ # Raise if no record was found
19
+ def find_by!(params = {}, options = nil)
20
+ _find_by(params, trace!(options))
21
+ end
22
+
23
+ private
24
+
25
+ def _find_by(params, options = {})
26
+ raise(DHS::Unprocessable.new, 'Cannot find Record without an ID') if params.any? && params.all? { |_, value| value.blank? }
27
+ options ||= {}
28
+ params = params.dup.merge(limit_key(:parameter) => 1).merge(options.fetch(:params, {}))
29
+ data = request(options.merge(params: params))
30
+ if data && data._proxy.is_a?(DHS::Collection)
31
+ data.first || raise(DHC::NotFound.new('No item was found.', data._request.response))
32
+ elsif data
33
+ data._record.new(data.unwrap_nested_item)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+
5
+ class DHS::Record
6
+
7
+ module First
8
+ extend ActiveSupport::Concern
9
+
10
+ module ClassMethods
11
+ def first(options = nil)
12
+ find_by({}, trace!(options))
13
+ end
14
+
15
+ def first!(options = nil)
16
+ find_by!({}, trace!(options))
17
+ end
18
+ end
19
+ end
20
+ end