cuprum-collections 0.3.0 → 0.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +48 -0
- data/DEVELOPMENT.md +2 -2
- data/README.md +13 -11
- data/lib/cuprum/collections/association.rb +256 -0
- data/lib/cuprum/collections/associations/belongs_to.rb +32 -0
- data/lib/cuprum/collections/associations/has_many.rb +23 -0
- data/lib/cuprum/collections/associations/has_one.rb +23 -0
- data/lib/cuprum/collections/associations.rb +10 -0
- data/lib/cuprum/collections/basic/collection.rb +39 -74
- data/lib/cuprum/collections/basic/commands/find_many.rb +1 -1
- data/lib/cuprum/collections/basic/commands/find_matching.rb +1 -1
- data/lib/cuprum/collections/basic/repository.rb +9 -33
- data/lib/cuprum/collections/basic.rb +1 -0
- data/lib/cuprum/collections/collection.rb +154 -0
- data/lib/cuprum/collections/commands/associations/find_many.rb +161 -0
- data/lib/cuprum/collections/commands/associations/require_many.rb +48 -0
- data/lib/cuprum/collections/commands/associations.rb +13 -0
- data/lib/cuprum/collections/commands/find_one_matching.rb +1 -1
- data/lib/cuprum/collections/commands.rb +1 -0
- data/lib/cuprum/collections/errors/abstract_find_error.rb +1 -1
- data/lib/cuprum/collections/relation.rb +401 -0
- data/lib/cuprum/collections/repository.rb +71 -4
- data/lib/cuprum/collections/resource.rb +65 -0
- data/lib/cuprum/collections/rspec/contracts/association_contracts.rb +2137 -0
- data/lib/cuprum/collections/rspec/contracts/basic/command_contracts.rb +484 -0
- data/lib/cuprum/collections/rspec/contracts/basic.rb +11 -0
- data/lib/cuprum/collections/rspec/contracts/collection_contracts.rb +429 -0
- data/lib/cuprum/collections/rspec/contracts/command_contracts.rb +1462 -0
- data/lib/cuprum/collections/rspec/contracts/query_contracts.rb +1093 -0
- data/lib/cuprum/collections/rspec/contracts/relation_contracts.rb +1381 -0
- data/lib/cuprum/collections/rspec/contracts/repository_contracts.rb +605 -0
- data/lib/cuprum/collections/rspec/contracts.rb +23 -0
- data/lib/cuprum/collections/rspec/fixtures.rb +85 -82
- data/lib/cuprum/collections/rspec.rb +4 -1
- data/lib/cuprum/collections/version.rb +1 -1
- data/lib/cuprum/collections.rb +9 -4
- metadata +23 -19
- data/lib/cuprum/collections/base.rb +0 -11
- data/lib/cuprum/collections/basic/rspec/command_contract.rb +0 -392
- data/lib/cuprum/collections/rspec/assign_one_command_contract.rb +0 -168
- data/lib/cuprum/collections/rspec/build_one_command_contract.rb +0 -93
- data/lib/cuprum/collections/rspec/collection_contract.rb +0 -190
- data/lib/cuprum/collections/rspec/destroy_one_command_contract.rb +0 -108
- data/lib/cuprum/collections/rspec/find_many_command_contract.rb +0 -407
- data/lib/cuprum/collections/rspec/find_matching_command_contract.rb +0 -194
- data/lib/cuprum/collections/rspec/find_one_command_contract.rb +0 -157
- data/lib/cuprum/collections/rspec/insert_one_command_contract.rb +0 -84
- data/lib/cuprum/collections/rspec/query_builder_contract.rb +0 -92
- data/lib/cuprum/collections/rspec/query_contract.rb +0 -650
- data/lib/cuprum/collections/rspec/querying_contract.rb +0 -298
- data/lib/cuprum/collections/rspec/repository_contract.rb +0 -235
- data/lib/cuprum/collections/rspec/update_one_command_contract.rb +0 -80
- data/lib/cuprum/collections/rspec/validate_one_command_contract.rb +0 -96
@@ -0,0 +1,605 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/collections/rspec/contracts'
|
4
|
+
|
5
|
+
module Cuprum::Collections::RSpec::Contracts
|
6
|
+
# Contracts for asserting on Repository objects.
|
7
|
+
module RepositoryContracts
|
8
|
+
# Contract validating the behavior of a Repository.
|
9
|
+
module ShouldBeARepositoryContract
|
10
|
+
extend RSpec::SleepingKingStudios::Contract
|
11
|
+
|
12
|
+
# @!method apply(example_group, abstract:, **options)
|
13
|
+
# Adds the contract to the example group.
|
14
|
+
#
|
15
|
+
# @param abstract [Boolean] if true, the repository is abstract and does
|
16
|
+
# not define certain methods. Defaults to false.
|
17
|
+
# @param example_group [RSpec::Core::ExampleGroup] the example group to
|
18
|
+
# which the contract is applied.
|
19
|
+
# @param options [Hash] additional options for the contract.
|
20
|
+
#
|
21
|
+
# @option options collection_class [Class, String] the expected class
|
22
|
+
# for created collections.
|
23
|
+
# @option options entity_class [Class, String] the expected entity
|
24
|
+
# class.
|
25
|
+
contract do |abstract: false, **options|
|
26
|
+
shared_examples 'should create the collection' do
|
27
|
+
let(:configured_collection_class) do
|
28
|
+
return super() if defined?(super())
|
29
|
+
|
30
|
+
configured = options[:collection_class]
|
31
|
+
|
32
|
+
# :nocov:
|
33
|
+
if configured.is_a?(String)
|
34
|
+
configured = Object.const_get(configured)
|
35
|
+
end
|
36
|
+
# :nocov:
|
37
|
+
|
38
|
+
configured
|
39
|
+
end
|
40
|
+
let(:configured_entity_class) do
|
41
|
+
return super() if defined?(super())
|
42
|
+
|
43
|
+
# :nocov:
|
44
|
+
expected =
|
45
|
+
if collection_options.key?(:entity_class)
|
46
|
+
collection_options[:entity_class]
|
47
|
+
elsif options.key?(:entity_class)
|
48
|
+
options[:entity_class]
|
49
|
+
else
|
50
|
+
qualified_name
|
51
|
+
.split('/')
|
52
|
+
.then { |ary| [*ary[0...-1], tools.str.singularize(ary[-1])] }
|
53
|
+
.map { |str| tools.str.camelize(str) }
|
54
|
+
.join('::')
|
55
|
+
end
|
56
|
+
# :nocov:
|
57
|
+
expected = Object.const_get(expected) if expected.is_a?(String)
|
58
|
+
|
59
|
+
expected
|
60
|
+
end
|
61
|
+
let(:configured_member_name) do
|
62
|
+
return super() if defined?(super())
|
63
|
+
|
64
|
+
tools.str.singularize(collection_name.to_s.split('/').last)
|
65
|
+
end
|
66
|
+
|
67
|
+
def tools
|
68
|
+
SleepingKingStudios::Tools::Toolbelt.instance
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should create the collection' do
|
72
|
+
create_collection(safe: false)
|
73
|
+
|
74
|
+
expect(repository.key?(qualified_name)).to be true
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should return the collection' do
|
78
|
+
collection = create_collection(safe: false)
|
79
|
+
|
80
|
+
expect(collection).to be repository[qualified_name]
|
81
|
+
end
|
82
|
+
|
83
|
+
it { expect(collection).to be_a configured_collection_class }
|
84
|
+
|
85
|
+
it 'should set the entity class' do
|
86
|
+
expect(collection.entity_class).to be == configured_entity_class
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should set the collection name' do
|
90
|
+
expect(collection.name).to be == collection_name.to_s
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should set the member name' do
|
94
|
+
expect(collection.singular_name).to be == configured_member_name
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should set the qualified name' do
|
98
|
+
expect(collection.qualified_name).to be == qualified_name
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should set the collection options' do
|
102
|
+
expect(collection).to have_attributes(
|
103
|
+
primary_key_name: primary_key_name,
|
104
|
+
primary_key_type: primary_key_type
|
105
|
+
)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe '#[]' do
|
110
|
+
let(:error_class) do
|
111
|
+
described_class::UndefinedCollectionError
|
112
|
+
end
|
113
|
+
let(:error_message) do
|
114
|
+
"repository does not define collection #{collection_name.inspect}"
|
115
|
+
end
|
116
|
+
|
117
|
+
it { expect(repository).to respond_to(:[]).with(1).argument }
|
118
|
+
|
119
|
+
describe 'with nil' do
|
120
|
+
let(:collection_name) { nil }
|
121
|
+
|
122
|
+
it 'should raise an exception' do
|
123
|
+
expect { repository[collection_name] }
|
124
|
+
.to raise_error(error_class, error_message)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe 'with an object' do
|
129
|
+
let(:collection_name) { Object.new.freeze }
|
130
|
+
|
131
|
+
it 'should raise an exception' do
|
132
|
+
expect { repository[collection_name] }
|
133
|
+
.to raise_error(error_class, error_message)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe 'with an invalid string' do
|
138
|
+
let(:collection_name) { 'invalid_name' }
|
139
|
+
|
140
|
+
it 'should raise an exception' do
|
141
|
+
expect { repository[collection_name] }
|
142
|
+
.to raise_error(error_class, error_message)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe 'with an invalid symbol' do
|
147
|
+
let(:collection_name) { :invalid_name }
|
148
|
+
|
149
|
+
it 'should raise an exception' do
|
150
|
+
expect { repository[collection_name] }
|
151
|
+
.to raise_error(error_class, error_message)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
wrap_context 'when the repository has many collections' do
|
156
|
+
describe 'with an invalid string' do
|
157
|
+
let(:collection_name) { 'invalid_name' }
|
158
|
+
|
159
|
+
it 'should raise an exception' do
|
160
|
+
expect { repository[collection_name] }
|
161
|
+
.to raise_error(error_class, error_message)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe 'with an invalid symbol' do
|
166
|
+
let(:collection_name) { :invalid_name }
|
167
|
+
|
168
|
+
it 'should raise an exception' do
|
169
|
+
expect { repository[collection_name] }
|
170
|
+
.to raise_error(error_class, error_message)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe 'with a valid string' do
|
175
|
+
let(:collection) { collections.values.first }
|
176
|
+
let(:collection_name) { collections.keys.first }
|
177
|
+
|
178
|
+
it { expect(repository[collection_name]).to be collection }
|
179
|
+
end
|
180
|
+
|
181
|
+
describe 'with a valid symbol' do
|
182
|
+
let(:collection) { collections.values.first }
|
183
|
+
let(:collection_name) { collections.keys.first.intern }
|
184
|
+
|
185
|
+
it { expect(repository[collection_name]).to be collection }
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
describe '#add' do
|
191
|
+
let(:error_class) do
|
192
|
+
described_class::InvalidCollectionError
|
193
|
+
end
|
194
|
+
let(:error_message) do
|
195
|
+
"#{collection.inspect} is not a valid collection"
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'should define the method' do
|
199
|
+
expect(repository)
|
200
|
+
.to respond_to(:add)
|
201
|
+
.with(1).argument
|
202
|
+
.and_keywords(:force)
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'should alias #add as #<<' do
|
206
|
+
expect(repository.method(:<<)).to be == repository.method(:add)
|
207
|
+
end
|
208
|
+
|
209
|
+
describe 'with nil' do
|
210
|
+
let(:collection) { nil }
|
211
|
+
|
212
|
+
it 'should raise an exception' do
|
213
|
+
expect { repository.add(collection) }
|
214
|
+
.to raise_error(error_class, error_message)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe 'with an object' do
|
219
|
+
let(:collection) { Object.new.freeze }
|
220
|
+
|
221
|
+
it 'should raise an exception' do
|
222
|
+
expect { repository.add(collection) }
|
223
|
+
.to raise_error(error_class, error_message)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
describe 'with a collection' do
|
228
|
+
it { expect(repository.add(example_collection)).to be repository }
|
229
|
+
|
230
|
+
it 'should add the collection to the repository' do
|
231
|
+
repository.add(example_collection)
|
232
|
+
|
233
|
+
expect(repository[example_collection.qualified_name])
|
234
|
+
.to be example_collection
|
235
|
+
end
|
236
|
+
|
237
|
+
describe 'with force: true' do
|
238
|
+
it 'should add the collection to the repository' do
|
239
|
+
repository.add(example_collection, force: true)
|
240
|
+
|
241
|
+
expect(repository[example_collection.qualified_name])
|
242
|
+
.to be example_collection
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
context 'when the collection already exists' do
|
247
|
+
let(:error_message) do
|
248
|
+
"collection #{example_collection.qualified_name} already exists"
|
249
|
+
end
|
250
|
+
|
251
|
+
before(:example) do
|
252
|
+
allow(repository)
|
253
|
+
.to receive(:key?)
|
254
|
+
.with(example_collection.qualified_name)
|
255
|
+
.and_return(true)
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'should raise an exception' do
|
259
|
+
expect { repository.add(example_collection) }
|
260
|
+
.to raise_error(
|
261
|
+
described_class::DuplicateCollectionError,
|
262
|
+
error_message
|
263
|
+
)
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'should not update the repository' do
|
267
|
+
begin
|
268
|
+
repository.add(example_collection)
|
269
|
+
rescue described_class::DuplicateCollectionError
|
270
|
+
# Do nothing.
|
271
|
+
end
|
272
|
+
|
273
|
+
expect { repository[example_collection.qualified_name] }
|
274
|
+
.to raise_error(
|
275
|
+
described_class::UndefinedCollectionError,
|
276
|
+
'repository does not define collection ' \
|
277
|
+
"#{example_collection.qualified_name.inspect}"
|
278
|
+
)
|
279
|
+
end
|
280
|
+
|
281
|
+
describe 'with force: true' do
|
282
|
+
it 'should add the collection to the repository' do
|
283
|
+
repository.add(example_collection, force: true)
|
284
|
+
|
285
|
+
expect(repository[example_collection.qualified_name])
|
286
|
+
.to be example_collection
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
describe '#create' do
|
294
|
+
let(:collection_name) { 'books' }
|
295
|
+
let(:qualified_name) { collection_name.to_s }
|
296
|
+
let(:primary_key_name) { 'id' }
|
297
|
+
let(:primary_key_type) { Integer }
|
298
|
+
let(:collection_options) { {} }
|
299
|
+
let(:collection) do
|
300
|
+
create_collection
|
301
|
+
|
302
|
+
repository[qualified_name]
|
303
|
+
end
|
304
|
+
let(:error_message) do
|
305
|
+
"#{described_class.name} is an abstract class. Define a " \
|
306
|
+
'repository subclass and implement the #build_collection method.'
|
307
|
+
end
|
308
|
+
|
309
|
+
def create_collection(force: false, safe: true, **options)
|
310
|
+
if safe
|
311
|
+
begin
|
312
|
+
repository.create(force: force, **collection_options, **options)
|
313
|
+
rescue StandardError
|
314
|
+
# Do nothing.
|
315
|
+
end
|
316
|
+
else
|
317
|
+
repository.create(force: force, **collection_options, **options)
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
it 'should define the method' do
|
322
|
+
expect(repository)
|
323
|
+
.to respond_to(:create)
|
324
|
+
.with(0).arguments
|
325
|
+
.and_keywords(:collection_name, :entity_class, :force)
|
326
|
+
.and_any_keywords
|
327
|
+
end
|
328
|
+
|
329
|
+
if abstract
|
330
|
+
it 'should raise an exception' do
|
331
|
+
expect { create_collection(safe: false) }
|
332
|
+
.to raise_error(
|
333
|
+
described_class::AbstractRepositoryError,
|
334
|
+
error_message
|
335
|
+
)
|
336
|
+
end
|
337
|
+
|
338
|
+
next
|
339
|
+
end
|
340
|
+
|
341
|
+
describe 'with entity_class: a Class' do
|
342
|
+
let(:entity_class) { Book }
|
343
|
+
let(:collection_options) do
|
344
|
+
super().merge(entity_class: entity_class)
|
345
|
+
end
|
346
|
+
|
347
|
+
include_examples 'should create the collection'
|
348
|
+
end
|
349
|
+
|
350
|
+
describe 'with entity_class: a String' do
|
351
|
+
let(:entity_class) { 'Book' }
|
352
|
+
let(:collection_options) do
|
353
|
+
super().merge(entity_class: entity_class)
|
354
|
+
end
|
355
|
+
|
356
|
+
include_examples 'should create the collection'
|
357
|
+
end
|
358
|
+
|
359
|
+
describe 'with name: a String' do
|
360
|
+
let(:collection_name) { 'books' }
|
361
|
+
let(:collection_options) do
|
362
|
+
super().merge(name: collection_name)
|
363
|
+
end
|
364
|
+
|
365
|
+
include_examples 'should create the collection'
|
366
|
+
end
|
367
|
+
|
368
|
+
describe 'with name: a Symbol' do
|
369
|
+
let(:collection_name) { :books }
|
370
|
+
let(:collection_options) do
|
371
|
+
super().merge(name: collection_name)
|
372
|
+
end
|
373
|
+
|
374
|
+
include_examples 'should create the collection'
|
375
|
+
end
|
376
|
+
|
377
|
+
describe 'with collection options' do
|
378
|
+
let(:primary_key_name) { 'uuid' }
|
379
|
+
let(:primary_key_type) { String }
|
380
|
+
let(:collection_options) do
|
381
|
+
super().merge(
|
382
|
+
name: collection_name,
|
383
|
+
primary_key_name: primary_key_name,
|
384
|
+
primary_key_type: primary_key_type
|
385
|
+
)
|
386
|
+
end
|
387
|
+
|
388
|
+
include_examples 'should create the collection'
|
389
|
+
end
|
390
|
+
|
391
|
+
context 'when the collection already exists' do
|
392
|
+
let(:collection_name) { 'books' }
|
393
|
+
let(:collection_options) do
|
394
|
+
super().merge(name: collection_name)
|
395
|
+
end
|
396
|
+
let(:error_message) do
|
397
|
+
"collection #{qualified_name} already exists"
|
398
|
+
end
|
399
|
+
|
400
|
+
before { create_collection(old: true) }
|
401
|
+
|
402
|
+
it 'should raise an exception' do
|
403
|
+
expect { create_collection(safe: false) }
|
404
|
+
.to raise_error(
|
405
|
+
described_class::DuplicateCollectionError,
|
406
|
+
error_message
|
407
|
+
)
|
408
|
+
end
|
409
|
+
|
410
|
+
it 'should not update the repository' do
|
411
|
+
create_collection(old: false)
|
412
|
+
|
413
|
+
collection = repository[qualified_name]
|
414
|
+
|
415
|
+
expect(collection.options[:old]).to be true
|
416
|
+
end
|
417
|
+
|
418
|
+
describe 'with force: true' do
|
419
|
+
it 'should update the repository' do
|
420
|
+
create_collection(force: true, old: false)
|
421
|
+
|
422
|
+
collection = repository[qualified_name]
|
423
|
+
|
424
|
+
expect(collection.options[:old]).to be false
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
describe '#find_or_create' do
|
431
|
+
let(:collection_name) { 'books' }
|
432
|
+
let(:qualified_name) { collection_name.to_s }
|
433
|
+
let(:primary_key_name) { 'id' }
|
434
|
+
let(:primary_key_type) { Integer }
|
435
|
+
let(:collection_options) { {} }
|
436
|
+
let(:collection) do
|
437
|
+
create_collection
|
438
|
+
|
439
|
+
repository[qualified_name]
|
440
|
+
end
|
441
|
+
let(:error_message) do
|
442
|
+
"#{described_class.name} is an abstract class. Define a " \
|
443
|
+
'repository subclass and implement the #build_collection method.'
|
444
|
+
end
|
445
|
+
|
446
|
+
def create_collection(safe: true, **options)
|
447
|
+
if safe
|
448
|
+
begin
|
449
|
+
repository.find_or_create(**collection_options, **options)
|
450
|
+
rescue StandardError
|
451
|
+
# Do nothing.
|
452
|
+
end
|
453
|
+
else
|
454
|
+
repository.find_or_create(**collection_options, **options)
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
it 'should define the method' do
|
459
|
+
expect(repository)
|
460
|
+
.to respond_to(:find_or_create)
|
461
|
+
.with(0).arguments
|
462
|
+
.and_keywords(:entity_class)
|
463
|
+
.and_any_keywords
|
464
|
+
end
|
465
|
+
|
466
|
+
if abstract
|
467
|
+
let(:collection_options) { { name: collection_name } }
|
468
|
+
|
469
|
+
it 'should raise an exception' do
|
470
|
+
expect { create_collection(safe: false) }
|
471
|
+
.to raise_error(
|
472
|
+
described_class::AbstractRepositoryError,
|
473
|
+
error_message
|
474
|
+
)
|
475
|
+
end
|
476
|
+
|
477
|
+
next
|
478
|
+
end
|
479
|
+
|
480
|
+
describe 'with entity_class: a Class' do
|
481
|
+
let(:entity_class) { Book }
|
482
|
+
let(:collection_options) do
|
483
|
+
super().merge(entity_class: entity_class)
|
484
|
+
end
|
485
|
+
|
486
|
+
include_examples 'should create the collection'
|
487
|
+
end
|
488
|
+
|
489
|
+
describe 'with entity_class: a String' do
|
490
|
+
let(:entity_class) { Book }
|
491
|
+
let(:collection_options) do
|
492
|
+
super().merge(entity_class: entity_class)
|
493
|
+
end
|
494
|
+
|
495
|
+
include_examples 'should create the collection'
|
496
|
+
end
|
497
|
+
|
498
|
+
describe 'with name: a String' do
|
499
|
+
let(:collection_name) { 'books' }
|
500
|
+
let(:collection_options) do
|
501
|
+
super().merge(name: collection_name)
|
502
|
+
end
|
503
|
+
|
504
|
+
include_examples 'should create the collection'
|
505
|
+
end
|
506
|
+
|
507
|
+
describe 'with name: a Symbol' do
|
508
|
+
let(:collection_name) { :books }
|
509
|
+
let(:collection_options) do
|
510
|
+
super().merge(name: collection_name)
|
511
|
+
end
|
512
|
+
|
513
|
+
include_examples 'should create the collection'
|
514
|
+
end
|
515
|
+
|
516
|
+
describe 'with collection options' do
|
517
|
+
let(:primary_key_name) { 'uuid' }
|
518
|
+
let(:primary_key_type) { String }
|
519
|
+
let(:qualified_name) { 'spec/scoped_books' }
|
520
|
+
let(:collection_options) do
|
521
|
+
super().merge(
|
522
|
+
name: collection_name,
|
523
|
+
primary_key_name: primary_key_name,
|
524
|
+
primary_key_type: primary_key_type,
|
525
|
+
qualified_name: qualified_name
|
526
|
+
)
|
527
|
+
end
|
528
|
+
|
529
|
+
include_examples 'should create the collection'
|
530
|
+
end
|
531
|
+
|
532
|
+
context 'when the collection already exists' do
|
533
|
+
let(:collection_name) { 'books' }
|
534
|
+
let(:collection_options) do
|
535
|
+
super().merge(name: collection_name)
|
536
|
+
end
|
537
|
+
let(:error_message) do
|
538
|
+
"collection #{qualified_name} already exists"
|
539
|
+
end
|
540
|
+
|
541
|
+
before { create_collection(old: true) }
|
542
|
+
|
543
|
+
describe 'with non-matching options' do
|
544
|
+
it 'should raise an exception' do
|
545
|
+
expect { create_collection(old: false, safe: false) }
|
546
|
+
.to raise_error(
|
547
|
+
described_class::DuplicateCollectionError,
|
548
|
+
error_message
|
549
|
+
)
|
550
|
+
end
|
551
|
+
|
552
|
+
it 'should not update the repository' do
|
553
|
+
create_collection(old: false)
|
554
|
+
|
555
|
+
collection = repository[qualified_name]
|
556
|
+
|
557
|
+
expect(collection.options[:old]).to be true
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
561
|
+
describe 'with matching options' do
|
562
|
+
it 'should return the collection' do
|
563
|
+
collection = create_collection(old: true)
|
564
|
+
|
565
|
+
expect(collection.options[:old]).to be true
|
566
|
+
end
|
567
|
+
end
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
describe '#key?' do
|
572
|
+
it { expect(repository).to respond_to(:key?).with(1).argument }
|
573
|
+
|
574
|
+
it { expect(repository.key?(nil)).to be false }
|
575
|
+
|
576
|
+
it { expect(repository.key?(Object.new.freeze)).to be false }
|
577
|
+
|
578
|
+
it { expect(repository.key?('invalid_name')).to be false }
|
579
|
+
|
580
|
+
it { expect(repository.key?(:invalid_name)).to be false }
|
581
|
+
|
582
|
+
wrap_context 'when the repository has many collections' do
|
583
|
+
it { expect(repository.key?('invalid_name')).to be false }
|
584
|
+
|
585
|
+
it { expect(repository.key?(:invalid_name)).to be false }
|
586
|
+
|
587
|
+
it { expect(repository.key?(collections.keys.first)).to be true }
|
588
|
+
|
589
|
+
it 'should include the key' do
|
590
|
+
expect(repository.key?(collections.keys.first.intern)).to be true
|
591
|
+
end
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
describe '#keys' do
|
596
|
+
include_examples 'should define reader', :keys, []
|
597
|
+
|
598
|
+
wrap_context 'when the repository has many collections' do
|
599
|
+
it { expect(repository.keys).to be == collections.keys }
|
600
|
+
end
|
601
|
+
end
|
602
|
+
end
|
603
|
+
end
|
604
|
+
end
|
605
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/collections/rspec'
|
4
|
+
|
5
|
+
module Cuprum::Collections::RSpec
|
6
|
+
# Namespace for RSpec contract objects.
|
7
|
+
module Contracts
|
8
|
+
autoload :AssociationContracts,
|
9
|
+
'cuprum/collections/rspec/contracts/association_contracts'
|
10
|
+
autoload :Basic,
|
11
|
+
'cuprum/collections/rspec/contracts/basic'
|
12
|
+
autoload :CollectionContracts,
|
13
|
+
'cuprum/collections/rspec/contracts/collection_contracts'
|
14
|
+
autoload :CommandContracts,
|
15
|
+
'cuprum/collections/rspec/contracts/command_contracts'
|
16
|
+
autoload :QueryContracts,
|
17
|
+
'cuprum/collections/rspec/contracts/query_contracts'
|
18
|
+
autoload :RelationContracts,
|
19
|
+
'cuprum/collections/rspec/contracts/relation_contracts'
|
20
|
+
autoload :RepositoryContracts,
|
21
|
+
'cuprum/collections/rspec/contracts/repository_contracts'
|
22
|
+
end
|
23
|
+
end
|