cuprum-collections 0.3.0 → 0.4.0.rc.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +48 -0
  3. data/DEVELOPMENT.md +2 -2
  4. data/README.md +13 -11
  5. data/lib/cuprum/collections/association.rb +256 -0
  6. data/lib/cuprum/collections/associations/belongs_to.rb +32 -0
  7. data/lib/cuprum/collections/associations/has_many.rb +23 -0
  8. data/lib/cuprum/collections/associations/has_one.rb +23 -0
  9. data/lib/cuprum/collections/associations.rb +10 -0
  10. data/lib/cuprum/collections/basic/collection.rb +39 -74
  11. data/lib/cuprum/collections/basic/commands/find_many.rb +1 -1
  12. data/lib/cuprum/collections/basic/commands/find_matching.rb +1 -1
  13. data/lib/cuprum/collections/basic/repository.rb +9 -33
  14. data/lib/cuprum/collections/basic.rb +1 -0
  15. data/lib/cuprum/collections/collection.rb +154 -0
  16. data/lib/cuprum/collections/commands/associations/find_many.rb +161 -0
  17. data/lib/cuprum/collections/commands/associations/require_many.rb +48 -0
  18. data/lib/cuprum/collections/commands/associations.rb +13 -0
  19. data/lib/cuprum/collections/commands/find_one_matching.rb +1 -1
  20. data/lib/cuprum/collections/commands.rb +1 -0
  21. data/lib/cuprum/collections/errors/abstract_find_error.rb +1 -1
  22. data/lib/cuprum/collections/relation.rb +401 -0
  23. data/lib/cuprum/collections/repository.rb +71 -4
  24. data/lib/cuprum/collections/resource.rb +65 -0
  25. data/lib/cuprum/collections/rspec/contracts/association_contracts.rb +2137 -0
  26. data/lib/cuprum/collections/rspec/contracts/basic/command_contracts.rb +484 -0
  27. data/lib/cuprum/collections/rspec/contracts/basic.rb +11 -0
  28. data/lib/cuprum/collections/rspec/contracts/collection_contracts.rb +429 -0
  29. data/lib/cuprum/collections/rspec/contracts/command_contracts.rb +1462 -0
  30. data/lib/cuprum/collections/rspec/contracts/query_contracts.rb +1093 -0
  31. data/lib/cuprum/collections/rspec/contracts/relation_contracts.rb +1381 -0
  32. data/lib/cuprum/collections/rspec/contracts/repository_contracts.rb +605 -0
  33. data/lib/cuprum/collections/rspec/contracts.rb +23 -0
  34. data/lib/cuprum/collections/rspec/fixtures.rb +85 -82
  35. data/lib/cuprum/collections/rspec.rb +4 -1
  36. data/lib/cuprum/collections/version.rb +3 -3
  37. data/lib/cuprum/collections.rb +9 -4
  38. metadata +25 -21
  39. data/lib/cuprum/collections/base.rb +0 -11
  40. data/lib/cuprum/collections/basic/rspec/command_contract.rb +0 -392
  41. data/lib/cuprum/collections/rspec/assign_one_command_contract.rb +0 -168
  42. data/lib/cuprum/collections/rspec/build_one_command_contract.rb +0 -93
  43. data/lib/cuprum/collections/rspec/collection_contract.rb +0 -190
  44. data/lib/cuprum/collections/rspec/destroy_one_command_contract.rb +0 -108
  45. data/lib/cuprum/collections/rspec/find_many_command_contract.rb +0 -407
  46. data/lib/cuprum/collections/rspec/find_matching_command_contract.rb +0 -194
  47. data/lib/cuprum/collections/rspec/find_one_command_contract.rb +0 -157
  48. data/lib/cuprum/collections/rspec/insert_one_command_contract.rb +0 -84
  49. data/lib/cuprum/collections/rspec/query_builder_contract.rb +0 -92
  50. data/lib/cuprum/collections/rspec/query_contract.rb +0 -650
  51. data/lib/cuprum/collections/rspec/querying_contract.rb +0 -298
  52. data/lib/cuprum/collections/rspec/repository_contract.rb +0 -235
  53. data/lib/cuprum/collections/rspec/update_one_command_contract.rb +0 -80
  54. data/lib/cuprum/collections/rspec/validate_one_command_contract.rb +0 -96
