cuprum-collections 0.1.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 (72) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +59 -0
  3. data/CODE_OF_CONDUCT.md +132 -0
  4. data/DEVELOPMENT.md +25 -0
  5. data/LICENSE +22 -0
  6. data/README.md +950 -0
  7. data/lib/cuprum/collections/base.rb +11 -0
  8. data/lib/cuprum/collections/basic/collection.rb +135 -0
  9. data/lib/cuprum/collections/basic/command.rb +112 -0
  10. data/lib/cuprum/collections/basic/commands/assign_one.rb +54 -0
  11. data/lib/cuprum/collections/basic/commands/build_one.rb +45 -0
  12. data/lib/cuprum/collections/basic/commands/destroy_one.rb +48 -0
  13. data/lib/cuprum/collections/basic/commands/find_many.rb +65 -0
  14. data/lib/cuprum/collections/basic/commands/find_matching.rb +126 -0
  15. data/lib/cuprum/collections/basic/commands/find_one.rb +49 -0
  16. data/lib/cuprum/collections/basic/commands/insert_one.rb +50 -0
  17. data/lib/cuprum/collections/basic/commands/update_one.rb +52 -0
  18. data/lib/cuprum/collections/basic/commands/validate_one.rb +69 -0
  19. data/lib/cuprum/collections/basic/commands.rb +18 -0
  20. data/lib/cuprum/collections/basic/query.rb +160 -0
  21. data/lib/cuprum/collections/basic/query_builder.rb +69 -0
  22. data/lib/cuprum/collections/basic/rspec/command_contract.rb +392 -0
  23. data/lib/cuprum/collections/basic/rspec.rb +8 -0
  24. data/lib/cuprum/collections/basic.rb +22 -0
  25. data/lib/cuprum/collections/command.rb +26 -0
  26. data/lib/cuprum/collections/commands/abstract_find_many.rb +77 -0
  27. data/lib/cuprum/collections/commands/abstract_find_matching.rb +64 -0
  28. data/lib/cuprum/collections/commands/abstract_find_one.rb +44 -0
  29. data/lib/cuprum/collections/commands.rb +8 -0
  30. data/lib/cuprum/collections/constraints/attribute_name.rb +22 -0
  31. data/lib/cuprum/collections/constraints/order/attributes_array.rb +26 -0
  32. data/lib/cuprum/collections/constraints/order/attributes_hash.rb +27 -0
  33. data/lib/cuprum/collections/constraints/order/complex_ordering.rb +46 -0
  34. data/lib/cuprum/collections/constraints/order/sort_direction.rb +32 -0
  35. data/lib/cuprum/collections/constraints/order.rb +8 -0
  36. data/lib/cuprum/collections/constraints/ordering.rb +114 -0
  37. data/lib/cuprum/collections/constraints/query_hash.rb +25 -0
  38. data/lib/cuprum/collections/constraints.rb +8 -0
  39. data/lib/cuprum/collections/errors/already_exists.rb +86 -0
  40. data/lib/cuprum/collections/errors/extra_attributes.rb +66 -0
  41. data/lib/cuprum/collections/errors/failed_validation.rb +66 -0
  42. data/lib/cuprum/collections/errors/invalid_parameters.rb +50 -0
  43. data/lib/cuprum/collections/errors/invalid_query.rb +55 -0
  44. data/lib/cuprum/collections/errors/missing_default_contract.rb +49 -0
  45. data/lib/cuprum/collections/errors/not_found.rb +81 -0
  46. data/lib/cuprum/collections/errors/unknown_operator.rb +71 -0
  47. data/lib/cuprum/collections/errors.rb +8 -0
  48. data/lib/cuprum/collections/queries/ordering.rb +74 -0
  49. data/lib/cuprum/collections/queries/parse.rb +22 -0
  50. data/lib/cuprum/collections/queries/parse_block.rb +206 -0
  51. data/lib/cuprum/collections/queries/parse_strategy.rb +91 -0
  52. data/lib/cuprum/collections/queries.rb +25 -0
  53. data/lib/cuprum/collections/query.rb +247 -0
  54. data/lib/cuprum/collections/query_builder.rb +61 -0
  55. data/lib/cuprum/collections/rspec/assign_one_command_contract.rb +168 -0
  56. data/lib/cuprum/collections/rspec/build_one_command_contract.rb +93 -0
  57. data/lib/cuprum/collections/rspec/collection_contract.rb +153 -0
  58. data/lib/cuprum/collections/rspec/destroy_one_command_contract.rb +106 -0
  59. data/lib/cuprum/collections/rspec/find_many_command_contract.rb +327 -0
  60. data/lib/cuprum/collections/rspec/find_matching_command_contract.rb +194 -0
  61. data/lib/cuprum/collections/rspec/find_one_command_contract.rb +154 -0
  62. data/lib/cuprum/collections/rspec/fixtures.rb +89 -0
  63. data/lib/cuprum/collections/rspec/insert_one_command_contract.rb +83 -0
  64. data/lib/cuprum/collections/rspec/query_builder_contract.rb +92 -0
  65. data/lib/cuprum/collections/rspec/query_contract.rb +650 -0
  66. data/lib/cuprum/collections/rspec/querying_contract.rb +298 -0
  67. data/lib/cuprum/collections/rspec/update_one_command_contract.rb +79 -0
  68. data/lib/cuprum/collections/rspec/validate_one_command_contract.rb +96 -0
  69. data/lib/cuprum/collections/rspec.rb +8 -0
  70. data/lib/cuprum/collections/version.rb +59 -0
  71. data/lib/cuprum/collections.rb +26 -0
  72. metadata +219 -0
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/collections/rspec'
4
+
5
+ module Cuprum::Collections::RSpec
6
+ # Contract validating the behavior of a Collection.
7
+ COLLECTION_CONTRACT = lambda do
8
+ shared_examples 'should define the command' do |command_name, command_class|
9
+ tools = SleepingKingStudios::Tools::Toolbelt.instance
10
+ class_name = tools.str.camelize(command_name)
11
+
12
+ describe "::#{class_name}" do
13
+ let(:constructor_options) { {} }
14
+ let(:command) do
15
+ collection.const_get(class_name).new(**constructor_options)
16
+ end
17
+
18
+ it { expect(collection).to define_constant(class_name) }
19
+
20
+ it { expect(collection.const_get(class_name)).to be_a Class }
21
+
22
+ it { expect(collection.const_get(class_name)).to be < command_class }
23
+
24
+ command_options.each do |option_name|
25
+ it "should set the ##{option_name}" do
26
+ expect(command.send(option_name))
27
+ .to be == collection.send(option_name)
28
+ end
29
+ end
30
+
31
+ describe 'with options' do
32
+ let(:constructor_options) do
33
+ {
34
+ data: [],
35
+ member_name: 'tome'
36
+ }
37
+ end
38
+
39
+ command_options.each do |option_name|
40
+ it "should set the ##{option_name}" do
41
+ expect(command.send(option_name)).to(
42
+ be == constructor_options.fetch(option_name) do
43
+ collection.send(option_name)
44
+ end
45
+ )
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ describe "##{command_name}" do
52
+ let(:constructor_options) { {} }
53
+ let(:command) do
54
+ collection.send(command_name, **constructor_options)
55
+ end
56
+
57
+ it 'should define the command' do
58
+ expect(collection)
59
+ .to respond_to(command_name)
60
+ .with(0).arguments
61
+ .and_any_keywords
62
+ end
63
+
64
+ it { expect(command).to be_a collection.const_get(class_name) }
65
+
66
+ command_options.each do |option_name|
67
+ it "should set the ##{option_name}" do
68
+ expect(command.send(option_name))
69
+ .to be == collection.send(option_name)
70
+ end
71
+ end
72
+
73
+ describe 'with options' do
74
+ let(:constructor_options) do
75
+ {
76
+ data: [],
77
+ member_name: 'tome'
78
+ }
79
+ end
80
+
81
+ command_options.each do |option_name|
82
+ it "should set the ##{option_name}" do
83
+ expect(command.send(option_name)).to(
84
+ be == constructor_options.fetch(option_name) do
85
+ collection.send(option_name)
86
+ end
87
+ )
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ include_examples 'should define the command',
95
+ :assign_one,
96
+ commands_namespace::AssignOne
97
+
98
+ include_examples 'should define the command',
99
+ :build_one,
100
+ commands_namespace::BuildOne
101
+
102
+ include_examples 'should define the command',
103
+ :destroy_one,
104
+ commands_namespace::DestroyOne
105
+
106
+ include_examples 'should define the command',
107
+ :find_many,
108
+ commands_namespace::FindMany
109
+
110
+ include_examples 'should define the command',
111
+ :find_matching,
112
+ commands_namespace::FindMatching
113
+
114
+ include_examples 'should define the command',
115
+ :find_one,
116
+ commands_namespace::FindOne
117
+
118
+ include_examples 'should define the command',
119
+ :insert_one,
120
+ commands_namespace::InsertOne
121
+
122
+ include_examples 'should define the command',
123
+ :update_one,
124
+ commands_namespace::UpdateOne
125
+
126
+ include_examples 'should define the command',
127
+ :validate_one,
128
+ commands_namespace::ValidateOne
129
+
130
+ describe '#query' do
131
+ let(:default_order) { defined?(super()) ? super() : {} }
132
+ let(:query) { collection.query }
133
+
134
+ it { expect(collection).to respond_to(:query).with(0).arguments }
135
+
136
+ it { expect(collection.query).to be_a query_class }
137
+
138
+ it 'should set the query options' do
139
+ query_options.each do |option, value|
140
+ expect(collection.query.send option).to be == value
141
+ end
142
+ end
143
+
144
+ it { expect(query.criteria).to be == [] }
145
+
146
+ it { expect(query.limit).to be nil }
147
+
148
+ it { expect(query.offset).to be nil }
149
+
150
+ it { expect(query.order).to be == default_order }
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/collections/rspec'
4
+
5
+ module Cuprum::Collections::RSpec
6
+ # Contract validating the behavior of a FindOne command implementation.
7
+ DESTROY_ONE_COMMAND_CONTRACT = lambda do
8
+ describe '#call' do
9
+ let(:mapped_data) do
10
+ defined?(super()) ? super() : data
11
+ end
12
+ let(:primary_key_name) { defined?(super()) ? super() : :id }
13
+ let(:primary_key_type) { defined?(super()) ? super() : Integer }
14
+ let(:invalid_primary_key_value) do
15
+ defined?(super()) ? super() : 100
16
+ end
17
+ let(:valid_primary_key_value) do
18
+ defined?(super()) ? super() : 0
19
+ end
20
+
21
+ it 'should validate the :primary_key keyword' do
22
+ expect(command)
23
+ .to validate_parameter(:call, :primary_key)
24
+ .using_constraint(primary_key_type)
25
+ end
26
+
27
+ describe 'with an invalid primary key' do
28
+ let(:primary_key) { invalid_primary_key_value }
29
+ let(:expected_error) do
30
+ Cuprum::Collections::Errors::NotFound.new(
31
+ collection_name: command.collection_name,
32
+ primary_key_name: primary_key_name,
33
+ primary_key_values: primary_key
34
+ )
35
+ end
36
+
37
+ it 'should return a failing result' do
38
+ expect(command.call(primary_key: primary_key))
39
+ .to be_a_failing_result
40
+ .with_error(expected_error)
41
+ end
42
+
43
+ it 'should not remove an entity from the collection' do
44
+ expect { command.call(primary_key: primary_key) }
45
+ .not_to(change { query.reset.count })
46
+ end
47
+ end
48
+
49
+ context 'when the collection has many items' do
50
+ let(:data) { fixtures_data }
51
+ let(:matching_data) do
52
+ mapped_data.find { |item| item[primary_key_name.to_s] == primary_key }
53
+ end
54
+ let!(:expected_data) do
55
+ defined?(super()) ? super() : matching_data
56
+ end
57
+
58
+ describe 'with an invalid primary key' do
59
+ let(:primary_key) { invalid_primary_key_value }
60
+ let(:expected_error) do
61
+ Cuprum::Collections::Errors::NotFound.new(
62
+ collection_name: command.collection_name,
63
+ primary_key_name: primary_key_name,
64
+ primary_key_values: primary_key
65
+ )
66
+ end
67
+
68
+ it 'should return a failing result' do
69
+ expect(command.call(primary_key: primary_key))
70
+ .to be_a_failing_result
71
+ .with_error(expected_error)
72
+ end
73
+
74
+ it 'should not remove an entity from the collection' do
75
+ expect { command.call(primary_key: primary_key) }
76
+ .not_to(change { query.reset.count })
77
+ end
78
+ end
79
+
80
+ describe 'with a valid primary key' do
81
+ let(:primary_key) { valid_primary_key_value }
82
+
83
+ it 'should return a passing result' do
84
+ expect(command.call(primary_key: primary_key))
85
+ .to be_a_passing_result
86
+ .with_value(expected_data)
87
+ end
88
+
89
+ it 'should remove an entity from the collection' do
90
+ expect { command.call(primary_key: primary_key) }
91
+ .to(
92
+ change { query.reset.count }.by(-1)
93
+ )
94
+ end
95
+
96
+ it 'should remove the entity from the collection' do
97
+ command.call(primary_key: primary_key)
98
+
99
+ expect(query.map { |item| item[primary_key_name.to_s] })
100
+ .not_to include primary_key
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,327 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/collections/rspec'
4
+
5
+ module Cuprum::Collections::RSpec
6
+ # Contract validating the behavior of a FindMany command implementation.
7
+ FIND_MANY_COMMAND_CONTRACT = lambda do
8
+ describe '#call' do
9
+ let(:mapped_data) do
10
+ defined?(super()) ? super() : data
11
+ end
12
+ let(:primary_key_name) { defined?(super()) ? super() : :id }
13
+ let(:primary_key_type) { defined?(super()) ? super() : Integer }
14
+ let(:primary_keys_contract) do
15
+ Stannum::Constraints::Types::ArrayType.new(item_type: primary_key_type)
16
+ end
17
+ let(:invalid_primary_key_values) do
18
+ defined?(super()) ? super() : [100, 101, 102]
19
+ end
20
+ let(:valid_primary_key_values) do
21
+ defined?(super()) ? super() : [0, 1, 2]
22
+ end
23
+
24
+ it 'should validate the :allow_partial keyword' do
25
+ expect(command)
26
+ .to validate_parameter(:call, :allow_partial)
27
+ .using_constraint(Stannum::Constraints::Boolean.new)
28
+ end
29
+
30
+ it 'should validate the :envelope keyword' do
31
+ expect(command)
32
+ .to validate_parameter(:call, :envelope)
33
+ .using_constraint(Stannum::Constraints::Boolean.new)
34
+ end
35
+
36
+ it 'should validate the :primary_keys keyword' do
37
+ expect(command)
38
+ .to validate_parameter(:call, :primary_keys)
39
+ .using_constraint(Array)
40
+ end
41
+
42
+ it 'should validate the :primary_keys keyword items' do
43
+ expect(command)
44
+ .to validate_parameter(:call, :primary_keys)
45
+ .with_value([nil])
46
+ .using_constraint(primary_keys_contract)
47
+ end
48
+
49
+ it 'should validate the :scope keyword' do
50
+ expect(command)
51
+ .to validate_parameter(:call, :scope)
52
+ .using_constraint(
53
+ Stannum::Constraints::Type.new(query.class, optional: true)
54
+ )
55
+ .with_value(Object.new.freeze)
56
+ end
57
+
58
+ describe 'with an array of invalid primary keys' do
59
+ let(:primary_keys) { invalid_primary_key_values }
60
+ let(:expected_error) do
61
+ Cuprum::Collections::Errors::NotFound.new(
62
+ collection_name: command.collection_name,
63
+ primary_key_name: primary_key_name,
64
+ primary_key_values: primary_keys
65
+ )
66
+ end
67
+
68
+ it 'should return a failing result' do
69
+ expect(command.call(primary_keys: primary_keys))
70
+ .to be_a_failing_result
71
+ .with_error(expected_error)
72
+ end
73
+ end
74
+
75
+ context 'when the collection has many items' do
76
+ let(:data) { fixtures_data }
77
+ let(:matching_data) do
78
+ primary_keys
79
+ .map do |key|
80
+ mapped_data.find { |item| item[primary_key_name.to_s] == key }
81
+ end
82
+ .compact
83
+ end
84
+ let(:expected_data) do
85
+ defined?(super()) ? super() : matching_data
86
+ end
87
+
88
+ describe 'with an array of invalid primary keys' do
89
+ let(:primary_keys) { invalid_primary_key_values }
90
+ let(:expected_error) do
91
+ Cuprum::Collections::Errors::NotFound.new(
92
+ collection_name: command.collection_name,
93
+ primary_key_name: primary_key_name,
94
+ primary_key_values: primary_keys
95
+ )
96
+ end
97
+
98
+ it 'should return a failing result' do
99
+ expect(command.call(primary_keys: primary_keys))
100
+ .to be_a_failing_result
101
+ .with_error(expected_error)
102
+ end
103
+ end
104
+
105
+ describe 'with a partially valid array of primary keys' do
106
+ let(:primary_keys) do
107
+ invalid_primary_key_values + valid_primary_key_values
108
+ end
109
+ let(:expected_error) do
110
+ Cuprum::Collections::Errors::NotFound.new(
111
+ collection_name: command.collection_name,
112
+ primary_key_name: primary_key_name,
113
+ primary_key_values: invalid_primary_key_values
114
+ )
115
+ end
116
+
117
+ it 'should return a failing result' do
118
+ expect(command.call(primary_keys: primary_keys))
119
+ .to be_a_failing_result
120
+ .with_error(expected_error)
121
+ end
122
+ end
123
+
124
+ describe 'with a valid array of primary keys' do
125
+ let(:primary_keys) { valid_primary_key_values }
126
+
127
+ it 'should return a passing result' do
128
+ expect(command.call(primary_keys: primary_keys))
129
+ .to be_a_passing_result
130
+ .with_value(expected_data)
131
+ end
132
+
133
+ describe 'with an ordered array of primary keys' do
134
+ let(:primary_keys) { valid_primary_key_values.reverse }
135
+
136
+ it 'should return a passing result' do
137
+ expect(command.call(primary_keys: primary_keys))
138
+ .to be_a_passing_result
139
+ .with_value(expected_data)
140
+ end
141
+ end
142
+ end
143
+
144
+ describe 'with allow_partial: true' do
145
+ describe 'with an array of invalid primary keys' do
146
+ let(:primary_keys) { invalid_primary_key_values }
147
+ let(:expected_error) do
148
+ Cuprum::Collections::Errors::NotFound.new(
149
+ collection_name: command.collection_name,
150
+ primary_key_name: primary_key_name,
151
+ primary_key_values: primary_keys
152
+ )
153
+ end
154
+
155
+ it 'should return a failing result' do
156
+ expect(command.call(primary_keys: primary_keys))
157
+ .to be_a_failing_result
158
+ .with_error(expected_error)
159
+ end
160
+ end
161
+
162
+ describe 'with a partially valid array of primary keys' do
163
+ let(:primary_keys) do
164
+ invalid_primary_key_values + valid_primary_key_values
165
+ end
166
+
167
+ it 'should return a passing result' do
168
+ expect(
169
+ command.call(primary_keys: primary_keys, allow_partial: true)
170
+ )
171
+ .to be_a_passing_result
172
+ .with_value(expected_data)
173
+ end
174
+ end
175
+
176
+ describe 'with a valid array of primary keys' do
177
+ let(:primary_keys) { valid_primary_key_values }
178
+
179
+ it 'should return a passing result' do
180
+ expect(
181
+ command.call(primary_keys: primary_keys, allow_partial: true)
182
+ )
183
+ .to be_a_passing_result
184
+ .with_value(expected_data)
185
+ end
186
+
187
+ describe 'with an ordered array of primary keys' do
188
+ let(:primary_keys) { valid_primary_key_values.reverse }
189
+
190
+ it 'should return a passing result' do
191
+ expect(
192
+ command.call(primary_keys: primary_keys, allow_partial: true)
193
+ )
194
+ .to be_a_passing_result
195
+ .with_value(expected_data)
196
+ end
197
+ end
198
+ end
199
+ end
200
+
201
+ describe 'with envelope: true' do
202
+ describe 'with a valid array of primary keys' do
203
+ let(:primary_keys) { valid_primary_key_values }
204
+
205
+ it 'should return a passing result' do
206
+ expect(command.call(primary_keys: primary_keys, envelope: true))
207
+ .to be_a_passing_result
208
+ .with_value({ collection_name => expected_data })
209
+ end
210
+
211
+ describe 'with an ordered array of primary keys' do
212
+ let(:primary_keys) { valid_primary_key_values.reverse }
213
+
214
+ it 'should return a passing result' do
215
+ expect(command.call(primary_keys: primary_keys, envelope: true))
216
+ .to be_a_passing_result
217
+ .with_value({ collection_name => expected_data })
218
+ end
219
+ end
220
+ end
221
+ end
222
+
223
+ describe 'with scope: query' do
224
+ let(:scope_filter) { -> { {} } }
225
+
226
+ describe 'with an array of invalid primary keys' do
227
+ let(:primary_keys) { invalid_primary_key_values }
228
+ let(:expected_error) do
229
+ Cuprum::Collections::Errors::NotFound.new(
230
+ collection_name: command.collection_name,
231
+ primary_key_name: primary_key_name,
232
+ primary_key_values: primary_keys
233
+ )
234
+ end
235
+
236
+ it 'should return a failing result' do
237
+ expect(command.call(primary_keys: primary_keys, scope: scope))
238
+ .to be_a_failing_result
239
+ .with_error(expected_error)
240
+ end
241
+ end
242
+
243
+ describe 'with a scope that does not match any keys' do
244
+ let(:scope_filter) { -> { { author: 'Ursula K. LeGuin' } } }
245
+
246
+ describe 'with a valid array of primary keys' do
247
+ let(:primary_keys) { valid_primary_key_values }
248
+ let(:expected_error) do
249
+ Cuprum::Collections::Errors::NotFound.new(
250
+ collection_name: command.collection_name,
251
+ primary_key_name: primary_key_name,
252
+ primary_key_values: primary_keys
253
+ )
254
+ end
255
+
256
+ it 'should return a failing result' do
257
+ expect(command.call(primary_keys: primary_keys, scope: scope))
258
+ .to be_a_failing_result
259
+ .with_error(expected_error)
260
+ end
261
+ end
262
+ end
263
+
264
+ describe 'with a scope that matches some keys' do
265
+ let(:scope_filter) { -> { { series: nil } } }
266
+ let(:matching_data) do
267
+ super().select { |item| item['series'].nil? }
268
+ end
269
+
270
+ describe 'with a valid array of primary keys' do
271
+ let(:primary_keys) { valid_primary_key_values }
272
+ let(:expected_error) do
273
+ found_keys =
274
+ matching_data.map { |item| item[primary_key_name.to_s] }
275
+ missing_keys = primary_keys - found_keys
276
+
277
+ Cuprum::Collections::Errors::NotFound.new(
278
+ collection_name: command.collection_name,
279
+ primary_key_name: primary_key_name,
280
+ primary_key_values: missing_keys
281
+ )
282
+ end
283
+
284
+ it 'should return a failing result' do
285
+ expect(command.call(primary_keys: primary_keys, scope: scope))
286
+ .to be_a_failing_result
287
+ .with_error(expected_error)
288
+ end
289
+ end
290
+
291
+ describe 'with allow_partial: true' do
292
+ describe 'with a valid array of primary keys' do
293
+ let(:primary_keys) { valid_primary_key_values }
294
+
295
+ it 'should return a passing result' do
296
+ expect(
297
+ command.call(
298
+ allow_partial: true,
299
+ primary_keys: primary_keys,
300
+ scope: scope
301
+ )
302
+ )
303
+ .to be_a_passing_result
304
+ .with_value(expected_data)
305
+ end
306
+ end
307
+ end
308
+ end
309
+
310
+ describe 'with a scope that matches all keys' do
311
+ let(:scope_filter) { -> { { author: 'J.R.R. Tolkien' } } }
312
+
313
+ describe 'with a valid array of primary keys' do
314
+ let(:primary_keys) { valid_primary_key_values }
315
+
316
+ it 'should return a passing result' do
317
+ expect(command.call(primary_keys: primary_keys))
318
+ .to be_a_passing_result
319
+ .with_value(expected_data)
320
+ end
321
+ end
322
+ end
323
+ end
324
+ end
325
+ end
326
+ end
327
+ end