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,1430 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/collections/queries'
|
4
|
+
require 'cuprum/collections/rspec/contracts/scopes'
|
5
|
+
require 'cuprum/collections/scopes/base'
|
6
|
+
require 'cuprum/collections/scopes/builder'
|
7
|
+
require 'cuprum/collections/scopes/conjunction_scope'
|
8
|
+
require 'cuprum/collections/scopes/criteria_scope'
|
9
|
+
require 'cuprum/collections/scopes/disjunction_scope'
|
10
|
+
require 'cuprum/collections/scopes/none_scope'
|
11
|
+
|
12
|
+
module Cuprum::Collections::RSpec::Contracts::Scopes
|
13
|
+
# Contracts for validating the behavior of scope composition.
|
14
|
+
module CompositionContracts
|
15
|
+
# Contract validating the fluent interface for scope composition.
|
16
|
+
module ShouldComposeScopesContract
|
17
|
+
extend RSpec::SleepingKingStudios::Contract
|
18
|
+
|
19
|
+
# @!method apply(example_group, except: [])
|
20
|
+
# Adds the contract to the example group.
|
21
|
+
#
|
22
|
+
# @param example_group [RSpec::Core::ExampleGroup] the example group to
|
23
|
+
# which the contract is applied.
|
24
|
+
# @param except [Array<Symbol>] names of composition methods where the
|
25
|
+
# scope defines custom behavior.
|
26
|
+
contract do |except: []|
|
27
|
+
shared_context 'with an all scope' do
|
28
|
+
let(:original) do
|
29
|
+
Cuprum::Collections::Scopes::AllScope.new
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
shared_context 'with a none scope' do
|
34
|
+
let(:original) do
|
35
|
+
Cuprum::Collections::Scopes::NoneScope.new
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
shared_context 'with an empty conjunction scope' do
|
40
|
+
let(:original) do
|
41
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(scopes: [])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
shared_context 'with an empty criteria scope' do
|
46
|
+
let(:original) do
|
47
|
+
Cuprum::Collections::Scopes::CriteriaScope.new(criteria: [])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
shared_context 'with an empty disjunction scope' do
|
52
|
+
let(:original) do
|
53
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(scopes: [])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
shared_context 'with a non-empty conjunction scope' do
|
58
|
+
let(:original) do
|
59
|
+
operators = Cuprum::Collections::Queries::Operators
|
60
|
+
criteria = [
|
61
|
+
[
|
62
|
+
'category',
|
63
|
+
operators::EQUAL,
|
64
|
+
'Science Fiction and Fantasy'
|
65
|
+
]
|
66
|
+
]
|
67
|
+
wrapped =
|
68
|
+
Cuprum::Collections::Scopes::CriteriaScope.new(criteria:)
|
69
|
+
|
70
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(scopes: [wrapped])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
shared_examples 'with a non-empty criteria scope' do
|
75
|
+
let(:original) do
|
76
|
+
operators = Cuprum::Collections::Queries::Operators
|
77
|
+
criteria = [
|
78
|
+
[
|
79
|
+
'category',
|
80
|
+
operators::EQUAL,
|
81
|
+
'Science Fiction and Fantasy'
|
82
|
+
]
|
83
|
+
]
|
84
|
+
|
85
|
+
Cuprum::Collections::Scopes::CriteriaScope.new(criteria:)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
shared_context 'with a non-empty disjunction scope' do
|
90
|
+
let(:original) do
|
91
|
+
operators = Cuprum::Collections::Queries::Operators
|
92
|
+
criteria = [
|
93
|
+
[
|
94
|
+
'category',
|
95
|
+
operators::EQUAL,
|
96
|
+
'Science Fiction and Fantasy'
|
97
|
+
]
|
98
|
+
]
|
99
|
+
wrapped =
|
100
|
+
Cuprum::Collections::Scopes::CriteriaScope.new(criteria:)
|
101
|
+
|
102
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(scopes: [wrapped])
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#and' do
|
107
|
+
it 'should define the method' do
|
108
|
+
expect(subject)
|
109
|
+
.to respond_to(:and)
|
110
|
+
.with(0..1).arguments
|
111
|
+
.and_a_block
|
112
|
+
end
|
113
|
+
|
114
|
+
it { expect(subject).to have_aliased_method(:and).as(:where) }
|
115
|
+
|
116
|
+
next if except.include?(:and)
|
117
|
+
|
118
|
+
describe 'with a block' do
|
119
|
+
let(:block) { -> { { 'title' => 'A Wizard of Earthsea' } } }
|
120
|
+
let(:expected) do
|
121
|
+
wrapped = Cuprum::Collections::Scope.new(&block)
|
122
|
+
|
123
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
124
|
+
scopes: [subject, wrapped]
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
it { expect(subject.and(&block)).to be == expected }
|
129
|
+
end
|
130
|
+
|
131
|
+
describe 'with a hash' do
|
132
|
+
let(:value) { { 'title' => 'A Wizard of Earthsea' } }
|
133
|
+
let(:expected) do
|
134
|
+
wrapped = Cuprum::Collections::Scope.new(value)
|
135
|
+
|
136
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
137
|
+
scopes: [subject, wrapped]
|
138
|
+
)
|
139
|
+
end
|
140
|
+
|
141
|
+
it { expect(subject.and(value)).to be == expected }
|
142
|
+
end
|
143
|
+
|
144
|
+
wrap_context 'with an all scope' do
|
145
|
+
it { expect(subject.and(original)).to be subject }
|
146
|
+
end
|
147
|
+
|
148
|
+
wrap_context 'with a none scope' do
|
149
|
+
it { expect(subject.and(original)).to be == original }
|
150
|
+
end
|
151
|
+
|
152
|
+
wrap_context 'with an empty conjunction scope' do
|
153
|
+
it { expect(subject.and(original)).to be subject }
|
154
|
+
end
|
155
|
+
|
156
|
+
wrap_context 'with an empty criteria scope' do
|
157
|
+
it { expect(subject.and(original)).to be subject }
|
158
|
+
end
|
159
|
+
|
160
|
+
wrap_context 'with an empty disjunction scope' do
|
161
|
+
it { expect(subject.and(original)).to be subject }
|
162
|
+
end
|
163
|
+
|
164
|
+
wrap_context 'with a non-empty conjunction scope' do
|
165
|
+
let(:expected) do
|
166
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
167
|
+
scopes: [subject, *original.scopes]
|
168
|
+
)
|
169
|
+
end
|
170
|
+
|
171
|
+
it { expect(subject.and(original)).to be == expected }
|
172
|
+
end
|
173
|
+
|
174
|
+
wrap_context 'with a non-empty criteria scope' do
|
175
|
+
let(:expected) do
|
176
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
177
|
+
scopes: [subject, original]
|
178
|
+
)
|
179
|
+
end
|
180
|
+
|
181
|
+
it { expect(subject.and(original)).to be == expected }
|
182
|
+
end
|
183
|
+
|
184
|
+
wrap_context 'with a non-empty disjunction scope' do
|
185
|
+
let(:expected) do
|
186
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
187
|
+
scopes: [subject, original]
|
188
|
+
)
|
189
|
+
end
|
190
|
+
|
191
|
+
it { expect(subject.and(original)).to be == expected }
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
describe '#not' do
|
196
|
+
it 'should define the method' do
|
197
|
+
expect(subject)
|
198
|
+
.to respond_to(:not)
|
199
|
+
.with(0..1).arguments
|
200
|
+
.and_a_block
|
201
|
+
end
|
202
|
+
|
203
|
+
next if except.include?(:not)
|
204
|
+
|
205
|
+
describe 'with a block' do
|
206
|
+
let(:block) { -> { { 'title' => 'A Wizard of Earthsea' } } }
|
207
|
+
let(:block) { -> { { 'title' => 'A Wizard of Earthsea' } } }
|
208
|
+
let(:expected) do
|
209
|
+
wrapped = Cuprum::Collections::Scope.new(&block)
|
210
|
+
|
211
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
212
|
+
scopes: [subject, wrapped.invert]
|
213
|
+
)
|
214
|
+
end
|
215
|
+
|
216
|
+
it { expect(subject.not(&block)).to be == expected }
|
217
|
+
end
|
218
|
+
|
219
|
+
describe 'with a hash' do
|
220
|
+
let(:value) { { 'title' => 'A Wizard of Earthsea' } }
|
221
|
+
let(:expected) do
|
222
|
+
wrapped = Cuprum::Collections::Scope.new(value)
|
223
|
+
|
224
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
225
|
+
scopes: [subject, wrapped.invert]
|
226
|
+
)
|
227
|
+
end
|
228
|
+
|
229
|
+
it { expect(subject.not(value)).to be == expected }
|
230
|
+
end
|
231
|
+
|
232
|
+
wrap_context 'with an all scope' do
|
233
|
+
let(:expected) { Cuprum::Collections::Scopes::NoneScope.new }
|
234
|
+
|
235
|
+
it { expect(subject.not(original)).to be == expected }
|
236
|
+
end
|
237
|
+
|
238
|
+
wrap_context 'with a none scope' do
|
239
|
+
it { expect(subject.not(original)).to be subject }
|
240
|
+
end
|
241
|
+
|
242
|
+
wrap_context 'with an empty conjunction scope' do
|
243
|
+
it { expect(subject.not(original)).to be subject }
|
244
|
+
end
|
245
|
+
|
246
|
+
wrap_context 'with an empty criteria scope' do
|
247
|
+
it { expect(subject.not(original)).to be subject }
|
248
|
+
end
|
249
|
+
|
250
|
+
wrap_context 'with an empty disjunction scope' do
|
251
|
+
it { expect(subject.not(original)).to be subject }
|
252
|
+
end
|
253
|
+
|
254
|
+
wrap_context 'with a non-empty conjunction scope' do
|
255
|
+
let(:expected) do
|
256
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
257
|
+
scopes: [subject, original.invert]
|
258
|
+
)
|
259
|
+
end
|
260
|
+
|
261
|
+
it { expect(subject.not(original)).to be == expected }
|
262
|
+
end
|
263
|
+
|
264
|
+
wrap_context 'with a non-empty criteria scope' do
|
265
|
+
let(:expected) do
|
266
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
267
|
+
scopes: [subject, original.invert]
|
268
|
+
)
|
269
|
+
end
|
270
|
+
|
271
|
+
it { expect(subject.not(original)).to be == expected }
|
272
|
+
end
|
273
|
+
|
274
|
+
wrap_context 'with a non-empty disjunction scope' do
|
275
|
+
let(:expected) do
|
276
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
277
|
+
scopes: [subject, *original.invert.scopes]
|
278
|
+
)
|
279
|
+
end
|
280
|
+
|
281
|
+
it { expect(subject.not(original)).to be == expected }
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
describe '#or' do
|
286
|
+
it 'should define the method' do
|
287
|
+
expect(subject)
|
288
|
+
.to respond_to(:or)
|
289
|
+
.with(0..1).arguments
|
290
|
+
.and_a_block
|
291
|
+
end
|
292
|
+
|
293
|
+
next if except.include?(:or)
|
294
|
+
|
295
|
+
describe 'with a block' do
|
296
|
+
let(:block) { -> { { 'title' => 'A Wizard of Earthsea' } } }
|
297
|
+
let(:expected) do
|
298
|
+
wrapped = Cuprum::Collections::Scope.new(&block)
|
299
|
+
|
300
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(
|
301
|
+
scopes: [subject, wrapped]
|
302
|
+
)
|
303
|
+
end
|
304
|
+
|
305
|
+
it { expect(subject.or(&block)).to be == expected }
|
306
|
+
end
|
307
|
+
|
308
|
+
describe 'with a hash' do
|
309
|
+
let(:value) { { 'title' => 'A Wizard of Earthsea' } }
|
310
|
+
let(:expected) do
|
311
|
+
wrapped = Cuprum::Collections::Scope.new(value)
|
312
|
+
|
313
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(
|
314
|
+
scopes: [subject, wrapped]
|
315
|
+
)
|
316
|
+
end
|
317
|
+
|
318
|
+
it { expect(subject.or(value)).to be == expected }
|
319
|
+
end
|
320
|
+
|
321
|
+
wrap_context 'with an all scope' do
|
322
|
+
it { expect(subject.or(original)).to be == original }
|
323
|
+
end
|
324
|
+
|
325
|
+
wrap_context 'with a none scope' do
|
326
|
+
it { expect(subject.or(original)).to be subject }
|
327
|
+
end
|
328
|
+
|
329
|
+
wrap_context 'with an empty conjunction scope' do
|
330
|
+
it { expect(subject.or(original)).to be subject }
|
331
|
+
end
|
332
|
+
|
333
|
+
wrap_context 'with an empty criteria scope' do
|
334
|
+
it { expect(subject.or(original)).to be subject }
|
335
|
+
end
|
336
|
+
|
337
|
+
wrap_context 'with an empty disjunction scope' do
|
338
|
+
it { expect(subject.or(original)).to be subject }
|
339
|
+
end
|
340
|
+
|
341
|
+
wrap_context 'with a non-empty conjunction scope' do
|
342
|
+
let(:expected) do
|
343
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(
|
344
|
+
scopes: [subject, original]
|
345
|
+
)
|
346
|
+
end
|
347
|
+
|
348
|
+
it { expect(subject.or(original)).to be == expected }
|
349
|
+
end
|
350
|
+
|
351
|
+
wrap_context 'with a non-empty criteria scope' do
|
352
|
+
let(:expected) do
|
353
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(
|
354
|
+
scopes: [subject, original]
|
355
|
+
)
|
356
|
+
end
|
357
|
+
|
358
|
+
it { expect(subject.or(original)).to be == expected }
|
359
|
+
end
|
360
|
+
|
361
|
+
wrap_context 'with a non-empty disjunction scope' do
|
362
|
+
let(:expected) do
|
363
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(
|
364
|
+
scopes: [subject, *original.scopes]
|
365
|
+
)
|
366
|
+
end
|
367
|
+
|
368
|
+
it { expect(subject.or(original)).to be == expected }
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
# Contract validating scope composition for conjunction scopes.
|
375
|
+
module ShouldComposeScopesForConjunctionContract
|
376
|
+
extend RSpec::SleepingKingStudios::Contract
|
377
|
+
include Cuprum::Collections::RSpec::Contracts::Scopes::CompositionContracts # rubocop:disable Layout/LineLength
|
378
|
+
|
379
|
+
# @!method apply(example_group)
|
380
|
+
# Adds the contract to the example group.
|
381
|
+
#
|
382
|
+
# @param example_group [RSpec::Core::ExampleGroup] the example group to
|
383
|
+
# which the contract is applied.
|
384
|
+
contract do
|
385
|
+
shared_context 'when the scope has many child scopes' do
|
386
|
+
let(:scopes) do
|
387
|
+
[
|
388
|
+
build_scope({ 'author' => 'J.R.R. Tolkien' }),
|
389
|
+
build_scope({ 'series' => 'The Lord of the Rings' }),
|
390
|
+
build_scope do |scope|
|
391
|
+
{ 'published_at' => scope.less_than('1955-01-01') }
|
392
|
+
end
|
393
|
+
]
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
include_contract 'should compose scopes', except: %i[and not]
|
398
|
+
|
399
|
+
describe '#and' do
|
400
|
+
describe 'with a block' do
|
401
|
+
let(:block) { -> { { 'title' => 'A Wizard of Earthsea' } } }
|
402
|
+
let(:expected) do
|
403
|
+
wrapped = Cuprum::Collections::Scope.new(&block)
|
404
|
+
|
405
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
406
|
+
scopes: [*subject.scopes, wrapped]
|
407
|
+
)
|
408
|
+
end
|
409
|
+
|
410
|
+
it { expect(subject.and(&block)).to be == expected }
|
411
|
+
end
|
412
|
+
|
413
|
+
describe 'with a hash' do
|
414
|
+
let(:value) { { 'title' => 'A Wizard of Earthsea' } }
|
415
|
+
let(:expected) do
|
416
|
+
wrapped = Cuprum::Collections::Scope.new(value)
|
417
|
+
|
418
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
419
|
+
scopes: [*subject.scopes, wrapped]
|
420
|
+
)
|
421
|
+
end
|
422
|
+
|
423
|
+
it { expect(subject.and(value)).to be == expected }
|
424
|
+
end
|
425
|
+
|
426
|
+
wrap_context 'with an all scope' do
|
427
|
+
it { expect(subject.and(original)).to be subject }
|
428
|
+
end
|
429
|
+
|
430
|
+
wrap_context 'with a none scope' do
|
431
|
+
it { expect(subject.and(original)).to be == original }
|
432
|
+
end
|
433
|
+
|
434
|
+
wrap_context 'with an empty conjunction scope' do
|
435
|
+
it { expect(subject.and(original)).to be subject }
|
436
|
+
|
437
|
+
wrap_context 'when the scope has many child scopes' do
|
438
|
+
it { expect(subject.and(original)).to be subject }
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
wrap_context 'with an empty criteria scope' do
|
443
|
+
it { expect(subject.and(original)).to be subject }
|
444
|
+
end
|
445
|
+
|
446
|
+
wrap_context 'with an empty disjunction scope' do
|
447
|
+
it { expect(subject.and(original)).to be subject }
|
448
|
+
end
|
449
|
+
|
450
|
+
wrap_context 'with a non-empty conjunction scope' do
|
451
|
+
let(:expected) do
|
452
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
453
|
+
scopes: [*subject.scopes, *original.scopes]
|
454
|
+
)
|
455
|
+
end
|
456
|
+
|
457
|
+
it { expect(subject.and(original)).to be == expected }
|
458
|
+
|
459
|
+
wrap_context 'when the scope has many child scopes' do
|
460
|
+
it { expect(subject.and(original)).to be == expected }
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
wrap_context 'with a non-empty criteria scope' do
|
465
|
+
let(:expected) do
|
466
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
467
|
+
scopes: [*subject.scopes, original]
|
468
|
+
)
|
469
|
+
end
|
470
|
+
|
471
|
+
it { expect(subject.and(original)).to be == expected }
|
472
|
+
|
473
|
+
wrap_context 'when the scope has many child scopes' do
|
474
|
+
it { expect(subject.and(original)).to be == expected }
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
wrap_context 'with a non-empty disjunction scope' do
|
479
|
+
let(:expected) do
|
480
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
481
|
+
scopes: [*subject.scopes, original]
|
482
|
+
)
|
483
|
+
end
|
484
|
+
|
485
|
+
it { expect(subject.and(original)).to be == expected }
|
486
|
+
|
487
|
+
wrap_context 'when the scope has many child scopes' do
|
488
|
+
it { expect(subject.and(original)).to be == expected }
|
489
|
+
end
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
describe '#not' do
|
494
|
+
describe 'with a block' do
|
495
|
+
let(:block) { -> { { 'title' => 'A Wizard of Earthsea' } } }
|
496
|
+
let(:expected) do
|
497
|
+
wrapped = Cuprum::Collections::Scope.new(&block)
|
498
|
+
|
499
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
500
|
+
scopes: [*subject.scopes, wrapped.invert]
|
501
|
+
)
|
502
|
+
end
|
503
|
+
|
504
|
+
it { expect(subject.not(&block)).to be == expected }
|
505
|
+
|
506
|
+
wrap_context 'when the scope has many child scopes' do
|
507
|
+
it { expect(subject.not(&block)).to be == expected }
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
describe 'with a hash' do
|
512
|
+
let(:value) { { 'title' => 'A Wizard of Earthsea' } }
|
513
|
+
let(:expected) do
|
514
|
+
wrapped = Cuprum::Collections::Scope.new(value)
|
515
|
+
|
516
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
517
|
+
scopes: [*subject.scopes, wrapped.invert]
|
518
|
+
)
|
519
|
+
end
|
520
|
+
|
521
|
+
it { expect(subject.not(value)).to be == expected }
|
522
|
+
|
523
|
+
wrap_context 'when the scope has many child scopes' do
|
524
|
+
it { expect(subject.not(value)).to be == expected }
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
wrap_context 'with an all scope' do
|
529
|
+
let(:expected) { Cuprum::Collections::Scopes::NoneScope.new }
|
530
|
+
|
531
|
+
it { expect(subject.not(original)).to be == expected }
|
532
|
+
end
|
533
|
+
|
534
|
+
wrap_context 'with a none scope' do
|
535
|
+
it { expect(subject.not(original)).to be subject }
|
536
|
+
end
|
537
|
+
|
538
|
+
wrap_context 'with an empty conjunction scope' do
|
539
|
+
it { expect(subject.not(original)).to be subject }
|
540
|
+
end
|
541
|
+
|
542
|
+
wrap_context 'with an empty criteria scope' do
|
543
|
+
it { expect(subject.not(original)).to be subject }
|
544
|
+
end
|
545
|
+
|
546
|
+
wrap_context 'with an empty disjunction scope' do
|
547
|
+
it { expect(subject.not(original)).to be subject }
|
548
|
+
end
|
549
|
+
|
550
|
+
wrap_context 'with a non-empty conjunction scope' do
|
551
|
+
let(:expected) do
|
552
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
553
|
+
scopes: [*subject.scopes, original.invert]
|
554
|
+
)
|
555
|
+
end
|
556
|
+
|
557
|
+
it { expect(subject.not(original)).to be == expected }
|
558
|
+
|
559
|
+
wrap_context 'when the scope has many child scopes' do
|
560
|
+
it { expect(subject.not(original)).to be == expected }
|
561
|
+
end
|
562
|
+
end
|
563
|
+
|
564
|
+
wrap_context 'with a non-empty criteria scope' do
|
565
|
+
let(:expected) do
|
566
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
567
|
+
scopes: [*subject.scopes, original.invert]
|
568
|
+
)
|
569
|
+
end
|
570
|
+
|
571
|
+
it { expect(subject.not(original)).to be == expected }
|
572
|
+
|
573
|
+
wrap_context 'when the scope has many child scopes' do
|
574
|
+
it { expect(subject.not(original)).to be == expected }
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
wrap_context 'with a non-empty disjunction scope' do
|
579
|
+
let(:expected) do
|
580
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
581
|
+
scopes: [*subject.scopes, *original.invert.scopes]
|
582
|
+
)
|
583
|
+
end
|
584
|
+
|
585
|
+
it { expect(subject.not(original)).to be == expected }
|
586
|
+
|
587
|
+
wrap_context 'when the scope has many child scopes' do
|
588
|
+
it { expect(subject.not(original)).to be == expected }
|
589
|
+
end
|
590
|
+
end
|
591
|
+
end
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
# Contract validating scope composition for criteria scopes.
|
596
|
+
module ShouldComposeScopesForCriteriaContract
|
597
|
+
extend RSpec::SleepingKingStudios::Contract
|
598
|
+
include Cuprum::Collections::RSpec::Contracts::Scopes::CompositionContracts # rubocop:disable Layout/LineLength
|
599
|
+
|
600
|
+
# @!method apply(example_group)
|
601
|
+
# Adds the contract to the example group.
|
602
|
+
#
|
603
|
+
# @param example_group [RSpec::Core::ExampleGroup] the example group to
|
604
|
+
# which the contract is applied.
|
605
|
+
contract do
|
606
|
+
shared_context 'when the scope has multiple criteria' do
|
607
|
+
let(:criteria) do
|
608
|
+
operators = Cuprum::Collections::Queries::Operators
|
609
|
+
|
610
|
+
[
|
611
|
+
[
|
612
|
+
'author',
|
613
|
+
operators::EQUAL,
|
614
|
+
'Ursula K. LeGuin'
|
615
|
+
],
|
616
|
+
[
|
617
|
+
'published_at',
|
618
|
+
operators::LESS_THAN,
|
619
|
+
'1970-01-01'
|
620
|
+
]
|
621
|
+
]
|
622
|
+
end
|
623
|
+
end
|
624
|
+
|
625
|
+
include_contract 'should compose scopes', except: %i[and not or]
|
626
|
+
|
627
|
+
describe '#and' do
|
628
|
+
describe 'with a block' do
|
629
|
+
let(:block) { ->(_) { { 'title' => 'A Wizard of Earthsea' } } }
|
630
|
+
let(:expected) do
|
631
|
+
operators = Cuprum::Collections::Queries::Operators
|
632
|
+
criteria = [
|
633
|
+
[
|
634
|
+
'title',
|
635
|
+
operators::EQUAL,
|
636
|
+
'A Wizard of Earthsea'
|
637
|
+
]
|
638
|
+
]
|
639
|
+
|
640
|
+
Cuprum::Collections::Scopes::CriteriaScope.new(
|
641
|
+
criteria: [*self.criteria, *criteria]
|
642
|
+
)
|
643
|
+
end
|
644
|
+
|
645
|
+
it { expect(subject.and(&block)).to be == expected }
|
646
|
+
|
647
|
+
wrap_context 'when the scope has multiple criteria' do
|
648
|
+
it { expect(subject.and(&block)).to be == expected }
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
describe 'with a hash' do
|
653
|
+
let(:value) { { 'title' => 'A Wizard of Earthsea' } }
|
654
|
+
let(:expected) do
|
655
|
+
operators = Cuprum::Collections::Queries::Operators
|
656
|
+
criteria = [
|
657
|
+
[
|
658
|
+
'title',
|
659
|
+
operators::EQUAL,
|
660
|
+
'A Wizard of Earthsea'
|
661
|
+
]
|
662
|
+
]
|
663
|
+
|
664
|
+
Cuprum::Collections::Scopes::CriteriaScope.new(
|
665
|
+
criteria: [*self.criteria, *criteria]
|
666
|
+
)
|
667
|
+
end
|
668
|
+
|
669
|
+
it { expect(subject.and(value)).to be == expected }
|
670
|
+
|
671
|
+
wrap_context 'when the scope has multiple criteria' do
|
672
|
+
it { expect(subject.and(value)).to be == expected }
|
673
|
+
end
|
674
|
+
end
|
675
|
+
|
676
|
+
wrap_context 'with an all scope' do
|
677
|
+
it { expect(subject.and(original)).to be == original }
|
678
|
+
|
679
|
+
wrap_context 'when the scope has multiple criteria' do
|
680
|
+
it { expect(subject.and(original)).to be subject }
|
681
|
+
end
|
682
|
+
end
|
683
|
+
|
684
|
+
wrap_context 'with a none scope' do
|
685
|
+
it { expect(subject.and(original)).to be == original }
|
686
|
+
|
687
|
+
wrap_context 'when the scope has multiple criteria' do
|
688
|
+
it { expect(subject.and(original)).to be == original }
|
689
|
+
end
|
690
|
+
end
|
691
|
+
|
692
|
+
wrap_context 'with an empty conjunction scope' do
|
693
|
+
it { expect(subject.and(original)).to be subject }
|
694
|
+
|
695
|
+
wrap_context 'when the scope has multiple criteria' do
|
696
|
+
it { expect(subject.and(original)).to be subject }
|
697
|
+
end
|
698
|
+
end
|
699
|
+
|
700
|
+
wrap_context 'with an empty criteria scope' do
|
701
|
+
it { expect(subject.and(original)).to be subject }
|
702
|
+
|
703
|
+
wrap_context 'when the scope has multiple criteria' do
|
704
|
+
it { expect(subject.and(original)).to be subject }
|
705
|
+
end
|
706
|
+
end
|
707
|
+
|
708
|
+
context 'with an empty inverted criteria scope' do
|
709
|
+
include_context 'with an empty criteria scope'
|
710
|
+
|
711
|
+
let(:inverted) { original.invert }
|
712
|
+
|
713
|
+
it { expect(subject.and(inverted)).to be subject }
|
714
|
+
|
715
|
+
wrap_context 'when the scope has multiple criteria' do
|
716
|
+
it { expect(subject.and(original)).to be subject }
|
717
|
+
end
|
718
|
+
end
|
719
|
+
|
720
|
+
wrap_context 'with an empty disjunction scope' do
|
721
|
+
it { expect(subject.and(original)).to be subject }
|
722
|
+
|
723
|
+
wrap_context 'when the scope has multiple criteria' do
|
724
|
+
it { expect(subject.and(original)).to be subject }
|
725
|
+
end
|
726
|
+
end
|
727
|
+
|
728
|
+
wrap_context 'with a non-empty conjunction scope' do
|
729
|
+
it { expect(subject.and(original)).to be == original }
|
730
|
+
|
731
|
+
wrap_context 'when the scope has multiple criteria' do
|
732
|
+
let(:expected) do
|
733
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
734
|
+
scopes: [subject, *original.scopes]
|
735
|
+
)
|
736
|
+
end
|
737
|
+
|
738
|
+
it { expect(subject.and(original)).to be == expected }
|
739
|
+
end
|
740
|
+
end
|
741
|
+
|
742
|
+
wrap_context 'with a non-empty criteria scope' do
|
743
|
+
let(:expected) do
|
744
|
+
Cuprum::Collections::Scopes::CriteriaScope.new(
|
745
|
+
criteria: [*subject.criteria, *original.criteria]
|
746
|
+
)
|
747
|
+
end
|
748
|
+
|
749
|
+
it { expect(subject.and(original)).to be == expected }
|
750
|
+
|
751
|
+
wrap_context 'when the scope has multiple criteria' do
|
752
|
+
it { expect(subject.and(original)).to be == expected }
|
753
|
+
end
|
754
|
+
end
|
755
|
+
|
756
|
+
context 'with a non-empty inverted criteria scope' do
|
757
|
+
include_context 'with a non-empty criteria scope'
|
758
|
+
|
759
|
+
let(:inverted) { original.invert }
|
760
|
+
|
761
|
+
it { expect(subject.and(inverted)).to be == inverted }
|
762
|
+
|
763
|
+
wrap_context 'when the scope has multiple criteria' do
|
764
|
+
let(:expected) do
|
765
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
766
|
+
scopes: [subject, inverted]
|
767
|
+
)
|
768
|
+
end
|
769
|
+
|
770
|
+
it { expect(subject.and(inverted)).to be == expected }
|
771
|
+
end
|
772
|
+
end
|
773
|
+
|
774
|
+
wrap_context 'with a non-empty disjunction scope' do
|
775
|
+
it { expect(subject.and(original)).to be == original }
|
776
|
+
|
777
|
+
wrap_context 'when the scope has multiple criteria' do
|
778
|
+
let(:expected) do
|
779
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
780
|
+
scopes: [subject, original]
|
781
|
+
)
|
782
|
+
end
|
783
|
+
|
784
|
+
it { expect(subject.and(original)).to be == expected }
|
785
|
+
end
|
786
|
+
end
|
787
|
+
|
788
|
+
wrap_context 'when initialized with inverted: true' do
|
789
|
+
describe 'with a block' do
|
790
|
+
let(:block) { -> { { 'title' => 'A Wizard of Earthsea' } } }
|
791
|
+
let(:expected) do
|
792
|
+
Cuprum::Collections::Scope.new(&block)
|
793
|
+
end
|
794
|
+
|
795
|
+
it { expect(subject.and(&block)).to be == expected }
|
796
|
+
|
797
|
+
wrap_context 'when the scope has multiple criteria' do
|
798
|
+
let(:expected) do
|
799
|
+
wrapped = Cuprum::Collections::Scope.new(&block)
|
800
|
+
|
801
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
802
|
+
scopes: [subject, wrapped]
|
803
|
+
)
|
804
|
+
end
|
805
|
+
|
806
|
+
it { expect(subject.and(&block)).to be == expected }
|
807
|
+
end
|
808
|
+
end
|
809
|
+
|
810
|
+
describe 'with a hash' do
|
811
|
+
let(:value) { { 'title' => 'A Wizard of Earthsea' } }
|
812
|
+
let(:expected) do
|
813
|
+
Cuprum::Collections::Scope.new(value)
|
814
|
+
end
|
815
|
+
|
816
|
+
it { expect(subject.and(value)).to be == expected }
|
817
|
+
|
818
|
+
wrap_context 'when the scope has multiple criteria' do
|
819
|
+
let(:expected) do
|
820
|
+
wrapped = Cuprum::Collections::Scope.new(value)
|
821
|
+
|
822
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
823
|
+
scopes: [subject, wrapped]
|
824
|
+
)
|
825
|
+
end
|
826
|
+
|
827
|
+
it { expect(subject.and(value)).to be == expected }
|
828
|
+
end
|
829
|
+
end
|
830
|
+
|
831
|
+
wrap_context 'with an empty criteria scope' do
|
832
|
+
it { expect(subject.and(original)).to be subject }
|
833
|
+
|
834
|
+
wrap_context 'when the scope has multiple criteria' do
|
835
|
+
it { expect(subject.and(original)).to be subject }
|
836
|
+
end
|
837
|
+
end
|
838
|
+
|
839
|
+
context 'with an empty inverted criteria scope' do
|
840
|
+
include_context 'with an empty criteria scope'
|
841
|
+
|
842
|
+
let(:inverted) { original.invert }
|
843
|
+
|
844
|
+
it { expect(subject.and(inverted)).to be subject }
|
845
|
+
|
846
|
+
wrap_context 'when the scope has multiple criteria' do
|
847
|
+
it { expect(subject.and(inverted)).to be subject }
|
848
|
+
end
|
849
|
+
end
|
850
|
+
|
851
|
+
wrap_context 'with a non-empty criteria scope' do
|
852
|
+
it { expect(subject.and(original)).to be == original }
|
853
|
+
|
854
|
+
wrap_context 'when the scope has multiple criteria' do
|
855
|
+
let(:expected) do
|
856
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
857
|
+
scopes: [subject, original]
|
858
|
+
)
|
859
|
+
end
|
860
|
+
|
861
|
+
it { expect(subject.and(original)).to be == expected }
|
862
|
+
end
|
863
|
+
end
|
864
|
+
|
865
|
+
context 'with a non-empty inverted criteria scope' do
|
866
|
+
include_context 'with a non-empty criteria scope'
|
867
|
+
|
868
|
+
let(:inverted) { original.invert }
|
869
|
+
|
870
|
+
it { expect(subject.and(inverted)).to be == inverted }
|
871
|
+
|
872
|
+
wrap_context 'when the scope has multiple criteria' do
|
873
|
+
let(:expected) do
|
874
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
875
|
+
scopes: [subject, inverted]
|
876
|
+
)
|
877
|
+
end
|
878
|
+
|
879
|
+
it { expect(subject.and(inverted)).to be == expected }
|
880
|
+
end
|
881
|
+
end
|
882
|
+
end
|
883
|
+
end
|
884
|
+
|
885
|
+
describe '#not' do
|
886
|
+
describe 'with a block' do
|
887
|
+
let(:block) { -> { { 'title' => 'A Wizard of Earthsea' } } }
|
888
|
+
let(:expected) do
|
889
|
+
Cuprum::Collections::Scope.new(&block).invert
|
890
|
+
end
|
891
|
+
|
892
|
+
it { expect(subject.not(&block)).to be == expected }
|
893
|
+
|
894
|
+
wrap_context 'when the scope has multiple criteria' do
|
895
|
+
let(:expected) do
|
896
|
+
wrapped = Cuprum::Collections::Scope.new(&block)
|
897
|
+
|
898
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
899
|
+
scopes: [subject, wrapped.invert]
|
900
|
+
)
|
901
|
+
end
|
902
|
+
|
903
|
+
it { expect(subject.not(&block)).to be == expected }
|
904
|
+
end
|
905
|
+
end
|
906
|
+
|
907
|
+
describe 'with a hash' do
|
908
|
+
let(:value) { { 'title' => 'A Wizard of Earthsea' } }
|
909
|
+
let(:expected) do
|
910
|
+
Cuprum::Collections::Scope.new(value).invert
|
911
|
+
end
|
912
|
+
|
913
|
+
it { expect(subject.not(value)).to be == expected }
|
914
|
+
|
915
|
+
wrap_context 'when the scope has multiple criteria' do
|
916
|
+
let(:expected) do
|
917
|
+
wrapped = Cuprum::Collections::Scope.new(value)
|
918
|
+
|
919
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
920
|
+
scopes: [subject, wrapped.invert]
|
921
|
+
)
|
922
|
+
end
|
923
|
+
|
924
|
+
it { expect(subject.not(value)).to be == expected }
|
925
|
+
end
|
926
|
+
end
|
927
|
+
|
928
|
+
wrap_context 'with an all scope' do
|
929
|
+
it { expect(subject.not(original)).to be == original.invert }
|
930
|
+
|
931
|
+
wrap_context 'when the scope has multiple criteria' do
|
932
|
+
it { expect(subject.not(original)).to be == original.invert }
|
933
|
+
end
|
934
|
+
end
|
935
|
+
|
936
|
+
wrap_context 'with a none scope' do
|
937
|
+
it { expect(subject.not(original)).to be == original.invert }
|
938
|
+
|
939
|
+
wrap_context 'when the scope has multiple criteria' do
|
940
|
+
it { expect(subject.not(original)).to be subject }
|
941
|
+
end
|
942
|
+
end
|
943
|
+
|
944
|
+
wrap_context 'with an empty conjunction scope' do
|
945
|
+
it { expect(subject.not(original)).to be subject }
|
946
|
+
|
947
|
+
wrap_context 'when the scope has multiple criteria' do
|
948
|
+
it { expect(subject.not(original)).to be subject }
|
949
|
+
end
|
950
|
+
end
|
951
|
+
|
952
|
+
wrap_context 'with an empty criteria scope' do
|
953
|
+
it { expect(subject.not(original)).to be subject }
|
954
|
+
|
955
|
+
wrap_context 'when the scope has multiple criteria' do
|
956
|
+
it { expect(subject.not(original)).to be subject }
|
957
|
+
end
|
958
|
+
end
|
959
|
+
|
960
|
+
context 'with an empty inverted criteria scope' do
|
961
|
+
include_context 'with an empty criteria scope'
|
962
|
+
|
963
|
+
let(:inverted) { original.invert }
|
964
|
+
|
965
|
+
it { expect(subject.not(inverted)).to be subject }
|
966
|
+
|
967
|
+
wrap_context 'when the scope has multiple criteria' do
|
968
|
+
it { expect(subject.not(original)).to be subject }
|
969
|
+
end
|
970
|
+
end
|
971
|
+
|
972
|
+
wrap_context 'with an empty disjunction scope' do
|
973
|
+
it { expect(subject.not(original)).to be subject }
|
974
|
+
|
975
|
+
wrap_context 'when the scope has multiple criteria' do
|
976
|
+
it { expect(subject.not(original)).to be subject }
|
977
|
+
end
|
978
|
+
end
|
979
|
+
|
980
|
+
wrap_context 'with a non-empty conjunction scope' do
|
981
|
+
it { expect(subject.not(original)).to be == original.invert }
|
982
|
+
|
983
|
+
wrap_context 'when the scope has multiple criteria' do
|
984
|
+
let(:expected) do
|
985
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
986
|
+
scopes: [subject, original.invert]
|
987
|
+
)
|
988
|
+
end
|
989
|
+
|
990
|
+
it { expect(subject.not(original)).to be == expected }
|
991
|
+
end
|
992
|
+
end
|
993
|
+
|
994
|
+
wrap_context 'with a non-empty criteria scope' do
|
995
|
+
it { expect(subject.not(original)).to be == original.invert }
|
996
|
+
|
997
|
+
wrap_context 'when the scope has multiple criteria' do
|
998
|
+
let(:expected) do
|
999
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
1000
|
+
scopes: [subject, original.invert]
|
1001
|
+
)
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
it { expect(subject.not(original)).to be == expected }
|
1005
|
+
end
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
context 'with a non-empty inverted criteria scope' do
|
1009
|
+
include_context 'with a non-empty criteria scope'
|
1010
|
+
|
1011
|
+
let(:inverted) { original.invert }
|
1012
|
+
|
1013
|
+
it { expect(subject.not(inverted)).to be == original }
|
1014
|
+
|
1015
|
+
wrap_context 'when the scope has multiple criteria' do
|
1016
|
+
let(:expected) do
|
1017
|
+
Cuprum::Collections::Scopes::CriteriaScope.new(
|
1018
|
+
criteria: [*subject.criteria, *original.criteria]
|
1019
|
+
)
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
it { expect(subject.not(inverted)).to be == expected }
|
1023
|
+
end
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
wrap_context 'with a non-empty disjunction scope' do
|
1027
|
+
it { expect(subject.not(original)).to be == original.invert }
|
1028
|
+
|
1029
|
+
wrap_context 'when the scope has multiple criteria' do
|
1030
|
+
let(:expected) do
|
1031
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
1032
|
+
scopes: [subject, *original.invert.scopes]
|
1033
|
+
)
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
it { expect(subject.not(original)).to be == expected }
|
1037
|
+
end
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
wrap_context 'when initialized with inverted: true' do
|
1041
|
+
describe 'with a block' do
|
1042
|
+
let(:block) { -> { { 'title' => 'A Wizard of Earthsea' } } }
|
1043
|
+
let(:expected) do
|
1044
|
+
Cuprum::Collections::Scope.new(&block).invert
|
1045
|
+
end
|
1046
|
+
|
1047
|
+
it { expect(subject.not(&block)).to be == expected }
|
1048
|
+
|
1049
|
+
wrap_context 'when the scope has multiple criteria' do
|
1050
|
+
let(:expected) do
|
1051
|
+
wrapped = Cuprum::Collections::Scope.new(&block)
|
1052
|
+
|
1053
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
1054
|
+
scopes: [subject, wrapped.invert]
|
1055
|
+
)
|
1056
|
+
end
|
1057
|
+
|
1058
|
+
it { expect(subject.not(&block)).to be == expected }
|
1059
|
+
end
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
describe 'with a hash' do
|
1063
|
+
let(:value) { { 'title' => 'A Wizard of Earthsea' } }
|
1064
|
+
let(:expected) do
|
1065
|
+
Cuprum::Collections::Scope.new(value).invert
|
1066
|
+
end
|
1067
|
+
|
1068
|
+
it { expect(subject.not(value)).to be == expected }
|
1069
|
+
|
1070
|
+
wrap_context 'when the scope has multiple criteria' do
|
1071
|
+
let(:expected) do
|
1072
|
+
wrapped = Cuprum::Collections::Scope.new(value)
|
1073
|
+
|
1074
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
1075
|
+
scopes: [subject, wrapped.invert]
|
1076
|
+
)
|
1077
|
+
end
|
1078
|
+
|
1079
|
+
it { expect(subject.not(value)).to be == expected }
|
1080
|
+
end
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
wrap_context 'with an all scope' do
|
1084
|
+
it { expect(subject.not(original)).to be == original.invert }
|
1085
|
+
|
1086
|
+
wrap_context 'when the scope has multiple criteria' do
|
1087
|
+
it { expect(subject.not(original)).to be == original.invert }
|
1088
|
+
end
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
wrap_context 'with a none scope' do
|
1092
|
+
it { expect(subject.not(original)).to be == original.invert }
|
1093
|
+
|
1094
|
+
wrap_context 'when the scope has multiple criteria' do
|
1095
|
+
it { expect(subject.not(original)).to be subject }
|
1096
|
+
end
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
wrap_context 'with an empty conjunction scope' do
|
1100
|
+
it { expect(subject.not(original)).to be subject }
|
1101
|
+
|
1102
|
+
wrap_context 'when the scope has multiple criteria' do
|
1103
|
+
it { expect(subject.not(original)).to be subject }
|
1104
|
+
end
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
wrap_context 'with an empty criteria scope' do
|
1108
|
+
it { expect(subject.not(original)).to be subject }
|
1109
|
+
|
1110
|
+
wrap_context 'when the scope has multiple criteria' do
|
1111
|
+
it { expect(subject.not(original)).to be subject }
|
1112
|
+
end
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
context 'with an empty inverted criteria scope' do
|
1116
|
+
include_context 'with an empty criteria scope'
|
1117
|
+
|
1118
|
+
let(:inverted) { original.invert }
|
1119
|
+
|
1120
|
+
it { expect(subject.not(inverted)).to be subject }
|
1121
|
+
|
1122
|
+
wrap_context 'when the scope has multiple criteria' do
|
1123
|
+
it { expect(subject.not(original)).to be subject }
|
1124
|
+
end
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
wrap_context 'with an empty disjunction scope' do
|
1128
|
+
it { expect(subject.not(original)).to be subject }
|
1129
|
+
|
1130
|
+
wrap_context 'when the scope has multiple criteria' do
|
1131
|
+
it { expect(subject.not(original)).to be subject }
|
1132
|
+
end
|
1133
|
+
end
|
1134
|
+
|
1135
|
+
wrap_context 'with a non-empty conjunction scope' do
|
1136
|
+
it { expect(subject.not(original)).to be == original.invert }
|
1137
|
+
|
1138
|
+
wrap_context 'when the scope has multiple criteria' do
|
1139
|
+
let(:expected) do
|
1140
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
1141
|
+
scopes: [subject, original.invert]
|
1142
|
+
)
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
it { expect(subject.not(original)).to be == expected }
|
1146
|
+
end
|
1147
|
+
end
|
1148
|
+
|
1149
|
+
wrap_context 'with a non-empty criteria scope' do
|
1150
|
+
it { expect(subject.not(original)).to be == original.invert }
|
1151
|
+
|
1152
|
+
wrap_context 'when the scope has multiple criteria' do
|
1153
|
+
let(:expected) do
|
1154
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
1155
|
+
scopes: [subject, original.invert]
|
1156
|
+
)
|
1157
|
+
end
|
1158
|
+
|
1159
|
+
it { expect(subject.not(original)).to be == expected }
|
1160
|
+
end
|
1161
|
+
end
|
1162
|
+
|
1163
|
+
context 'with a non-empty inverted criteria scope' do
|
1164
|
+
include_context 'with a non-empty criteria scope'
|
1165
|
+
|
1166
|
+
let(:inverted) { original.invert }
|
1167
|
+
|
1168
|
+
it { expect(subject.not(inverted)).to be == original }
|
1169
|
+
|
1170
|
+
wrap_context 'when the scope has multiple criteria' do
|
1171
|
+
let(:expected) do
|
1172
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
1173
|
+
scopes: [subject, original]
|
1174
|
+
)
|
1175
|
+
end
|
1176
|
+
|
1177
|
+
it { expect(subject.not(inverted)).to be == expected }
|
1178
|
+
end
|
1179
|
+
end
|
1180
|
+
|
1181
|
+
wrap_context 'with a non-empty disjunction scope' do
|
1182
|
+
it { expect(subject.not(original)).to be == original.invert }
|
1183
|
+
|
1184
|
+
wrap_context 'when the scope has multiple criteria' do
|
1185
|
+
let(:expected) do
|
1186
|
+
Cuprum::Collections::Scopes::ConjunctionScope.new(
|
1187
|
+
scopes: [subject, *original.invert.scopes]
|
1188
|
+
)
|
1189
|
+
end
|
1190
|
+
|
1191
|
+
it { expect(subject.not(original)).to be == expected }
|
1192
|
+
end
|
1193
|
+
end
|
1194
|
+
end
|
1195
|
+
end
|
1196
|
+
|
1197
|
+
describe '#or' do
|
1198
|
+
describe 'with a block' do
|
1199
|
+
let(:block) { -> { { 'title' => 'A Wizard of Earthsea' } } }
|
1200
|
+
let(:expected) do
|
1201
|
+
Cuprum::Collections::Scope.new(&block)
|
1202
|
+
end
|
1203
|
+
|
1204
|
+
it { expect(subject.or(&block)).to be == expected }
|
1205
|
+
|
1206
|
+
wrap_context 'when the scope has multiple criteria' do
|
1207
|
+
let(:expected) do
|
1208
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(
|
1209
|
+
scopes: [subject, super()]
|
1210
|
+
)
|
1211
|
+
end
|
1212
|
+
|
1213
|
+
it { expect(subject.or(&block)).to be == expected }
|
1214
|
+
end
|
1215
|
+
end
|
1216
|
+
|
1217
|
+
describe 'with a hash' do
|
1218
|
+
let(:value) { { 'title' => 'A Wizard of Earthsea' } }
|
1219
|
+
let(:expected) do
|
1220
|
+
Cuprum::Collections::Scope.new(value)
|
1221
|
+
end
|
1222
|
+
|
1223
|
+
it { expect(subject.or(value)).to be == expected }
|
1224
|
+
|
1225
|
+
wrap_context 'when the scope has multiple criteria' do
|
1226
|
+
let(:expected) do
|
1227
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(
|
1228
|
+
scopes: [subject, super()]
|
1229
|
+
)
|
1230
|
+
end
|
1231
|
+
|
1232
|
+
it { expect(subject.or(value)).to be == expected }
|
1233
|
+
end
|
1234
|
+
end
|
1235
|
+
|
1236
|
+
wrap_context 'with an all scope' do
|
1237
|
+
it { expect(subject.or(original)).to be == original }
|
1238
|
+
|
1239
|
+
wrap_context 'when the scope has multiple criteria' do
|
1240
|
+
it { expect(subject.or(original)).to be == original }
|
1241
|
+
end
|
1242
|
+
end
|
1243
|
+
|
1244
|
+
wrap_context 'with a none scope' do
|
1245
|
+
it { expect(subject.or(original)).to be subject }
|
1246
|
+
|
1247
|
+
wrap_context 'when the scope has multiple criteria' do
|
1248
|
+
it { expect(subject.or(original)).to be subject }
|
1249
|
+
end
|
1250
|
+
end
|
1251
|
+
|
1252
|
+
wrap_context 'with an empty conjunction scope' do
|
1253
|
+
it { expect(subject.or(original)).to be subject }
|
1254
|
+
|
1255
|
+
wrap_context 'when the scope has multiple criteria' do
|
1256
|
+
it { expect(subject.or(original)).to be subject }
|
1257
|
+
end
|
1258
|
+
end
|
1259
|
+
|
1260
|
+
wrap_context 'with an empty criteria scope' do
|
1261
|
+
it { expect(subject.or(original)).to be subject }
|
1262
|
+
|
1263
|
+
wrap_context 'when the scope has multiple criteria' do
|
1264
|
+
it { expect(subject.or(original)).to be subject }
|
1265
|
+
end
|
1266
|
+
end
|
1267
|
+
|
1268
|
+
wrap_context 'with an empty disjunction scope' do
|
1269
|
+
it { expect(subject.or(original)).to be subject }
|
1270
|
+
|
1271
|
+
wrap_context 'when the scope has multiple criteria' do
|
1272
|
+
it { expect(subject.or(original)).to be subject }
|
1273
|
+
end
|
1274
|
+
end
|
1275
|
+
|
1276
|
+
wrap_context 'with a non-empty conjunction scope' do
|
1277
|
+
it { expect(subject.or(original)).to be == original }
|
1278
|
+
|
1279
|
+
wrap_context 'when the scope has multiple criteria' do
|
1280
|
+
let(:expected) do
|
1281
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(
|
1282
|
+
scopes: [subject, original]
|
1283
|
+
)
|
1284
|
+
end
|
1285
|
+
|
1286
|
+
it { expect(subject.or(original)).to be == expected }
|
1287
|
+
end
|
1288
|
+
end
|
1289
|
+
|
1290
|
+
wrap_context 'with a non-empty criteria scope' do
|
1291
|
+
it { expect(subject.or(original)).to be == original }
|
1292
|
+
|
1293
|
+
wrap_context 'when the scope has multiple criteria' do
|
1294
|
+
let(:expected) do
|
1295
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(
|
1296
|
+
scopes: [subject, original]
|
1297
|
+
)
|
1298
|
+
end
|
1299
|
+
|
1300
|
+
it { expect(subject.or(original)).to be == expected }
|
1301
|
+
end
|
1302
|
+
end
|
1303
|
+
|
1304
|
+
wrap_context 'with a non-empty disjunction scope' do
|
1305
|
+
it { expect(subject.or(original)).to be == original }
|
1306
|
+
|
1307
|
+
wrap_context 'when the scope has multiple criteria' do
|
1308
|
+
let(:expected) do
|
1309
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(
|
1310
|
+
scopes: [subject, *original.scopes]
|
1311
|
+
)
|
1312
|
+
end
|
1313
|
+
|
1314
|
+
it { expect(subject.or(original)).to be == expected }
|
1315
|
+
end
|
1316
|
+
end
|
1317
|
+
end
|
1318
|
+
end
|
1319
|
+
end
|
1320
|
+
|
1321
|
+
# Contract validating scope composition for disjunction scopes.
|
1322
|
+
module ShouldComposeScopesForDisjunctionContract
|
1323
|
+
extend RSpec::SleepingKingStudios::Contract
|
1324
|
+
include Cuprum::Collections::RSpec::Contracts::Scopes::CompositionContracts # rubocop:disable Layout/LineLength
|
1325
|
+
|
1326
|
+
# @!method apply(example_group)
|
1327
|
+
# Adds the contract to the example group.
|
1328
|
+
#
|
1329
|
+
# @param example_group [RSpec::Core::ExampleGroup] the example group to
|
1330
|
+
# which the contract is applied.
|
1331
|
+
contract do
|
1332
|
+
shared_context 'when the scope has many child scopes' do
|
1333
|
+
let(:scopes) do
|
1334
|
+
[
|
1335
|
+
build_scope({ 'author' => 'J.R.R. Tolkien' }),
|
1336
|
+
build_scope({ 'series' => 'The Lord of the Rings' }),
|
1337
|
+
build_scope do |scope|
|
1338
|
+
{ 'published_at' => scope.less_than('1955-01-01') }
|
1339
|
+
end
|
1340
|
+
]
|
1341
|
+
end
|
1342
|
+
end
|
1343
|
+
|
1344
|
+
include_contract 'should compose scopes', except: %i[or]
|
1345
|
+
|
1346
|
+
describe '#or' do
|
1347
|
+
describe 'with a block' do
|
1348
|
+
let(:block) { -> { { 'title' => 'A Wizard of Earthsea' } } }
|
1349
|
+
let(:expected) do
|
1350
|
+
wrapped = Cuprum::Collections::Scope.new(&block)
|
1351
|
+
|
1352
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(
|
1353
|
+
scopes: [*subject.scopes, wrapped]
|
1354
|
+
)
|
1355
|
+
end
|
1356
|
+
|
1357
|
+
it { expect(subject.or(&block)).to be == expected }
|
1358
|
+
end
|
1359
|
+
|
1360
|
+
describe 'with a hash' do
|
1361
|
+
let(:value) { { 'title' => 'A Wizard of Earthsea' } }
|
1362
|
+
let(:expected) do
|
1363
|
+
wrapped = Cuprum::Collections::Scope.new(value)
|
1364
|
+
|
1365
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(
|
1366
|
+
scopes: [*subject.scopes, wrapped]
|
1367
|
+
)
|
1368
|
+
end
|
1369
|
+
|
1370
|
+
it { expect(subject.or(value)).to be == expected }
|
1371
|
+
end
|
1372
|
+
|
1373
|
+
wrap_context 'with an all scope' do
|
1374
|
+
it { expect(subject.or(original)).to be == original }
|
1375
|
+
end
|
1376
|
+
|
1377
|
+
wrap_context 'with a none scope' do
|
1378
|
+
it { expect(subject.or(original)).to be subject }
|
1379
|
+
end
|
1380
|
+
|
1381
|
+
wrap_context 'with an empty conjunction scope' do
|
1382
|
+
it { expect(subject.or(original)).to be subject }
|
1383
|
+
end
|
1384
|
+
|
1385
|
+
wrap_context 'with an empty criteria scope' do
|
1386
|
+
it { expect(subject.or(original)).to be subject }
|
1387
|
+
end
|
1388
|
+
|
1389
|
+
wrap_context 'with an empty disjunction scope' do
|
1390
|
+
it { expect(subject.or(original)).to be subject }
|
1391
|
+
end
|
1392
|
+
|
1393
|
+
wrap_context 'with a non-empty conjunction scope' do
|
1394
|
+
let(:expected) do
|
1395
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(
|
1396
|
+
scopes: [*subject.scopes, original]
|
1397
|
+
)
|
1398
|
+
end
|
1399
|
+
|
1400
|
+
it { expect(subject.or(original)).to be == expected }
|
1401
|
+
end
|
1402
|
+
|
1403
|
+
wrap_context 'with a non-empty criteria scope' do
|
1404
|
+
let(:expected) do
|
1405
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(
|
1406
|
+
scopes: [*subject.scopes, original]
|
1407
|
+
)
|
1408
|
+
end
|
1409
|
+
|
1410
|
+
it { expect(subject.or(original)).to be == expected }
|
1411
|
+
end
|
1412
|
+
|
1413
|
+
wrap_context 'with a non-empty disjunction scope' do
|
1414
|
+
let(:expected) do
|
1415
|
+
Cuprum::Collections::Scopes::DisjunctionScope.new(
|
1416
|
+
scopes: [*subject.scopes, *original.scopes]
|
1417
|
+
)
|
1418
|
+
end
|
1419
|
+
|
1420
|
+
it { expect(subject.or(original)).to be == expected }
|
1421
|
+
|
1422
|
+
wrap_context 'when the scope has many child scopes' do
|
1423
|
+
it { expect(subject.or(original)).to be == expected }
|
1424
|
+
end
|
1425
|
+
end
|
1426
|
+
end
|
1427
|
+
end
|
1428
|
+
end
|
1429
|
+
end
|
1430
|
+
end
|