praxis 2.0.pre.17 → 2.0.pre.21

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 (235) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +54 -0
  3. data/.simplecov +3 -1
  4. data/.travis.yml +2 -1
  5. data/CHANGELOG.md +19 -0
  6. data/CONTRIBUTING.md +2 -79
  7. data/Gemfile +5 -1
  8. data/Guardfile +6 -4
  9. data/LICENSE +0 -2
  10. data/MAINTAINERS.md +1 -0
  11. data/README.md +15 -22
  12. data/Rakefile +4 -2
  13. data/bin/praxis +55 -58
  14. data/lib/praxis/action_definition/headers_dsl_compiler.rb +5 -6
  15. data/lib/praxis/action_definition.rb +65 -95
  16. data/lib/praxis/api_definition.rb +21 -29
  17. data/lib/praxis/api_general_info.rb +55 -66
  18. data/lib/praxis/application.rb +15 -32
  19. data/lib/praxis/blueprint.rb +80 -73
  20. data/lib/praxis/bootloader.rb +24 -33
  21. data/lib/praxis/bootloader_stages/environment.rb +5 -10
  22. data/lib/praxis/bootloader_stages/file_loader.rb +3 -6
  23. data/lib/praxis/bootloader_stages/plugin_config_load.rb +4 -6
  24. data/lib/praxis/bootloader_stages/plugin_config_prepare.rb +2 -2
  25. data/lib/praxis/bootloader_stages/plugin_loader.rb +3 -7
  26. data/lib/praxis/bootloader_stages/plugin_setup.rb +3 -3
  27. data/lib/praxis/bootloader_stages/routing.rb +5 -8
  28. data/lib/praxis/bootloader_stages/subgroup_loader.rb +2 -10
  29. data/lib/praxis/bootloader_stages/warn_unloaded_files.rb +15 -19
  30. data/lib/praxis/callbacks.rb +12 -11
  31. data/lib/praxis/collection.rb +11 -14
  32. data/lib/praxis/config.rb +17 -28
  33. data/lib/praxis/config_hash.rb +2 -1
  34. data/lib/praxis/controller.rb +7 -6
  35. data/lib/praxis/dispatcher.rb +34 -42
  36. data/lib/praxis/docs/open_api/info_object.rb +11 -8
  37. data/lib/praxis/docs/open_api/media_type_object.rb +18 -17
  38. data/lib/praxis/docs/open_api/operation_object.rb +7 -4
  39. data/lib/praxis/docs/open_api/parameter_object.rb +17 -14
  40. data/lib/praxis/docs/open_api/paths_object.rb +11 -9
  41. data/lib/praxis/docs/open_api/request_body_object.rb +14 -13
  42. data/lib/praxis/docs/open_api/response_object.rb +24 -18
  43. data/lib/praxis/docs/open_api/responses_object.rb +3 -1
  44. data/lib/praxis/docs/open_api/schema_object.rb +61 -29
  45. data/lib/praxis/docs/open_api/server_object.rb +5 -2
  46. data/lib/praxis/docs/open_api/tag_object.rb +9 -6
  47. data/lib/praxis/docs/open_api_generator.rb +114 -150
  48. data/lib/praxis/endpoint_definition.rb +60 -77
  49. data/lib/praxis/error_handler.rb +2 -2
  50. data/lib/praxis/exception.rb +2 -0
  51. data/lib/praxis/exceptions/config.rb +3 -1
  52. data/lib/praxis/exceptions/config_load.rb +2 -0
  53. data/lib/praxis/exceptions/config_validation.rb +3 -1
  54. data/lib/praxis/exceptions/invalid_configuration.rb +3 -1
  55. data/lib/praxis/exceptions/invalid_response.rb +3 -1
  56. data/lib/praxis/exceptions/invalid_trait.rb +3 -1
  57. data/lib/praxis/exceptions/stage_not_found.rb +3 -1
  58. data/lib/praxis/exceptions/validation.rb +4 -3
  59. data/lib/praxis/extensions/attribute_filtering/active_record_filter_query_builder.rb +163 -149
  60. data/lib/praxis/extensions/attribute_filtering/active_record_patches/5x.rb +18 -13
  61. data/lib/praxis/extensions/attribute_filtering/active_record_patches/6_0.rb +13 -9
  62. data/lib/praxis/extensions/attribute_filtering/active_record_patches/6_1_plus.rb +14 -11
  63. data/lib/praxis/extensions/attribute_filtering/active_record_patches.rb +12 -9
  64. data/lib/praxis/extensions/attribute_filtering/filter_tree_node.rb +8 -5
  65. data/lib/praxis/extensions/attribute_filtering/filtering_params.rb +89 -65
  66. data/lib/praxis/extensions/attribute_filtering/filters_parser.rb +68 -62
  67. data/lib/praxis/extensions/attribute_filtering.rb +3 -1
  68. data/lib/praxis/extensions/field_expansion.rb +6 -4
  69. data/lib/praxis/extensions/field_selection/active_record_query_selector.rb +10 -8
  70. data/lib/praxis/extensions/field_selection/field_selector.rb +91 -92
  71. data/lib/praxis/extensions/field_selection/sequel_query_selector.rb +12 -12
  72. data/lib/praxis/extensions/field_selection.rb +3 -1
  73. data/lib/praxis/extensions/pagination/active_record_pagination_handler.rb +6 -4
  74. data/lib/praxis/extensions/pagination/header_generator.rb +16 -11
  75. data/lib/praxis/extensions/pagination/ordering_params.rb +29 -28
  76. data/lib/praxis/extensions/pagination/pagination_handler.rb +44 -42
  77. data/lib/praxis/extensions/pagination/pagination_params.rb +29 -48
  78. data/lib/praxis/extensions/pagination/sequel_pagination_handler.rb +8 -7
  79. data/lib/praxis/extensions/pagination.rb +10 -15
  80. data/lib/praxis/extensions/rails_compat/request_methods.rb +3 -4
  81. data/lib/praxis/extensions/rails_compat.rb +2 -0
  82. data/lib/praxis/extensions/rendering.rb +12 -12
  83. data/lib/praxis/field_expander.rb +8 -9
  84. data/lib/praxis/file_group.rb +8 -12
  85. data/lib/praxis/finalizable.rb +1 -0
  86. data/lib/praxis/handlers/json.rb +5 -2
  87. data/lib/praxis/handlers/plain.rb +2 -1
  88. data/lib/praxis/handlers/www_form.rb +6 -3
  89. data/lib/praxis/handlers/{xml-sample.rb → xml_sample.rb} +26 -22
  90. data/lib/praxis/mapper/active_model_compat.rb +13 -10
  91. data/lib/praxis/mapper/resource.rb +196 -181
  92. data/lib/praxis/mapper/selector_generator.rb +106 -112
  93. data/lib/praxis/mapper/sequel_compat.rb +70 -67
  94. data/lib/praxis/media_type.rb +2 -2
  95. data/lib/praxis/media_type_identifier.rb +26 -22
  96. data/lib/praxis/middleware_app.rb +18 -15
  97. data/lib/praxis/multipart/parser.rb +46 -51
  98. data/lib/praxis/multipart/part.rb +78 -110
  99. data/lib/praxis/notifications.rb +2 -4
  100. data/lib/praxis/plugin.rb +11 -18
  101. data/lib/praxis/plugin_concern.rb +12 -15
  102. data/lib/praxis/plugins/mapper_plugin.rb +15 -13
  103. data/lib/praxis/plugins/pagination_plugin.rb +8 -6
  104. data/lib/praxis/plugins/rails_plugin.rb +33 -28
  105. data/lib/praxis/renderer.rb +11 -15
  106. data/lib/praxis/request.rb +48 -44
  107. data/lib/praxis/request_stages/action.rb +4 -6
  108. data/lib/praxis/request_stages/load_request.rb +2 -4
  109. data/lib/praxis/request_stages/request_stage.rb +19 -23
  110. data/lib/praxis/request_stages/response.rb +4 -6
  111. data/lib/praxis/request_stages/validate.rb +3 -5
  112. data/lib/praxis/request_stages/validate_params_and_headers.rb +15 -22
  113. data/lib/praxis/request_stages/validate_payload.rb +25 -28
  114. data/lib/praxis/request_superclassing.rb +3 -3
  115. data/lib/praxis/resource_definition.rb +1 -0
  116. data/lib/praxis/response.rb +24 -26
  117. data/lib/praxis/response_definition.rb +77 -122
  118. data/lib/praxis/response_template.rb +11 -15
  119. data/lib/praxis/responses/http.rb +23 -44
  120. data/lib/praxis/responses/internal_server_error.rb +18 -21
  121. data/lib/praxis/responses/multipart_ok.rb +4 -9
  122. data/lib/praxis/responses/validation_error.rb +8 -15
  123. data/lib/praxis/route.rb +8 -10
  124. data/lib/praxis/router/rack.rb +13 -7
  125. data/lib/praxis/router/simple.rb +10 -5
  126. data/lib/praxis/router.rb +27 -34
  127. data/lib/praxis/routing_config.rb +52 -29
  128. data/lib/praxis/simple_media_type.rb +5 -8
  129. data/lib/praxis/stage.rb +17 -25
  130. data/lib/praxis/tasks/api_docs.rb +17 -16
  131. data/lib/praxis/tasks/console.rb +3 -1
  132. data/lib/praxis/tasks/environment.rb +2 -0
  133. data/lib/praxis/tasks/routes.rb +26 -24
  134. data/lib/praxis/tasks.rb +3 -1
  135. data/lib/praxis/trait.rb +37 -46
  136. data/lib/praxis/types/fuzzy_hash.rb +13 -14
  137. data/lib/praxis/types/media_type_common.rb +11 -10
  138. data/lib/praxis/types/multipart_array/part_definition.rb +14 -17
  139. data/lib/praxis/types/multipart_array.rb +100 -115
  140. data/lib/praxis/validation_handler.rb +5 -3
  141. data/lib/praxis/version.rb +3 -1
  142. data/lib/praxis.rb +4 -5
  143. data/praxis.gemspec +22 -21
  144. data/spec/functional_spec.rb +44 -56
  145. data/spec/praxis/action_definition_spec.rb +39 -48
  146. data/spec/praxis/api_definition_spec.rb +45 -47
  147. data/spec/praxis/api_general_info_spec.rb +28 -29
  148. data/spec/praxis/application_spec.rb +18 -14
  149. data/spec/praxis/blueprint_spec.rb +33 -34
  150. data/spec/praxis/bootloader_spec.rb +32 -30
  151. data/spec/praxis/callbacks_spec.rb +37 -37
  152. data/spec/praxis/collection_spec.rb +18 -25
  153. data/spec/praxis/config_hash_spec.rb +5 -4
  154. data/spec/praxis/config_spec.rb +27 -26
  155. data/spec/praxis/controller_spec.rb +8 -9
  156. data/spec/praxis/endpoint_definition_spec.rb +25 -32
  157. data/spec/praxis/extensions/attribute_filtering/active_record_filter_query_builder_spec.rb +171 -114
  158. data/spec/praxis/extensions/attribute_filtering/filter_tree_node_spec.rb +22 -21
  159. data/spec/praxis/extensions/attribute_filtering/filtering_params_spec.rb +112 -60
  160. data/spec/praxis/extensions/attribute_filtering/filters_parser_spec.rb +37 -38
  161. data/spec/praxis/extensions/field_expansion_spec.rb +8 -10
  162. data/spec/praxis/extensions/field_selection/active_record_query_selector_spec.rb +14 -13
  163. data/spec/praxis/extensions/field_selection/field_selector_spec.rb +9 -16
  164. data/spec/praxis/extensions/field_selection/sequel_query_selector_spec.rb +50 -49
  165. data/spec/praxis/extensions/pagination/active_record_pagination_handler_spec.rb +32 -31
  166. data/spec/praxis/extensions/rendering_spec.rb +9 -9
  167. data/spec/praxis/extensions/support/spec_resources_active_model.rb +32 -49
  168. data/spec/praxis/extensions/support/spec_resources_sequel.rb +48 -48
  169. data/spec/praxis/field_expander_spec.rb +6 -5
  170. data/spec/praxis/file_group_spec.rb +3 -1
  171. data/spec/praxis/handlers/json_spec.rb +6 -5
  172. data/spec/praxis/mapper/resource_spec.rb +39 -29
  173. data/spec/praxis/mapper/selector_generator_spec.rb +80 -46
  174. data/spec/praxis/media_type_identifier_spec.rb +13 -10
  175. data/spec/praxis/media_type_spec.rb +12 -12
  176. data/spec/praxis/middleware_app_spec.rb +23 -22
  177. data/spec/praxis/multipart/parser_spec.rb +7 -9
  178. data/spec/praxis/notifications_spec.rb +4 -4
  179. data/spec/praxis/plugin_concern_spec.rb +5 -6
  180. data/spec/praxis/renderer_spec.rb +10 -9
  181. data/spec/praxis/request_spec.rb +38 -41
  182. data/spec/praxis/request_stages/action_spec.rb +14 -15
  183. data/spec/praxis/request_stages/request_stage_spec.rb +30 -41
  184. data/spec/praxis/request_stages/validate_spec.rb +3 -1
  185. data/spec/praxis/response_definition_spec.rb +79 -92
  186. data/spec/praxis/response_spec.rb +35 -40
  187. data/spec/praxis/responses/internal_server_error_spec.rb +6 -9
  188. data/spec/praxis/responses/validation_error_spec.rb +17 -18
  189. data/spec/praxis/route_spec.rb +4 -7
  190. data/spec/praxis/router_spec.rb +69 -79
  191. data/spec/praxis/routing_config_spec.rb +15 -14
  192. data/spec/praxis/stage_spec.rb +56 -53
  193. data/spec/praxis/trait_spec.rb +17 -17
  194. data/spec/praxis/types/fuzzy_hash_spec.rb +11 -9
  195. data/spec/praxis/types/multipart_array/part_definition_spec.rb +3 -2
  196. data/spec/praxis/types/multipart_array_spec.rb +33 -48
  197. data/spec/spec_app/app/concerns/authenticated.rb +5 -5
  198. data/spec/spec_app/app/concerns/basic_api.rb +3 -1
  199. data/spec/spec_app/app/concerns/log_wrapper.rb +5 -3
  200. data/spec/spec_app/app/controllers/base_class.rb +6 -5
  201. data/spec/spec_app/app/controllers/instances.rb +31 -34
  202. data/spec/spec_app/app/controllers/volumes.rb +6 -6
  203. data/spec/spec_app/app/responses/multipart.rb +1 -2
  204. data/spec/spec_app/app/responses/other_response.rb +2 -2
  205. data/spec/spec_app/config/environment.rb +19 -6
  206. data/spec/spec_app/config.ru +4 -3
  207. data/spec/spec_app/design/api.rb +13 -15
  208. data/spec/spec_app/design/media_types/instance.rb +6 -6
  209. data/spec/spec_app/design/media_types/volume.rb +2 -1
  210. data/spec/spec_app/design/media_types/volume_snapshot.rb +2 -1
  211. data/spec/spec_app/design/resources/instances.rb +11 -17
  212. data/spec/spec_app/design/resources/volume_snapshots.rb +4 -5
  213. data/spec/spec_app/design/resources/volumes.rb +4 -5
  214. data/spec/spec_helper.rb +11 -13
  215. data/spec/support/be_deep_equal_matcher.rb +5 -0
  216. data/spec/support/spec_authorization_plugin.rb +7 -12
  217. data/spec/support/spec_blueprints.rb +5 -4
  218. data/spec/support/spec_complex_authentication_plugin.rb +17 -34
  219. data/spec/support/spec_endpoint_definitions.rb +2 -3
  220. data/spec/support/spec_media_types.rb +28 -35
  221. data/spec/support/spec_resources.rb +22 -16
  222. data/spec/support/spec_simple_authentication_plugin.rb +5 -9
  223. data/tasks/loader.thor +4 -2
  224. data/tasks/thor/app.rb +7 -5
  225. data/tasks/thor/example.rb +23 -22
  226. data/tasks/thor/model.rb +7 -7
  227. data/tasks/thor/scaffold.rb +23 -23
  228. data/tasks/thor/templates/generator/example_app/app/v1/resources/user.rb +0 -8
  229. data/tasks/thor/templates/generator/scaffold/implementation/resources/item.rb +1 -2
  230. metadata +72 -84
  231. data/MAINTAINERS +0 -2
  232. data/TODO.md +0 -25
  233. data/spec/praxis/api_resource_spec.rb +0 -0
  234. data/spec/praxis/dispatcher_spec.rb +0 -0
  235. data/spec/spec_app/app/responses/bulk_response.rb +0 -0
