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
@@ -17,43 +17,53 @@ module Cuprum::Collections::RSpec::Contracts
|
|
17
17
|
OPERATORS = Cuprum::Collections::Queries::Operators
|
18
18
|
private_constant :OPERATORS
|
19
19
|
|
20
|
-
# @!method apply(example_group,
|
20
|
+
# @!method apply(example_group, abstract: false)
|
21
21
|
# Adds the contract to the example group.
|
22
22
|
#
|
23
23
|
# @param example_group [RSpec::Core::ExampleGroup] the example group to
|
24
24
|
# which the contract is applied.
|
25
|
-
# @param
|
26
|
-
|
25
|
+
# @param abstract [Boolean] if true, the query does not implement
|
26
|
+
# methods for operating on a collection. Defaults to false.
|
27
|
+
contract do |abstract: false|
|
27
28
|
include Cuprum::Collections::RSpec::Contracts::QueryContracts
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
shared_context 'when initialized with a scope' do
|
31
|
+
let(:initial_scope) do
|
32
|
+
Cuprum::Collections::Scope.new do |scope|
|
33
|
+
{ 'published_at' => scope.less_than('1973-01-01') }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
let(:filtered_data) do
|
37
|
+
super().select { |item| item['published_at'] < '1973-01-01' }
|
38
|
+
end
|
39
|
+
end
|
32
40
|
|
33
41
|
shared_context 'when the query has composed filters' do
|
34
42
|
let(:scoped_query) do
|
35
43
|
super()
|
36
44
|
.where { { author: 'Ursula K. LeGuin' } }
|
37
|
-
.where { { series: not_equal('Earthsea') } }
|
45
|
+
.where { |scope| { series: scope.not_equal('Earthsea') } }
|
38
46
|
end
|
39
|
-
let(:
|
47
|
+
let(:filtered_data) do
|
40
48
|
super()
|
41
49
|
.select { |item| item['author'] == 'Ursula K. LeGuin' }
|
42
50
|
.reject { |item| item['series'] == 'Earthsea' }
|
43
51
|
end
|
44
52
|
end
|
45
53
|
|
54
|
+
let(:filter) { nil }
|
55
|
+
let(:limit) { nil }
|
56
|
+
let(:offset) { nil }
|
57
|
+
let(:order) { nil }
|
46
58
|
let(:scoped_query) do
|
47
|
-
# :nocov:
|
48
59
|
scoped =
|
49
60
|
if filter.is_a?(Proc)
|
50
|
-
|
51
|
-
elsif
|
52
|
-
|
61
|
+
subject.where(&filter)
|
62
|
+
elsif filter
|
63
|
+
subject.where(filter)
|
53
64
|
else
|
54
|
-
|
65
|
+
subject
|
55
66
|
end
|
56
|
-
# :nocov:
|
57
67
|
scoped = scoped.limit(limit) if limit
|
58
68
|
scoped = scoped.offset(offset) if offset
|
59
69
|
scoped = scoped.order(order) if order
|
@@ -66,19 +76,11 @@ module Cuprum::Collections::RSpec::Contracts
|
|
66
76
|
end
|
67
77
|
|
68
78
|
describe '#count' do
|
69
|
-
let(:data) { [] }
|
70
|
-
let(:matching_data) { data }
|
71
|
-
let(:expected_data) do
|
72
|
-
defined?(super()) ? super() : matching_data
|
73
|
-
end
|
74
|
-
|
75
79
|
it { expect(query).to respond_to(:count).with(0).arguments }
|
76
80
|
|
77
|
-
|
81
|
+
next if abstract
|
78
82
|
|
79
|
-
|
80
|
-
it { expect(scoped_query.count).to be == expected_data.count }
|
81
|
-
end
|
83
|
+
it { expect(query.count).to be 0 }
|
82
84
|
|
83
85
|
context 'when the collection data changes' do
|
84
86
|
let(:item) { BOOKS_FIXTURES.first }
|
@@ -89,16 +91,26 @@ module Cuprum::Collections::RSpec::Contracts
|
|
89
91
|
add_item_to_collection(item)
|
90
92
|
end
|
91
93
|
|
92
|
-
it { expect(query.count).to be
|
94
|
+
it { expect(query.count).to be 0 }
|
93
95
|
end
|
94
96
|
|
95
97
|
context 'when the collection has many items' do
|
96
98
|
let(:data) { BOOKS_FIXTURES }
|
97
99
|
|
98
|
-
|
99
|
-
|
100
|
-
wrap_context 'when the query has composed filters' do
|
100
|
+
include_contract 'should query the collection', :ignore_order do
|
101
101
|
it { expect(scoped_query.count).to be == expected_data.count }
|
102
|
+
|
103
|
+
wrap_context 'when the query has composed filters' do
|
104
|
+
it { expect(scoped_query.count).to be == expected_data.count }
|
105
|
+
end
|
106
|
+
|
107
|
+
wrap_context 'when initialized with a scope' do
|
108
|
+
it { expect(scoped_query.count).to be == expected_data.count }
|
109
|
+
|
110
|
+
wrap_context 'when the query has composed filters' do
|
111
|
+
it { expect(scoped_query.count).to be == expected_data.count }
|
112
|
+
end
|
113
|
+
end
|
102
114
|
end
|
103
115
|
|
104
116
|
context 'when the collection data changes' do
|
@@ -116,75 +128,12 @@ module Cuprum::Collections::RSpec::Contracts
|
|
116
128
|
end
|
117
129
|
end
|
118
130
|
|
119
|
-
describe '#criteria' do
|
120
|
-
include_examples 'should have reader', :criteria, []
|
121
|
-
|
122
|
-
wrap_context 'when the query has where: a simple block filter' do
|
123
|
-
let(:expected) { [['author', :equal, 'Ursula K. LeGuin']] }
|
124
|
-
|
125
|
-
it { expect(scoped_query.criteria).to be == expected }
|
126
|
-
end
|
127
|
-
|
128
|
-
wrap_context 'when the query has where: a complex block filter' do
|
129
|
-
let(:expected) do
|
130
|
-
[
|
131
|
-
['author', :equal, 'Ursula K. LeGuin'],
|
132
|
-
['series', :not_equal, 'Earthsea']
|
133
|
-
]
|
134
|
-
end
|
135
|
-
|
136
|
-
if operators.include?(OPERATORS::EQUAL) &&
|
137
|
-
operators.include?(OPERATORS::NOT_EQUAL)
|
138
|
-
it { expect(scoped_query.criteria).to be == expected }
|
139
|
-
else
|
140
|
-
# :nocov:
|
141
|
-
pending
|
142
|
-
# :nocov:
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
wrap_context 'when the query has composed filters' do
|
147
|
-
let(:expected) do
|
148
|
-
[
|
149
|
-
['author', :equal, 'Ursula K. LeGuin'],
|
150
|
-
['series', :not_equal, 'Earthsea']
|
151
|
-
]
|
152
|
-
end
|
153
|
-
|
154
|
-
it { expect(scoped_query.criteria).to be == expected }
|
155
|
-
end
|
156
|
-
|
157
|
-
wrap_context 'when the query has where: an equal block filter' do
|
158
|
-
let(:expected) { [['author', :equal, 'Ursula K. LeGuin']] }
|
159
|
-
|
160
|
-
if operators.include?(OPERATORS::EQUAL)
|
161
|
-
it { expect(scoped_query.criteria).to be == expected }
|
162
|
-
else
|
163
|
-
# :nocov:
|
164
|
-
pending
|
165
|
-
# :nocov:
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
wrap_context 'when the query has where: a not_equal block filter' do
|
170
|
-
let(:expected) { [['author', :not_equal, 'Ursula K. LeGuin']] }
|
171
|
-
|
172
|
-
if operators.include?(OPERATORS::NOT_EQUAL)
|
173
|
-
it { expect(scoped_query.criteria).to be == expected }
|
174
|
-
else
|
175
|
-
# :nocov:
|
176
|
-
pending
|
177
|
-
# :nocov:
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
131
|
describe '#each' do
|
183
132
|
shared_examples 'should enumerate the matching data' do
|
184
133
|
describe 'with no arguments' do
|
185
134
|
it { expect(scoped_query.each).to be_a Enumerator }
|
186
135
|
|
187
|
-
it { expect(scoped_query.each.count).to be ==
|
136
|
+
it { expect(scoped_query.each.count).to be == expected_data.size }
|
188
137
|
|
189
138
|
it { expect(scoped_query.each.to_a).to deep_match expected_data }
|
190
139
|
end
|
@@ -197,26 +146,12 @@ module Cuprum::Collections::RSpec::Contracts
|
|
197
146
|
end
|
198
147
|
end
|
199
148
|
|
200
|
-
|
201
|
-
let(:matching_data) { data }
|
202
|
-
let(:expected_data) do
|
203
|
-
defined?(super()) ? super() : matching_data
|
204
|
-
end
|
149
|
+
next if abstract
|
205
150
|
|
206
151
|
it { expect(query).to respond_to(:each).with(0).arguments }
|
207
152
|
|
208
153
|
include_examples 'should enumerate the matching data'
|
209
154
|
|
210
|
-
include_contract 'should perform queries',
|
211
|
-
block: lambda {
|
212
|
-
include_examples 'should enumerate the matching data'
|
213
|
-
},
|
214
|
-
operators: operators
|
215
|
-
|
216
|
-
wrap_context 'when the query has composed filters' do
|
217
|
-
include_examples 'should enumerate the matching data'
|
218
|
-
end
|
219
|
-
|
220
155
|
context 'when the collection data changes' do
|
221
156
|
let(:item) { BOOKS_FIXTURES.first }
|
222
157
|
|
@@ -232,16 +167,20 @@ module Cuprum::Collections::RSpec::Contracts
|
|
232
167
|
context 'when the collection has many items' do
|
233
168
|
let(:data) { BOOKS_FIXTURES }
|
234
169
|
|
235
|
-
|
170
|
+
include_contract 'should query the collection' do
|
171
|
+
include_examples 'should enumerate the matching data'
|
236
172
|
|
237
|
-
|
238
|
-
block: lambda {
|
173
|
+
wrap_context 'when the query has composed filters' do
|
239
174
|
include_examples 'should enumerate the matching data'
|
240
|
-
|
241
|
-
operators: operators
|
175
|
+
end
|
242
176
|
|
243
|
-
|
244
|
-
|
177
|
+
wrap_context 'when initialized with a scope' do
|
178
|
+
include_examples 'should enumerate the matching data'
|
179
|
+
|
180
|
+
wrap_context 'when the query has composed filters' do
|
181
|
+
include_examples 'should enumerate the matching data'
|
182
|
+
end
|
183
|
+
end
|
245
184
|
end
|
246
185
|
|
247
186
|
context 'when the collection data changes' do
|
@@ -261,39 +200,35 @@ module Cuprum::Collections::RSpec::Contracts
|
|
261
200
|
|
262
201
|
describe '#exists?' do
|
263
202
|
shared_examples 'should check the existence of matching data' do
|
264
|
-
|
203
|
+
let(:data) { [] }
|
204
|
+
let(:expected_data) { defined?(super()) ? super() : data }
|
205
|
+
|
206
|
+
it { expect(query.exists?).to be == !expected_data.empty? }
|
265
207
|
end
|
266
208
|
|
267
|
-
|
268
|
-
let(:matching_data) { data }
|
209
|
+
next if abstract
|
269
210
|
|
270
211
|
include_examples 'should define predicate', :exists?
|
271
212
|
|
272
213
|
include_examples 'should check the existence of matching data'
|
273
214
|
|
274
|
-
include_contract 'should perform queries',
|
275
|
-
block: lambda {
|
276
|
-
include_examples 'should check the existence of matching data'
|
277
|
-
},
|
278
|
-
operators: operators
|
279
|
-
|
280
|
-
wrap_context 'when the query has composed filters' do
|
281
|
-
include_examples 'should check the existence of matching data'
|
282
|
-
end
|
283
|
-
|
284
215
|
context 'when the collection has many items' do
|
285
216
|
let(:data) { BOOKS_FIXTURES }
|
286
217
|
|
287
|
-
|
218
|
+
include_contract 'should query the collection', :ignore_order do
|
219
|
+
include_examples 'should check the existence of matching data'
|
288
220
|
|
289
|
-
|
290
|
-
block: lambda {
|
221
|
+
wrap_context 'when the query has composed filters' do
|
291
222
|
include_examples 'should check the existence of matching data'
|
292
|
-
|
293
|
-
operators: operators
|
223
|
+
end
|
294
224
|
|
295
|
-
|
296
|
-
|
225
|
+
wrap_context 'when initialized with a scope' do
|
226
|
+
include_examples 'should check the existence of matching data'
|
227
|
+
|
228
|
+
wrap_context 'when the query has composed filters' do
|
229
|
+
include_examples 'should check the existence of matching data'
|
230
|
+
end
|
231
|
+
end
|
297
232
|
end
|
298
233
|
end
|
299
234
|
end
|
@@ -495,6 +430,8 @@ module Cuprum::Collections::RSpec::Contracts
|
|
495
430
|
|
496
431
|
it { expect(query.reset).not_to be query }
|
497
432
|
|
433
|
+
next if abstract
|
434
|
+
|
498
435
|
it { expect(query.reset.to_a).to be == query.to_a }
|
499
436
|
|
500
437
|
context 'when the collection data changes' do
|
@@ -539,52 +476,93 @@ module Cuprum::Collections::RSpec::Contracts
|
|
539
476
|
end
|
540
477
|
end
|
541
478
|
|
542
|
-
describe '#
|
543
|
-
|
544
|
-
let(:matching_data) { data }
|
545
|
-
let(:expected_data) do
|
546
|
-
defined?(super()) ? super() : matching_data
|
547
|
-
end
|
479
|
+
describe '#scope' do
|
480
|
+
include_examples 'should define reader', :scope
|
548
481
|
|
549
|
-
it { expect(query).to
|
482
|
+
it { expect(query.scope).to be_a Cuprum::Collections::Scopes::Base }
|
483
|
+
|
484
|
+
it { expect(query.scope.type).to be :all }
|
485
|
+
|
486
|
+
wrap_context 'when initialized with a scope' do
|
487
|
+
let(:expected) do
|
488
|
+
Cuprum::Collections::Scope.new do |scope|
|
489
|
+
{
|
490
|
+
'published_at' => scope.less_than('1973-01-01')
|
491
|
+
}
|
492
|
+
end
|
493
|
+
end
|
550
494
|
|
551
|
-
|
495
|
+
it { expect(scoped_query.scope).to be == expected }
|
496
|
+
|
497
|
+
wrap_context 'when the query has composed filters' do
|
498
|
+
let(:expected) do
|
499
|
+
Cuprum::Collections::Scope.new do |scope|
|
500
|
+
{
|
501
|
+
'published_at' => scope.less_than('1973-01-01'),
|
502
|
+
'author' => 'Ursula K. LeGuin',
|
503
|
+
'series' => scope.not_equal('Earthsea')
|
504
|
+
}
|
505
|
+
end
|
506
|
+
end
|
552
507
|
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
},
|
557
|
-
operators: operators
|
508
|
+
it { expect(scoped_query.scope).to be == expected }
|
509
|
+
end
|
510
|
+
end
|
558
511
|
|
559
512
|
wrap_context 'when the query has composed filters' do
|
560
|
-
|
513
|
+
let(:expected) do
|
514
|
+
Cuprum::Collections::Scope.new do |scope|
|
515
|
+
{
|
516
|
+
'author' => 'Ursula K. LeGuin',
|
517
|
+
'series' => scope.not_equal('Earthsea')
|
518
|
+
}
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
it { expect(scoped_query.scope).to be == expected }
|
561
523
|
end
|
524
|
+
end
|
525
|
+
|
526
|
+
describe '#to_a' do
|
527
|
+
let(:data) { [] }
|
528
|
+
let(:queried_data) { scoped_query.to_a }
|
529
|
+
let(:expected_data) { defined?(super()) ? super() : data }
|
530
|
+
|
531
|
+
it { expect(query).to respond_to(:to_a).with(0).arguments }
|
532
|
+
|
533
|
+
next if abstract
|
534
|
+
|
535
|
+
it { expect(queried_data).to be == [] }
|
562
536
|
|
563
537
|
context 'when the collection data changes' do
|
564
538
|
let(:item) { BOOKS_FIXTURES.first }
|
565
539
|
|
566
540
|
before(:example) do
|
567
|
-
|
541
|
+
scoped_query.to_a # Cache query results.
|
568
542
|
|
569
543
|
add_item_to_collection(item)
|
570
544
|
end
|
571
545
|
|
572
|
-
it { expect(
|
546
|
+
it { expect(queried_data).to be == [] }
|
573
547
|
end
|
574
548
|
|
575
549
|
context 'when the collection has many items' do
|
576
550
|
let(:data) { BOOKS_FIXTURES }
|
577
551
|
|
578
|
-
|
552
|
+
include_contract 'should query the collection' do
|
553
|
+
it { expect(queried_data).to be == expected_data }
|
554
|
+
|
555
|
+
wrap_context 'when the query has composed filters' do
|
556
|
+
it { expect(queried_data).to be == expected_data }
|
557
|
+
end
|
579
558
|
|
580
|
-
|
581
|
-
|
582
|
-
it { expect(scoped_query.to_a).to deep_match expected_data }
|
583
|
-
},
|
584
|
-
operators: operators
|
559
|
+
wrap_context 'when initialized with a scope' do
|
560
|
+
it { expect(queried_data).to be == expected_data }
|
585
561
|
|
586
|
-
|
587
|
-
|
562
|
+
wrap_context 'when the query has composed filters' do
|
563
|
+
it { expect(queried_data).to be == expected_data }
|
564
|
+
end
|
565
|
+
end
|
588
566
|
end
|
589
567
|
|
590
568
|
context 'when the collection data changes' do
|
@@ -592,181 +570,195 @@ module Cuprum::Collections::RSpec::Contracts
|
|
592
570
|
let(:item) { BOOKS_FIXTURES.last }
|
593
571
|
|
594
572
|
before(:example) do
|
595
|
-
|
573
|
+
scoped_query.to_a # Cache query results.
|
596
574
|
|
597
575
|
add_item_to_collection(item)
|
598
576
|
end
|
599
577
|
|
600
|
-
it { expect(
|
578
|
+
it { expect(queried_data).to deep_match expected_data }
|
601
579
|
end
|
602
580
|
end
|
603
581
|
end
|
604
582
|
|
605
583
|
describe '#where' do
|
606
|
-
let(:block) { -> { { title: '
|
584
|
+
let(:block) { -> { { title: 'Gideon the Ninth' } } }
|
607
585
|
|
608
586
|
it 'should define the method' do
|
609
|
-
expect(
|
587
|
+
expect(subject)
|
610
588
|
.to respond_to(:where)
|
611
589
|
.with(0..1).arguments
|
612
|
-
.and_keywords(:strategy)
|
613
590
|
.and_a_block
|
614
591
|
end
|
615
592
|
|
616
|
-
|
617
|
-
it { expect(query.where).to be_a described_class }
|
593
|
+
it { expect(subject.where(&block)).to be_a described_class }
|
618
594
|
|
619
|
-
|
620
|
-
end
|
595
|
+
it { expect(subject.where(&block)).not_to be subject }
|
621
596
|
|
622
|
-
|
623
|
-
|
597
|
+
it 'should set the scope' do
|
598
|
+
expect(subject.where(&block).scope)
|
599
|
+
.to be_a Cuprum::Collections::Scopes::Base
|
600
|
+
end
|
624
601
|
|
625
|
-
|
602
|
+
it 'should not change the original query scope' do
|
603
|
+
expect { subject.where(&block) }
|
604
|
+
.not_to change(subject, :scope)
|
626
605
|
end
|
627
606
|
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
.to be_a described_class
|
607
|
+
context 'when the query does not have a scope' do
|
608
|
+
let(:expected) do
|
609
|
+
Cuprum::Collections::Scope.new({ 'title' => 'Gideon the Ninth' })
|
632
610
|
end
|
633
611
|
|
634
|
-
|
635
|
-
|
612
|
+
describe 'with a block' do
|
613
|
+
let(:block) { -> { { 'title' => 'Gideon the Ninth' } } }
|
636
614
|
|
637
|
-
|
638
|
-
let(:error_class) do
|
639
|
-
Cuprum::Collections::QueryBuilder::ParseError
|
615
|
+
it { expect(subject.where(&block).scope).to be == expected }
|
640
616
|
end
|
641
|
-
let(:error_message) { 'unable to parse query with strategy nil' }
|
642
617
|
|
643
|
-
|
644
|
-
|
645
|
-
.to raise_error error_class, error_message
|
646
|
-
end
|
647
|
-
end
|
618
|
+
describe 'with a hash' do
|
619
|
+
let(:value) { { 'title' => 'Gideon the Ninth' } }
|
648
620
|
|
649
|
-
|
650
|
-
let(:error_class) do
|
651
|
-
Cuprum::Collections::QueryBuilder::ParseError
|
621
|
+
it { expect(subject.where(value).scope).to be == expected }
|
652
622
|
end
|
653
|
-
|
654
|
-
|
623
|
+
|
624
|
+
describe 'with a basic scope' do
|
625
|
+
let(:value) do
|
626
|
+
Cuprum::Collections::Scope
|
627
|
+
.new({ 'title' => 'Gideon the Ninth' })
|
628
|
+
end
|
629
|
+
|
630
|
+
it { expect(subject.where(value).scope).to be == value }
|
655
631
|
end
|
656
632
|
|
657
|
-
|
658
|
-
|
659
|
-
|
633
|
+
describe 'with a complex scope' do
|
634
|
+
let(:value) do
|
635
|
+
Cuprum::Collections::Scope
|
636
|
+
.new({ 'title' => 'Gideon the Ninth' })
|
637
|
+
.or({ 'title' => 'Harrow the Ninth' })
|
638
|
+
end
|
639
|
+
|
640
|
+
it { expect(subject.where(value).scope).to be == value }
|
660
641
|
end
|
661
642
|
end
|
662
643
|
|
663
|
-
|
664
|
-
let(:
|
665
|
-
Cuprum::Collections::
|
644
|
+
context 'when the query has a scope' do
|
645
|
+
let(:initial_scope) do
|
646
|
+
Cuprum::Collections::Scope.new({ 'author' => 'Tamsyn Muir' })
|
666
647
|
end
|
667
|
-
let(:
|
648
|
+
let(:expected) do
|
649
|
+
operators = Cuprum::Collections::Queries::Operators
|
668
650
|
|
669
|
-
|
670
|
-
|
671
|
-
|
651
|
+
[
|
652
|
+
[
|
653
|
+
'author',
|
654
|
+
operators::EQUAL,
|
655
|
+
'Tamsyn Muir'
|
656
|
+
],
|
657
|
+
[
|
658
|
+
'title',
|
659
|
+
operators::EQUAL,
|
660
|
+
'Gideon the Ninth'
|
661
|
+
]
|
662
|
+
]
|
672
663
|
end
|
673
|
-
end
|
674
|
-
end
|
675
|
-
end
|
676
|
-
end
|
677
|
-
|
678
|
-
# Contract validating the behavior of a QueryBuilder implementation.
|
679
|
-
module ShouldBeAQueryBuilderContract
|
680
|
-
extend RSpec::SleepingKingStudios::Contract
|
681
664
|
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
# @param example_group [RSpec::Core::ExampleGroup] the example group to
|
686
|
-
# which the contract is applied.
|
687
|
-
contract do
|
688
|
-
describe '#base_query' do
|
689
|
-
include_examples 'should define reader',
|
690
|
-
:base_query,
|
691
|
-
-> { base_query }
|
692
|
-
end
|
665
|
+
describe 'with a block' do
|
666
|
+
let(:block) { -> { { 'title' => 'Gideon the Ninth' } } }
|
667
|
+
let(:scope) { subject.where(&block).scope }
|
693
668
|
|
694
|
-
|
695
|
-
let(:criteria) { [['title', :equal, 'The Naked Sun']] }
|
696
|
-
let(:expected) { criteria }
|
697
|
-
let(:filter) { { title: 'The Naked Sun' } }
|
698
|
-
let(:strategy) { :custom }
|
699
|
-
let(:parser) do
|
700
|
-
instance_double(
|
701
|
-
Cuprum::Collections::Queries::Parse,
|
702
|
-
call: Cuprum::Result.new(value: criteria)
|
703
|
-
)
|
704
|
-
end
|
705
|
-
let(:query) do
|
706
|
-
builder.call(strategy: strategy, where: filter)
|
707
|
-
end
|
669
|
+
it { expect(scope).to be_a Cuprum::Collections::Scopes::Base }
|
708
670
|
|
709
|
-
|
710
|
-
allow(Cuprum::Collections::Queries::Parse)
|
711
|
-
.to receive(:new)
|
712
|
-
.and_return(parser)
|
713
|
-
end
|
671
|
+
it { expect(scope.type).to be :criteria }
|
714
672
|
|
715
|
-
|
716
|
-
|
717
|
-
.with(0).arguments
|
718
|
-
.and_keywords(:strategy, :where)
|
719
|
-
end
|
673
|
+
it { expect(scope.criteria).to be == expected }
|
674
|
+
end
|
720
675
|
|
721
|
-
|
722
|
-
|
676
|
+
describe 'with a value' do
|
677
|
+
let(:value) { { 'title' => 'Gideon the Ninth' } }
|
678
|
+
let(:scope) { subject.where(value).scope }
|
723
679
|
|
724
|
-
|
725
|
-
.to have_received(:call)
|
726
|
-
.with(strategy: strategy, where: filter)
|
727
|
-
end
|
680
|
+
it { expect(scope).to be_a Cuprum::Collections::Scopes::Base }
|
728
681
|
|
729
|
-
|
682
|
+
it { expect(scope.type).to be :criteria }
|
730
683
|
|
731
|
-
|
684
|
+
it { expect(scope.criteria).to be == expected }
|
685
|
+
end
|
732
686
|
|
733
|
-
|
687
|
+
describe 'with a basic scope' do
|
688
|
+
let(:value) do
|
689
|
+
Cuprum::Collections::Scope
|
690
|
+
.new({ 'title' => 'Gideon the Ninth' })
|
691
|
+
end
|
692
|
+
let(:scope) { subject.where(value).scope }
|
734
693
|
|
735
|
-
|
736
|
-
let(:strategy) { :unsafe }
|
737
|
-
let(:filter) { criteria }
|
694
|
+
it { expect(scope).to be_a Cuprum::Collections::Scopes::Base }
|
738
695
|
|
739
|
-
|
740
|
-
builder.call(strategy: strategy, where: filter)
|
696
|
+
it { expect(scope.type).to be :criteria }
|
741
697
|
|
742
|
-
expect(
|
698
|
+
it { expect(scope.criteria).to be == expected }
|
743
699
|
end
|
744
700
|
|
745
|
-
|
746
|
-
|
701
|
+
describe 'with a complex scope' do
|
702
|
+
let(:value) do
|
703
|
+
Cuprum::Collections::Scope
|
704
|
+
.new({ 'title' => 'Gideon the Ninth' })
|
705
|
+
.or({ 'title' => 'Harrow the Ninth' })
|
706
|
+
end
|
707
|
+
let(:scope) { subject.where(value).scope }
|
708
|
+
let(:outer) { scope.scopes.last }
|
709
|
+
let(:expected) do
|
710
|
+
operators = Cuprum::Collections::Queries::Operators
|
711
|
+
|
712
|
+
[
|
713
|
+
[
|
714
|
+
'author',
|
715
|
+
operators::EQUAL,
|
716
|
+
'Tamsyn Muir'
|
717
|
+
]
|
718
|
+
]
|
719
|
+
end
|
720
|
+
let(:expected_first) do
|
721
|
+
operators = Cuprum::Collections::Queries::Operators
|
722
|
+
|
723
|
+
[
|
724
|
+
[
|
725
|
+
'title',
|
726
|
+
operators::EQUAL,
|
727
|
+
'Gideon the Ninth'
|
728
|
+
]
|
729
|
+
]
|
730
|
+
end
|
731
|
+
let(:expected_second) do
|
732
|
+
operators = Cuprum::Collections::Queries::Operators
|
733
|
+
|
734
|
+
[
|
735
|
+
[
|
736
|
+
'title',
|
737
|
+
operators::EQUAL,
|
738
|
+
'Harrow the Ninth'
|
739
|
+
]
|
740
|
+
]
|
741
|
+
end
|
747
742
|
|
748
|
-
|
749
|
-
let(:old_criteria) { [['genre', :eq, 'Science Fiction']] }
|
750
|
-
let(:expected) { old_criteria + criteria }
|
751
|
-
let(:base_query) { super().send(:with_criteria, old_criteria) }
|
743
|
+
it { expect(scope).to be_a Cuprum::Collections::Scopes::Base }
|
752
744
|
|
753
|
-
|
754
|
-
end
|
745
|
+
it { expect(scope.type).to be :conjunction }
|
755
746
|
|
756
|
-
|
757
|
-
let(:error) { Cuprum::Error.new(message: 'Something went wrong.') }
|
758
|
-
let(:result) { Cuprum::Result.new(error: error) }
|
747
|
+
it { expect(scope.scopes.size).to be 2 }
|
759
748
|
|
760
|
-
|
761
|
-
allow(parser).to receive(:call).and_return(result)
|
762
|
-
end
|
749
|
+
it { expect(scope.scopes.first.type).to be :criteria }
|
763
750
|
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
751
|
+
it { expect(scope.scopes.first.criteria).to be == expected }
|
752
|
+
|
753
|
+
it { expect(outer).to be_a Cuprum::Collections::Scopes::Base }
|
754
|
+
|
755
|
+
it { expect(outer.type).to be :disjunction }
|
756
|
+
|
757
|
+
it { expect(outer.scopes.size).to be 2 }
|
758
|
+
|
759
|
+
it { expect(outer.scopes.first.criteria).to be == expected_first }
|
760
|
+
|
761
|
+
it { expect(outer.scopes.last.criteria).to be == expected_second }
|
770
762
|
end
|
771
763
|
end
|
772
764
|
end
|
@@ -774,318 +766,147 @@ module Cuprum::Collections::RSpec::Contracts
|
|
774
766
|
end
|
775
767
|
|
776
768
|
# Contract validating the behavior when performing queries.
|
777
|
-
module
|
769
|
+
module ShouldQueryTheCollectionContract
|
778
770
|
extend RSpec::SleepingKingStudios::Contract
|
779
771
|
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
# @!method apply(example_group, block:, operators:)
|
784
|
-
# Adds the contract to the example group.
|
785
|
-
#
|
786
|
-
# @param example_group [RSpec::Core::ExampleGroup] the example group to
|
787
|
-
# which the contract is applied.
|
788
|
-
# @param block [Proc] the expectations for each query context.
|
789
|
-
# @param operators [Array<Symbol>] the expected operators.
|
790
|
-
contract do |block:, operators: OPERATORS.values|
|
791
|
-
operators = Set.new(operators.map(&:to_sym))
|
792
|
-
|
793
|
-
wrap_context 'when the query has limit: value' do
|
794
|
-
instance_exec(&block)
|
795
|
-
end
|
772
|
+
contract do |*tags, &examples|
|
773
|
+
ignore_order = tags.include?(:ignore_order)
|
796
774
|
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
775
|
+
shared_examples 'should query the collection' do
|
776
|
+
# :nocov:
|
777
|
+
if examples
|
778
|
+
instance_exec(&examples)
|
779
|
+
else
|
780
|
+
it { expect(queried_data).to be == expected_data }
|
781
|
+
end
|
782
|
+
# :nocov:
|
803
783
|
end
|
804
784
|
|
805
|
-
|
806
|
-
|
807
|
-
end
|
785
|
+
shared_examples 'should apply limit and offset' do
|
786
|
+
include_examples 'should query the collection'
|
808
787
|
|
809
|
-
|
810
|
-
|
811
|
-
include_context 'when the query has where: a simple block filter'
|
788
|
+
context 'with limit: value' do
|
789
|
+
let(:limit) { 3 }
|
812
790
|
|
813
|
-
|
791
|
+
include_examples 'should query the collection'
|
814
792
|
end
|
815
793
|
|
816
|
-
context 'with
|
817
|
-
|
794
|
+
context 'with offset: value' do
|
795
|
+
let(:offset) { 2 }
|
818
796
|
|
819
|
-
|
820
|
-
operators.include?(OPERATORS::NOT_EQUAL)
|
821
|
-
instance_exec(&block)
|
822
|
-
else
|
823
|
-
# :nocov:
|
824
|
-
pending
|
825
|
-
# :nocov:
|
826
|
-
end
|
827
|
-
end
|
828
|
-
|
829
|
-
context 'with an equals filter' do
|
830
|
-
include_context 'when the query has where: an equal block filter'
|
831
|
-
|
832
|
-
if operators.include?(OPERATORS::EQUAL)
|
833
|
-
instance_exec(&block)
|
834
|
-
else
|
835
|
-
# :nocov:
|
836
|
-
pending
|
837
|
-
# :nocov:
|
838
|
-
end
|
797
|
+
include_examples 'should query the collection'
|
839
798
|
end
|
840
799
|
|
841
|
-
|
842
|
-
|
800
|
+
describe 'with limit: value and offset: value' do
|
801
|
+
let(:limit) { 3 }
|
802
|
+
let(:offset) { 2 }
|
843
803
|
|
844
|
-
|
845
|
-
instance_exec(&block)
|
846
|
-
else
|
847
|
-
# :nocov:
|
848
|
-
pending
|
849
|
-
# :nocov:
|
850
|
-
end
|
804
|
+
include_examples 'should query the collection'
|
851
805
|
end
|
806
|
+
end
|
852
807
|
|
853
|
-
|
854
|
-
|
855
|
-
'when the query has where: a greater_than_or_equal_to filter'
|
856
|
-
|
857
|
-
if operators.include?(OPERATORS::GREATER_THAN_OR_EQUAL_TO)
|
858
|
-
instance_exec(&block)
|
859
|
-
else
|
860
|
-
# :nocov:
|
861
|
-
pending
|
862
|
-
# :nocov:
|
863
|
-
end
|
864
|
-
end
|
808
|
+
shared_examples 'should order the results' do
|
809
|
+
include_examples 'should apply limit and offset'
|
865
810
|
|
866
|
-
|
867
|
-
include_context 'when the query has where: a less_than filter'
|
811
|
+
next if ignore_order
|
868
812
|
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
pending
|
874
|
-
# :nocov:
|
813
|
+
describe 'with a simple ordering' do
|
814
|
+
let(:order) { 'title' }
|
815
|
+
let(:ordered_data) do
|
816
|
+
filtered_data.sort_by { |item| item['title'] }
|
875
817
|
end
|
876
|
-
end
|
877
818
|
|
878
|
-
|
879
|
-
include_context \
|
880
|
-
'when the query has where: a less_than_or_equal_to filter'
|
881
|
-
|
882
|
-
if operators.include?(OPERATORS::LESS_THAN_OR_EQUAL_TO)
|
883
|
-
instance_exec(&block)
|
884
|
-
else
|
885
|
-
# :nocov:
|
886
|
-
pending
|
887
|
-
# :nocov:
|
888
|
-
end
|
819
|
+
include_examples 'should apply limit and offset'
|
889
820
|
end
|
890
821
|
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
# :nocov:
|
898
|
-
pending
|
899
|
-
# :nocov:
|
822
|
+
describe 'with a complex ordering' do
|
823
|
+
let(:order) do
|
824
|
+
{
|
825
|
+
'author' => :desc,
|
826
|
+
'published_at' => :asc
|
827
|
+
}
|
900
828
|
end
|
901
|
-
|
829
|
+
let(:ordered_data) do
|
830
|
+
filtered_data.sort do |u, v|
|
831
|
+
compare = u['author'] <=> v['author']
|
902
832
|
|
903
|
-
|
904
|
-
include_context \
|
905
|
-
'when the query has where: a not_one_of block filter'
|
833
|
+
next -compare unless compare.zero?
|
906
834
|
|
907
|
-
|
908
|
-
|
909
|
-
else
|
910
|
-
# :nocov:
|
911
|
-
pending
|
912
|
-
# :nocov:
|
835
|
+
u['published_at'] <=> v['published_at']
|
836
|
+
end
|
913
837
|
end
|
914
|
-
end
|
915
|
-
|
916
|
-
context 'with a one_of filter' do
|
917
|
-
include_context 'when the query has where: a one_of block filter'
|
918
838
|
|
919
|
-
|
920
|
-
instance_exec(&block)
|
921
|
-
else
|
922
|
-
# :nocov:
|
923
|
-
pending
|
924
|
-
# :nocov:
|
925
|
-
end
|
839
|
+
include_examples 'should apply limit and offset'
|
926
840
|
end
|
927
841
|
end
|
928
842
|
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
843
|
+
let(:filter) { defined?(super()) ? super() : nil }
|
844
|
+
let(:limit) { defined?(super()) ? super() : nil }
|
845
|
+
let(:offset) { defined?(super()) ? super() : nil }
|
846
|
+
let(:mapped_data) { defined?(super()) ? super() : data }
|
847
|
+
let(:filtered_data) { mapped_data }
|
848
|
+
let(:ordered_data) do
|
849
|
+
return super() if defined?(super())
|
934
850
|
|
935
|
-
|
936
|
-
module WithQueryContextsContract
|
937
|
-
extend RSpec::SleepingKingStudios::Contract
|
851
|
+
attr_name = defined?(default_order) ? default_order : 'id'
|
938
852
|
|
939
|
-
|
940
|
-
# Adds the contract to the example group.
|
941
|
-
#
|
942
|
-
# @param example_group [RSpec::Core::ExampleGroup] the example group to
|
943
|
-
# which the contract is applied.
|
944
|
-
contract do
|
945
|
-
let(:filter) { nil }
|
946
|
-
let(:strategy) { nil }
|
947
|
-
let(:limit) { nil }
|
948
|
-
let(:offset) { nil }
|
949
|
-
let(:order) { nil }
|
950
|
-
|
951
|
-
shared_context 'when the query has limit: value' do
|
952
|
-
let(:limit) { 3 }
|
953
|
-
let(:matching_data) { super()[0...limit] }
|
853
|
+
filtered_data.sort_by { |item| item[attr_name] }
|
954
854
|
end
|
855
|
+
let(:matching_data) do
|
856
|
+
data = ordered_data
|
857
|
+
data = data[offset..] || [] if offset
|
858
|
+
data = data[...limit] || [] if limit
|
955
859
|
|
956
|
-
|
957
|
-
let(:offset) { 2 }
|
958
|
-
let(:matching_data) { super()[offset..] || [] }
|
860
|
+
data
|
959
861
|
end
|
960
|
-
|
961
|
-
|
962
|
-
let(:order) { :title }
|
963
|
-
let(:matching_data) { super().sort_by { |item| item['title'] } }
|
862
|
+
let(:expected_data) do
|
863
|
+
defined?(super()) ? super() : matching_data
|
964
864
|
end
|
965
865
|
|
966
|
-
|
967
|
-
let(:order) do
|
968
|
-
{
|
969
|
-
author: :asc,
|
970
|
-
title: :desc
|
971
|
-
}
|
972
|
-
end
|
973
|
-
let(:matching_data) do
|
974
|
-
super().sort do |u, v|
|
975
|
-
cmp = u['author'] <=> v['author']
|
976
|
-
|
977
|
-
cmp.zero? ? (v['title'] <=> u['title']) : cmp
|
978
|
-
end
|
979
|
-
end
|
980
|
-
end
|
866
|
+
include_examples 'should order the results'
|
981
867
|
|
982
|
-
|
983
|
-
let(:filter) { -> { { author
|
984
|
-
let(:
|
868
|
+
describe 'with a block filter' do
|
869
|
+
let(:filter) { -> { { 'author' => 'Ursula K. LeGuin' } } }
|
870
|
+
let(:filtered_data) do
|
985
871
|
super().select { |item| item['author'] == 'Ursula K. LeGuin' }
|
986
872
|
end
|
987
|
-
end
|
988
873
|
|
989
|
-
|
990
|
-
let(:filter) do
|
991
|
-
lambda do
|
992
|
-
{
|
993
|
-
author: equals('Ursula K. LeGuin'),
|
994
|
-
series: not_equal('Earthsea')
|
995
|
-
}
|
996
|
-
end
|
997
|
-
end
|
998
|
-
let(:matching_data) do
|
999
|
-
super()
|
1000
|
-
.select { |item| item['author'] == 'Ursula K. LeGuin' }
|
1001
|
-
.reject { |item| item['series'] == 'Earthsea' }
|
1002
|
-
end
|
1003
|
-
end
|
1004
|
-
|
1005
|
-
shared_context 'when the query has where: a greater_than filter' do
|
1006
|
-
let(:filter) { -> { { published_at: greater_than('1970-12-01') } } }
|
1007
|
-
let(:matching_data) do
|
1008
|
-
super().select { |item| item['published_at'] > '1970-12-01' }
|
1009
|
-
end
|
874
|
+
include_examples 'should order the results'
|
1010
875
|
end
|
1011
876
|
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
-> { { published_at: greater_than_or_equal_to('1970-12-01') } }
|
1017
|
-
end
|
1018
|
-
let(:matching_data) do
|
1019
|
-
super().select { |item| item['published_at'] >= '1970-12-01' }
|
877
|
+
describe 'with a hash filter' do
|
878
|
+
let(:filter) { { 'author' => 'Ursula K. LeGuin' } }
|
879
|
+
let(:filtered_data) do
|
880
|
+
super().select { |item| item['author'] == 'Ursula K. LeGuin' }
|
1020
881
|
end
|
1021
|
-
end
|
1022
882
|
|
1023
|
-
|
1024
|
-
let(:filter) { -> { { published_at: less_than('1970-12-01') } } }
|
1025
|
-
let(:matching_data) do
|
1026
|
-
super().select { |item| item['published_at'] < '1970-12-01' }
|
1027
|
-
end
|
883
|
+
include_examples 'should order the results'
|
1028
884
|
end
|
1029
885
|
|
1030
|
-
|
1031
|
-
'less_than_or_equal_to filter' \
|
1032
|
-
do
|
886
|
+
describe 'with a basic scope filter' do
|
1033
887
|
let(:filter) do
|
1034
|
-
|
1035
|
-
end
|
1036
|
-
let(:matching_data) do
|
1037
|
-
super().select { |item| item['published_at'] <= '1970-12-01' }
|
888
|
+
Cuprum::Collections::Scope.new({ 'author' => 'Ursula K. LeGuin' })
|
1038
889
|
end
|
1039
|
-
|
1040
|
-
|
1041
|
-
shared_context 'when the query has where: an equal block filter' do
|
1042
|
-
let(:filter) { -> { { author: equals('Ursula K. LeGuin') } } }
|
1043
|
-
let(:matching_data) do
|
890
|
+
let(:filtered_data) do
|
1044
891
|
super().select { |item| item['author'] == 'Ursula K. LeGuin' }
|
1045
892
|
end
|
1046
|
-
end
|
1047
893
|
|
1048
|
-
|
1049
|
-
let(:filter) { -> { { author: not_equal('Ursula K. LeGuin') } } }
|
1050
|
-
let(:matching_data) do
|
1051
|
-
super().reject { |item| item['author'] == 'Ursula K. LeGuin' }
|
1052
|
-
end
|
894
|
+
include_examples 'should order the results'
|
1053
895
|
end
|
1054
896
|
|
1055
|
-
|
897
|
+
describe 'with a complex scope filter' do
|
1056
898
|
let(:filter) do
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
super().reject do |item|
|
1061
|
-
['Earthsea', 'The Lord of the Rings'].include?(item['series'])
|
1062
|
-
end
|
899
|
+
Cuprum::Collections::Scope
|
900
|
+
.new({ 'author' => 'Ursula K. LeGuin' })
|
901
|
+
.or({ 'series' => nil })
|
1063
902
|
end
|
1064
|
-
|
1065
|
-
|
1066
|
-
shared_context 'when the query has where: a one_of block filter' do
|
1067
|
-
let(:filter) do
|
1068
|
-
-> { { series: one_of(['Earthsea', 'The Lord of the Rings']) } }
|
1069
|
-
end
|
1070
|
-
let(:matching_data) do
|
903
|
+
let(:filtered_data) do
|
1071
904
|
super().select do |item|
|
1072
|
-
['
|
905
|
+
item['author'] == 'Ursula K. LeGuin' || item['series'].nil?
|
1073
906
|
end
|
1074
907
|
end
|
1075
|
-
end
|
1076
908
|
|
1077
|
-
|
1078
|
-
let(:filter) { -> { { author: 'Ursula K. LeGuin' } } }
|
1079
|
-
let(:strategy) { nil }
|
1080
|
-
let(:order) { { title: :desc } }
|
1081
|
-
let(:limit) { 2 }
|
1082
|
-
let(:offset) { 1 }
|
1083
|
-
let(:matching_data) do
|
1084
|
-
super()
|
1085
|
-
.select { |item| item['author'] == 'Ursula K. LeGuin' }
|
1086
|
-
.sort { |u, v| v['title'] <=> u['title'] }
|
1087
|
-
.slice(1, 2) || []
|
1088
|
-
end
|
909
|
+
include_examples 'should order the results'
|
1089
910
|
end
|
1090
911
|
end
|
1091
912
|
end
|