cuprum-rails 0.1.0 → 0.2.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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +145 -0
  3. data/DEVELOPMENT.md +20 -0
  4. data/README.md +356 -63
  5. data/lib/cuprum/rails/action.rb +32 -16
  6. data/lib/cuprum/rails/actions/create.rb +62 -15
  7. data/lib/cuprum/rails/actions/destroy.rb +23 -7
  8. data/lib/cuprum/rails/actions/edit.rb +23 -7
  9. data/lib/cuprum/rails/actions/index.rb +30 -10
  10. data/lib/cuprum/rails/actions/middleware/associations/cache.rb +112 -0
  11. data/lib/cuprum/rails/actions/middleware/associations/find.rb +23 -0
  12. data/lib/cuprum/rails/actions/middleware/associations/parent.rb +70 -0
  13. data/lib/cuprum/rails/actions/middleware/associations/query.rb +140 -0
  14. data/lib/cuprum/rails/actions/middleware/associations.rb +12 -0
  15. data/lib/cuprum/rails/actions/middleware/log_request.rb +126 -0
  16. data/lib/cuprum/rails/actions/middleware/log_result.rb +51 -0
  17. data/lib/cuprum/rails/actions/middleware/resources/find.rb +44 -0
  18. data/lib/cuprum/rails/actions/middleware/resources/query.rb +91 -0
  19. data/lib/cuprum/rails/actions/middleware/resources.rb +11 -0
  20. data/lib/cuprum/rails/actions/middleware.rb +13 -0
  21. data/lib/cuprum/rails/actions/new.rb +16 -4
  22. data/lib/cuprum/rails/actions/parameter_validation.rb +60 -0
  23. data/lib/cuprum/rails/actions/resource_action.rb +119 -42
  24. data/lib/cuprum/rails/actions/show.rb +23 -7
  25. data/lib/cuprum/rails/actions/update.rb +70 -22
  26. data/lib/cuprum/rails/actions.rb +11 -7
  27. data/lib/cuprum/rails/collection.rb +27 -47
  28. data/lib/cuprum/rails/command.rb +3 -1
  29. data/lib/cuprum/rails/commands/destroy_one.rb +10 -6
  30. data/lib/cuprum/rails/commands/find_many.rb +8 -1
  31. data/lib/cuprum/rails/commands/find_matching.rb +1 -1
  32. data/lib/cuprum/rails/commands/find_one.rb +8 -0
  33. data/lib/cuprum/rails/commands/insert_one.rb +17 -6
  34. data/lib/cuprum/rails/commands/update_one.rb +16 -5
  35. data/lib/cuprum/rails/constraints/parameters_contract.rb +14 -0
  36. data/lib/cuprum/rails/constraints.rb +10 -0
  37. data/lib/cuprum/rails/controller.rb +12 -2
  38. data/lib/cuprum/rails/controllers/action.rb +100 -0
  39. data/lib/cuprum/rails/controllers/class_methods/actions.rb +33 -7
  40. data/lib/cuprum/rails/controllers/class_methods/configuration.rb +36 -0
  41. data/lib/cuprum/rails/controllers/class_methods/middleware.rb +88 -0
  42. data/lib/cuprum/rails/controllers/class_methods/validations.rb +2 -2
  43. data/lib/cuprum/rails/controllers/configuration.rb +41 -1
  44. data/lib/cuprum/rails/controllers/middleware.rb +59 -0
  45. data/lib/cuprum/rails/controllers.rb +2 -0
  46. data/lib/cuprum/rails/errors/invalid_parameters.rb +55 -0
  47. data/lib/cuprum/rails/errors/invalid_statement.rb +11 -0
  48. data/lib/cuprum/rails/errors/missing_parameter.rb +42 -0
  49. data/lib/cuprum/rails/errors/resource_error.rb +46 -0
  50. data/lib/cuprum/rails/errors.rb +6 -1
  51. data/lib/cuprum/rails/map_errors.rb +29 -1
  52. data/lib/cuprum/rails/query.rb +1 -1
  53. data/lib/cuprum/rails/repository.rb +12 -25
  54. data/lib/cuprum/rails/request.rb +149 -60
  55. data/lib/cuprum/rails/resource.rb +119 -85
  56. data/lib/cuprum/rails/responders/base_responder.rb +78 -0
  57. data/lib/cuprum/rails/responders/html/plural_resource.rb +9 -39
  58. data/lib/cuprum/rails/responders/html/rendering.rb +81 -0
  59. data/lib/cuprum/rails/responders/html/resource.rb +107 -0
  60. data/lib/cuprum/rails/responders/html/singular_resource.rb +9 -38
  61. data/lib/cuprum/rails/responders/html.rb +2 -0
  62. data/lib/cuprum/rails/responders/html_responder.rb +8 -52
  63. data/lib/cuprum/rails/responders/json/resource.rb +3 -3
  64. data/lib/cuprum/rails/responders/json_responder.rb +31 -16
  65. data/lib/cuprum/rails/responders/matching.rb +29 -27
  66. data/lib/cuprum/rails/responders/serialization.rb +11 -9
  67. data/lib/cuprum/rails/responders.rb +1 -0
  68. data/lib/cuprum/rails/responses/head_response.rb +24 -0
  69. data/lib/cuprum/rails/responses/html/redirect_back_response.rb +55 -0
  70. data/lib/cuprum/rails/responses/html/redirect_response.rb +19 -4
  71. data/lib/cuprum/rails/responses/html/render_response.rb +17 -5
  72. data/lib/cuprum/rails/responses/html.rb +6 -2
  73. data/lib/cuprum/rails/responses.rb +1 -0
  74. data/lib/cuprum/rails/result.rb +36 -0
  75. data/lib/cuprum/rails/routes.rb +36 -23
  76. data/lib/cuprum/rails/rspec/contract_helpers.rb +57 -0
  77. data/lib/cuprum/rails/rspec/contracts/action_contracts.rb +754 -0
  78. data/lib/cuprum/rails/rspec/contracts/actions/create_contracts.rb +289 -0
  79. data/lib/cuprum/rails/rspec/contracts/actions/destroy_contracts.rb +164 -0
  80. data/lib/cuprum/rails/rspec/contracts/actions/edit_contracts.rb +73 -0
  81. data/lib/cuprum/rails/rspec/contracts/actions/index_contracts.rb +108 -0
  82. data/lib/cuprum/rails/rspec/contracts/actions/new_contracts.rb +111 -0
  83. data/lib/cuprum/rails/rspec/contracts/actions/show_contracts.rb +72 -0
  84. data/lib/cuprum/rails/rspec/contracts/actions/update_contracts.rb +263 -0
  85. data/lib/cuprum/rails/rspec/contracts/actions.rb +8 -0
  86. data/lib/cuprum/rails/rspec/contracts/command_contracts.rb +479 -0
  87. data/lib/cuprum/rails/rspec/contracts/responder_contracts.rb +232 -0
  88. data/lib/cuprum/rails/rspec/contracts/routes_contracts.rb +363 -0
  89. data/lib/cuprum/rails/rspec/contracts/serializers_contracts.rb +70 -0
  90. data/lib/cuprum/rails/rspec/contracts.rb +8 -0
  91. data/lib/cuprum/rails/rspec/matchers/be_a_result_matcher.rb +64 -0
  92. data/lib/cuprum/rails/rspec/matchers.rb +41 -0
  93. data/lib/cuprum/rails/serializers/base_serializer.rb +60 -0
  94. data/lib/cuprum/rails/serializers/context.rb +84 -0
  95. data/lib/cuprum/rails/serializers/json/active_record_serializer.rb +2 -2
  96. data/lib/cuprum/rails/serializers/json/array_serializer.rb +9 -8
  97. data/lib/cuprum/rails/serializers/json/attributes_serializer.rb +95 -172
  98. data/lib/cuprum/rails/serializers/json/error_serializer.rb +2 -2
  99. data/lib/cuprum/rails/serializers/json/hash_serializer.rb +9 -8
  100. data/lib/cuprum/rails/serializers/json/identity_serializer.rb +3 -3
  101. data/lib/cuprum/rails/serializers/json/properties_serializer.rb +252 -0
  102. data/lib/cuprum/rails/serializers/json.rb +2 -1
  103. data/lib/cuprum/rails/serializers.rb +3 -1
  104. data/lib/cuprum/rails/version.rb +1 -1
  105. data/lib/cuprum/rails.rb +19 -16
  106. metadata +73 -131
  107. data/lib/cuprum/rails/controller_action.rb +0 -121
  108. data/lib/cuprum/rails/errors/missing_parameters.rb +0 -33
  109. data/lib/cuprum/rails/errors/missing_primary_key.rb +0 -46
  110. data/lib/cuprum/rails/errors/undefined_permitted_attributes.rb +0 -34
  111. data/lib/cuprum/rails/rspec/command_contract.rb +0 -460
  112. data/lib/cuprum/rails/rspec/define_route_contract.rb +0 -84
  113. data/lib/cuprum/rails/serializers/json/serializer.rb +0 -66