@@ -1,12 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  require 'praxis/extensions/field_selection'
4
6
 
5
7
  describe Praxis::Extensions::FieldSelection::FieldSelector do
6
-
7
8
  let(:type) { described_class.for(Address) }
8
9
 
9
-
10
10
  subject(:field_selector) { type.load(fields) }
11
11
 
12
12
  context '.example' do
@@ -21,7 +21,6 @@ describe Praxis::Extensions::FieldSelection::FieldSelector do
21
21
  it 'validates' do
22
22
  expect(type.example.validate).to be_empty
23
23
  end
24
-
25
24
  end
26
25
 
27
26
  context '.load' do
@@ -32,22 +31,20 @@ describe Praxis::Extensions::FieldSelection::FieldSelector do
32
31
  expect(type.load('').fields).to be(true)
33
32
  end
34
33
 
35
-
36
34
  it 'loads fields' do
37
35
  fields = 'id,name,owner{name}'
38
36
 
39
- expect(Attributor::FieldSelector).to receive(:load).
40
- with(fields).and_return(parsed_fields)
37
+ expect(Attributor::FieldSelector).to receive(:load)
38
+ .with(fields).and_return(parsed_fields)
41
39
 
42
40
  result = type.load(fields)
43
41
  expect(result.fields).to be parsed_fields