@@ -1,392 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'cuprum/collections/basic/rspec'
4
-
5
- module Cuprum::Collections::Basic::RSpec
6
- # Contract validating the behavior of a basic command implementation.
7
- COMMAND_CONTRACT = lambda do
8
- describe '.subclass' do
9
- let(:subclass) { described_class.subclass }
10
- let(:constructor_options) do
11
- {
12
- collection_name: 'books',
13
- data: data,
14
- optional_key: 'optional value'
15
- }
16
- end
17
-
18
- it 'should define the class method' do
19
- expect(described_class)
20
- .to respond_to(:subclass)
21
- .with(0).arguments
22
- .and_any_keywords
23
- end
24
-
25
- it { expect(subclass).to be_a Class }
26
-
27
- it { expect(subclass).to be < described_class }
28
-
29
- it 'should define the constructor' do
30
- expect(subclass)
31
- .to respond_to(:new)
32
- .with(0).arguments
33
- .and_any_keywords
34
- end
35
-
36
- it 'should return the collection name' do
37
- expect(subclass.new(**constructor_options).collection_name)
38
- .to be collection_name
39
- end
40
-
41
- it 'should return the data' do
42
- expect(subclass.new(**constructor_options).data)
43
- .to be data
44
- end
45
-
46
- it 'should return the options' do
47
- expect(subclass.new(**constructor_options).options)
48
- .to be == { optional_key: 'optional value' }
49
- end
50
-
51
- describe 'with options' do
52
- let(:default_options) do
53
- {
54
- collection_name: 'books',
55
- custom_key: 'custom value'
56
- }
57
- end
58
- let(:constructor_options) do
59
- {
60
- data: data,
61
- optional_key: 'optional value'
62
- }
63
- end
64
- let(:subclass) { described_class.subclass(**default_options) }
65
-
66
- it { expect(subclass).to be_a Class }
67
-
68
- it { expect(subclass).to be < described_class }
69
-
70
- it 'should define the constructor' do
71
- expect(subclass)
72
- .to respond_to(:new)
73
- .with(0).arguments
74
- .and_any_keywords
75
- end
76
-
77
- it 'should return the collection name' do
78
- expect(subclass.new(**constructor_options).collection_name)
79
- .to be collection_name
80
- end
81
-
82
- it 'should return the data' do
83
- expect(subclass.new(**constructor_options).data)
84
- .to be data
85
- end
86
-
87
- it 'should return the options' do
88
- expect(subclass.new(**constructor_options).options)
89
- .to be == {
90
- custom_key: 'custom value',
91
- optional_key: 'optional value'
92
- }
93
- end
94
- end
95
- end
96
-
97
- describe '#collection_name' do
98
- include_examples 'should have reader',
99
- :collection_name,
100
- -> { collection_name }
101
-
102
- context 'when initialized with collection_name: symbol' do
103
- let(:collection_name) { :books }
104
-
105
- it { expect(command.collection_name).to be == collection_name.to_s }
106
- end
107
- end
108
-
109
- describe '#data' do
110
- include_examples 'should define reader', :data, -> { data }
111
- end
112
-
113
- describe '#default_contract' do
114
- include_examples 'should define reader', :default_contract, nil
115
-
116
- context 'when initialized with a default contract' do
117
- let(:default_contract) { Stannum::Contract.new }
118
- let(:constructor_options) do
119
- super().merge(default_contract: default_contract)
120
- end
121
-
122
- it { expect(command.default_contract).to be default_contract }
123
- end
124
- end
125
-
126
- describe '#member_name' do
127
- def tools
128
- SleepingKingStudios::Tools::Toolbelt.instance
129
- end
130
-
131
- include_examples 'should have reader',
132
- :member_name,
133
- -> { tools.str.singularize(collection_name) }
134
-
135
- context 'when initialized with collection_name: value' do
136
- let(:collection_name) { :books }
137
-
138
- it 'should return the singular collection name' do
139
- expect(command.member_name)
140
- .to be == tools.str.singularize(collection_name.to_s)
141
- end
142
- end
143
-
144
- context 'when initialized with member_name: string' do
145
- let(:member_name) { 'tome' }
146
- let(:constructor_options) { super().merge(member_name: member_name) }
147
-
148
- it 'should return the singular collection name' do
149
- expect(command.member_name).to be member_name
150
- end
151
- end
152
-
153
- context 'when initialized with member_name: symbol' do
154
- let(:member_name) { :tome }
155
- let(:constructor_options) { super().merge(member_name: member_name) }
156
-
157
- it 'should return the singular collection name' do
158
- expect(command.member_name).to be == member_name.to_s
159
- end
160
- end
161
- end
162
-
163
- describe '#options' do
164
- let(:expected_options) do
165
- defined?(super()) ? super() : constructor_options
166
- end
167
-
168
- include_examples 'should define reader',
169
- :options,
170
- -> { be == expected_options }
171
-
172
- context 'when initialized with options' do
173
- let(:constructor_options) { super().merge({ key: 'value' }) }
174
- let(:expected_options) { super().merge({ key: 'value' }) }
175
-
176
- it { expect(command.options).to be == expected_options }
177
- end
178
- end
179
-
180
- describe '#primary_key_name' do
181
- include_examples 'should define reader', :primary_key_name, :id
182
-
183
- context 'when initialized with a primary key name' do
184
- let(:primary_key_name) { :uuid }
185
- let(:constructor_options) do
186
- super().merge({ primary_key_name: primary_key_name })
187
- end
188
-
189
- it { expect(command.primary_key_name).to be == primary_key_name }
190
- end
191
- end
192
-
193
- describe '#primary_key_type' do
194
- include_examples 'should define reader', :primary_key_type, Integer
195
-
196
- context 'when initialized with a primary key type' do
197
- let(:primary_key_type) { String }
198
- let(:constructor_options) do
199
- super().merge({ primary_key_type: primary_key_type })
200
- end
201
-
202
- it { expect(command.primary_key_type).to be == primary_key_type }
203
- end
204
- end
205
-
206
- describe '#validate_primary_key' do
207
- let(:primary_key_type) { Integer }
208
- let(:expected_error) do
209
- type = primary_key_type
210
- contract = Stannum::Contracts::ParametersContract.new do
211
- keyword :primary_key, type
212
- end
213
- errors = contract.errors_for(
214
- {
215
- arguments: [],
216
- block: nil,
217
- keywords: { primary_key: nil }
218
- }
219
- )
220
-
221
- Cuprum::Collections::Errors::InvalidParameters.new(
222
- command: command,
223
- errors: errors
224
- )
225
- end
226
-
227
- it 'should define the private method' do
228
- expect(command)
229
- .to respond_to(:validate_primary_key, true)
230
- .with(1).argument
231
- end
232
-
233
- describe 'with nil' do
234
- it 'should return a failing result' do
235
- expect(command.send(:validate_primary_key, nil))
236
- .to be_a_failing_result
237
- .with_error(expected_error)
238
- end
239
- end
240
-
241
- describe 'with an Object' do
242
- it 'should return a failing result' do
243
- expect(command.send(:validate_primary_key, Object.new.freeze))
244
- .to be_a_failing_result
245
- .with_error(expected_error)
246
- end
247
- end
248
-
249
- describe 'with a String' do
250
- it 'should return a failing result' do
251
- expect(command.send(:validate_primary_key, '12345'))
252
- .to be_a_failing_result
253
- .with_error(expected_error)
254
- end
255
- end
256
-
257
- describe 'with an Integer' do
258
- it 'should not return a result' do
259
- expect(command.send(:validate_primary_key, 12_345)).not_to be_a_result
260
- end
261
- end
262
-
263
- context 'when initialized with a primary key type' do
264
- let(:primary_key_type) { String }
265
- let(:constructor_options) do
266
- super().merge({ primary_key_type: primary_key_type })
267
- end
268
-
269
- describe 'with an Integer' do
270
- it 'should return a failing result' do
271
- expect(command.send(:validate_primary_key, 12_345))
272
- .to be_a_failing_result
273
- .with_error(expected_error)
274
- end
275
- end
276
-
277
- describe 'with a String' do
278
- it 'should not return a result' do
279
- expect(command.send(:validate_primary_key, '12345'))
280
- .not_to be_a_result
281
- end
282
- end
283
- end
284
- end
285
-
286
- describe '#validate_primary_keys' do
287
- let(:primary_keys) { nil }
288
- let(:primary_key_type) { Integer }
289
- let(:expected_error) do
290
- type = primary_key_type
291
- contract = Stannum::Contracts::ParametersContract.new do
292
- keyword :primary_keys,
293
- Stannum::Constraints::Types::ArrayType.new(item_type: type)
294
- end
295
- errors = contract.errors_for(
296
- {
297
- arguments: [],
298
- block: nil,
299
- keywords: { primary_keys: primary_keys }
300
- }
301
- )
302
-
303
- Cuprum::Collections::Errors::InvalidParameters.new(
304
- command: command,
305
- errors: errors
306
- )
307
- end
308
-
309
- it 'should define the private method' do
310
- expect(command)
311
- .to respond_to(:validate_primary_keys, true)
312
- .with(1).argument
313
- end
314
-
315
- describe 'with nil' do
316
- it 'should return a failing result' do
317
- expect(command.send(:validate_primary_keys, nil))
318
- .to be_a_failing_result
319
- .with_error(expected_error)
320
- end
321
- end
322
-
323
- describe 'with an Object' do
324
- it 'should return a failing result' do
325
- expect(command.send(:validate_primary_keys, Object.new.freeze))
326
- .to be_a_failing_result
327
- .with_error(expected_error)
328
- end
329
- end
330
-
331
- describe 'with a String' do
332
- it 'should return a failing result' do
333
- expect(command.send(:validate_primary_keys, '12345'))
334
- .to be_a_failing_result
335
- .with_error(expected_error)
336
- end
337
- end
338
-
339
- describe 'with an Integer' do
340
- it 'should return a failing result' do
341
- expect(command.send(:validate_primary_keys, 12_345))
342
- .to be_a_failing_result
343
- .with_error(expected_error)
344
- end
345
- end
346
-
347
- describe 'with an empty Array' do
348
- it 'should not return a result' do
349
- expect(command.send(:validate_primary_keys, []))
350
- .not_to be_a_result
351
- end
352
- end
353
-
354
- describe 'with an Array with nil values' do
355
- let(:primary_keys) { Array.new(3, nil) }
356
-
357
- it 'should return a failing result' do
358
- expect(command.send(:validate_primary_keys, primary_keys))
359
- .to be_a_failing_result
360
- .with_error(expected_error)
361
- end
362
- end
363
-
364
- describe 'with an Array with Object values' do
365
- let(:primary_keys) { Array.new(3) { Object.new.freeze } }
366
-
367
- it 'should return a failing result' do
368
- expect(command.send(:validate_primary_keys, primary_keys))
369
- .to be_a_failing_result
370
- .with_error(expected_error)
371
- end
372
- end
373
-
374
- describe 'with an Array with String values' do
375
- let(:primary_keys) { %w[ichi ni san] }
376
-
377
- it 'should return a failing result' do
378
- expect(command.send(:validate_primary_keys, primary_keys))
379
- .to be_a_failing_result
380
- .with_error(expected_error)
381
- end
382
- end
383
-
384
- describe 'with an Array with Integer values' do
385
- it 'should not return a result' do
386
- expect(command.send(:validate_primary_keys, [0, 1, 2]))
387
- .not_to be_a_result
388
- end
389
- end
390
- end
391
- end
392
- end
@@ -1,168 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'stannum/constraints/presence'
4
- require 'stannum/constraints/types/hash_with_indifferent_keys'
5
- require 'stannum/rspec/validate_parameter'
6
-
7
- require 'cuprum/collections/rspec'
8
-
9
- module Cuprum::Collections::RSpec
10
- # Contract validating the behavior of an Assign command implementation.
11
- ASSIGN_ONE_COMMAND_CONTRACT = lambda do |allow_extra_attributes:|
12
- describe '#call' do
13
- shared_examples 'should assign the attributes' do
14
- it { expect(result).to be_a_passing_result }
15
-
16
- it { expect(result.value).to be_a entity.class }
17
-
18
- it { expect(result.value).to be == expected_value }
19
- end
20
-
21
- let(:attributes) { {} }
22
- let(:result) { command.call(attributes: attributes, entity: entity) }
23
- let(:expected_attributes) do
24
- initial_attributes.merge(attributes)
25
- end
26
- let(:expected_value) do
27
- defined?(super()) ? super() : expected_attributes
28
- end
29
-
30
- it 'should validate the :attributes keyword' do
31
- expect(command)
32
- .to validate_parameter(:call, :attributes)
33
- .using_constraint(
34
- Stannum::Constraints::Types::HashWithIndifferentKeys.new
35
- )
36
- end
37
-
38
- it 'should validate the :entity keyword' do
39
- expect(command)
40
- .to validate_parameter(:call, :entity)
41
- .using_constraint(entity_type)
42
- .with_parameters(attributes: {}, entity: nil)
43
- end
44
-
45
- describe 'with an empty attributes hash' do
46
- let(:attributes) { {} }
47
-
48
- include_examples 'should assign the attributes'
49
- end
50
-
51
- describe 'with an attributes hash with partial attributes' do
52
- let(:attributes) { { title: 'Gideon the Ninth' } }
53
-
54
- include_examples 'should assign the attributes'
55
- end
56
-
57
- describe 'with an attributes hash with full attributes' do
58
- let(:attributes) do
59
- {
60
- title: 'Gideon the Ninth',
61
- author: 'Tamsyn Muir',
62
- series: 'The Locked Tomb',
63
- category: 'Horror'
64
- }
65
- end
66
-
67
- include_examples 'should assign the attributes'
68
- end
69
-
70
- describe 'with an attributes hash with extra attributes' do
71
- let(:attributes) do
72
- {
73
- title: 'The Book of Lost Tales',
74
- audiobook: true
75
- }
76
- end
77
-
78
- if allow_extra_attributes
79
- include_examples 'should assign the attributes'
80
- else
81
- # :nocov:
82
- let(:valid_attributes) do
83
- defined?(super()) ? super() : expected_attributes.keys
84
- end
85
- let(:expected_error) do
86
- Cuprum::Collections::Errors::ExtraAttributes.new(
87
- entity_class: entity.class,
88
- extra_attributes: %w[audiobook],
89
- valid_attributes: valid_attributes
90
- )
91
- end
92
-
93
- it 'should return a failing result' do
94
- expect(result).to be_a_failing_result.with_error(expected_error)
95
- end
96
- # :nocov:
97
- end
98
- end
99
-
100
- context 'when the entity has existing attributes' do
101
- let(:initial_attributes) do
102
- # :nocov:
103
- if defined?(super())
104
- super().merge(fixtures_data.first)
105
- else
106
- fixtures_data.first
107
- end
108
- # :nocov:
109
- end
110
-
111
- describe 'with an empty attributes hash' do
112
- let(:attributes) { {} }
113
-
114
- include_examples 'should assign the attributes'
115
- end
116
-
117
- describe 'with an attributes hash with partial attributes' do
118
- let(:attributes) { { title: 'Gideon the Ninth' } }
119
-
120
- include_examples 'should assign the attributes'
121
- end
122
-
123
- describe 'with an attributes hash with full attributes' do
124
- let(:attributes) do
125
- {
126
- title: 'Gideon the Ninth',
127
- author: 'Tamsyn Muir',
128
- series: 'The Locked Tomb',
129
- category: 'Horror'
130
- }
131
- end
132
-
133
- include_examples 'should assign the attributes'
134
- end
135
-
136
- describe 'with an attributes hash with extra attributes' do
137
- let(:attributes) do
138
- {
139
- title: 'The Book of Lost Tales',
140
- audiobook: true
141
- }
142
- end
143
-
144
- if allow_extra_attributes
145
- include_examples 'should assign the attributes'
146
- else
147
- # :nocov:
148
- let(:valid_attributes) do
149
- defined?(super()) ? super() : expected_attributes.keys
150
- end
151
- let(:expected_error) do
152
- Cuprum::Collections::Errors::ExtraAttributes.new(
153
- entity_class: entity.class,
154
- extra_attributes: %w[audiobook],
155
- valid_attributes: valid_attributes
156
- )
157
- end
158
-
159
- it 'should return a failing result' do
160
- expect(result).to be_a_failing_result.with_error(expected_error)
161
- end
162
- # :nocov:
163
- end
164
- end
165
- end
166
- end
167
- end
168
- end
@@ -1,93 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'stannum/constraints/types/hash_with_indifferent_keys'
4
- require 'stannum/rspec/validate_parameter'
5
-
6
- require 'cuprum/collections/rspec'
7
-
8
- module Cuprum::Collections::RSpec
9
- # Contract validating the behavior of a Build command implementation.
10
- BUILD_ONE_COMMAND_CONTRACT = lambda do |allow_extra_attributes:|
11
- include Stannum::RSpec::Matchers
12
-
13
- describe '#call' do
14
- shared_examples 'should build the entity' do
15
- it { expect(result).to be_a_passing_result }
16
-
17
- it { expect(result.value).to be == expected_value }
18
- end
19
-
20
- let(:attributes) { {} }
21
- let(:result) { command.call(attributes: attributes) }
22
- let(:expected_attributes) do
23
- attributes
24
- end
25
- let(:expected_value) do
26
- defined?(super()) ? super() : attributes
27
- end
28
-
29
- it 'should validate the :attributes keyword' do
30
- expect(command)
31
- .to validate_parameter(:call, :attributes)
32
- .using_constraint(
33
- Stannum::Constraints::Types::HashWithIndifferentKeys.new
34
- )
35
- end
36
-
37
- describe 'with an empty attributes hash' do
38
- let(:attributes) { {} }
39
-
40
- include_examples 'should build the entity'
41
- end
42
-
43
- describe 'with an attributes hash with partial attributes' do
44
- let(:attributes) { { title: 'Gideon the Ninth' } }
45
-
46
- include_examples 'should build the entity'
47
- end
48
-
49
- describe 'with an attributes hash with full attributes' do
50
- let(:attributes) do
51
- {
52
- title: 'Gideon the Ninth',
53
- author: 'Tamsyn Muir',
54
- series: 'The Locked Tomb',
55
- category: 'Horror'
56
- }
57
- end
58
-
59
- include_examples 'should build the entity'
60
- end
61
-
62
- describe 'with an attributes hash with extra attributes' do
63
- let(:attributes) do
64
- {
65
- title: 'The Book of Lost Tales',
66
- audiobook: true
67
- }
68
- end
69
-
70
- if allow_extra_attributes
71
- include_examples 'should build the entity'
72
- else
73
- # :nocov:
74
- let(:valid_attributes) do
75
- defined?(super()) ? super() : expected_attributes.keys
76
- end
77
- let(:expected_error) do
78
- Cuprum::Collections::Errors::ExtraAttributes.new(
79
- entity_class: entity_type,
80
- extra_attributes: %w[audiobook],
81
- valid_attributes: valid_attributes
82
- )
83
- end
84
-
85
- it 'should return a failing result' do
86
- expect(result).to be_a_failing_result.with_error(expected_error)
87
- end
88
- # :nocov:
89
- end
90
- end
91
- end
92
- end
93
- end