@@ -1,121 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'forwardable'
4
-
5
- require 'cuprum/rails'
6
-
7
- module Cuprum::Rails
8
- # @api private
9
- #
10
- # Implements a controller action.
11
- #
12
- # @note This class should not be initialized directly. Instead, use the
13
- # Cuprum::Rails::Controller.action class method to define an action.
14
- class ControllerAction
15
- extend Forwardable
16
-
17
- # @param configuration [Cuprum::Rails::Controllers::Configuration] the
18
- # configuration for the originating controller.
19
- # @param action_class [Class] The class of the action command. Must be
20
- # constructible with keyword :resource.
21
- # @param action_name [String, Symbol] The name of the action.
22
- # @param member_action [Boolean] True if the action acts on a collection
23
- # item, not on the collection as a whole.
24
- # @param serializers
25
- # [Hash<Class, Object>, Hash<Symbol, Hash<Class, Object>>] The serializers
26
- # for converting result values into serialized data.
27
- def initialize(
28
- configuration,
29
- action_class:,
30
- action_name:,
31
- member_action: false,
32
- serializers: {}
33
- )
34
- @configuration = configuration
35
- @action_class = action_class
36
- @action_name = action_name
37
- @member_action = !!member_action # rubocop:disable Style/DoubleNegation
38
- @serializers = serializers
39
- end
40
-
41
- # @return [Class] the class of the action command.
42
- attr_reader :action_class
43
-
44
- # @return [String, Symbol] the name of the action.
45
- attr_reader :action_name
46
-
47
- # @return [Cuprum::Rails::Controllers::Configuration] the configuration for
48
- # the originating controller.
49
- attr_reader :configuration
50
-
51
- # @return [Hash<Class, Object>, Hash<Symbol, Hash<Class, Object>>] the
52
- # serializers for converting result values into serialized data.
53
- attr_reader :serializers
54
-
55
- # @!method resource
56
- # @return [Cuprum::Rails::Resource] the resource defined for the
57
- # controller.
58
-
59
- # @!method responder_for(format)
60
- # Finds the configured responder for the requested format.
61
- #
62
- # @param format [Symbol] The format to respond to.
63
- #
64
- # @return [Class] the responder class defined for the format.
65
- #
66
- # @raise [Cuprum::Rails::Controller::UnknownFormatError] if the controller
67
- # does not define a responder for the given format.
68
-
69
- def_delegators :@configuration,
70
- :resource,
71
- :responder_for
72
-
73
- # Executes the controller action.
74
- #
75
- # 1. Initializes the action command with the resource.
76
- # 2. Calls the command with the request.
77
- # 3. Builds the responder with the resource and action metadata.
78
- # 4. Calls the responder with the action result.
79
- #
80
- # @param request [ActionDispatch::Request] The request to process.
81
- #
82
- # @return [#call] The response object.
83
- def call(request)
84
- responder = build_responder(request)
85
- action = action_class.new(resource: resource)
86
- result = action.call(request: request)
87
-
88
- responder.call(result)
89
- end
90
-
91
- # @return [Boolean] true if the action acts on a collection item, not on the
92
- # collection as a whole.
93
- def member_action?
94
- @member_action
95
- end
96
-
97
- private
98
-
99
- def build_responder(request)
100
- responder_class = responder_for(request.format)
101
-
102
- responder_class.new(
103
- action_name: action_name,
104
- member_action: member_action?,
105
- resource: resource,
106
- serializers: merge_serializers_for(request.format)
107
- )
108
- end
109
-
110
- def merge_serializers_for(format)
111
- scoped_serializers(configuration.serializers, format: format)
112
- .merge(scoped_serializers(serializers, format: format))
113
- end
114
-
115
- def scoped_serializers(serializers, format:)
116
- serializers
117
- .select { |key, _| key.is_a?(Class) }
118
- .merge(serializers.fetch(format, {}))
119
- end
120
- end
121
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'cuprum/error'
4
-
5
- require 'cuprum/rails/errors'
6
-
7
- module Cuprum::Rails::Errors
8
- # Error class when a parameters hash does not include a resource.
9
- class MissingParameters < Cuprum::Error
10
- # Short string used to identify the type of error.
11
- TYPE = 'cuprum.rails.errors.missing_parameters'
12
-
13
- # @param resource_name [Cuprum::Rails::Resource] The name of the resource.
14
- def initialize(resource_name:)
15
- @resource_name = resource_name
16
-
17
- super(message: default_message, resource_name: resource_name)
18
- end
19
-
20
- # @return [Cuprum::Rails::Resource] the name of the resource.
21
- attr_reader :resource_name
22
-
23
- private
24
-
25
- def as_json_data
26
- { 'resource_name' => resource_name }
27
- end
28
-
29
- def default_message
30
- "The #{resource_name.inspect} parameter is missing or empty"
31
- end
32
- end
33
- end
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'cuprum/error'
4
-
5
- require 'cuprum/rails/errors'
6
-
7
- module Cuprum::Rails::Errors
8
- # Error class when a parameters hash does not include a primary key.
9
- class MissingPrimaryKey < Cuprum::Error
10
- # Short string used to identify the type of error.
11
- TYPE = 'cuprum.rails.errors.missing_primary_key'
12
-
13
- # @param primary_key [String, Symbol] The name of the resource primary key.
14
- # @param resource_name [Cuprum::Rails::Resource] The name of the resource.
15
- def initialize(primary_key:, resource_name:)
16
- @primary_key = primary_key
17
- @resource_name = resource_name
18
-
19
- super(
20
- message: default_message,
21
- primary_key: primary_key,
22
- resource_name: resource_name
23
- )
24
- end
25
-
26
- # @return [String] the name of the resource primary key.
27
- attr_reader :primary_key
28
-
29
- # @return [Cuprum::Rails::Resource] the name of the resource.
30
- attr_reader :resource_name
31
-
32
- private
33
-
34
- def as_json_data
35
- {
36
- 'primary_key' => primary_key,
37
- 'resource_name' => resource_name
38
- }
39
- end
40
-
41
- def default_message
42
- "Unable to find #{resource_name} because the #{primary_key.inspect}" \
43
- ' parameter is missing or empty'
44
- end
45
- end
46
- end
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'cuprum/error'
4
-
5
- require 'cuprum/rails/errors'
6
-
7
- module Cuprum::Rails::Errors
8
- # Error class when a resource does not define permitted attributes.
9
- class UndefinedPermittedAttributes < Cuprum::Error
10
- # Short string used to identify the type of error.
11
- TYPE = 'cuprum.rails.errors.undefined_permitted_attributes'
12
-
13
- # @param resource_name [Cuprum::Rails::Resource] The name of the resource.
14
- def initialize(resource_name:)
15
- @resource_name = resource_name
16
-
17
- super(message: default_message, resource_name: resource_name)
18
- end
19
-
20
- # @return [Cuprum::Rails::Resource] the name of the resource.
21
- attr_reader :resource_name
22
-
23
- private
24
-
25
- def as_json_data
26
- { 'resource_name' => resource_name }
27
- end
28
-
29
- def default_message
30
- "Resource #{resource_name.inspect} does not define" \
31
- ' permitted attributes'
32
- end
33
- end
34
- end
@@ -1,460 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'cuprum/rails/rspec'
4
-
5
- require 'support/book'
6
- require 'support/tome'
7
-
8
- module Cuprum::Rails::RSpec
9
- # Contract validating the behavior of a Rails command implementation.
10
- COMMAND_CONTRACT = lambda do
11
- describe '.subclass' do
12
- let(:subclass) { described_class.subclass }
13
- let(:constructor_options) do
14
- {
15
- record_class: Book,
16
- optional_key: 'optional value'
17
- }
18
- end
19
-
20
- it 'should define the class method' do
21
- expect(described_class)
22
- .to respond_to(:subclass)
23
- .with(0).arguments
24
- .and_any_keywords
25
- end
26
-
27
- it { expect(subclass).to be_a Class }
28
-
29
- it { expect(subclass).to be < described_class }
30
-
31
- it 'should define the constructor' do
32
- expect(subclass)
33
- .to respond_to(:new)
34
- .with(0).arguments
35
- .and_any_keywords
36
- end
37
-
38
- it 'should return the record class' do
39
- expect(subclass.new(**constructor_options).record_class)
40
- .to be record_class
41
- end
42
-
43
- it 'should return the options' do
44
- expect(subclass.new(**constructor_options).options)
45
- .to be == { optional_key: 'optional value' }
46
- end
47
-
48
- describe 'with options' do
49
- let(:default_options) do
50
- {
51
- record_class: Book,
52
- custom_key: 'custom value'
53
- }
54
- end
55
- let(:constructor_options) do
56
- {
57
- optional_key: 'optional value'
58
- }
59
- end
60
- let(:subclass) { described_class.subclass(**default_options) }
61
-
62
- it { expect(subclass).to be_a Class }
63
-
64
- it { expect(subclass).to be < described_class }
65
-
66
- it 'should define the constructor' do
67
- expect(subclass)
68
- .to respond_to(:new)
69
- .with(0).arguments
70
- .and_any_keywords
71
- end
72
-
73
- it 'should return the record class' do
74
- expect(subclass.new(**constructor_options).record_class)
75
- .to be record_class
76
- end
77
-
78
- it 'should return the options' do
79
- expect(subclass.new(**constructor_options).options)
80
- .to be == {
81
- custom_key: 'custom value',
82
- optional_key: 'optional value'
83
- }
84
- end
85
- end
86
- end
87
-
88
- describe '#collection_name' do
89
- let(:expected) { record_class.name.underscore.pluralize }
90
-
91
- include_examples 'should define reader',
92
- :collection_name,
93
- -> { be == expected }
94
-
95
- context 'when initialized with collection_name: string' do
96
- let(:collection_name) { 'books' }
97
- let(:constructor_options) do
98
- super().merge(collection_name: collection_name)
99
- end
100
-
101
- it { expect(command.collection_name).to be == collection_name }
102
- end
103
-
104
- context 'when initialized with collection_name: symbol' do
105
- let(:collection_name) { :books }
106
- let(:constructor_options) do
107
- super().merge(collection_name: collection_name)
108
- end
109
-
110
- it { expect(command.collection_name).to be == collection_name.to_s }
111
- end
112
- end
113
-
114
- describe '#member_name' do
115
- def tools
116
- SleepingKingStudios::Tools::Toolbelt.instance
117
- end
118
-
119
- include_examples 'should have reader',
120
- :member_name,
121
- -> { record_class.name.underscore }
122
-
123
- context 'when initialized with collection_name: value' do
124
- let(:collection_name) { :books }
125
-
126
- it 'should return the singular collection name' do
127
- expect(command.member_name)
128
- .to be == tools.str.singularize(collection_name.to_s)
129
- end
130
- end
131
-
132
- context 'when initialized with member_name: string' do
133
- let(:member_name) { 'tome' }
134
- let(:constructor_options) { super().merge(member_name: member_name) }
135
-
136
- it 'should return the singular collection name' do
137
- expect(command.member_name).to be member_name
138
- end
139
- end
140
-
141
- context 'when initialized with member_name: symbol' do
142
- let(:member_name) { :tome }
143
- let(:constructor_options) { super().merge(member_name: member_name) }
144
-
145
- it 'should return the singular collection name' do
146
- expect(command.member_name).to be == member_name.to_s
147
- end
148
- end
149
- end
150
-
151
- describe '#options' do
152
- let(:expected_options) do
153
- defined?(super()) ? super() : constructor_options
154
- end
155
-
156
- include_examples 'should define reader',
157
- :options,
158
- -> { be == expected_options }
159
-
160
- context 'when initialized with options' do
161
- let(:constructor_options) { super().merge({ key: 'value' }) }
162
- let(:expected_options) { super().merge({ key: 'value' }) }
163
-
164
- it { expect(command.options).to be == expected_options }
165
- end
166
- end
167
-
168
- describe '#primary_key_name' do
169
- include_examples 'should define reader', :primary_key_name, :id
170
-
171
- context 'with a record class with custom primary key' do
172
- let(:record_class) { Tome }
173
-
174
- include_examples 'should define reader', :primary_key_name, :uuid
175
- end
176
- end
177
-
178
- describe '#primary_key_type' do
179
- include_examples 'should define reader', :primary_key_type, Integer
180
-
181
- context 'with a record class with custom primary key' do
182
- let(:record_class) { Tome }
183
-
184
- include_examples 'should define reader', :primary_key_type, String
185
- end
186
- end
187
-
188
- describe '#record_class' do
189
- include_examples 'should define reader',
190
- :record_class,
191
- -> { record_class }
192
- end
193
-
194
- describe '#validate_entity' do
195
- let(:expected_error) do
196
- type = record_class
197
- contract = Stannum::Contracts::ParametersContract.new do
198
- keyword :entity, type
199
- end
200
- errors = contract.errors_for(
201
- {
202
- arguments: [],
203
- block: nil,
204
- keywords: { entity: nil }
205
- }
206
- )
207
-
208
- Cuprum::Collections::Errors::InvalidParameters.new(
209
- command: command,
210
- errors: errors
211
- )
212
- end
213
-
214
- it 'should define the private method' do
215
- expect(command)
216
- .to respond_to(:validate_entity, true)
217
- .with(1).argument
218
- end
219
-
220
- describe 'with nil' do
221
- it 'should return a failing result' do
222
- expect(command.send(:validate_entity, nil))
223
- .to be_a_failing_result
224
- .with_error(expected_error)
225
- end
226
- end
227
-
228
- describe 'with an Object' do
229
- it 'should return a failing result' do
230
- expect(command.send(:validate_entity, Object.new.freeze))
231
- .to be_a_failing_result
232
- .with_error(expected_error)
233
- end
234
- end
235
-
236
- describe 'with an invalid record instance' do
237
- it 'should return a failing result' do
238
- expect(command.send(:validate_entity, Tome.new))
239
- .to be_a_failing_result
240
- .with_error(expected_error)
241
- end
242
- end
243
-
244
- describe 'with a valid record instance' do
245
- it 'should not return a result' do
246
- expect(command.send(:validate_entity, Book.new))
247
- .not_to be_a_result
248
- end
249
- end
250
- end
251
-
252
- describe '#validate_primary_key' do
253
- let(:primary_key_type) { Integer }
254
- let(:expected_error) do
255
- type = primary_key_type
256
- contract = Stannum::Contracts::ParametersContract.new do
257
- keyword :primary_key, type
258
- end
259
- errors = contract.errors_for(
260
- {
261
- arguments: [],
262
- block: nil,
263
- keywords: { primary_key: nil }
264
- }
265
- )
266
-
267
- Cuprum::Collections::Errors::InvalidParameters.new(
268
- command: command,
269
- errors: errors
270
- )
271
- end
272
-
273
- it 'should define the private method' do
274
- expect(command)
275
- .to respond_to(:validate_primary_key, true)
276
- .with(1).argument
277
- end
278
-
279
- describe 'with nil' do
280
- it 'should return a failing result' do
281
- expect(command.send(:validate_primary_key, nil))
282
- .to be_a_failing_result
283
- .with_error(expected_error)
284
- end
285
- end
286
-
287
- describe 'with an Object' do
288
- it 'should return a failing result' do
289
- expect(command.send(:validate_primary_key, Object.new.freeze))
290
- .to be_a_failing_result
291
- .with_error(expected_error)
292
- end
293
- end
294
-
295
- describe 'with a String' do
296
- it 'should return a failing result' do
297
- expect(command.send(:validate_primary_key, '12345'))
298
- .to be_a_failing_result
299
- .with_error(expected_error)
300
- end
301
- end
302
-
303
- describe 'with an Integer' do
304
- it 'should not return a result' do
305
- expect(command.send(:validate_primary_key, 12_345)).not_to be_a_result
306
- end
307
- end
308
-
309
- context 'with a record class with custom primary key' do
310
- let(:record_class) { Tome }
311
- let(:primary_key_type) { String }
312
-
313
- describe 'with an Integer' do
314
- it 'should return a failing result' do
315
- expect(command.send(:validate_primary_key, 12_345))
316
- .to be_a_failing_result
317
- .with_error(expected_error)
318
- end
319
- end
320
-
321
- describe 'with a String' do
322
- it 'should not return a result' do
323
- expect(command.send(:validate_primary_key, '12345'))
324
- .not_to be_a_result
325
- end
326
- end
327
- end
328
- end
329
-
330
- describe '#validate_primary_keys' do
331
- let(:primary_keys) { nil }
332
- let(:primary_key_type) { Integer }
333
- let(:expected_error) do
334
- type = primary_key_type
335
- contract = Stannum::Contracts::ParametersContract.new do
336
- keyword :primary_keys,
337
- Stannum::Constraints::Types::ArrayType.new(item_type: type)
338
- end
339
- errors = contract.errors_for(
340
- {
341
- arguments: [],
342
- block: nil,
343
- keywords: { primary_keys: primary_keys }
344
- }
345
- )
346
-
347
- Cuprum::Collections::Errors::InvalidParameters.new(
348
- command: command,
349
- errors: errors
350
- )
351
- end
352
-
353
- it 'should define the private method' do
354
- expect(command)
355
- .to respond_to(:validate_primary_keys, true)
356
- .with(1).argument
357
- end
358
-
359
- describe 'with nil' do
360
- it 'should return a failing result' do
361
- expect(command.send(:validate_primary_keys, nil))
362
- .to be_a_failing_result
363
- .with_error(expected_error)
364
- end
365
- end
366
-
367
- describe 'with an Object' do
368
- it 'should return a failing result' do
369
- expect(command.send(:validate_primary_keys, Object.new.freeze))
370
- .to be_a_failing_result
371
- .with_error(expected_error)
372
- end
373
- end
374
-
375
- describe 'with a String' do
376
- it 'should return a failing result' do
377
- expect(command.send(:validate_primary_keys, '12345'))
378
- .to be_a_failing_result
379
- .with_error(expected_error)
380
- end
381
- end
382
-
383
- describe 'with an Integer' do
384
- it 'should return a failing result' do
385
- expect(command.send(:validate_primary_keys, 12_345))
386
- .to be_a_failing_result
387
- .with_error(expected_error)
388
- end
389
- end
390
-
391
- describe 'with an empty Array' do
392
- it 'should not return a result' do
393
- expect(command.send(:validate_primary_keys, []))
394
- .not_to be_a_result
395
- end
396
- end
397
-
398
- describe 'with an Array with nil values' do
399
- let(:primary_keys) { Array.new(3, nil) }
400
-
401
- it 'should return a failing result' do
402
- expect(command.send(:validate_primary_keys, primary_keys))
403
- .to be_a_failing_result
404
- .with_error(expected_error)
405
- end
406
- end
407
-
408
- describe 'with an Array with Object values' do
409
- let(:primary_keys) { Array.new(3) { Object.new.freeze } }
410
-
411
- it 'should return a failing result' do
412
- expect(command.send(:validate_primary_keys, primary_keys))
413
- .to be_a_failing_result
414
- .with_error(expected_error)
415
- end
416
- end
417
-
418
- describe 'with an Array with String values' do
419
- let(:primary_keys) { %w[ichi ni san] }
420
-
421
- it 'should return a failing result' do
422
- expect(command.send(:validate_primary_keys, primary_keys))
423
- .to be_a_failing_result
424
- .with_error(expected_error)
425
- end
426
- end
427
-
428
- describe 'with an Array with Integer values' do
429
- it 'should not return a result' do
430
- expect(command.send(:validate_primary_keys, [0, 1, 2]))
431
- .not_to be_a_result
432
- end
433
- end
434
-
435
- context 'with a record class with custom primary key' do
436
- let(:record_class) { Tome }
437
- let(:primary_key_type) { String }
438
-
439
- describe 'with an Array with String values' do
440
- let(:primary_keys) { %w[ichi ni san] }
441
-
442
- it 'should not return a result' do
443
- expect(command.send(:validate_primary_keys, primary_keys))
444
- .not_to be_a_result
445
- end
446
- end
447
-
448
- describe 'with an Array with Integer values' do
449
- let(:primary_keys) { [0, 1, 2] }
450
-
451
- it 'should return a failing result' do
452
- expect(command.send(:validate_primary_keys, primary_keys))
453
- .to be_a_failing_result
454
- .with_error(expected_error)
455
- end
456
- end
457
- end
458
- end
459
- end
460
- end