44
42
  end
45
-
46
43
  end
47
44
 
48
45
  context '#dump' do
49
46
  it 'is dumpable' do
50
- expect( type.load('id') ).to be_kind_of( Attributor::Dumpable )
47
+ expect(type.load('id')).to be_kind_of(Attributor::Dumpable)
51
48
  end
52
49
 
53
50
  it 'dumps nested fields properly' do
@@ -72,14 +69,13 @@ describe Praxis::Extensions::FieldSelection::FieldSelector do
72
69
  context 'validating subattributes' do
73
70
  let(:selector_string) { 'id,resident,owner{age}' }
74
71
  it 'validates subattributes' do
75
- errors = type.validate(selector_string)
72
+ errors = type.validate(selector_string)
76
73
  expect(errors).to match_array([
77
- "Attribute with name resident not found in Address",
78
- "Attribute with name age not found in Person"
79
- ])
74
+ 'Attribute with name resident not found in Address',
75
+ 'Attribute with name age not found in Person'
76
+ ])
80
77
  end
81
78
  end
82
-
83
79
  end
84
80
 
85
81
  context '#validate' do
@@ -90,7 +86,4 @@ describe Praxis::Extensions::FieldSelection::FieldSelector do
90
86
  expect(type.validate('id,owner{foo}')).to have(1).items
