cuprum-collections 0.5.0 → 0.6.0.rc.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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +51 -0
  3. data/README.md +1 -1
  4. data/config/locales/en.rb +18 -0
  5. data/lib/cuprum/collections/adaptable/collection.rb +18 -0
  6. data/lib/cuprum/collections/adaptable/command.rb +22 -0
  7. data/lib/cuprum/collections/adaptable/commands/abstract_assign_one.rb +27 -0
  8. data/lib/cuprum/collections/adaptable/commands/abstract_build_one.rb +25 -0
  9. data/lib/cuprum/collections/adaptable/commands/abstract_validate_one.rb +35 -0
  10. data/lib/cuprum/collections/adaptable/commands.rb +15 -0
  11. data/lib/cuprum/collections/adaptable/query.rb +64 -0
  12. data/lib/cuprum/collections/adaptable.rb +13 -0
  13. data/lib/cuprum/collections/adapter.rb +300 -0
  14. data/lib/cuprum/collections/adapters/data_adapter.rb +82 -0
  15. data/lib/cuprum/collections/adapters/entity_adapter.rb +76 -0
  16. data/lib/cuprum/collections/adapters/hash_adapter.rb +48 -0
  17. data/lib/cuprum/collections/adapters.rb +14 -0
  18. data/lib/cuprum/collections/basic/collection.rb +2 -20
  19. data/lib/cuprum/collections/basic/commands/destroy_one.rb +1 -1
  20. data/lib/cuprum/collections/basic/commands/find_many.rb +0 -31
  21. data/lib/cuprum/collections/basic/commands/find_matching.rb +0 -94
  22. data/lib/cuprum/collections/basic/commands/find_one.rb +0 -18
  23. data/lib/cuprum/collections/basic/commands/insert_one.rb +1 -1
  24. data/lib/cuprum/collections/basic/commands/update_one.rb +1 -1
  25. data/lib/cuprum/collections/basic/scopes/criteria_scope.rb +36 -21
  26. data/lib/cuprum/collections/basic.rb +6 -5
  27. data/lib/cuprum/collections/collection.rb +6 -0
  28. data/lib/cuprum/collections/collection_command.rb +1 -1
  29. data/lib/cuprum/collections/commands/abstract_find_many.rb +40 -3
  30. data/lib/cuprum/collections/commands/abstract_find_matching.rb +102 -0
  31. data/lib/cuprum/collections/commands/abstract_find_one.rb +23 -1
  32. data/lib/cuprum/collections/commands/associations/find_many.rb +1 -3
  33. data/lib/cuprum/collections/commands/associations/require_many.rb +1 -1
  34. data/lib/cuprum/collections/commands/find_one_matching.rb +10 -10
  35. data/lib/cuprum/collections/commands/query_command.rb +6 -4
  36. data/lib/cuprum/collections/commands/upsert.rb +0 -2
  37. data/lib/cuprum/collections/constraints/order/attributes_array.rb +5 -4
  38. data/lib/cuprum/collections/constraints/order/attributes_hash.rb +5 -4
  39. data/lib/cuprum/collections/constraints/order/sort_direction.rb +2 -2
  40. data/lib/cuprum/collections/constraints/ordering.rb +11 -9
  41. data/lib/cuprum/collections/constraints/query_hash.rb +2 -2
  42. data/lib/cuprum/collections/errors/abstract_find_error.rb +101 -23
  43. data/lib/cuprum/collections/errors/extra_attributes.rb +3 -3
  44. data/lib/cuprum/collections/errors/failed_validation.rb +3 -3
  45. data/lib/cuprum/collections/errors/missing_default_contract.rb +12 -4
  46. data/lib/cuprum/collections/queries.rb +4 -0
  47. data/lib/cuprum/collections/relation.rb +0 -2
  48. data/lib/cuprum/collections/relations/parameters.rb +120 -68
  49. data/lib/cuprum/collections/repository.rb +71 -6
  50. data/lib/cuprum/collections/rspec/contracts/query_contracts.rb +23 -4
  51. data/lib/cuprum/collections/rspec/contracts/repository_contracts.rb +18 -0
  52. data/lib/cuprum/collections/rspec/contracts/scope_contracts.rb +51 -0
  53. data/lib/cuprum/collections/rspec/contracts/scopes/builder_contracts.rb +10 -0
  54. data/lib/cuprum/collections/rspec/contracts/scopes/composition_contracts.rb +8 -0
  55. data/lib/cuprum/collections/rspec/contracts/scopes/criteria_contracts.rb +18 -366
  56. data/lib/cuprum/collections/rspec/contracts/scopes/logical_contracts.rb +30 -0
  57. data/lib/cuprum/collections/rspec/contracts/scopes.rb +2 -0
  58. data/lib/cuprum/collections/rspec/contracts.rb +2 -10
  59. data/lib/cuprum/collections/rspec/deferred/adapter_examples.rb +1077 -0
  60. data/lib/cuprum/collections/rspec/deferred/collection_examples.rb +27 -7
  61. data/lib/cuprum/collections/rspec/deferred/commands/assign_one_examples.rb +4 -4
  62. data/lib/cuprum/collections/rspec/deferred/commands/build_one_examples.rb +2 -2
  63. data/lib/cuprum/collections/rspec/deferred/commands/destroy_one_examples.rb +2 -2
  64. data/lib/cuprum/collections/rspec/deferred/commands/find_many_examples.rb +5 -5
  65. data/lib/cuprum/collections/rspec/deferred/commands/find_matching_examples.rb +45 -12
  66. data/lib/cuprum/collections/rspec/deferred/commands/find_one_examples.rb +2 -2
  67. data/lib/cuprum/collections/rspec/deferred/commands/insert_one_examples.rb +1 -1
  68. data/lib/cuprum/collections/rspec/deferred/commands/update_one_examples.rb +1 -1
  69. data/lib/cuprum/collections/rspec/deferred/query_examples.rb +930 -0
  70. data/lib/cuprum/collections/rspec/deferred/relation_examples.rb +48 -17
  71. data/lib/cuprum/collections/rspec/deferred/repository_examples.rb +961 -0
  72. data/lib/cuprum/collections/rspec/deferred/scope_examples.rb +598 -0
  73. data/lib/cuprum/collections/rspec/deferred/scopes/all_examples.rb +391 -0
  74. data/lib/cuprum/collections/rspec/deferred/scopes/builder_examples.rb +857 -0
  75. data/lib/cuprum/collections/rspec/deferred/scopes/composition_examples.rb +93 -0
  76. data/lib/cuprum/collections/rspec/deferred/scopes/conjunction_examples.rb +438 -0
  77. data/lib/cuprum/collections/rspec/deferred/scopes/criteria_examples.rb +1941 -0
  78. data/lib/cuprum/collections/rspec/deferred/scopes/disjunction_examples.rb +415 -0
  79. data/lib/cuprum/collections/rspec/deferred/scopes/none_examples.rb +385 -0
  80. data/lib/cuprum/collections/rspec/deferred/scopes/parser_examples.rb +740 -0
  81. data/lib/cuprum/collections/rspec/deferred/scopes.rb +8 -0
  82. data/lib/cuprum/collections/scope.rb +2 -2
  83. data/lib/cuprum/collections/scopes/container.rb +5 -4
  84. data/lib/cuprum/collections/scopes/criteria/parser.rb +24 -48
  85. data/lib/cuprum/collections/scopes/criteria.rb +7 -6
  86. data/lib/cuprum/collections/version.rb +3 -3
  87. data/lib/cuprum/collections.rb +5 -1
  88. metadata +48 -11
  89. data/lib/cuprum/collections/rspec/contracts/association_contracts.rb +0 -2127
  90. data/lib/cuprum/collections/rspec/contracts/basic.rb +0 -11
  91. data/lib/cuprum/collections/rspec/contracts/collection_contracts.rb +0 -387
  92. data/lib/cuprum/collections/rspec/contracts/command_contracts.rb +0 -169
  93. data/lib/cuprum/collections/rspec/contracts/relation_contracts.rb +0 -1264
