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