91
87
  end
92
88
  end
93
-
94
-
95
-
96
89
  end
@@ -1,46 +1,49 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
  require 'sequel'
3
5
 
4
6
  require 'praxis/extensions/field_selection/sequel_query_selector'
5
7
 
8
+ class QTest
9
+ attr_reader :object, :cols
6
10
 
7
- describe Praxis::Extensions::FieldSelection::SequelQuerySelector do
8
- class Q
9
- attr_reader :object, :cols
10
- def initialize
11
- @object = {}
12
- @cols = []
13
- end
14
- def eager(hash)
15
- raise "we are only calling eager one at a time!" if hash.keys.size > 1
16
- name = hash.keys.first
17
- # Actually call the incoming proc with an instance of Q, to collect the further select/eager calls
18
- @object[name] = hash[name].call(Q.new)
19
- self
20
- end
21
- def select(*names)
22
- @cols += names.map(&:column)
23
- self
24
- end
25
- def dump
26
- eagers = @object.each_with_object({}) do |(name, val), hash|
27
- hash[name] = val.dump
28
- end
29
- {
30
- columns: @cols,
31
- eagers: eagers
32
- }
33
- end
11
+ def initialize
12
+ @object = {}
13
+ @cols = []
14
+ end
15
+
16
+ def eager(hash)
17
+ raise 'we are only calling eager one at a time!' if hash.keys.size > 1
18
+
19
+ name = hash.keys.first
20
+ # Actually call the incoming proc with an instance of QTest, to collect the further select/eager calls
21
+ @object[name] = hash[name].call(QTest.new)
22
+ self
23
+ end
24
+
25
+ def select(*names)
26
+ @cols += names.map(&:column)
27
+ self
34
28
  end
35
29
 
30
+ def dump
31
+ eagers = @object.transform_values(&:dump)
32
+ {
33
+ columns: @cols,
34
+ eagers: eagers
35
+ }
36
+ end
37
+ end
36
38
 
39
+ describe Praxis::Extensions::FieldSelection::SequelQuerySelector do
37
40
  # Pay the price for creating and connecting only in this spec instead in spec helper
38
41
  # this way all other specs do not need to be slower and it's a better TDD experience
39
42
 
40
- require_relative '../support/spec_resources_sequel.rb'
41
-
43
+ require_relative '../support/spec_resources_sequel'
44
+
42
45
  let(:selector_fields) do
