lhs 24.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 (306) hide show
  1. checksums.yaml +7 -0
  2. data/.bundler-version +1 -0
  3. data/.gitignore +39 -0
  4. data/.rubocop.localch.yml +325 -0
  5. data/.rubocop.yml +52 -0
  6. data/.ruby-version +1 -0
  7. data/Gemfile +4 -0
  8. data/Gemfile.activesupport4 +5 -0
  9. data/Gemfile.activesupport5 +4 -0
  10. data/LICENSE +674 -0
  11. data/README.md +2836 -0
  12. data/Rakefile +25 -0
  13. data/cider-ci.yml +6 -0
  14. data/cider-ci/bin/bundle +51 -0
  15. data/cider-ci/bin/ruby_install +8 -0
  16. data/cider-ci/bin/ruby_version +25 -0
  17. data/cider-ci/jobs/rspec-activesupport-4.yml +27 -0
  18. data/cider-ci/jobs/rspec-activesupport-5.yml +26 -0
  19. data/cider-ci/jobs/rspec-activesupport-latest.yml +24 -0
  20. data/cider-ci/jobs/rubocop.yml +18 -0
  21. data/cider-ci/task_components/bundle.yml +22 -0
  22. data/cider-ci/task_components/rspec.yml +37 -0
  23. data/cider-ci/task_components/rubocop.yml +29 -0
  24. data/cider-ci/task_components/ruby.yml +15 -0
  25. data/friday.yml +2 -0
  26. data/lhs.gemspec +43 -0
  27. data/lib/lhs.rb +100 -0
  28. data/lib/lhs/collection.rb +84 -0
  29. data/lib/lhs/complex.rb +158 -0
  30. data/lib/lhs/concerns/autoload_records.rb +55 -0
  31. data/lib/lhs/concerns/collection/handle_nested.rb +43 -0
  32. data/lib/lhs/concerns/collection/internal_collection.rb +49 -0
  33. data/lib/lhs/concerns/configuration.rb +20 -0
  34. data/lib/lhs/concerns/data/becomes.rb +18 -0
  35. data/lib/lhs/concerns/data/equality.rb +14 -0
  36. data/lib/lhs/concerns/data/json.rb +14 -0
  37. data/lib/lhs/concerns/data/to_hash.rb +14 -0
  38. data/lib/lhs/concerns/inspect.rb +70 -0
  39. data/lib/lhs/concerns/is_href.rb +15 -0
  40. data/lib/lhs/concerns/item/destroy.rb +38 -0
  41. data/lib/lhs/concerns/item/endpoint_lookup.rb +27 -0
  42. data/lib/lhs/concerns/item/save.rb +55 -0
  43. data/lib/lhs/concerns/item/update.rb +50 -0
  44. data/lib/lhs/concerns/item/validation.rb +61 -0
  45. data/lib/lhs/concerns/o_auth.rb +25 -0
  46. data/lib/lhs/concerns/option_blocks.rb +26 -0
  47. data/lib/lhs/concerns/proxy/accessors.rb +132 -0
  48. data/lib/lhs/concerns/proxy/create.rb +45 -0
  49. data/lib/lhs/concerns/proxy/link.rb +25 -0
  50. data/lib/lhs/concerns/proxy/problems.rb +27 -0
  51. data/lib/lhs/concerns/record/attribute_assignment.rb +25 -0
  52. data/lib/lhs/concerns/record/batch.rb +40 -0
  53. data/lib/lhs/concerns/record/chainable.rb +465 -0
  54. data/lib/lhs/concerns/record/configuration.rb +103 -0
  55. data/lib/lhs/concerns/record/create.rb +24 -0
  56. data/lib/lhs/concerns/record/custom_setters.rb +22 -0
  57. data/lib/lhs/concerns/record/destroy.rb +18 -0
  58. data/lib/lhs/concerns/record/endpoints.rb +108 -0
  59. data/lib/lhs/concerns/record/equality.rb +14 -0
  60. data/lib/lhs/concerns/record/find.rb +86 -0
  61. data/lib/lhs/concerns/record/find_by.rb +38 -0
  62. data/lib/lhs/concerns/record/first.rb +20 -0
  63. data/lib/lhs/concerns/record/href_for.rb +19 -0
  64. data/lib/lhs/concerns/record/last.rb +27 -0
  65. data/lib/lhs/concerns/record/mapping.rb +25 -0
  66. data/lib/lhs/concerns/record/merge.rb +26 -0
  67. data/lib/lhs/concerns/record/model.rb +23 -0
  68. data/lib/lhs/concerns/record/pagination.rb +47 -0
  69. data/lib/lhs/concerns/record/provider.rb +23 -0
  70. data/lib/lhs/concerns/record/relations.rb +26 -0
  71. data/lib/lhs/concerns/record/request.rb +620 -0
  72. data/lib/lhs/concerns/record/scope.rb +25 -0
  73. data/lib/lhs/concerns/record/tracing.rb +24 -0
  74. data/lib/lhs/concerns/record/update.rb +17 -0
  75. data/lib/lhs/config.rb +24 -0
  76. data/lib/lhs/data.rb +165 -0
  77. data/lib/lhs/endpoint.rb +12 -0
  78. data/lib/lhs/interceptors/auto_oauth/interceptor.rb +33 -0
  79. data/lib/lhs/interceptors/auto_oauth/thread_registry.rb +18 -0
  80. data/lib/lhs/interceptors/extended_rollbar/handler.rb +40 -0
  81. data/lib/lhs/interceptors/extended_rollbar/interceptor.rb +20 -0
  82. data/lib/lhs/interceptors/extended_rollbar/thread_registry.rb +19 -0
  83. data/lib/lhs/interceptors/request_cycle_cache/interceptor.rb +41 -0
  84. data/lib/lhs/interceptors/request_cycle_cache/thread_registry.rb +18 -0
  85. data/lib/lhs/item.rb +59 -0
  86. data/lib/lhs/pagination/base.rb +90 -0
  87. data/lib/lhs/pagination/link.rb +21 -0
  88. data/lib/lhs/pagination/offset.rb +22 -0
  89. data/lib/lhs/pagination/page.rb +18 -0
  90. data/lib/lhs/pagination/start.rb +22 -0
  91. data/lib/lhs/problems/base.rb +113 -0
  92. data/lib/lhs/problems/errors.rb +69 -0
  93. data/lib/lhs/problems/nested/base.rb +54 -0
  94. data/lib/lhs/problems/nested/errors.rb +16 -0
  95. data/lib/lhs/problems/nested/warnings.rb +15 -0
  96. data/lib/lhs/problems/warnings.rb +24 -0
  97. data/lib/lhs/proxy.rb +68 -0
  98. data/lib/lhs/railtie.rb +34 -0
  99. data/lib/lhs/record.rb +112 -0
  100. data/lib/lhs/rspec.rb +10 -0
  101. data/lib/lhs/test/stubbable_records.rb +34 -0
  102. data/lib/lhs/unprocessable.rb +6 -0
  103. data/lib/lhs/version.rb +5 -0
  104. data/script/ci/build.sh +18 -0
  105. data/spec/auto_oauth_spec.rb +169 -0
  106. data/spec/autoloading_spec.rb +48 -0
  107. data/spec/collection/accessors_spec.rb +31 -0
  108. data/spec/collection/collection_items_spec.rb +44 -0
  109. data/spec/collection/configurable_spec.rb +43 -0
  110. data/spec/collection/delegate_spec.rb +21 -0
  111. data/spec/collection/enumerable_spec.rb +27 -0
  112. data/spec/collection/href_spec.rb +17 -0
  113. data/spec/collection/meta_data_spec.rb +57 -0
  114. data/spec/collection/respond_to_spec.rb +20 -0
  115. data/spec/collection/to_a_spec.rb +34 -0
  116. data/spec/collection/to_ary_spec.rb +40 -0
  117. data/spec/collection/without_object_items_spec.rb +27 -0
  118. data/spec/complex/reduce_spec.rb +202 -0
  119. data/spec/concerns/record/request_spec.rb +78 -0
  120. data/spec/data/collection_spec.rb +56 -0
  121. data/spec/data/equality_spec.rb +23 -0
  122. data/spec/data/inspect_spec.rb +88 -0
  123. data/spec/data/is_item_or_collection_spec.rb +40 -0
  124. data/spec/data/item_spec.rb +106 -0
  125. data/spec/data/merge_spec.rb +27 -0
  126. data/spec/data/parent_spec.rb +39 -0
  127. data/spec/data/raw_spec.rb +48 -0
  128. data/spec/data/respond_to_spec.rb +26 -0
  129. data/spec/data/root_spec.rb +25 -0
  130. data/spec/data/select_spec.rb +27 -0
  131. data/spec/data/to_ary_spec.rb +28 -0
  132. data/spec/data/to_json_spec.rb +68 -0
  133. data/spec/dummy/Rakefile +8 -0
  134. data/spec/dummy/app/assets/images/.keep +0 -0
  135. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  136. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  137. data/spec/dummy/app/controllers/application_controller.rb +26 -0
  138. data/spec/dummy/app/controllers/automatic_authentication_controller.rb +29 -0
  139. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  140. data/spec/dummy/app/controllers/error_handling_with_chains_controller.rb +36 -0
  141. data/spec/dummy/app/controllers/extended_rollbar_controller.rb +10 -0
  142. data/spec/dummy/app/controllers/option_blocks_controller.rb +15 -0
  143. data/spec/dummy/app/controllers/request_cycle_cache_controller.rb +27 -0
  144. data/spec/dummy/app/helpers/application_helper.rb +4 -0
  145. data/spec/dummy/app/mailers/.keep +0 -0
  146. data/spec/dummy/app/models/.keep +0 -0
  147. data/spec/dummy/app/models/concerns/.keep +0 -0
  148. data/spec/dummy/app/models/dummy_customer.rb +6 -0
  149. data/spec/dummy/app/models/dummy_record.rb +6 -0
  150. data/spec/dummy/app/models/dummy_record_with_auto_oauth_provider.rb +6 -0
  151. data/spec/dummy/app/models/dummy_record_with_multiple_oauth_providers1.rb +7 -0
  152. data/spec/dummy/app/models/dummy_record_with_multiple_oauth_providers2.rb +7 -0
  153. data/spec/dummy/app/models/dummy_record_with_multiple_providers_per_endpoint.rb +6 -0
  154. data/spec/dummy/app/models/dummy_record_with_oauth.rb +7 -0
  155. data/spec/dummy/app/models/dummy_user.rb +6 -0
  156. data/spec/dummy/app/models/providers/customer_system.rb +7 -0
  157. data/spec/dummy/app/models/providers/internal_services.rb +7 -0
  158. data/spec/dummy/app/views/error_handling_with_chains/error.html.erb +1 -0
  159. data/spec/dummy/app/views/error_handling_with_chains/show.html.erb +3 -0
  160. data/spec/dummy/app/views/form_for.html.erb +5 -0
  161. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  162. data/spec/dummy/bin/bundle +5 -0
  163. data/spec/dummy/bin/rails +6 -0
  164. data/spec/dummy/bin/rake +6 -0
  165. data/spec/dummy/config.ru +6 -0
  166. data/spec/dummy/config/application.rb +16 -0
  167. data/spec/dummy/config/boot.rb +7 -0
  168. data/spec/dummy/config/environment.rb +7 -0
  169. data/spec/dummy/config/environments/development.rb +36 -0
  170. data/spec/dummy/config/environments/production.rb +77 -0
  171. data/spec/dummy/config/environments/test.rb +40 -0
  172. data/spec/dummy/config/initializers/assets.rb +10 -0
  173. data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
  174. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  175. data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  176. data/spec/dummy/config/initializers/inflections.rb +18 -0
  177. data/spec/dummy/config/initializers/mime_types.rb +6 -0
  178. data/spec/dummy/config/initializers/rollbar.rb +9 -0
  179. data/spec/dummy/config/initializers/session_store.rb +5 -0
  180. data/spec/dummy/config/initializers/wrap_parameters.rb +11 -0
  181. data/spec/dummy/config/locales/en.yml +23 -0
  182. data/spec/dummy/config/routes.rb +27 -0
  183. data/spec/dummy/config/secrets.yml +22 -0
  184. data/spec/dummy/lib/assets/.keep +0 -0
  185. data/spec/dummy/public/404.html +67 -0
  186. data/spec/dummy/public/422.html +67 -0
  187. data/spec/dummy/public/500.html +66 -0
  188. data/spec/dummy/public/favicon.ico +0 -0
  189. data/spec/endpoint/for_url_spec.rb +27 -0
  190. data/spec/extended_rollbar_spec.rb +67 -0
  191. data/spec/item/access_errors_spec.rb +33 -0
  192. data/spec/item/accessors_spec.rb +21 -0
  193. data/spec/item/add_error_spec.rb +21 -0
  194. data/spec/item/becomes_spec.rb +38 -0
  195. data/spec/item/blacklisted_keywords_spec.rb +30 -0
  196. data/spec/item/delegate_spec.rb +32 -0
  197. data/spec/item/destroy_spec.rb +113 -0
  198. data/spec/item/dig_spec.rb +29 -0
  199. data/spec/item/error_codes_spec.rb +55 -0
  200. data/spec/item/errors_spec.rb +324 -0
  201. data/spec/item/fetch_spec.rb +39 -0
  202. data/spec/item/getter_spec.rb +24 -0
  203. data/spec/item/internal_data_structure_spec.rb +37 -0
  204. data/spec/item/map_spec.rb +46 -0
  205. data/spec/item/nested_errors_spec.rb +28 -0
  206. data/spec/item/partial_update_spec.rb +170 -0
  207. data/spec/item/respond_to_spec.rb +31 -0
  208. data/spec/item/save_spec.rb +115 -0
  209. data/spec/item/setter_spec.rb +44 -0
  210. data/spec/item/translate_errors_spec.rb +257 -0
  211. data/spec/item/update_spec.rb +161 -0
  212. data/spec/item/validation_spec.rb +131 -0
  213. data/spec/item/warning_codes_spec.rb +55 -0
  214. data/spec/item/warnings_spec.rb +52 -0
  215. data/spec/option_blocks/ensure_reset_between_requests_spec.rb +23 -0
  216. data/spec/option_blocks/main_spec.rb +55 -0
  217. data/spec/pagination/link/current_page_spec.rb +19 -0
  218. data/spec/pagination/link/pages_left_spec.rb +36 -0
  219. data/spec/pagination/link/parallel_spec.rb +19 -0
  220. data/spec/pagination/link/total_spec.rb +46 -0
  221. data/spec/pagination/offset/pages_left_spec.rb +26 -0
  222. data/spec/pagination/parameters_spec.rb +61 -0
  223. data/spec/proxy/create_sub_resource_spec.rb +182 -0
  224. data/spec/proxy/load_spec.rb +75 -0
  225. data/spec/proxy/record_identification_spec.rb +35 -0
  226. data/spec/rails_helper.rb +13 -0
  227. data/spec/record/all_spec.rb +133 -0
  228. data/spec/record/attribute_assignment_spec.rb +28 -0
  229. data/spec/record/build_spec.rb +26 -0
  230. data/spec/record/cast_nested_data_spec.rb +78 -0
  231. data/spec/record/create_spec.rb +160 -0
  232. data/spec/record/creation_failed_spec.rb +55 -0
  233. data/spec/record/custom_setters_spec.rb +45 -0
  234. data/spec/record/definitions_spec.rb +29 -0
  235. data/spec/record/destroy_spec.rb +38 -0
  236. data/spec/record/dig_configuration_spec.rb +75 -0
  237. data/spec/record/dup_spec.rb +20 -0
  238. data/spec/record/endpoint_inheritance_spec.rb +65 -0
  239. data/spec/record/endpoint_options_spec.rb +52 -0
  240. data/spec/record/endpoint_priorities_spec.rb +26 -0
  241. data/spec/record/endpoints_spec.rb +96 -0
  242. data/spec/record/equality_spec.rb +27 -0
  243. data/spec/record/error_handling_integration_spec.rb +25 -0
  244. data/spec/record/error_handling_spec.rb +40 -0
  245. data/spec/record/expanded_spec.rb +69 -0
  246. data/spec/record/fetch_spec.rb +41 -0
  247. data/spec/record/find_by_chains_spec.rb +21 -0
  248. data/spec/record/find_by_spec.rb +76 -0
  249. data/spec/record/find_each_spec.rb +57 -0
  250. data/spec/record/find_in_batches_spec.rb +122 -0
  251. data/spec/record/find_in_parallel_spec.rb +67 -0
  252. data/spec/record/find_spec.rb +104 -0
  253. data/spec/record/first_spec.rb +39 -0
  254. data/spec/record/force_merge_spec.rb +56 -0
  255. data/spec/record/handle_includes_errors_spec.rb +32 -0
  256. data/spec/record/has_many_spec.rb +120 -0
  257. data/spec/record/has_one_spec.rb +116 -0
  258. data/spec/record/href_for_spec.rb +25 -0
  259. data/spec/record/ignore_errors_spec.rb +139 -0
  260. data/spec/record/immutable_chains_spec.rb +22 -0
  261. data/spec/record/includes_first_page_spec.rb +737 -0
  262. data/spec/record/includes_spec.rb +693 -0
  263. data/spec/record/includes_warning_spec.rb +46 -0
  264. data/spec/record/item_key_spec.rb +81 -0
  265. data/spec/record/items_created_key_configuration_spec.rb +37 -0
  266. data/spec/record/last_spec.rb +68 -0
  267. data/spec/record/loading_twice_spec.rb +19 -0
  268. data/spec/record/mapping_spec.rb +102 -0
  269. data/spec/record/model_name_spec.rb +17 -0
  270. data/spec/record/new_spec.rb +106 -0
  271. data/spec/record/options_getter_spec.rb +26 -0
  272. data/spec/record/options_spec.rb +164 -0
  273. data/spec/record/paginatable_collection_spec.rb +360 -0
  274. data/spec/record/pagination_chain_spec.rb +101 -0
  275. data/spec/record/pagination_links_spec.rb +72 -0
  276. data/spec/record/pagination_spec.rb +71 -0
  277. data/spec/record/persisted_spec.rb +52 -0
  278. data/spec/record/provider_spec.rb +41 -0
  279. data/spec/record/references_spec.rb +53 -0
  280. data/spec/record/relation_caching_spec.rb +121 -0
  281. data/spec/record/reload_by_id_spec.rb +43 -0
  282. data/spec/record/reload_spec.rb +65 -0
  283. data/spec/record/request_spec.rb +90 -0
  284. data/spec/record/save_spec.rb +40 -0
  285. data/spec/record/scope_chains_spec.rb +39 -0
  286. data/spec/record/select_spec.rb +17 -0
  287. data/spec/record/to_ary_spec.rb +65 -0
  288. data/spec/record/to_hash_spec.rb +22 -0
  289. data/spec/record/to_json_spec.rb +22 -0
  290. data/spec/record/tracing_spec.rb +154 -0
  291. data/spec/record/update_spec.rb +62 -0
  292. data/spec/record/where_chains_spec.rb +57 -0
  293. data/spec/record/where_spec.rb +62 -0
  294. data/spec/record/where_values_hash_spec.rb +32 -0
  295. data/spec/request_cycle_cache_spec.rb +106 -0
  296. data/spec/require_lhs_spec.rb +9 -0
  297. data/spec/spec_helper.rb +6 -0
  298. data/spec/stubs/all_spec.rb +72 -0
  299. data/spec/support/fixtures/json/feedback.json +11 -0
  300. data/spec/support/fixtures/json/feedbacks.json +174 -0
  301. data/spec/support/fixtures/json/localina_content_ad.json +23 -0
  302. data/spec/support/load_json.rb +5 -0
  303. data/spec/support/request_cycle_cache.rb +10 -0
  304. data/spec/support/reset.rb +67 -0
  305. data/spec/views/form_for_spec.rb +20 -0
  306. metadata +776 -0
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHS::Record do
6
+ let(:offset) { 0 }
7
+ let(:data_hash) { { items: 98.times.map { { foo: 'bar' } }, total: 98, offset: offset, limit: 10 } }
8
+
9
+ let(:data) do
10
+ LHS::Data.new(data_hash, nil, Record)
11
+ end
12
+
13
+ let(:pagination) { LHS::Pagination::Offset.new(data) }
14
+
15
+ it 'responds to pages_left' do
16
+ expect(pagination.pages_left).to eq(9)
17
+ end
18
+
19
+ context 'when there is no offset' do
20
+ let(:offset) { nil }
21
+
22
+ it 'responds to pages_left' do
23
+ expect(pagination.pages_left).to eq(9)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+ require 'webrick'
5
+
6
+ describe LHS::Record do
7
+
8
+ before do
9
+ class Location < LHS::Record
10
+ endpoint 'http://uberall/locations'
11
+ configuration(
12
+ limit_key: { body: %i[response max], parameter: :max },
13
+ pagination_key: { body: %i[response offset], parameter: :offset },
14
+ total_key: %i[response count],
15
+ items_key: %i[response locations],
16
+ pagination_strategy: :offset
17
+ )
18
+ end
19
+ end
20
+
21
+ context 'explicit pagination parameters for retrieving pages' do
22
+
23
+ it 'uses explicit parameters when retrieving pages' do
24
+ stub_request(:get, "http://uberall/locations?max=100")
25
+ .to_return(body: {
26
+ response: {
27
+ locations: 10.times.map { |_| { name: WEBrick::Utils.random_string(10) } },
28
+ max: 10,
29
+ offset: 0,
30
+ count: 30
31
+ }
32
+ }.to_json)
33
+
34
+ stub_request(:get, "http://uberall/locations?max=10&offset=10")
35
+ .to_return(body: {
36
+ response: {
37
+ locations: 10.times.map { |_| { name: WEBrick::Utils.random_string(10) } },
38
+ max: 10,
39
+ offset: 10,
40
+ count: 30
41
+ }
42
+ }.to_json)
43
+
44
+ stub_request(:get, "http://uberall/locations?max=10&offset=20")
45
+ .to_return(body: {
46
+ response: {
47
+ locations: 10.times.map { |_| { name: WEBrick::Utils.random_string(10) } },
48
+ max: 10,
49
+ offset: 20,
50
+ count: 30
51
+ }
52
+ }.to_json)
53
+
54
+ locations = Location.all.fetch
55
+ expect(locations.length).to eq 30
56
+ expect(locations.count).to eq 30
57
+ expect(locations.offset).to eq 20
58
+ expect(locations.limit).to eq 10
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,182 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHS::Item do
6
+ before do
7
+ class Feedback < LHS::Record
8
+ endpoint 'http://datastore/v2/feedbacks/{id}'
9
+ end
10
+
11
+ class Review < LHS::Record
12
+ endpoint 'http://datastore/v2/feedbacks/{feedback_id}/reviews'
13
+ end
14
+ end
15
+
16
+ context 'create sub-resource' do
17
+ let!(:create_review_request) do
18
+ stub_request(:post, "http://datastore/v2/feedbacks/1/reviews")
19
+ .to_return(body: {
20
+ href: 'http://datastore/v2/feedbacks/1/reviews/1',
21
+ title: 'Simply awesome'
22
+ }.to_json)
23
+ end
24
+
25
+ context 'for a nested item' do
26
+ let(:feedback) { Feedback.find(1) }
27
+ let(:review) do
28
+ feedback.review.create(
29
+ title: 'Simply awesome'
30
+ )
31
+ end
32
+
33
+ before do
34
+ stub_request(:get, "http://datastore/v2/feedbacks/1/reviews")
35
+ .to_return(body: {
36
+ href: 'http://datastore/v2/feedbacks/1/reviews',
37
+ title: 'Simply awesome'
38
+ }.to_json)
39
+ end
40
+
41
+ context 'without the object' do
42
+ before do
43
+ stub_request(:get, "http://datastore/v2/feedbacks/1")
44
+ .to_return(body: {
45
+ review: {
46
+ href: 'http://datastore/v2/feedbacks/1/reviews'
47
+ }
48
+ }.to_json)
49
+ end
50
+
51
+ it 'creates an item' do
52
+ review
53
+ assert_requested(create_review_request)
54
+
55
+ expect(feedback.review.title).to eq 'Simply awesome'
56
+ expect(review.title).to eq 'Simply awesome'
57
+ end
58
+ end
59
+
60
+ context 'with existing item' do
61
+ before do
62
+ stub_request(:get, "http://datastore/v2/feedbacks/1")
63
+ .to_return(body: {
64
+ review: {
65
+ href: 'http://datastore/v2/feedbacks/1/reviews',
66
+ title: 'Simply awesome'
67
+ }
68
+ }.to_json)
69
+ end
70
+
71
+ it 'raises error' do
72
+ expect { review }.to raise_error(ArgumentError)
73
+
74
+ assert_not_requested(create_review_request)
75
+ end
76
+ end
77
+ end
78
+
79
+ context 'for a nested collection' do
80
+ let(:review) do
81
+ feedback.reviews.create(
82
+ title: 'Simply awesome'
83
+ )
84
+ end
85
+
86
+ before do
87
+ stub_request(:get, "http://datastore/v2/feedbacks/1/reviews")
88
+ .to_return(body: {
89
+ items: [{
90
+ href: 'http://datastore/v2/feedbacks/1/reviews/1',
91
+ title: 'Simply awesome'
92
+ }]
93
+ }.to_json)
94
+ end
95
+
96
+ context 'when expanded' do
97
+ before do
98
+ stub_request(:get, "http://datastore/v2/feedbacks/1")
99
+ .to_return(body: {
100
+ reviews: {
101
+ href: 'http://datastore/v2/feedbacks/1/reviews',
102
+ items: []
103
+ }
104
+ }.to_json)
105
+ end
106
+
107
+ let(:feedback) { Feedback.includes(:reviews).find(1) }
108
+
109
+ it 'creates an item' do
110
+ review
111
+ assert_requested(create_review_request)
112
+
113
+ expect(feedback.reviews.first.title).to eq 'Simply awesome'
114
+ expect(review.title).to eq 'Simply awesome'
115
+ end
116
+ end
117
+
118
+ context 'when not expanded' do
119
+ before do
120
+ stub_request(:get, "http://datastore/v2/feedbacks/1")
121
+ .to_return(body: {
122
+ reviews: {
123
+ href: 'http://datastore/v2/feedbacks/1/reviews'
124
+ }
125
+ }.to_json)
126
+ end
127
+
128
+ let(:feedback) { Feedback.find(1) }
129
+
130
+ it 'creates an item' do
131
+ review
132
+ assert_requested(create_review_request)
133
+
134
+ expect(feedback.reviews.first.title).to eq 'Simply awesome'
135
+ expect(review.title).to eq 'Simply awesome'
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ context 'error messages' do
142
+ let!(:create_review_request) do
143
+ stub_request(:post, "http://datastore/v2/feedbacks/1/reviews")
144
+ .to_return(
145
+ status: 400,
146
+ body: {
147
+ status: 400,
148
+ message: 'Validation failed',
149
+ field_errors: [{
150
+ code: 'UNSATISFIED_PROPERTY_VALUE_MAXIMUM_LENGTH',
151
+ path: ['title'],
152
+ message: 'Title is too long'
153
+ }]
154
+ }.to_json
155
+ )
156
+ end
157
+
158
+ let(:feedback) { Feedback.find(1) }
159
+ let(:review) do
160
+ feedback.review.create(
161
+ title: 'Simply awesome'
162
+ )
163
+ end
164
+
165
+ before do
166
+ stub_request(:get, "http://datastore/v2/feedbacks/1")
167
+ .to_return(body: {
168
+ review: {
169
+ href: 'http://datastore/v2/feedbacks/1/reviews'
170
+ }
171
+ }.to_json)
172
+ end
173
+
174
+ it 'are propagated when creation fails' do
175
+ review
176
+ assert_requested(create_review_request)
177
+
178
+ expect(review.title).to eq 'Simply awesome'
179
+ expect(review.errors.messages[:title]).to include('UNSATISFIED_PROPERTY_VALUE_MAXIMUM_LENGTH')
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHS::Proxy do
6
+ before do
7
+ class Record < LHS::Record
8
+ endpoint '{+datastore}/v2/feedbacks'
9
+ end
10
+
11
+ stub_request(:get, 'http://local.ch/v2/content-ads/51dfc5690cf271c375c5a12d')
12
+ .to_return(status: 200, body: load_json(:localina_content_ad))
13
+ end
14
+
15
+ let(:json) do
16
+ load_json(:feedbacks)
17
+ end
18
+
19
+ let(:data) do
20
+ LHS::Data.new(json, nil, Record)
21
+ end
22
+
23
+ let(:item) do
24
+ data[0]
25
+ end
26
+
27
+ let(:link) do
28
+ item.campaign
29
+ end
30
+
31
+ context 'load' do
32
+ it 'is loading data remotely when not present yet' do
33
+ expect(link.load!.id).to be_present
34
+ expect(link.id).to be_present
35
+ end
36
+
37
+ it 'can be reloaded' do
38
+ expect(link.load!.id).to be_present
39
+ stub_request(:get, 'http://local.ch/v2/content-ads/51dfc5690cf271c375c5a12d')
40
+ .to_return(status: 404)
41
+ expect(-> { link.reload!.id })
42
+ .to raise_error LHC::NotFound
43
+ end
44
+ end
45
+
46
+ context 'endpoint options' do
47
+ before do
48
+ class AnotherRecord < LHS::Record
49
+ endpoint '{+datastore}/v2/feedbacks', params: { color: :blue }
50
+ end
51
+ end
52
+
53
+ let(:record) do
54
+ AnotherRecord.new(href: 'http://datastore/v2/feedbacks')
55
+ end
56
+
57
+ it 'applies endpoint options on load!' do
58
+ stub_request(:get, 'http://datastore/v2/feedbacks?color=blue')
59
+ .to_return(body: {}.to_json)
60
+ record.load!
61
+ end
62
+ end
63
+
64
+ context 'per request options' do
65
+ let(:record) do
66
+ Record.new(href: 'http://datastore/v2/feedbacks')
67
+ end
68
+
69
+ it 'applies options passed to load' do
70
+ stub_request(:get, 'http://datastore/v2/feedbacks?color=blue')
71
+ .to_return(body: {}.to_json)
72
+ record.load!(params: { color: 'blue' })
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHS::Proxy do
6
+ before do
7
+ class Search < LHS::Record
8
+ endpoint 'http://search/results', items_key: :docs
9
+ end
10
+
11
+ class Feedback < LHS::Record
12
+ endpoint 'http://datastore/places/{place_id}/feedbacks'
13
+ end
14
+ end
15
+
16
+ context 'identifying records' do
17
+ it 'identifies records correctly even if parent record has another configuration set' do
18
+ stub_request(:get, "http://search/results?what=Blumen")
19
+ .to_return(body: {
20
+ place: { href: 'http://datastore/places/1' }
21
+ }.to_json)
22
+ stub_request(:get, "http://datastore/places/1")
23
+ .to_return(body: {
24
+ feedbacks: { href: 'http://datastore/places/1/feedbacks?limit=10&offset=0' }
25
+ }.to_json)
26
+ stub_request(:get, "http://datastore/places/1/feedbacks?limit=10&offset=0")
27
+ .to_return(body: {
28
+ items: [{ review: 'Nice restaurant' }]
29
+ }.to_json)
30
+ result = Search.where(what: 'Blumen').includes_first_page(place: :feedbacks)
31
+ expect(result.place.feedbacks).to be_kind_of Feedback
32
+ expect(result.place.feedbacks.first.review).to eq 'Nice restaurant'
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ ENV["RAILS_ENV"] ||= 'test'
4
+ ENV['DUMMYAPP_PATH'] = "spec/dummy"
5
+
6
+ require 'rails/rollbar_runner'
7
+ require 'spec_helper'
8
+ require File.expand_path("../dummy/config/environment", __FILE__)
9
+ require 'rspec/rails'
10
+
11
+ RSpec.configure do |config|
12
+ config.infer_spec_type_from_file_location!
13
+ end
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHS::Record do
6
+ context 'all' do
7
+ before do
8
+ class Record < LHS::Record
9
+ endpoint 'http://datastore/feedbacks'
10
+ end
11
+ end
12
+
13
+ it 'is querying endpoint without pagination when using all' do
14
+ stub_request(:get, "http://datastore/feedbacks?limit=100").to_return(body: { items: 300.times.map { { foo: 'bar' } }, total: 300 }.to_json)
15
+ records = Record.all
16
+ expect(records).to be_kind_of Record
17
+ expect(records.size).to eq(300)
18
+ end
19
+
20
+ context 'is chainable with where and works like where' do
21
+ let(:total) { 22 }
22
+ let(:limit) { 10 }
23
+ let!(:first_page_request) do
24
+ stub_request(:get, "http://datastore/feedbacks?color=blue&limit=100")
25
+ .to_return(body: { items: 10.times.map { { foo: 'bar' } }, total: total, limit: limit, offset: 0 }.to_json)
26
+ end
27
+ let!(:second_page_request) do
28
+ stub_request(:get, "http://datastore/feedbacks?color=blue&limit=#{limit}&offset=10")
29
+ .to_return(body: { items: 10.times.map { { foo: 'bar' } }, total: total, limit: limit, offset: 10 }.to_json)
30
+ end
31
+ let!(:third_page_request) do
32
+ stub_request(:get, "http://datastore/feedbacks?color=blue&limit=#{limit}&offset=20")
33
+ .to_return(body: { items: 2.times.map { { foo: 'bar' } }, total: total, limit: limit, offset: 20 }.to_json)
34
+ end
35
+
36
+ it 'fetches all remote objects' do
37
+ records = Record.where(color: 'blue').all
38
+ expect(records.length).to eq total
39
+ expect(first_page_request).to have_been_requested.times(1)
40
+ expect(second_page_request).to have_been_requested.times(1)
41
+ expect(third_page_request).to have_been_requested.times(1)
42
+ records = Record.all.where(color: 'blue')
43
+ expect(records.length).to eq total
44
+ expect(first_page_request).to have_been_requested.times(2)
45
+ expect(second_page_request).to have_been_requested.times(2)
46
+ expect(third_page_request).to have_been_requested.times(2)
47
+ records = Record.all(color: 'blue')
48
+ expect(records.length).to eq total
49
+ expect(first_page_request).to have_been_requested.times(3)
50
+ expect(second_page_request).to have_been_requested.times(3)
51
+ expect(third_page_request).to have_been_requested.times(3)
52
+ end
53
+
54
+ it 'works in combination with include and includes' do
55
+ records = Record.includes_first_page(:product).includes(:options).all(color: 'blue')
56
+ expect(records.length).to eq total
57
+ expect(first_page_request).to have_been_requested.times(1)
58
+ expect(second_page_request).to have_been_requested.times(1)
59
+ expect(third_page_request).to have_been_requested.times(1)
60
+ end
61
+ end
62
+ end
63
+
64
+ context 'all without current page indicator' do
65
+ before do
66
+ class Category < LHS::Record
67
+ configuration(
68
+ items_key: %i(response results),
69
+ limit_key: :max,
70
+ pagination_key: :offset,
71
+ pagination_strategy: :offset
72
+ )
73
+
74
+ endpoint 'http://store/categories'
75
+ end
76
+ end
77
+
78
+ def stub_batch(url, items = 10)
79
+ stub_request(:get, url)
80
+ .to_return(
81
+ body: {
82
+ response: {
83
+ results: items.times.map { { name: 'category' } }
84
+ }
85
+ }.to_json
86
+ )
87
+ end
88
+
89
+ it 'is able to fetch all remote objects without any current page indicator by simply increasing the offset until response is empty with a limit' do
90
+ stub_batch('http://store/categories?language=en&max=10&offset=0')
91
+ stub_batch('http://store/categories?language=en&max=10&offset=10')
92
+ stub_batch('http://store/categories?language=en&max=10&offset=20')
93
+ stub_batch('http://store/categories?language=en&max=10&offset=30', 0)
94
+ records = Category.limit(10).all(language: 'en').fetch
95
+ expect(records.length).to eq 30
96
+ end
97
+
98
+ it 'is able to fetch all remote objects without any current page indicator by simply increasing the offset until response is empty' do
99
+ stub_batch('http://store/categories?language=en&max=100', 100)
100
+ stub_batch('http://store/categories?language=en&max=100&offset=100', 100)
101
+ stub_batch('http://store/categories?language=en&max=100&offset=200', 100)
102
+ stub_batch('http://store/categories?language=en&max=100&offset=300', 0)
103
+ records = Category.all(language: 'en').fetch
104
+ expect(records.length).to eq 300
105
+ end
106
+
107
+ it 'outputs a warning, if all is requested, but endpoint does not implement pagination meta data' do
108
+ stub_batch('http://store/categories?language=en&max=100', 100)
109
+ stub_batch('http://store/categories?language=en&max=100&offset=100', 100)
110
+ stub_batch('http://store/categories?language=en&max=100&offset=200', 100)
111
+ stub_batch('http://store/categories?language=en&max=100&offset=300', 0)
112
+ expect(-> { Category.all(language: 'en').fetch }).to output(
113
+ %r{\[Warning\] "all" has been requested, but endpoint does not provide pagination meta data. If you just want to fetch the first response, use "where" or "fetch".}
114
+ ).to_stderr
115
+ end
116
+
117
+ context 'with record set to not paginated' do
118
+ before do
119
+ class Record < LHS::Record
120
+ configuration paginated: false
121
+ endpoint 'http://datastore/records'
122
+ end
123
+ end
124
+
125
+ it 'just fetches the first response' do
126
+ stub_request(:get, "http://datastore/records")
127
+ .to_return(body: [{ name: 'Steve' }].to_json)
128
+ records = Record.all
129
+ expect(records.first.name).to eq 'Steve'
130
+ end
131
+ end
132
+ end
133
+ end