@@ -1,2127 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'cuprum/collections/rspec/contracts'
4
- require 'cuprum/collections/rspec/contracts/relation_contracts'
5
-
6
- module Cuprum::Collections::RSpec::Contracts
7
- # Contracts for asserting on Association objects.
8
- #
9
- # @deprecated 0.5.0 Association contracts are deprecated. Use
10
- # Deferred::AssociationExamples instead.
11
- module AssociationContracts
12
- # Contract validating the behavior of an Association.
13
- module ShouldBeAnAssociationContract
14
- extend RSpec::SleepingKingStudios::Contract
15
-
16
- # @!method apply(example_group)
17
- # Adds the contract to the example group.
18
- #
19
- # @param example_group [RSpec::Core::ExampleGroup] the example group to
20
- # which the contract is applied.
21
- contract do
22
- include Cuprum::Collections::RSpec::Contracts::RelationContracts
23
-
24
- example_class 'Author'
25
- example_class 'Chapter'
26
- example_class 'Writer'
27
-
28
- include_contract 'should be a relation'
29
-
30
- include_contract 'should define primary keys'
31
-
32
- describe '#build_entities_query' do
33
- it 'should define the method' do
34
- expect(association)
35
- .to respond_to(:build_entities_query)
36
- .with_unlimited_arguments
37
- .and_keywords(:allow_nil, :deduplicate)
38
- end
39
- end
40
-
41
- describe '#build_keys_query' do
42
- it 'should define the method' do
43
- expect(association)
44
- .to respond_to(:build_keys_query)
45
- .with_unlimited_arguments
46
- .and_keywords(:allow_nil, :deduplicate)
47
- end
48
- end
49
-
50
- describe '#foreign_key_name' do
51
- include_examples 'should define reader', :foreign_key_name
52
- end
53
-
54
- describe '#inverse' do
55
- include_examples 'should define reader', :inverse, nil
56
-
57
- context 'when initialized with inverse: value' do
58
- let(:inverse) { described_class.new(name: 'authors') }
59
- let(:constructor_options) do
60
- super().merge(inverse:)
61
- end
62
-
63
- it { expect(subject.inverse).to be == inverse }
64
- end
65
-
66
- context 'with a copy with assigned inverse' do
67
- subject { super().with_inverse(new_inverse) }
68
-
69
- let(:new_inverse) { described_class.new(name: 'chapters') }
70
-
71
- it { expect(subject.inverse).to be == new_inverse }
72
-
73
- context 'when initialized with inverse: value' do
74
- let(:inverse) { described_class.new(name: 'authors') }
75
- let(:constructor_options) do
76
- super().merge(inverse:)
77
- end
78
-
79
- it { expect(subject.inverse).to be == new_inverse }
80
- end
81
- end
82
- end
83
-
84
- describe '#inverse_class' do
85
- include_examples 'should define reader', :inverse_class, nil
86
-
87
- context 'when initialized with inverse: value' do
88
- let(:inverse) { described_class.new(name: 'authors') }
89
- let(:constructor_options) do
90
- super().merge(inverse:)
91
- end
92
-
93
- it { expect(subject.inverse_class).to be == Author }
94
-
95
- context 'when initialized with inverse_class: a Class' do
96
- let(:constructor_options) do
97
- super().merge(inverse_class: Writer)
98
- end
99
-
100
- it { expect(subject.inverse_class).to be == Writer }
101
- end
102
-
103
- context 'when initialized with inverse_class: a String' do
104
- let(:constructor_options) do
105
- super().merge(inverse_class: 'Writer')
106
- end
107
-
108
- it { expect(subject.inverse_class).to be == Writer }
109
- end
110
- end
111
-
112
- context 'when initialized with inverse_class: a Class' do
113
- let(:constructor_options) do
114
- super().merge(inverse_class: Writer)
115
- end
116
-
117
- it { expect(subject.inverse_class).to be == Writer }
118
- end
119
-
120
- context 'when initialized with inverse_class: a String' do
121
- let(:constructor_options) do
122
- super().merge(inverse_class: 'Writer')
123
- end
124
-
125
- it { expect(subject.inverse_class).to be == Writer }
126
- end
127
-
128
- context 'with a copy with assigned inverse' do
129
- subject do
130
- super().tap(&:inverse_class).with_inverse(new_inverse)
131
- end
132
-
133
- let(:new_inverse) { described_class.new(name: 'chapters') }
134
-
135
- it { expect(subject.inverse_class).to be == Chapter }
136
-
137
- context 'when initialized with inverse_class: a Class' do
138
- let(:constructor_options) do
139
- super().merge(inverse_class: Writer)
140
- end
141
-
142
- it { expect(subject.inverse_class).to be == Writer }
143
- end
144
-
145
- context 'when initialized with inverse_class: a String' do
146
- let(:constructor_options) do
147
- super().merge(inverse_class: 'Writer')
148
- end
149
-
150
- it { expect(subject.inverse_class).to be == Writer }
151
- end
152
-
153
- context 'when initialized with inverse: value' do
154
- let(:inverse) { described_class.new(name: 'authors') }
155
- let(:constructor_options) do
156
- super().merge(inverse:)
157
- end
158
-
159
- it { expect(subject.inverse_class).to be == Chapter }
160
- end
161
- end
162
- end
163
-
164
- describe '#inverse_key_name' do
165
- include_examples 'should define reader', :inverse_key_name
166
- end
167
-
168
- describe '#inverse_name' do
169
- include_examples 'should define reader', :inverse_name, nil
170
-
171
- context 'when initialized with inverse: value' do
172
- let(:inverse) { described_class.new(name: 'authors') }
173
- let(:constructor_options) do
174
- super().merge(inverse:)
175
- end
176
-
177
- it { expect(subject.inverse_name).to be == 'authors' }
178
-
179
- context 'when initialized with inverse_name: a String' do
180
- let(:constructor_options) do
181
- super().merge(inverse_name: 'writers')
182
- end
183
-
184
- it { expect(subject.inverse_name).to be == 'writers' }
185
- end
186
-
187
- context 'when initialized with inverse_name: a Symbol' do
188
- let(:constructor_options) do
189
- super().merge(inverse_name: :writers)
190
- end
191
-
192
- it { expect(subject.inverse_name).to be == 'writers' }
193
- end
194
- end
195
-
196
- context 'when initialized with inverse_name: a String' do
197
- let(:constructor_options) do
198
- super().merge(inverse_name: 'writers')
199
- end
200
-
201
- it { expect(subject.inverse_name).to be == 'writers' }
202
- end
203
-
204
- context 'when initialized with inverse_name: a Symbol' do
205
- let(:constructor_options) do
206
- super().merge(inverse_name: :writers)
207
- end
208
-
209
- it { expect(subject.inverse_name).to be == 'writers' }
210
- end
211
-
212
- context 'with a copy with assigned inverse' do
213
- subject do
214
- super().tap(&:inverse_name).with_inverse(new_inverse)
215
- end
216
-
217
- let(:new_inverse) { described_class.new(name: 'chapters') }
218
-
219
- it { expect(subject.inverse_name).to be == 'chapters' }
220
-
221
- context 'when initialized with inverse: value' do
222
- let(:inverse) { described_class.new(name: 'authors') }
223
- let(:constructor_options) do
224
- super().merge(inverse:)
225
- end
226
-
227
- it { expect(subject.inverse_name).to be == 'chapters' }
228
- end
229
-
230
- context 'when initialized with inverse_name: a String' do
231
- let(:constructor_options) do
232
- super().merge(inverse_name: 'writers')
233
- end
234
-
235
- it { expect(subject.inverse_name).to be == 'writers' }
236
- end
237
-
238
- context 'when initialized with inverse_name: a Symbol' do
239
- let(:constructor_options) do
240
- super().merge(inverse_name: :writers)
241
- end
242
-
243
- it { expect(subject.inverse_name).to be == 'writers' }
244
- end
245
- end
246
- end
247
-
248
- describe '#map_entities_to_keys' do
249
- it 'should define the method' do
250
- expect(subject)
251
- .to respond_to(:map_entities_to_keys)
252
- .with_unlimited_arguments
253
- .and_keywords(:allow_nil, :deduplicate, :strict)
254
- end
255
- end
256
-
257
- describe '#options' do
258
- context 'when initialized with inverse: value' do
259
- let(:inverse) { described_class.new(name: 'authors') }
260
- let(:constructor_options) do
261
- super().merge(inverse:)
262
- end
263
-
264
- it { expect(subject.options).to be == {} }
265
- end
266
- end
267
-
268
- describe '#plural?' do
269
- include_examples 'should define predicate', :plural?
270
- end
271
-
272
- describe '#primary_key_query?' do
273
- include_examples 'should define predicate', :primary_key_query?
274
- end
275
-
276
- describe '#query_key_name' do
277
- include_examples 'should define reader', :query_key_name
278
- end
279
-
280
- describe '#singular_inverse_name' do
281
- include_examples 'should define reader', :singular_inverse_name, nil
282
-
283
- context 'when initialized with inverse: value' do
284
- let(:inverse) { described_class.new(name: 'authors') }
285
- let(:constructor_options) do
286
- super().merge(inverse:)
287
- end
288
-
289
- it { expect(subject.singular_inverse_name).to be == 'author' }
290
-
291
- context 'when initialized with singular_inverse_name: a String' do
292
- let(:singular_inverse_name) { 'writer' }
293
- let(:constructor_options) do
294
- super().merge(singular_inverse_name:)
295
- end
296
-
297
- it { expect(subject.singular_inverse_name).to be == 'writer' }
298
- end
299
-
300
- context 'when initialized with singular_inverse_name: a Symbol' do
301
- let(:singular_inverse_name) { :writer }
302
- let(:constructor_options) do
303
- super().merge(singular_inverse_name:)
304
- end
305
-
306
- it { expect(subject.singular_inverse_name).to be == 'writer' }
307
- end
308
- end
309
-
310
- context 'when initialized with inverse_name: value' do
311
- let(:inverse_name) { 'authors' }
312
- let(:constructor_options) do
313
- super().merge(inverse_name:)
314
- end
315
-
316
- it { expect(subject.singular_inverse_name).to be == 'author' }
317
-
318
- context 'when initialized with singular_inverse_name: a String' do
319
- let(:singular_inverse_name) { 'writer' }
320
- let(:constructor_options) do
321
- super().merge(singular_inverse_name:)
322
- end
323
-
324
- it { expect(subject.singular_inverse_name).to be == 'writer' }
325
- end
326
-
327
- context 'when initialized with singular_inverse_name: a Symbol' do
328
- let(:singular_inverse_name) { :writer }
329
- let(:constructor_options) do
330
- super().merge(singular_inverse_name:)
331
- end
332
-
333
- it { expect(subject.singular_inverse_name).to be == 'writer' }
334
- end
335
- end
336
-
337
- context 'when initialized with singular_inverse_name: a String' do
338
- let(:singular_inverse_name) { 'writer' }
339
- let(:constructor_options) do
340
- super().merge(singular_inverse_name:)
341
- end
342
-
343
- it { expect(subject.singular_inverse_name).to be == 'writer' }
344
- end
345
-
346
- context 'when initialized with singular_inverse_name: a Symbol' do
347
- let(:singular_inverse_name) { :writer }
348
- let(:constructor_options) do
349
- super().merge(singular_inverse_name:)
350
- end
351
-
352
- it { expect(subject.singular_inverse_name).to be == 'writer' }
353
- end
354
-
355
- context 'with a copy with assigned inverse' do
356
- subject do
357
- super().tap(&:singular_inverse_name).with_inverse(new_inverse)
358
- end
359
-
360
- let(:new_inverse) { described_class.new(name: 'chapters') }
361
-
362
- it { expect(subject.singular_inverse_name).to be == 'chapter' }
363
-
364
- context 'when initialized with inverse: value' do
365
- let(:inverse) { described_class.new(name: 'authors') }
366
- let(:constructor_options) do
367
- super().merge(inverse:)
368
- end
369
-
370
- it { expect(subject.singular_inverse_name).to be == 'chapter' }
371
- end
372
-
373
- context 'when initialized with inverse_name: value' do
374
- let(:inverse_name) { 'authors' }
375
- let(:constructor_options) do
376
- super().merge(inverse_name:)
377
- end
378
-
379
- it { expect(subject.singular_inverse_name).to be == 'chapter' }
380
-
381
- context 'when initialized with singular_inverse_name: a String' do
382
- let(:singular_inverse_name) { 'writer' }
383
- let(:constructor_options) do
384
- super().merge(singular_inverse_name:)
385
- end
386
-
387
- it { expect(subject.singular_inverse_name).to be == 'writer' }
388
- end
389
-
390
- context 'when initialized with singular_inverse_name: a Symbol' do
391
- let(:singular_inverse_name) { :writer }
392
- let(:constructor_options) do
393
- super().merge(singular_inverse_name:)
394
- end
395
-
396
- it { expect(subject.singular_inverse_name).to be == 'writer' }
397
- end
398
- end
399
-
400
- context 'when initialized with singular_inverse_name: a String' do
401
- let(:singular_inverse_name) { 'writer' }
402
- let(:constructor_options) do
403
- super().merge(singular_inverse_name:)
404
- end
405
-
406
- it { expect(subject.singular_inverse_name).to be == 'writer' }
407
- end
408
-
409
- context 'when initialized with singular_inverse_name: a Symbol' do
410
- let(:singular_inverse_name) { :writer }
411
- let(:constructor_options) do
412
- super().merge(singular_inverse_name:)
413
- end
414
-
415
- it { expect(subject.singular_inverse_name).to be == 'writer' }
416
- end
417
- end
418
- end
419
-
420
- describe '#singular?' do
421
- include_examples 'should define predicate', :singular?
422
- end
423
-
424
- describe '#with_inverse' do
425
- it 'should define the method' do
426
- expect(association).to respond_to(:with_inverse).with(1).argument
427
- end
428
-
429
- context 'with a copy with assigned inverse' do
430
- let(:new_inverse) { described_class.new(name: 'chapters') }
431
- let(:copy) { subject.with_inverse(new_inverse) }
432
-
433
- it { expect(copy).to be_a described_class }
434
-
435
- it { expect(copy.inverse).to be == new_inverse }
436
-
437
- it { expect(subject.inverse).to be nil }
438
- end
439
- end
440
- end
441
- end
442
-
443
- # Contract validating the behavior of a BelongsToAssociation.
444
- module ShouldBeABelongsToAssociationContract
445
- extend RSpec::SleepingKingStudios::Contract
446
-
447
- # @!method apply(example_group)
448
- # Adds the contract to the example group.
449
- #
450
- # @param example_group [RSpec::Core::ExampleGroup] the example group to
451
- # which the contract is applied.
452
- contract do
453
- include Cuprum::Collections::RSpec::Contracts::RelationContracts
454
-
455
- include_contract 'should be an association'
456
-
457
- describe '#build_entities_query' do
458
- let(:key) { subject.foreign_key_name }
459
- let(:entities) { [] }
460
- let(:options) { {} }
461
- let(:query) do
462
- association.build_entities_query(*entities, **options)
463
- end
464
- let(:evaluated) do
465
- query.call(Spec::QueryBuilder.new)
466
- end
467
-
468
- example_class 'Spec::Entity' do |klass|
469
- klass.define_method(:initialize) do |**attributes|
470
- attributes.each do |key, value|
471
- instance_variable_set(:"@#{key}", value)
472
- end
473
- end
474
-
475
- klass.attr_reader :book_id
476
- end
477
-
478
- example_class 'Spec::QueryBuilder' do |klass|
479
- klass.define_method(:one_of) { |values| { 'one_of' => values } }
480
- end
481
-
482
- describe 'with no entities' do
483
- let(:entities) { [] }
484
-
485
- it { expect(query).to be_a Proc }
486
-
487
- it { expect(evaluated).to be == {} }
488
- end
489
-
490
- describe 'with one nil entity' do
491
- let(:entities) { [nil] }
492
-
493
- it { expect(evaluated).to be == {} }
494
- end
495
-
496
- describe 'with one invalid entity' do
497
- let(:entities) { [Object.new.freeze] }
498
- let(:error_message) do
499
- "undefined method :[] or :#{key} for #{entities.first.inspect}"
500
- end
501
-
502
- it 'should raise an exception' do
503
- expect { association.build_entities_query(*entities) }
504
- .to raise_error ArgumentError, error_message
505
- end
506
- end
507
-
508
- describe 'with one entity that responds to #[] and key: nil' do
509
- let(:entities) { [{ key => nil }] }
510
-
511
- it { expect(evaluated).to be == {} }
512
-
513
- describe 'with allow_nil: true' do
514
- let(:options) { super().merge(allow_nil: true) }
515
-
516
- it { expect(evaluated).to be == { 'id' => nil } }
517
- end
518
- end
519
-
520
- describe 'with one entity that responds to #[] and key: value' do
521
- let(:entities) { [{ key => 0 }] }
522
-
523
- it { expect(evaluated).to be == { 'id' => 0 } }
524
- end
525
-
526
- describe 'with one entity that responds to #id and key: nil' do
527
- let(:entities) { [Spec::Entity.new(key => nil)] }
528
-
529
- it { expect(evaluated).to be == {} }
530
-
531
- describe 'with allow_nil: true' do
532
- let(:options) { super().merge(allow_nil: true) }
533
-
534
- it { expect(evaluated).to be == { 'id' => nil } }
535
- end
536
- end
537
-
538
- describe 'with one entity that responds to #id and key: value' do
539
- let(:entities) { [Spec::Entity.new(key => 0)] }
540
-
541
- it { expect(evaluated).to be == { 'id' => 0 } }
542
- end
543
-
544
- describe 'with multiple entities' do
545
- let(:entities) do
546
- [
547
- Spec::Entity.new(key => 0),
548
- Spec::Entity.new(key => 1),
549
- Spec::Entity.new(key => 2)
550
- ]
551
- end
552
- let(:expected) do
553
- { 'id' => { 'one_of' => [0, 1, 2] } }
554
- end
555
-
556
- it { expect(evaluated).to be == expected }
557
- end
558
-
559
- describe 'with multiple entities including nil' do
560
- let(:entities) do
561
- [
562
- Spec::Entity.new(key => 0),
563
- nil,
564
- Spec::Entity.new(key => 1),
565
- nil,
566
- Spec::Entity.new(key => 2)
567
- ]
568
- end
569
- let(:expected) do
570
- { 'id' => { 'one_of' => [0, 1, 2] } }
571
- end
572
-
573
- it { expect(evaluated).to be == expected }
574
- end
575
-
576
- describe 'with multiple entities including nil ids' do
577
- let(:entities) do
578
- [
579
- Spec::Entity.new(key => 0),
580
- Spec::Entity.new(key => nil),
581
- Spec::Entity.new(key => 1),
582
- Spec::Entity.new(key => nil),
583
- Spec::Entity.new(key => 2)
584
- ]
585
- end
586
- let(:expected) do
587
- { 'id' => { 'one_of' => [0, 1, 2] } }
588
- end
589
-
590
- it { expect(evaluated).to be == expected }
591
-
592
- describe 'with allow_nil: true' do
593
- let(:options) { super().merge(allow_nil: true) }
594
- let(:expected) do
595
- { 'id' => { 'one_of' => [0, nil, 1, 2] } }
596
- end
597
-
598
- it { expect(evaluated).to be == expected }
599
- end
600
- end
601
-
602
- describe 'with multiple entities including duplicate ids' do
603
- let(:entities) do
604
- [
605
- Spec::Entity.new(key => 0),
606
- Spec::Entity.new(key => 1),
607
- Spec::Entity.new(key => 0),
608
- Spec::Entity.new(key => 1),
609
- Spec::Entity.new(key => 2)
610
- ]
611
- end
612
- let(:expected) do
613
- { 'id' => { 'one_of' => [0, 1, 2] } }
614
- end
615
-
616
- it { expect(evaluated).to be == expected }
617
-
618
- describe 'with deduplicate: false' do
619
- let(:options) { super().merge(deduplicate: false) }
620
- let(:expected) do
621
- { 'id' => { 'one_of' => [0, 1, 0, 1, 2] } }
622
- end
623
-
624
- it { expect(evaluated).to be == expected }
625
- end
626
- end
627
- end
628
-
629
- describe '#build_keys_query' do
630
- let(:keys) { [] }
631
- let(:options) { {} }
632
- let(:query) do
633
- association.build_keys_query(*keys, **options)
634
- end
635
- let(:evaluated) do
636
- query.call(Spec::QueryBuilder.new)
637
- end
638
-
639
- example_class 'Spec::QueryBuilder' do |klass|
640
- klass.define_method(:one_of) { |values| { 'one_of' => values } }
641
- end
642
-
643
- describe 'with no keys' do
644
- let(:keys) { [] }
645
-
646
- it { expect(query).to be_a Proc }
647
-
648
- it { expect(evaluated).to be == {} }
649
- end
650
-
651
- describe 'with one nil key' do
652
- let(:keys) { [nil] }
653
-
654
- it { expect(evaluated).to be == {} }
655
-
656
- describe 'with allow_nil: true' do
657
- let(:options) { { allow_nil: true } }
658
-
659
- it { expect(evaluated).to be == { 'id' => nil } }
660
- end
661
- end
662
-
663
- describe 'with one non-nil key' do
664
- let(:keys) { [0] }
665
-
666
- it { expect(evaluated).to be == { 'id' => 0 } }
667
- end
668
-
669
- describe 'with many keys' do
670
- let(:keys) { [0, 1, 2] }
671
- let(:expected) { { 'id' => { 'one_of' => keys } } }
672
-
673
- it { expect(evaluated).to be == expected }
674
- end
675
-
676
- describe 'with many keys including nil' do
677
- let(:keys) { [0, nil, 2] }
678
- let(:expected) { { 'id' => { 'one_of' => [0, 2] } } }
679
-
680
- it { expect(evaluated).to be == expected }
681
-
682
- describe 'with allow_nil: true' do
683
- let(:options) { { allow_nil: true } }
684
- let(:expected) do
685
- { 'id' => { 'one_of' => [0, nil, 2] } }
686
- end
687
-
688
- it { expect(evaluated).to be == expected }
689
- end
690
- end
691
-
692
- describe 'with many non-unique keys' do
693
- let(:keys) { [0, 1, 2, 1, 2] }
694
- let(:expected) { { 'id' => { 'one_of' => keys.uniq } } }
695
-
696
- it { expect(evaluated).to be == expected }
697
-
698
- describe 'with deduplicate: false' do
699
- let(:options) { super().merge(deduplicate: false) }
700
- let(:expected) do
701
- { 'id' => { 'one_of' => [0, 1, 2, 1, 2] } }
702
- end
703
-
704
- it { expect(evaluated).to be == expected }
705
- end
706
- end
707
- end
708
-
709
- describe '#foreign_key_name' do
710
- let(:expected) { "#{tools.str.singularize(name)}_id" }
711
-
712
- def tools
713
- SleepingKingStudios::Tools::Toolbelt.instance
714
- end
715
-
716
- it { expect(subject.foreign_key_name).to be == expected }
717
-
718
- context 'when initialized with foreign_key_name: a String' do
719
- let(:foreign_key_name) { 'writer_id' }
720
- let(:constructor_options) do
721
- super().merge(foreign_key_name:)
722
- end
723
-
724
- it { expect(subject.foreign_key_name).to be == 'writer_id' }
725
- end
726
-
727
- context 'when initialized with foreign_key_name: a String' do
728
- let(:foreign_key_name) { :writer_id }
729
- let(:constructor_options) do
730
- super().merge(foreign_key_name:)
731
- end
732
-
733
- it { expect(subject.foreign_key_name).to be == 'writer_id' }
734
- end
735
-
736
- context 'when initialized with singular_name: value' do
737
- let(:singular_name) { 'author' }
738
- let(:constructor_options) do
739
- super().merge(singular_name:)
740
- end
741
-
742
- it { expect(subject.foreign_key_name).to be == 'author_id' }
743
-
744
- context 'when initialized with foreign_key_name: a String' do
745
- let(:foreign_key_name) { 'writer_id' }
746
- let(:constructor_options) do
747
- super().merge(foreign_key_name:)
748
- end
749
-
750
- it { expect(subject.foreign_key_name).to be == 'writer_id' }
751
- end
752
-
753
- context 'when initialized with foreign_key_name: a String' do
754
- let(:foreign_key_name) { :writer_id }
755
- let(:constructor_options) do
756
- super().merge(foreign_key_name:)
757
- end
758
-
759
- it { expect(subject.foreign_key_name).to be == 'writer_id' }
760
- end
761
- end
762
- end
763
-
764
- describe '#inverse_key_name' do
765
- let(:expected) { "#{tools.str.singularize(name)}_id" }
766
-
767
- def tools
768
- SleepingKingStudios::Tools::Toolbelt.instance
769
- end
770
-
771
- it { expect(subject.inverse_key_name).to be == expected }
772
-
773
- context 'when initialized with foreign_key_name: a String' do
774
- let(:foreign_key_name) { 'writer_id' }
775
- let(:constructor_options) do
776
- super().merge(foreign_key_name:)
777
- end
778
-
779
- it { expect(subject.inverse_key_name).to be == 'writer_id' }
780
- end
781
-
782
- context 'when initialized with foreign_key_name: a String' do
783
- let(:foreign_key_name) { :writer_id }
784
- let(:constructor_options) do
785
- super().merge(foreign_key_name:)
786
- end
787
-
788
- it { expect(subject.inverse_key_name).to be == 'writer_id' }
789
- end
790
-
791
- context 'when initialized with singular_name: value' do
792
- let(:singular_name) { 'author' }
793
- let(:constructor_options) do
794
- super().merge(singular_name:)
795
- end
796
-
797
- it { expect(subject.inverse_key_name).to be == 'author_id' }
798
-
799
- context 'when initialized with foreign_key_name: a String' do
800
- let(:foreign_key_name) { 'writer_id' }
801
- let(:constructor_options) do
802
- super().merge(foreign_key_name:)
803
- end
804
-
805
- it { expect(subject.inverse_key_name).to be == 'writer_id' }
806
- end
807
-
808
- context 'when initialized with foreign_key_name: a String' do
809
- let(:foreign_key_name) { :writer_id }
810
- let(:constructor_options) do
811
- super().merge(foreign_key_name:)
812
- end
813
-
814
- it { expect(subject.inverse_key_name).to be == 'writer_id' }
815
- end
816
- end
817
- end
818
-
819
- describe '#map_entities_to_keys' do
820
- let(:key) { subject.foreign_key_name }
821
- let(:entities) { [] }
822
- let(:options) { {} }
823
- let(:keys) do
824
- association.map_entities_to_keys(*entities, **options)
825
- end
826
-
827
- example_class 'Spec::Entity' do |klass|
828
- klass.define_method(:initialize) do |**attributes|
829
- attributes.each do |key, value|
830
- instance_variable_set(:"@#{key}", value)
831
- end
832
- end
833
-
834
- klass.attr_reader :book_id
835
- end
836
-
837
- describe 'with no entities' do
838
- let(:entities) { [] }
839
-
840
- it { expect(keys).to be == [] }
841
- end
842
-
843
- describe 'with one nil entity' do
844
- let(:entities) { [nil] }
845
-
846
- it { expect(keys).to be == [] }
847
- end
848
-
849
- describe 'with one invalid entity' do
850
- let(:entities) { [Object.new.freeze] }
851
- let(:error_message) do
852
- "undefined method :[] or :#{key} for #{entities.first.inspect}"
853
- end
854
-
855
- it 'should raise an exception' do
856
- expect { association.map_entities_to_keys(*entities) }
857
- .to raise_error ArgumentError, error_message
858
- end
859
-
860
- describe 'with strict: false' do
861
- it 'should raise an exception' do
862
- expect do
863
- association.map_entities_to_keys(*entities, strict: false)
864
- end
865
- .to raise_error ArgumentError, error_message
866
- end
867
- end
868
- end
869
-
870
- describe 'with one Integer' do
871
- let(:entities) { [0] }
872
- let(:error_message) do
873
- "undefined method :[] or :#{key} for #{entities.first.inspect}"
874
- end
875
-
876
- it 'should raise an exception' do
877
- expect { association.map_entities_to_keys(*entities) }
878
- .to raise_error ArgumentError, error_message
879
- end
880
-
881
- describe 'with strict: false' do
882
- it 'should raise an exception' do
883
- expect(
884
- association.map_entities_to_keys(*entities, strict: false)
885
- )
886
- .to be == entities
887
- end
888
- end
889
-
890
- context 'when initialized with primary_key_type: String' do
891
- let(:constructor_options) do
892
- super().merge(primary_key_type: String)
893
- end
894
-
895
- describe 'with strict: false' do
896
- it 'should raise an exception' do
897
- expect do
898
- association.map_entities_to_keys(*entities, strict: false)
899
- end
900
- .to raise_error ArgumentError, error_message
901
- end
902
- end
903
- end
904
- end
905
-
906
- describe 'with one String' do
907
- let(:entities) { %w[0] }
908
- let(:error_message) do
909
- "undefined method :[] or :#{key} for #{entities.first.inspect}"
910
- end
911
-
912
- it 'should raise an exception' do
913
- expect { association.map_entities_to_keys(*entities) }
914
- .to raise_error ArgumentError, error_message
915
- end
916
-
917
- describe 'with strict: false' do
918
- it 'should raise an exception' do
919
- expect do
920
- association.map_entities_to_keys(*entities, strict: false)
921
- end
922
- .to raise_error ArgumentError, error_message
923
- end
924
- end
925
-
926
- context 'when initialized with primary_key_type: String' do
927
- let(:constructor_options) do
928
- super().merge(primary_key_type: String)
929
- end
930
-
931
- describe 'with strict: false' do
932
- it 'should raise an exception' do
933
- expect(
934
- association.map_entities_to_keys(*entities, strict: false)
935
- )
936
- .to be == entities
937
- end
938
- end
939
- end
940
- end
941
-
942
- describe 'with one entity that responds to #[] and key: nil' do
943
- let(:entities) { [{ key => nil }] }
944
-
945
- it { expect(keys).to be == [] }
946
-
947
- describe 'with allow_nil: true' do
948
- let(:options) { super().merge(allow_nil: true) }
949
-
950
- it { expect(keys).to be == [nil] }
951
- end
952
- end
953
-
954
- describe 'with one entity that responds to #[] and key: value' do
955
- let(:entities) { [{ key => 0 }] }
956
-
957
- it { expect(keys).to be == [0] }
958
- end
959
-
960
- describe 'with one entity that responds to #id and key: nil' do
961
- let(:entities) { [Spec::Entity.new(key => nil)] }
962
-
963
- it { expect(keys).to be == [] }
964
-
965
- describe 'with allow_nil: true' do
966
- let(:options) { super().merge(allow_nil: true) }
967
-
968
- it { expect(keys).to be == [nil] }
969
- end
970
- end
971
-
972
- describe 'with one entity that responds to #id and key: value' do
973
- let(:entities) { [Spec::Entity.new(key => 0)] }
974
-
975
- it { expect(keys).to be == [0] }
976
- end
977
-
978
- describe 'with multiple entities' do
979
- let(:entities) do
980
- [
981
- Spec::Entity.new(key => 0),
982
- Spec::Entity.new(key => 1),
983
- Spec::Entity.new(key => 2)
984
- ]
985
- end
986
-
987
- it { expect(keys).to be == [0, 1, 2] }
988
- end
989
-
990
- describe 'with multiple entities including nil' do
991
- let(:entities) do
992
- [
993
- Spec::Entity.new(key => 0),
994
- nil,
995
- Spec::Entity.new(key => 1),
996
- nil,
997
- Spec::Entity.new(key => 2)
998
- ]
999
- end
1000
-
1001
- it { expect(keys).to be == [0, 1, 2] }
1002
- end
1003
-
1004
- describe 'with multiple entities including nil ids' do
1005
- let(:entities) do
1006
- [
1007
- Spec::Entity.new(key => 0),
1008
- Spec::Entity.new(key => nil),
1009
- Spec::Entity.new(key => 1),
1010
- Spec::Entity.new(key => nil),
1011
- Spec::Entity.new(key => 2)
1012
- ]
1013
- end
1014
-
1015
- it { expect(keys).to be == [0, 1, 2] }
1016
-
1017
- describe 'with allow_nil: true' do
1018
- let(:options) { super().merge(allow_nil: true) }
1019
-
1020
- it { expect(keys).to be == [0, nil, 1, 2] }
1021
- end
1022
- end
1023
-
1024
- describe 'with multiple entities including duplicate ids' do
1025
- let(:entities) do
1026
- [
1027
- Spec::Entity.new(key => 0),
1028
- Spec::Entity.new(key => 1),
1029
- Spec::Entity.new(key => 0),
1030
- Spec::Entity.new(key => 1),
1031
- Spec::Entity.new(key => 2)
1032
- ]
1033
- end
1034
-
1035
- it { expect(keys).to be == [0, 1, 2] }
1036
-
1037
- describe 'with deduplicate: false' do
1038
- let(:options) { super().merge(deduplicate: false) }
1039
-
1040
- it { expect(keys).to be == [0, 1, 0, 1, 2] }
1041
- end
1042
- end
1043
-
1044
- describe 'with multiple Integers' do
1045
- let(:entities) { [0, 1, 2] }
1046
- let(:error_message) do
1047
- "undefined method :[] or :#{key} for #{entities.first.inspect}"
1048
- end
1049
-
1050
- it 'should raise an exception' do
1051
- expect { association.map_entities_to_keys(*entities) }
1052
- .to raise_error ArgumentError, error_message
1053
- end
1054
-
1055
- describe 'with strict: false' do
1056
- it 'should raise an exception' do
1057
- expect(
1058
- association.map_entities_to_keys(*entities, strict: false)
1059
- )
1060
- .to be == entities
1061
- end
1062
- end
1063
-
1064
- context 'when initialized with primary_key_type: String' do
1065
- let(:constructor_options) do
1066
- super().merge(primary_key_type: String)
1067
- end
1068
-
1069
- describe 'with strict: false' do
1070
- it 'should raise an exception' do
1071
- expect do
1072
- association.map_entities_to_keys(*entities, strict: false)
1073
- end
1074
- .to raise_error ArgumentError, error_message
1075
- end
1076
- end
1077
- end
1078
- end
1079
-
1080
- describe 'with multiple Strings' do
1081
- let(:entities) { %w[0 1 2] }
1082
- let(:error_message) do
1083
- "undefined method :[] or :#{key} for #{entities.first.inspect}"
1084
- end
1085
-
1086
- it 'should raise an exception' do
1087
- expect { association.map_entities_to_keys(*entities) }
1088
- .to raise_error ArgumentError, error_message
1089
- end
1090
-
1091
- describe 'with strict: false' do
1092
- it 'should raise an exception' do
1093
- expect do
1094
- association.map_entities_to_keys(*entities, strict: false)
1095
- end
1096
- .to raise_error ArgumentError, error_message
1097
- end
1098
- end
1099
-
1100
- context 'when initialized with primary_key_type: String' do
1101
- let(:constructor_options) do
1102
- super().merge(primary_key_type: String)
1103
- end
1104
-
1105
- describe 'with strict: false' do
1106
- it 'should raise an exception' do
1107
- expect(
1108
- association.map_entities_to_keys(*entities, strict: false)
1109
- )
1110
- .to be == entities
1111
- end
1112
- end
1113
- end
1114
- end
1115
- end
1116
-
1117
- describe '#primary_key_query?' do
1118
- it { expect(subject.primary_key_query?).to be true }
1119
- end
1120
-
1121
- describe '#query_key_name' do
1122
- it { expect(subject.query_key_name).to be == 'id' }
1123
-
1124
- context 'when initialized with primary_key_name: a String' do
1125
- let(:primary_key_name) { 'uuid' }
1126
- let(:constructor_options) do
1127
- super().merge(primary_key_name:)
1128
- end
1129
-
1130
- it { expect(subject.query_key_name).to be == primary_key_name }
1131
- end
1132
-
1133
- context 'when initialized with primary_key_name: a Symbol' do
1134
- let(:primary_key_name) { :uuid }
1135
- let(:constructor_options) do
1136
- super().merge(primary_key_name:)
1137
- end
1138
-
1139
- it 'should set the primary key name' do
1140
- expect(subject.query_key_name).to be == primary_key_name.to_s
1141
- end
1142
- end
1143
- end
1144
- end
1145
- end
1146
-
1147
- # Contract validating the behavior of a HasAssociation.
1148
- module ShouldBeAHasAssociationContract
1149
- extend RSpec::SleepingKingStudios::Contract
1150
-
1151
- # @!method apply(example_group)
1152
- # Adds the contract to the example group.
1153
- #
1154
- # @param example_group [RSpec::Core::ExampleGroup] the example group to
1155
- # which the contract is applied.
1156
- contract do
1157
- include Cuprum::Collections::RSpec::Contracts::RelationContracts
1158
-
1159
- include_contract 'should be an association'
1160
-
1161
- describe '#build_entities_query' do
1162
- let(:key) { subject.primary_key_name }
1163
- let(:entities) { [] }
1164
- let(:options) { {} }
1165
- let(:query) do
1166
- association.build_entities_query(*entities, **options)
1167
- end
1168
- let(:evaluated) do
1169
- query.call(Spec::QueryBuilder.new)
1170
- end
1171
-
1172
- example_class 'Spec::Entity' do |klass|
1173
- klass.define_method(:initialize) do |**attributes|
1174
- attributes.each do |key, value|
1175
- instance_variable_set(:"@#{key}", value)
1176
- end
1177
- end
1178
-
1179
- klass.attr_reader :id
1180
- end
1181
-
1182
- example_class 'Spec::QueryBuilder' do |klass|
1183
- klass.define_method(:one_of) { |values| { 'one_of' => values } }
1184
- end
1185
-
1186
- context 'when the foreign key name is blank' do
1187
- let(:error_message) do
1188
- "foreign key name can't be blank"
1189
- end
1190
-
1191
- it 'should raise an exception' do
1192
- expect { association.build_entities_query(*entities) }
1193
- .to raise_error ArgumentError, error_message
1194
- end
1195
- end
1196
-
1197
- context 'when initialized with foreign_key_name: value' do
1198
- let(:foreign_key_name) { 'author_id' }
1199
- let(:constructor_options) do
1200
- super().merge(foreign_key_name:)
1201
- end
1202
-
1203
- describe 'with no entities' do
1204
- let(:entities) { [] }
1205
-
1206
- it { expect(query).to be_a Proc }
1207
-
1208
- it { expect(evaluated).to be == {} }
1209
- end
1210
-
1211
- describe 'with one nil entity' do
1212
- let(:entities) { [nil] }
1213
-
1214
- it { expect(evaluated).to be == {} }
1215
- end
1216
-
1217
- describe 'with one invalid entity' do
1218
- let(:entities) { [Object.new.freeze] }
1219
- let(:error_message) do
1220
- "undefined method :[] or :#{key} for #{entities.first.inspect}"
1221
- end
1222
-
1223
- it 'should raise an exception' do
1224
- expect { association.build_entities_query(*entities) }
1225
- .to raise_error ArgumentError, error_message
1226
- end
1227
- end
1228
-
1229
- describe 'with one entity that responds to #[] and key: nil' do
1230
- let(:entities) { [{ key => nil }] }
1231
-
1232
- it { expect(evaluated).to be == {} }
1233
-
1234
- describe 'with allow_nil: true' do
1235
- let(:options) { super().merge(allow_nil: true) }
1236
-
1237
- it { expect(evaluated).to be == { 'author_id' => nil } }
1238
- end
1239
- end
1240
-
1241
- describe 'with one entity that responds to #[] and key: value' do
1242
- let(:entities) { [{ key => 0 }] }
1243
-
1244
- it { expect(evaluated).to be == { 'author_id' => 0 } }
1245
- end
1246
-
1247
- describe 'with one entity that responds to #id and key: nil' do
1248
- let(:entities) { [Spec::Entity.new(key => nil)] }
1249
-
1250
- it { expect(evaluated).to be == {} }
1251
-
1252
- describe 'with allow_nil: true' do
1253
- let(:options) { super().merge(allow_nil: true) }
1254
-
1255
- it { expect(evaluated).to be == { 'author_id' => nil } }
1256
- end
1257
- end
1258
-
1259
- describe 'with one entity that responds to #id and key: value' do
1260
- let(:entities) { [Spec::Entity.new(key => 0)] }
1261
-
1262
- it { expect(evaluated).to be == { 'author_id' => 0 } }
1263
- end
1264
-
1265
- describe 'with multiple entities' do
1266
- let(:entities) do
1267
- [
1268
- Spec::Entity.new(key => 0),
1269
- Spec::Entity.new(key => 1),
1270
- Spec::Entity.new(key => 2)
1271
- ]
1272
- end
1273
- let(:expected) do
1274
- { 'author_id' => { 'one_of' => [0, 1, 2] } }
1275
- end
1276
-
1277
- it { expect(evaluated).to be == expected }
1278
- end
1279
-
1280
- describe 'with multiple entities including nil' do
1281
- let(:entities) do
1282
- [
1283
- Spec::Entity.new(key => 0),
1284
- nil,
1285
- Spec::Entity.new(key => 1),
1286
- nil,
1287
- Spec::Entity.new(key => 2)
1288
- ]
1289
- end
1290
- let(:expected) do
1291
- { 'author_id' => { 'one_of' => [0, 1, 2] } }
1292
- end
1293
-
1294
- it { expect(evaluated).to be == expected }
1295
- end
1296
-
1297
- describe 'with multiple entities including nil ids' do
1298
- let(:entities) do
1299
- [
1300
- Spec::Entity.new(key => 0),
1301
- Spec::Entity.new(key => nil),
1302
- Spec::Entity.new(key => 1),
1303
- Spec::Entity.new(key => nil),
1304
- Spec::Entity.new(key => 2)
1305
- ]
1306
- end
1307
- let(:expected) do
1308
- { 'author_id' => { 'one_of' => [0, 1, 2] } }
1309
- end
1310
-
1311
- it { expect(evaluated).to be == expected }
1312
-
1313
- describe 'with allow_nil: true' do
1314
- let(:options) { super().merge(allow_nil: true) }
1315
- let(:expected) do
1316
- { 'author_id' => { 'one_of' => [0, nil, 1, 2] } }
1317
- end
1318
-
1319
- it { expect(evaluated).to be == expected }
1320
- end
1321
- end
1322
-
1323
- describe 'with multiple entities including duplicate ids' do
1324
- let(:entities) do
1325
- [
1326
- Spec::Entity.new(key => 0),
1327
- Spec::Entity.new(key => 1),
1328
- Spec::Entity.new(key => 0),
1329
- Spec::Entity.new(key => 1),
1330
- Spec::Entity.new(key => 2)
1331
- ]
1332
- end
1333
- let(:expected) do
1334
- { 'author_id' => { 'one_of' => [0, 1, 2] } }
1335
- end
1336
-
1337
- it { expect(evaluated).to be == expected }
1338
-
1339
- describe 'with deduplicate: false' do
1340
- let(:options) { super().merge(deduplicate: false) }
1341
- let(:expected) do
1342
- { 'author_id' => { 'one_of' => [0, 1, 0, 1, 2] } }
1343
- end
1344
-
1345
- it { expect(evaluated).to be == expected }
1346
- end
1347
- end
1348
- end
1349
- end
1350
-
1351
- describe '#build_keys_query' do
1352
- let(:keys) { [] }
1353
- let(:options) { {} }
1354
- let(:query) do
1355
- association.build_keys_query(*keys, **options)
1356
- end
1357
- let(:evaluated) do
1358
- query.call(Spec::QueryBuilder.new)
1359
- end
1360
-
1361
- example_class 'Spec::QueryBuilder' do |klass|
1362
- klass.define_method(:one_of) { |values| { 'one_of' => values } }
1363
- end
1364
-
1365
- context 'when the foreign key name is blank' do
1366
- let(:error_message) do
1367
- "foreign key name can't be blank"
1368
- end
1369
-
1370
- it 'should raise an exception' do
1371
- expect { association.build_keys_query(*keys) }
1372
- .to raise_error ArgumentError, error_message
1373
- end
1374
- end
1375
-
1376
- context 'when initialized with foreign_key_name: value' do
1377
- let(:foreign_key_name) { 'author_id' }
1378
- let(:constructor_options) do
1379
- super().merge(foreign_key_name:)
1380
- end
1381
-
1382
- describe 'with no keys' do
1383
- let(:keys) { [] }
1384
-
1385
- it { expect(query).to be_a Proc }
1386
-
1387
- it { expect(evaluated).to be == {} }
1388
- end
1389
-
1390
- describe 'with one nil key' do
1391
- let(:keys) { [nil] }
1392
-
1393
- it { expect(evaluated).to be == {} }
1394
-
1395
- describe 'with allow_nil: true' do
1396
- let(:options) { { allow_nil: true } }
1397
-
1398
- it { expect(evaluated).to be == { 'author_id' => nil } }
1399
- end
1400
- end
1401
-
1402
- describe 'with one non-nil key' do
1403
- let(:keys) { [0] }
1404
-
1405
- it { expect(evaluated).to be == { 'author_id' => 0 } }
1406
- end
1407
-
1408
- describe 'with many keys' do
1409
- let(:keys) { [0, 1, 2] }
1410
- let(:expected) { { 'author_id' => { 'one_of' => keys } } }
1411
-
1412
- it { expect(evaluated).to be == expected }
1413
- end
1414
-
1415
- describe 'with many keys including nil' do
1416
- let(:keys) { [0, nil, 2] }
1417
- let(:expected) { { 'author_id' => { 'one_of' => [0, 2] } } }
1418
-
1419
- it { expect(evaluated).to be == expected }
1420
-
1421
- describe 'with allow_nil: true' do
1422
- let(:options) { { allow_nil: true } }
1423
- let(:expected) do
1424
- { 'author_id' => { 'one_of' => [0, nil, 2] } }
1425
- end
1426
-
1427
- it { expect(evaluated).to be == expected }
1428
- end
1429
- end
1430
-
1431
- describe 'with many non-unique keys' do
1432
- let(:keys) { [0, 1, 2, 1, 2] }
1433
- let(:expected) { { 'author_id' => { 'one_of' => keys.uniq } } }
1434
-
1435
- it { expect(evaluated).to be == expected }
1436
-
1437
- describe 'with deduplicate: false' do
1438
- let(:options) { super().merge(deduplicate: false) }
1439
- let(:expected) do
1440
- { 'author_id' => { 'one_of' => [0, 1, 2, 1, 2] } }
1441
- end
1442
-
1443
- it { expect(evaluated).to be == expected }
1444
- end
1445
- end
1446
- end
1447
- end
1448
-
1449
- describe '#foreign_key_name' do
1450
- it { expect(subject.foreign_key_name).to be nil }
1451
-
1452
- context 'when initialized with foreign_key_name: a String' do
1453
- let(:foreign_key_name) { 'writer_id' }
1454
- let(:constructor_options) do
1455
- super().merge(foreign_key_name:)
1456
- end
1457
-
1458
- it { expect(subject.foreign_key_name).to be == 'writer_id' }
1459
- end
1460
-
1461
- context 'when initialized with foreign_key_name: a String' do
1462
- let(:foreign_key_name) { :writer_id }
1463
- let(:constructor_options) do
1464
- super().merge(foreign_key_name:)
1465
- end
1466
-
1467
- it { expect(subject.foreign_key_name).to be == 'writer_id' }
1468
- end
1469
-
1470
- context 'when initialized with inverse: value' do
1471
- let(:inverse) { described_class.new(name: 'authors') }
1472
- let(:constructor_options) do
1473
- super().merge(inverse:)
1474
- end
1475
-
1476
- it { expect(subject.foreign_key_name).to be == 'author_id' }
1477
-
1478
- context 'when initialized with foreign_key_name: a String' do
1479
- let(:foreign_key_name) { 'writer_id' }
1480
- let(:constructor_options) do
1481
- super().merge(foreign_key_name:)
1482
- end
1483
-
1484
- it { expect(subject.foreign_key_name).to be == 'writer_id' }
1485
- end
1486
-
1487
- context 'when initialized with foreign_key_name: a String' do
1488
- let(:foreign_key_name) { :writer_id }
1489
- let(:constructor_options) do
1490
- super().merge(foreign_key_name:)
1491
- end
1492
-
1493
- it { expect(subject.foreign_key_name).to be == 'writer_id' }
1494
- end
1495
-
1496
- context 'when initialized with inverse_name: value' do
1497
- let(:inverse_name) { 'writers' }
1498
- let(:constructor_options) do
1499
- super().merge(inverse_name:)
1500
- end
1501
-
1502
- it { expect(subject.foreign_key_name).to be == 'author_id' }
1503
- end
1504
-
1505
- context 'when initialized with singular_inverse_name: value' do
1506
- let(:singular_inverse_name) { 'writer' }
1507
- let(:constructor_options) do
1508
- super().merge(singular_inverse_name:)
1509
- end
1510
-
1511
- it { expect(subject.foreign_key_name).to be == 'writer_id' }
1512
- end
1513
- end
1514
-
1515
- context 'when initialized with inverse_name: value' do
1516
- let(:inverse_name) { 'authors' }
1517
- let(:constructor_options) do
1518
- super().merge(inverse_name:)
1519
- end
1520
-
1521
- it { expect(subject.foreign_key_name).to be == 'author_id' }
1522
-
1523
- context 'when initialized with foreign_key_name: a String' do
1524
- let(:foreign_key_name) { 'writer_id' }
1525
- let(:constructor_options) do
1526
- super().merge(foreign_key_name:)
1527
- end
1528
-
1529
- it { expect(subject.foreign_key_name).to be == 'writer_id' }
1530
- end
1531
-
1532
- context 'when initialized with foreign_key_name: a String' do
1533
- let(:foreign_key_name) { :writer_id }
1534
- let(:constructor_options) do
1535
- super().merge(foreign_key_name:)
1536
- end
1537
-
1538
- it { expect(subject.foreign_key_name).to be == 'writer_id' }
1539
- end
1540
- end
1541
-
1542
- context 'when initialized with singular_inverse_name: value' do
1543
- let(:singular_inverse_name) { 'author' }
1544
- let(:constructor_options) do
1545
- super().merge(singular_inverse_name:)
1546
- end
1547
-
1548
- it { expect(subject.foreign_key_name).to be == 'author_id' }
1549
-
1550
- context 'when initialized with foreign_key_name: a String' do
1551
- let(:foreign_key_name) { 'writer_id' }
1552
- let(:constructor_options) do
1553
- super().merge(foreign_key_name:)
1554
- end
1555
-
1556
- it { expect(subject.foreign_key_name).to be == 'writer_id' }
1557
- end
1558
-
1559
- context 'when initialized with foreign_key_name: a String' do
1560
- let(:foreign_key_name) { :writer_id }
1561
- let(:constructor_options) do
1562
- super().merge(foreign_key_name:)
1563
- end
1564
-
1565
- it { expect(subject.foreign_key_name).to be == 'writer_id' }
1566
- end
1567
- end
1568
-
1569
- context 'with a copy with assigned inverse' do
1570
- subject do
1571
- super().tap(&:foreign_key_name).with_inverse(new_inverse)
1572
- end
1573
-
1574
- let(:new_inverse) { described_class.new(name: 'chapters') }
1575
-
1576
- it { expect(subject.foreign_key_name).to be == 'chapter_id' }
1577
-
1578
- context 'when initialized with foreign_key_name: a String' do
1579
- let(:foreign_key_name) { 'writer_id' }
1580
- let(:constructor_options) do
1581
- super().merge(foreign_key_name:)
1582
- end
1583
-
1584
- it { expect(subject.foreign_key_name).to be == 'writer_id' }
1585
- end
1586
-
1587
- context 'when initialized with foreign_key_name: a String' do
1588
- let(:foreign_key_name) { :writer_id }
1589
- let(:constructor_options) do
1590
- super().merge(foreign_key_name:)
1591
- end
1592
-
1593
- it { expect(subject.foreign_key_name).to be == 'writer_id' }
1594
- end
1595
-
1596
- context 'when initialized with inverse: value' do
1597
- let(:inverse) { described_class.new(name: 'authors') }
1598
- let(:constructor_options) do
1599
- super().merge(inverse:)
1600
- end
1601
-
1602
- it { expect(subject.foreign_key_name).to be == 'chapter_id' }
1603
- end
1604
-
1605
- context 'when initialized with inverse_name: value' do
1606
- let(:inverse_name) { 'authors' }
1607
- let(:constructor_options) do
1608
- super().merge(inverse_name:)
1609
- end
1610
-
1611
- it { expect(subject.foreign_key_name).to be == 'chapter_id' }
1612
- end
1613
-
1614
- context 'when initialized with singular_inverse_name: value' do
1615
- let(:singular_inverse_name) { 'author' }
1616
- let(:constructor_options) do
1617
- super().merge(singular_inverse_name:)
1618
- end
1619
-
1620
- it { expect(subject.foreign_key_name).to be == 'author_id' }
1621
- end
1622
- end
1623
- end
1624
-
1625
- describe '#inverse_key_name' do
1626
- it { expect(subject.inverse_key_name).to be == 'id' }
1627
-
1628
- context 'when initialized with primary_key_name: a String' do
1629
- let(:primary_key_name) { 'uuid' }
1630
- let(:constructor_options) do
1631
- super().merge(primary_key_name:)
1632
- end
1633
-
1634
- it { expect(subject.inverse_key_name).to be == primary_key_name }
1635
- end
1636
-
1637
- context 'when initialized with primary_key_name: a Symbol' do
1638
- let(:primary_key_name) { :uuid }
1639
- let(:constructor_options) do
1640
- super().merge(primary_key_name:)
1641
- end
1642
-
1643
- it 'should set the primary key name' do
1644
- expect(subject.inverse_key_name).to be == primary_key_name.to_s
1645
- end
1646
- end
1647
- end
1648
-
1649
- describe '#map_entities_to_keys' do
1650
- let(:key) { subject.primary_key_name }
1651
- let(:entities) { [] }
1652
- let(:options) { {} }
1653
- let(:keys) { subject.map_entities_to_keys(*entities, **options) }
1654
-
1655
- example_class 'Spec::Entity' do |klass|
1656
- klass.define_method(:initialize) do |**attributes|
1657
- attributes.each do |key, value|
1658
- instance_variable_set(:"@#{key}", value)
1659
- end
1660
- end
1661
-
1662
- klass.attr_reader :id
1663
- end
1664
-
1665
- describe 'with no entities' do
1666
- let(:entities) { [] }
1667
-
1668
- it { expect(keys).to be == [] }
1669
- end
1670
-
1671
- describe 'with one nil entity' do
1672
- let(:entities) { [nil] }
1673
-
1674
- it { expect(keys).to be == [] }
1675
- end
1676
-
1677
- describe 'with one invalid entity' do
1678
- let(:entities) { [Object.new.freeze] }
1679
- let(:error_message) do
1680
- "undefined method :[] or :#{key} for #{entities.first.inspect}"
1681
- end
1682
-
1683
- it 'should raise an exception' do
1684
- expect { association.map_entities_to_keys(*entities) }
1685
- .to raise_error ArgumentError, error_message
1686
- end
1687
- end
1688
-
1689
- describe 'with one Integer' do
1690
- let(:entities) { [0] }
1691
- let(:error_message) do
1692
- "undefined method :[] or :#{key} for #{entities.first.inspect}"
1693
- end
1694
-
1695
- it 'should raise an exception' do
1696
- expect { association.map_entities_to_keys(*entities) }
1697
- .to raise_error ArgumentError, error_message
1698
- end
1699
-
1700
- describe 'with strict: false' do
1701
- it 'should raise an exception' do
1702
- expect(
1703
- association.map_entities_to_keys(*entities, strict: false)
1704
- )
1705
- .to be == entities
1706
- end
1707
- end
1708
-
1709
- context 'when initialized with primary_key_type: String' do
1710
- let(:constructor_options) do
1711
- super().merge(primary_key_type: String)
1712
- end
1713
-
1714
- describe 'with strict: false' do
1715
- it 'should raise an exception' do
1716
- expect do
1717
- association.map_entities_to_keys(*entities, strict: false)
1718
- end
1719
- .to raise_error ArgumentError, error_message
1720
- end
1721
- end
1722
- end
1723
- end
1724
-
1725
- describe 'with one String' do
1726
- let(:entities) { %w[0] }
1727
- let(:error_message) do
1728
- "undefined method :[] or :#{key} for #{entities.first.inspect}"
1729
- end
1730
-
1731
- it 'should raise an exception' do
1732
- expect { association.map_entities_to_keys(*entities) }
1733
- .to raise_error ArgumentError, error_message
1734
- end
1735
-
1736
- describe 'with strict: false' do
1737
- it 'should raise an exception' do
1738
- expect do
1739
- association.map_entities_to_keys(*entities, strict: false)
1740
- end
1741
- .to raise_error ArgumentError, error_message
1742
- end
1743
- end
1744
-
1745
- context 'when initialized with primary_key_type: String' do
1746
- let(:constructor_options) do
1747
- super().merge(primary_key_type: String)
1748
- end
1749
-
1750
- describe 'with strict: false' do
1751
- it 'should raise an exception' do
1752
- expect(
1753
- association.map_entities_to_keys(*entities, strict: false)
1754
- )
1755
- .to be == entities
1756
- end
1757
- end
1758
- end
1759
- end
1760
-
1761
- describe 'with one entity that responds to #[] and key: nil' do
1762
- let(:entities) { [{ key => nil }] }
1763
-
1764
- it { expect(keys).to be == [] }
1765
-
1766
- describe 'with allow_nil: true' do
1767
- let(:options) { super().merge(allow_nil: true) }
1768
-
1769
- it { expect(keys).to be == [nil] }
1770
- end
1771
- end
1772
-
1773
- describe 'with one entity that responds to #[] and key: value' do
1774
- let(:entities) { [{ key => 0 }] }
1775
-
1776
- it { expect(keys).to be == [0] }
1777
- end
1778
-
1779
- describe 'with one entity that responds to #id and key: nil' do
1780
- let(:entities) { [Spec::Entity.new(key => nil)] }
1781
-
1782
- it { expect(keys).to be == [] }
1783
-
1784
- describe 'with allow_nil: true' do
1785
- let(:options) { super().merge(allow_nil: true) }
1786
-
1787
- it { expect(keys).to be == [nil] }
1788
- end
1789
- end
1790
-
1791
- describe 'with one entity that responds to #id and key: value' do
1792
- let(:entities) { [Spec::Entity.new(key => 0)] }
1793
-
1794
- it { expect(keys).to be == [0] }
1795
- end
1796
-
1797
- describe 'with multiple entities' do
1798
- let(:entities) do
1799
- [
1800
- Spec::Entity.new(key => 0),
1801
- Spec::Entity.new(key => 1),
1802
- Spec::Entity.new(key => 2)
1803
- ]
1804
- end
1805
-
1806
- it { expect(keys).to be == [0, 1, 2] }
1807
- end
1808
-
1809
- describe 'with multiple entities including nil' do
1810
- let(:entities) do
1811
- [
1812
- Spec::Entity.new(key => 0),
1813
- nil,
1814
- Spec::Entity.new(key => 1),
1815
- nil,
1816
- Spec::Entity.new(key => 2)
1817
- ]
1818
- end
1819
-
1820
- it { expect(keys).to be == [0, 1, 2] }
1821
- end
1822
-
1823
- describe 'with multiple entities including nil ids' do
1824
- let(:entities) do
1825
- [
1826
- Spec::Entity.new(key => 0),
1827
- Spec::Entity.new(key => nil),
1828
- Spec::Entity.new(key => 1),
1829
- Spec::Entity.new(key => nil),
1830
- Spec::Entity.new(key => 2)
1831
- ]
1832
- end
1833
-
1834
- it { expect(keys).to be == [0, 1, 2] }
1835
-
1836
- describe 'with allow_nil: true' do
1837
- let(:options) { super().merge(allow_nil: true) }
1838
-
1839
- it { expect(keys).to be == [0, nil, 1, 2] }
1840
- end
1841
- end
1842
-
1843
- describe 'with multiple entities including duplicate ids' do
1844
- let(:entities) do
1845
- [
1846
- Spec::Entity.new(key => 0),
1847
- Spec::Entity.new(key => 1),
1848
- Spec::Entity.new(key => 0),
1849
- Spec::Entity.new(key => 1),
1850
- Spec::Entity.new(key => 2)
1851
- ]
1852
- end
1853
-
1854
- it { expect(keys).to be == [0, 1, 2] }
1855
-
1856
- describe 'with deduplicate: false' do
1857
- let(:options) { super().merge(deduplicate: false) }
1858
-
1859
- it { expect(keys).to be == [0, 1, 0, 1, 2] }
1860
- end
1861
- end
1862
-
1863
- describe 'with multiple Integers' do
1864
- let(:entities) { [0, 1, 2] }
1865
- let(:error_message) do
1866
- "undefined method :[] or :#{key} for #{entities.first.inspect}"
1867
- end
1868
-
1869
- it 'should raise an exception' do
1870
- expect { association.map_entities_to_keys(*entities) }
1871
- .to raise_error ArgumentError, error_message
1872
- end
1873
-
1874
- describe 'with strict: false' do
1875
- it 'should raise an exception' do
1876
- expect(
1877
- association.map_entities_to_keys(*entities, strict: false)
1878
- )
1879
- .to be == entities
1880
- end
1881
- end
1882
-
1883
- context 'when initialized with primary_key_type: String' do
1884
- let(:constructor_options) do
1885
- super().merge(primary_key_type: String)
1886
- end
1887
-
1888
- describe 'with strict: false' do
1889
- it 'should raise an exception' do
1890
- expect do
1891
- association.map_entities_to_keys(*entities, strict: false)
1892
- end
1893
- .to raise_error ArgumentError, error_message
1894
- end
1895
- end
1896
- end
1897
- end
1898
-
1899
- describe 'with multiple Strings' do
1900
- let(:entities) { %w[0 1 2] }
1901
- let(:error_message) do
1902
- "undefined method :[] or :#{key} for #{entities.first.inspect}"
1903
- end
1904
-
1905
- it 'should raise an exception' do
1906
- expect { association.map_entities_to_keys(*entities) }
1907
- .to raise_error ArgumentError, error_message
1908
- end
1909
-
1910
- describe 'with strict: false' do
1911
- it 'should raise an exception' do
1912
- expect do
1913
- association.map_entities_to_keys(*entities, strict: false)
1914
- end
1915
- .to raise_error ArgumentError, error_message
1916
- end
1917
- end
1918
-
1919
- context 'when initialized with primary_key_type: String' do
1920
- let(:constructor_options) do
1921
- super().merge(primary_key_type: String)
1922
- end
1923
-
1924
- describe 'with strict: false' do
1925
- it 'should raise an exception' do
1926
- expect(
1927
- association.map_entities_to_keys(*entities, strict: false)
1928
- )
1929
- .to be == entities
1930
- end
1931
- end
1932
- end
1933
- end
1934
- end
1935
-
1936
- describe '#primary_key_query?' do
1937
- it { expect(subject.primary_key_query?).to be false }
1938
- end
1939
-
1940
- describe '#query_key_name' do
1941
- context 'when the foreign key name is blank' do
1942
- let(:error_message) do
1943
- "foreign key name can't be blank"
1944
- end
1945
-
1946
- it 'should raise an exception' do
1947
- expect { association.query_key_name }
1948
- .to raise_error ArgumentError, error_message
1949
- end
1950
- end
1951
-
1952
- context 'when initialized with foreign_key_name: a String' do
1953
- let(:foreign_key_name) { 'writer_id' }
1954
- let(:constructor_options) do
1955
- super().merge(foreign_key_name:)
1956
- end
1957
-
1958
- it { expect(subject.query_key_name).to be == 'writer_id' }
1959
- end
1960
-
1961
- context 'when initialized with foreign_key_name: a String' do
1962
- let(:foreign_key_name) { :writer_id }
1963
- let(:constructor_options) do
1964
- super().merge(foreign_key_name:)
1965
- end
1966
-
1967
- it { expect(subject.query_key_name).to be == 'writer_id' }
1968
- end
1969
-
1970
- context 'when initialized with inverse: value' do
1971
- let(:inverse) { described_class.new(name: 'authors') }
1972
- let(:constructor_options) do
1973
- super().merge(inverse:)
1974
- end
1975
-
1976
- it { expect(subject.query_key_name).to be == 'author_id' }
1977
-
1978
- context 'when initialized with foreign_key_name: a String' do
1979
- let(:foreign_key_name) { 'writer_id' }
1980
- let(:constructor_options) do
1981
- super().merge(foreign_key_name:)
1982
- end
1983
-
1984
- it { expect(subject.query_key_name).to be == 'writer_id' }
1985
- end
1986
-
1987
- context 'when initialized with foreign_key_name: a String' do
1988
- let(:foreign_key_name) { :writer_id }
1989
- let(:constructor_options) do
1990
- super().merge(foreign_key_name:)
1991
- end
1992
-
1993
- it { expect(subject.query_key_name).to be == 'writer_id' }
1994
- end
1995
-
1996
- context 'when initialized with inverse_name: value' do
1997
- let(:inverse_name) { 'writers' }
1998
- let(:constructor_options) do
1999
- super().merge(inverse_name:)
2000
- end
2001
-
2002
- it { expect(subject.query_key_name).to be == 'author_id' }
2003
- end
2004
-
2005
- context 'when initialized with singular_inverse_name: value' do
2006
- let(:singular_inverse_name) { 'writer' }
2007
- let(:constructor_options) do
2008
- super().merge(singular_inverse_name:)
2009
- end
2010
-
2011
- it { expect(subject.query_key_name).to be == 'writer_id' }
2012
- end
2013
- end
2014
-
2015
- context 'when initialized with inverse_name: value' do
2016
- let(:inverse_name) { 'authors' }
2017
- let(:constructor_options) do
2018
- super().merge(inverse_name:)
2019
- end
2020
-
2021
- it { expect(subject.query_key_name).to be == 'author_id' }
2022
-
2023
- context 'when initialized with foreign_key_name: a String' do
2024
- let(:foreign_key_name) { 'writer_id' }
2025
- let(:constructor_options) do
2026
- super().merge(foreign_key_name:)
2027
- end
2028
-
2029
- it { expect(subject.query_key_name).to be == 'writer_id' }
2030
- end
2031
-
2032
- context 'when initialized with foreign_key_name: a String' do
2033
- let(:foreign_key_name) { :writer_id }
2034
- let(:constructor_options) do
2035
- super().merge(foreign_key_name:)
2036
- end
2037
-
2038
- it { expect(subject.query_key_name).to be == 'writer_id' }
2039
- end
2040
- end
2041
-
2042
- context 'when initialized with singular_inverse_name: value' do
2043
- let(:singular_inverse_name) { 'author' }
2044
- let(:constructor_options) do
2045
- super().merge(singular_inverse_name:)
2046
- end
2047
-
2048
- it { expect(subject.query_key_name).to be == 'author_id' }
2049
-
2050
- context 'when initialized with foreign_key_name: a String' do
2051
- let(:foreign_key_name) { 'writer_id' }
2052
- let(:constructor_options) do
2053
- super().merge(foreign_key_name:)
2054
- end
2055
-
2056
- it { expect(subject.query_key_name).to be == 'writer_id' }
2057
- end
2058
-
2059
- context 'when initialized with foreign_key_name: a String' do
2060
- let(:foreign_key_name) { :writer_id }
2061
- let(:constructor_options) do
2062
- super().merge(foreign_key_name:)
2063
- end
2064
-
2065
- it { expect(subject.query_key_name).to be == 'writer_id' }
2066
- end
2067
- end
2068
-
2069
- context 'with a copy with assigned inverse' do
2070
- subject do
2071
- super().tap(&:foreign_key_name).with_inverse(new_inverse)
2072
- end
2073
-
2074
- let(:new_inverse) { described_class.new(name: 'chapters') }
2075
-
2076
- it { expect(subject.query_key_name).to be == 'chapter_id' }
2077
-
2078
- context 'when initialized with foreign_key_name: a String' do
2079
- let(:foreign_key_name) { 'writer_id' }
2080
- let(:constructor_options) do
2081
- super().merge(foreign_key_name:)
2082
- end
2083
-
2084
- it { expect(subject.query_key_name).to be == 'writer_id' }
2085
- end
2086
-
2087
- context 'when initialized with foreign_key_name: a String' do
2088
- let(:foreign_key_name) { :writer_id }
2089
- let(:constructor_options) do
2090
- super().merge(foreign_key_name:)
2091
- end
2092
-
2093
- it { expect(subject.query_key_name).to be == 'writer_id' }
2094
- end
2095
-
2096
- context 'when initialized with inverse: value' do
2097
- let(:inverse) { described_class.new(name: 'authors') }
2098
- let(:constructor_options) do
2099
- super().merge(inverse:)
2100
- end
2101
-
2102
- it { expect(subject.query_key_name).to be == 'chapter_id' }
2103
- end
2104
-
2105
- context 'when initialized with inverse_name: value' do
2106
- let(:inverse_name) { 'authors' }
2107
- let(:constructor_options) do
2108
- super().merge(inverse_name:)
2109
- end
2110
-
2111
- it { expect(subject.query_key_name).to be == 'chapter_id' }
2112
- end
2113
-
2114
- context 'when initialized with singular_inverse_name: value' do
2115
- let(:singular_inverse_name) { 'author' }
2116
- let(:constructor_options) do
2117
- super().merge(singular_inverse_name:)
2118
- end
2119
-
2120
- it { expect(subject.query_key_name).to be == 'author_id' }
2121
- end
2122
- end
2123
- end
2124
- end
2125
- end
2126
- end
2127
- end