43
- {
46
+ {
44
47
  name: true,
45
48
  other_model: {
46
49
  id: true
@@ -64,15 +67,15 @@ describe Praxis::Extensions::FieldSelection::SequelQuerySelector do
64
67
  ]
65
68
  end
66
69
 
67
- let(:selector_node) { Praxis::Mapper::SelectorGenerator.new.add(SequelSimpleResource,selector_fields).selectors }
68
- subject {described_class.new(query: query, selectors: selector_node, debug: debug) }
70
+ let(:selector_node) { Praxis::Mapper::SelectorGenerator.new.add(SequelSimpleResource, selector_fields).selectors }
71
+ subject { described_class.new(query: query, selectors: selector_node, debug: debug) }
69
72
 
70
73
  context 'generate' do
71
74
  let(:debug) { false }
72
75
  context 'using the real models and DB' do
73
76
  let(:query) { SequelSimpleModel }
74
77
 
75
- it 'calls the select columns for the top level, and includes the right association hashes' do
78
+ it 'calls the select columns for the top level, and includes the right association hashes' do
76
79
  ds = subject.generate
77
80
  opts = ds.opts
78
81
  # Top model is our simplemodel
@@ -80,26 +83,26 @@ describe Praxis::Extensions::FieldSelection::SequelQuerySelector do
80
83
  selected_column_names = opts[:select].map(&:column)
81
84
  expect(selected_column_names).to match_array(expected_select_from_to_query)
82
85
  # 2 Eager loaded associations as well
83
- expect(opts[:eager].keys).to match_array([:other_model, :parent, :tags])
86
+ expect(opts[:eager].keys).to match_array(%i[other_model parent tags])
84
87
  # We can not introspect those eagers, as they are procs...but at least validate they are
85
88
  expect(opts[:eager][:other_model]).to be_a Proc
86
89
  expect(opts[:eager][:parent]).to be_a Proc
87
-
90
+
88
91
  # Also, let's make sure the query actually works by making Sequel attempt to retrieve it and finding the right things.
89
92
  result = ds.all
90
93
  # 2 simple models
91
- expect(result.size).to be 2
94
+ expect(result.size).to be 2
92
95
  # First simple model points to other_model 11 and parent 1
93
- simple_one = result.find{|i| i.id == 1}
96
+ simple_one = result.find { |i| i.id == 1 }
94
97
  expect(simple_one.other_model.id).to be 11
95
98
  expect(simple_one.parent.id).to be 1
96
99
  # also, its' parent in turn has 2 children (1 and 2) linked by its parent_uuid
97
- expect(simple_one.parent.children.map(&:id)).to match_array([1,2])
100
+ expect(simple_one.parent.children.map(&:id)).to match_array([1, 2])
98
101
  # Has the blue and red tags
99
- expect(simple_one.tags.map(&:tag_name)).to match_array(['blue','red'])
102
+ expect(simple_one.tags.map(&:tag_name)).to match_array(%w[blue red])
100
103
 
101
104
  # second simple model points to other_model 22 and parent 2
102
- simple_two = result.find{|i| i.id == 2}
105
+ simple_two = result.find { |i| i.id == 2 }
103
106
  expect(simple_two.other_model.id).to be 22
104
107
  expect(simple_two.parent.id).to be 2
105
108
  # also, its' parent in turn has no children (as no simple models point to it by uuid)
@@ -112,36 +115,34 @@ describe Praxis::Extensions::FieldSelection::SequelQuerySelector do
112
115
  # Actually make it run all the way...but suppressing the output
113
116
  subject.generate
114
117
  end
115
- end
118
+ end
116
119
  end
117
120
  context 'just mocking the query' do
118
- let(:query) { Q.new }
121
+ let(:query) { QTest.new }
119
122
 
120
- it 'creates the right recursive lambdas for the eager loading' do
121
-
123
+ it 'creates the right recursive lambdas for the eager loading' do
122
124
  ds = subject.generate
123
125
  result = ds.dump
124
126
  expect(result[:columns]).to match_array(expected_select_from_to_query)
125
127
  # 2 eager loads
126
- expect(result[:eagers].keys).to match_array([:other_model, :parent, :tags])
128
+ expect(result[:eagers].keys).to match_array(%i[other_model parent tags])
127
129
  # 1 - other model
128
130
  other_model_eagers = result[:eagers][:other_model]
129
131
  expect(other_model_eagers[:columns]).to match_array([:id])
130
132
 
131
133
  # 2 - parent association
132
134
  parent_eagers = result[:eagers][:parent]
133
- expect(parent_eagers[:columns]).to match_array([:id,:uuid]) # uuid is necessary for the "children" assoc
135
+ expect(parent_eagers[:columns]).to match_array(%i[id uuid]) # uuid is necessary for the "children" assoc
134
136
  expect(parent_eagers[:eagers].keys).to match_array([:children])
135
137
  # 2.1 - children association off of the parent
136
138
  parent_children_eagers = parent_eagers[:eagers][:children]
137
- expect(parent_children_eagers[:columns]).to match_array([:id,:parent_uuid]) # parent_uuid is required for the assoc
139
+ expect(parent_children_eagers[:columns]).to match_array(%i[id parent_uuid]) # parent_uuid is required for the assoc
138
140
  expect(parent_children_eagers[:eagers]).to be_empty
139
141
 
140
142
  # 3 - tags association
141
143
  tags_eagers = result[:eagers][:tags]
142
- expect(tags_eagers[:columns]).to match_array([:id, :tag_name]) # uuid is necessary for the "children" assoc
144
+ expect(tags_eagers[:columns]).to match_array(%i[id tag_name]) # uuid is necessary for the "children" assoc
143
145
  expect(tags_eagers[:eagers].keys).to be_empty
144
-
145
146
  end
146
147
  end
147
148
  end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
- require_relative '../support/spec_resources_active_model.rb'
5
+ require_relative '../support/spec_resources_active_model'
4
6
  require 'praxis/extensions/pagination'
5
7
 
6
8
  class Book < Praxis::MediaType
@@ -15,7 +17,7 @@ BookPaginationParamsAttribute = Attributor::Attribute.new(Praxis::Types::Paginat
15
17
  max_items 3
16
18
  page_size 2
17
19
  # disallow :paging
18
- default by: :id
20
+ default by: :id
19
21
  end
20
22
 
21
23
  BookOrderingParamsAttribute = Attributor::Attribute.new(Praxis::Types::OrderingParams.for(Book)) do
@@ -49,10 +51,9 @@ describe Praxis::Extensions::Pagination::ActiveRecordPaginationHandler do
49
51
  Praxis::Extensions::Pagination::PaginationStruct.new(paginator_params, order_params)
50
52
  end
51
53
 
52
-
53
54
  context '.paginate' do
54
- subject {described_class.paginate(query, pagination) }
55
-
55
+ subject { described_class.paginate(query, pagination) }
56
+
56
57
  context 'empty struct' do
57
58
  let(:paginator_params) { nil }
58
59
 
@@ -63,68 +64,68 @@ describe Praxis::Extensions::Pagination::ActiveRecordPaginationHandler do
63
64
 
64
65
  context 'page-based' do
65
66
  it_behaves_like 'paginates_the_same', 'page=1,items=3',
66
- ::ActiveBook.limit(3)
67
+ ::ActiveBook.limit(3)
67
68
  it_behaves_like 'paginates_the_same', 'page=2,items=3',
68
- ::ActiveBook.offset(3).limit(3)
69
+ ::ActiveBook.offset(3).limit(3)
69
70
  end
70
71
 
71
72
  context 'page-based with defaults' do
72
73
  it_behaves_like 'paginates_the_same', '',
73
- ::ActiveBook.offset(0).limit(2)
74
+ ::ActiveBook.offset(0).limit(2)
74
75
  it_behaves_like 'paginates_the_same', 'page=2',
75
- ::ActiveBook.offset(2).limit(2)
76
+ ::ActiveBook.offset(2).limit(2)
76
77
  end
77
78
 
78
79
  context 'cursor-based' do
79
80
  it_behaves_like 'paginates_the_same', 'by=id,items=3',
80
- ::ActiveBook.limit(3).order(id: :asc)
81
+ ::ActiveBook.limit(3).order(id: :asc)
81
82
  it_behaves_like 'paginates_the_same', 'by=id,from=1000,items=3',
82
- ::ActiveBook.where("id > 1000").limit(3).order(id: :asc)
83
+ ::ActiveBook.where('id > 1000').limit(3).order(id: :asc)
83
84
  it_behaves_like 'paginates_the_same', 'by=simple_name,from=Book1000,items=3',
84
- ::ActiveBook.where("simple_name > 'Book1000'").limit(3).order(simple_name: :asc)
85
+ ::ActiveBook.where("simple_name > 'Book1000'").limit(3).order(simple_name: :asc)
85
86
  end
86
87
 
87
88
  context 'cursor-based with defaults' do
88
89
  it_behaves_like 'paginates_the_same', '',
89
- ::ActiveBook.limit(2).order(id: :asc)
90
+ ::ActiveBook.limit(2).order(id: :asc)
90
91
  it_behaves_like 'paginates_the_same', 'by=id,from=1000',
91
- ::ActiveBook.where("id > 1000").limit(2).order(id: :asc)
92
+ ::ActiveBook.where('id > 1000').limit(2).order(id: :asc)
92
93
  end
93
94
 
94
95
  context 'including order' do
95
96
  let(:order_params) { BookOrderingParamsAttribute.load(op_string) }
96
97
 
97
98
  context 'when compatible with cursor' do
98
- let(:op_string){ 'id'}
99
+ let(:op_string) { 'id' }
99
100
  # Compatible cursor field
100
101
  it_behaves_like 'paginates_the_same', 'by=id,items=3',
101
- ::ActiveBook.limit(3).order(id: :asc)
102
+ ::ActiveBook.limit(3).order(id: :asc)
102
103
  end
103
-
104
+
104
105
  context 'when incompatible with cursor' do
105
- let(:op_string){ 'id'}
106
+ let(:op_string) { 'id' }
106
107
  let(:paginator_params) { BookPaginationParamsAttribute.load('by=simple_name,items=3') }
107
- it do
108
- expect{subject.all}.to raise_error(described_class::PaginationException, /is incompatible with pagination/)
108
+ it do
109
+ expect { subject.all }.to raise_error(described_class::PaginationException, /is incompatible with pagination/)
109
110
  end
110
111
  end
111
112
  end
112
113
  end
113
114
 
114
- context '.order' do
115
- subject {described_class.order(query, pagination.order) }
116
-
115
+ context '.order' do
116
+ subject { described_class.order(query, pagination.order) }
117
+
117
118
  it 'does not change the query with an empty struct' do
118
119
  expect(subject).to be(query)
119
120
  end
120
121
 
121
- it_behaves_like 'sorts_the_same', 'simple_name',
122
- ::ActiveBook.order(simple_name: :asc)
123
- it_behaves_like 'sorts_the_same', '-simple_name',
124
- ::ActiveBook.order(simple_name: :desc)
125
- it_behaves_like 'sorts_the_same', '-simple_name,id',
126
- ::ActiveBook.order(simple_name: :desc, id: :asc)
127
- it_behaves_like 'sorts_the_same', '-simple_name,-id',
128
- ::ActiveBook.order(simple_name: :desc, id: :desc)
122
+ it_behaves_like 'sorts_the_same', 'simple_name',
123
+ ::ActiveBook.order(simple_name: :asc)
124
+ it_behaves_like 'sorts_the_same', '-simple_name',
125
+ ::ActiveBook.order(simple_name: :desc)
126
+ it_behaves_like 'sorts_the_same', '-simple_name,id',
127
+ ::ActiveBook.order(simple_name: :desc, id: :asc)
128
+ it_behaves_like 'sorts_the_same', '-simple_name,-id',
129
+ ::ActiveBook.order(simple_name: :desc, id: :desc)
129
130
  end
130
131
  end
@@ -1,19 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Praxis::Extensions::Rendering do
4
-
5
6
  let(:test_class) do
6
- Struct.new(:media_type, :expanded_fields, :response, :request) do |klass|
7
+ Struct.new(:media_type, :expanded_fields, :response, :request) do |_klass|
7
8
  include Praxis::Extensions::Rendering
8
9
  end
9
10
  end
10
11
 
11
12
  let(:media_type) { Person }
12
- let(:expanded_fields) { {id: true, name: true} }
13
+ let(:expanded_fields) { { id: true, name: true } }
13
14
  let(:response) { double('response', headers: {}) }
14
15
  let(:request) { double('request') }
15
16
 
16
- let(:object) { {id: '1', name: 'bob', href: '/people/bob'} }
17
+ let(:object) { { id: '1', name: 'bob', href: '/people/bob' } }
17
18
  subject(:instance) { test_class.new(media_type, expanded_fields, response, request) }
18
19
 
19
20
  context '#render' do
@@ -26,7 +27,7 @@ describe Praxis::Extensions::Rendering do
26
27
  context '#display' do
27
28
  context 'without exception' do
28
29
  before do
29
- expect(response).to receive(:body=).with({id: 1, name: 'bob'})
30
+ expect(response).to receive(:body=).with({ id: 1, name: 'bob' })
30
31
  end
31
32
 
32
33
  subject!(:output) { instance.display(object) }
@@ -43,15 +44,15 @@ describe Praxis::Extensions::Rendering do
43
44
  context 'with a rendering exception' do
44
45
  let(:handler_params) do
45
46
  {
46
- summary: "Circular Rendering Error when rendering response. " +
47
- "Please especify a view to narrow the dependent fields, or narrow your field set.",
47
+ summary: 'Circular Rendering Error when rendering response. ' \
48
+ 'Please especify a view to narrow the dependent fields, or narrow your field set.',
48
49
  exception: circular_exception,
49
50
  request: request,
50
51
  stage: :action,
51
52
  errors: nil
52
53
  }
53
54
  end
54
- let(:circular_exception){ Praxis::Renderer::CircularRenderingError.new(object, "ctx") }
55
+ let(:circular_exception) { Praxis::Renderer::CircularRenderingError.new(object, 'ctx') }
55
56
  it 'catches a circular rendering exception' do
56
57
  expect(instance).to receive(:render).and_raise(circular_exception)
57
58
  expect(Praxis::Application.instance.validation_handler).to receive(:handle!).with(handler_params)
@@ -59,5 +60,4 @@ describe Praxis::Extensions::Rendering do
59
60
  end
60
61
  end
61
62
  end
62
-
63
63
  end
@@ -1,16 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_record'
2
4
 
3
5
  require 'praxis/mapper/active_model_compat'
4
6
 
5
7
  # Creates a new in-memory DB, and the necessary tables (and mini-seeds) for the models in this file
6
8
  def create_tables
7
-
8
9
  ActiveRecord::Base.establish_connection(
9
- adapter: 'sqlite3',
10
- dbfile: ':memory:',
11
- database: ':memory:'
10
+ adapter: 'sqlite3',
11
+ dbfile: ':memory:',
12
+ database: ':memory:'
12
13
  )
13
-
14
+
14
15
  ActiveRecord::Schema.define do
15
16
  ActiveRecord::Migration.suppress_messages do
16
17
  create_table :active_books do |table|
@@ -19,20 +20,20 @@ def create_tables
19
20
  table.column :category_uuid, :string
20
21
  table.column :author_id, :integer
21
22
  end
22
-
23
+
23
24
  create_table :active_authors do |table|
24
25
  table.column :name, :string
25
26
  end
26
-
27
+
27
28
  create_table :active_categories do |table|
28
29
  table.column :uuid, :string
29
30
  table.column :name, :string
30
31
  end
31
-
32
+
32
33
  create_table :active_tags do |table|
33
34
  table.column :name, :string
34
35
  end
35
-
36
+
36
37
  create_table :active_taggings do |table|
37
38
  table.column :book_id, :integer
38
39
  table.column :tag_id, :integer
@@ -51,7 +52,7 @@ class ActiveBook < ActiveRecord::Base
51
52
  belongs_to :author, class_name: 'ActiveAuthor'
52
53
 
53
54
  has_many :taggings, class_name: 'ActiveTagging', foreign_key: :book_id
54
- has_many :primary_taggings, lambda { where(label: 'primary')}, class_name: 'ActiveTagging', foreign_key: :book_id
55
+ has_many :primary_taggings, -> { where(label: 'primary') }, class_name: 'ActiveTagging', foreign_key: :book_id
55
56
 
56
57
  has_many :tags, class_name: 'ActiveTag', through: :taggings
57
58
  has_many :primary_tags, class_name: 'ActiveTag', through: :primary_taggings, source: :tag
@@ -79,7 +80,6 @@ class ActiveTagging < ActiveRecord::Base
79
80
  belongs_to :tag, class_name: 'ActiveTag', foreign_key: :tag_id
80
81
  end
81
82
 
82
-
83
83
  # A set of resource classes for use in specs
84
84
  class ActiveBaseResource < Praxis::Mapper::Resource
85
85
  end
@@ -102,63 +102,47 @@ class ActiveBookResource < ActiveBaseResource
102
102
  model ActiveBook
103
103
 
104
104
  filters_mapping(
105
- id: :id,
106
- # category_uuid: :category_uuid #NOTE: we do not need to define same-name-mappings if they exist
107
105
  'fake_nested.name': 'simple_name',
108
106
  'name': 'simple_name',
109
107
  'name_is_not': lambda do |spec| # Silly way to use a proc, but good enough for testing
110
- { name: :simple_name, value: spec[:value] , op: '!=' } # Can be an array for multiple conditions as well
111
- end,
112
- 'author.id': 'author.id',
113
- 'author.name': 'author.name',
114
- 'taggings.label': 'taggings.label',
115
- 'taggings.tag_id': 'taggings.tag_id',
116
- 'taggings.tag.taggings.tag_id': 'taggings.tag.taggings.tag_id',
117
- 'tags.name': 'tags.name',
118
- 'primary_tags.name': 'primary_tags.name',
119
- 'category.name': 'category.name',
120
- 'category.books.name': 'category.books.simple_name',
121
- 'category.books.taggings.tag_id': 'category.books.taggings.tag_id',
122
- 'category.books.taggings.label': 'category.books.taggings.label',
123
- 'primary_tags': 'primary_tags',
124
- 'category.books.taggings': 'category.books.taggings',
108
+ { name: :simple_name, value: spec[:value], op: '!=' } # Can be an array for multiple conditions as well
109
+ end,
110
+ 'category.books.name': 'category.books.simple_name'
125
111
  )
126
112
  # Forces to add an extra column (added_column)...and yet another (author_id) that will serve
127
113
  # to check that if that's already automatically added due to an association, it won't interfere or duplicate
128
- property :author, dependencies: [:author, :added_column, :author_id]
114
+ property :author, dependencies: %i[author added_column author_id]
129
115
 
130
116
  property :name, dependencies: [:simple_name]
131
117
  end
132
118
 
133
-
134
119
  def seed_data
135
- cat1 = ActiveCategory.create( id: 1 , uuid: 'deadbeef1', name: 'cat1' )
136
- cat2 = ActiveCategory.create( id: 2 , uuid: 'deadbeef2', name: 'cat2' )
137
-
138
- author1 = ActiveAuthor.create( id: 11, name: 'author1' )
139
- author2 = ActiveAuthor.create( id: 22, name: 'author2' )
140
- author3 = ActiveAuthor.create( id: 33, name: nil )
141
-
142
- tag_blue = ActiveTag.create(id: 1 , name: 'blue' )
143
- tag_red = ActiveTag.create(id: 2 , name: 'red' )
144
- tag_green = ActiveTag.create(id: 3 , name: 'green' )
145
-
146
- book1 = ActiveBook.create( id: 1 , simple_name: 'Book1', category_uuid: 'deadbeef1')
120
+ cat1 = ActiveCategory.create(id: 1, uuid: 'deadbeef1', name: 'cat1')
121
+ cat2 = ActiveCategory.create(id: 2, uuid: 'deadbeef2', name: 'cat2')
122
+
123
+ author1 = ActiveAuthor.create(id: 11, name: 'author1')
124
+ author2 = ActiveAuthor.create(id: 22, name: 'author2')
125
+ author3 = ActiveAuthor.create(id: 33, name: nil)
126
+
127
+ tag_blue = ActiveTag.create(id: 1, name: 'blue')
128
+ tag_red = ActiveTag.create(id: 2, name: 'red')
129
+ tag_green = ActiveTag.create(id: 3, name: 'green')
130
+
131
+ book1 = ActiveBook.create(id: 1, simple_name: 'Book1', category_uuid: 'deadbeef1')
147
132
  book1.author = author1
148
133
  book1.category = cat1
149
134
  book1.save
150
135
  ActiveTagging.create(book: book1, tag: tag_blue, label: 'primary')
151
136
  ActiveTagging.create(book: book1, tag: tag_red)
152
137
  ActiveTagging.create(book: book1, tag: tag_green, label: 'primary')
153
-
154
138
 
155
- book2 = ActiveBook.create( id: 2 , simple_name: 'Book2', category_uuid: 'deadbeef1')
139
+ book2 = ActiveBook.create(id: 2, simple_name: 'Book2', category_uuid: 'deadbeef1')
156
140
  book2.author = author2
157
141
  book2.category = cat2
158
142
  book2.save
159
143
  ActiveTagging.create(book: book2, tag: tag_red, label: 'primary')
160
144
 
161
- book3 = ActiveBook.create( id: 3 , simple_name: 'Book3', category_uuid: 'deadbeef1')
145
+ book3 = ActiveBook.create(id: 3, simple_name: 'Book3', category_uuid: 'deadbeef1')
162
146
  book3.author = author3
163
147
  book3.save
164
148
  ActiveTagging.create(book: book3, tag: tag_red, label: 'primary')
@@ -166,10 +150,9 @@ def seed_data
166
150
  # More stuff
167
151
 
168
152
  10.times do |i|
169
- bid = 1000+i
170
- ActiveBook.create( id: bid , simple_name: "Book#{bid}")
153
+ bid = 1000 + i
154
+ ActiveBook.create(id: bid, simple_name: "Book#{bid}")
171
155
  end
172
-
173
156
  end
174
157
 
175
- seed_data
158
+ seed_data