cuprum-collections 0.5.1 → 0.6.0.rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +47 -0
- data/lib/cuprum/collections/adaptable/collection.rb +18 -0
- data/lib/cuprum/collections/adaptable/command.rb +22 -0
- data/lib/cuprum/collections/adaptable/commands/abstract_assign_one.rb +27 -0
- data/lib/cuprum/collections/adaptable/commands/abstract_build_one.rb +25 -0
- data/lib/cuprum/collections/adaptable/commands/abstract_validate_one.rb +35 -0
- data/lib/cuprum/collections/adaptable/commands.rb +15 -0
- data/lib/cuprum/collections/adaptable/query.rb +64 -0
- data/lib/cuprum/collections/adaptable.rb +13 -0
- data/lib/cuprum/collections/adapter.rb +300 -0
- data/lib/cuprum/collections/adapters/data_adapter.rb +82 -0
- data/lib/cuprum/collections/adapters/entity_adapter.rb +76 -0
- data/lib/cuprum/collections/adapters/hash_adapter.rb +48 -0
- data/lib/cuprum/collections/adapters.rb +14 -0
- data/lib/cuprum/collections/basic/collection.rb +2 -20
- data/lib/cuprum/collections/basic/commands/destroy_one.rb +1 -1
- data/lib/cuprum/collections/basic/commands/find_many.rb +0 -31
- data/lib/cuprum/collections/basic/commands/find_matching.rb +0 -94
- data/lib/cuprum/collections/basic/commands/find_one.rb +0 -18
- data/lib/cuprum/collections/basic/commands/insert_one.rb +1 -1
- data/lib/cuprum/collections/basic/commands/update_one.rb +1 -1
- data/lib/cuprum/collections/basic/scopes/criteria_scope.rb +36 -21
- data/lib/cuprum/collections/basic.rb +6 -5
- data/lib/cuprum/collections/collection.rb +6 -0
- data/lib/cuprum/collections/collection_command.rb +1 -1
- data/lib/cuprum/collections/commands/abstract_find_many.rb +40 -3
- data/lib/cuprum/collections/commands/abstract_find_matching.rb +102 -0
- data/lib/cuprum/collections/commands/abstract_find_one.rb +23 -1
- data/lib/cuprum/collections/commands/associations/find_many.rb +1 -3
- data/lib/cuprum/collections/commands/associations/require_many.rb +1 -1
- data/lib/cuprum/collections/commands/find_one_matching.rb +10 -10
- data/lib/cuprum/collections/commands/query_command.rb +6 -4
- data/lib/cuprum/collections/commands/upsert.rb +0 -2
- data/lib/cuprum/collections/constraints/order/attributes_array.rb +5 -4
- data/lib/cuprum/collections/constraints/order/attributes_hash.rb +5 -4
- data/lib/cuprum/collections/constraints/order/sort_direction.rb +2 -2
- data/lib/cuprum/collections/constraints/ordering.rb +11 -9
- data/lib/cuprum/collections/constraints/query_hash.rb +2 -2
- data/lib/cuprum/collections/errors/abstract_find_error.rb +101 -23
- data/lib/cuprum/collections/errors/extra_attributes.rb +3 -3
- data/lib/cuprum/collections/errors/failed_validation.rb +3 -3
- data/lib/cuprum/collections/errors/missing_default_contract.rb +12 -4
- data/lib/cuprum/collections/queries.rb +4 -0
- data/lib/cuprum/collections/relation.rb +0 -2
- data/lib/cuprum/collections/relations/parameters.rb +120 -68
- data/lib/cuprum/collections/repository.rb +71 -6
- data/lib/cuprum/collections/rspec/contracts/query_contracts.rb +23 -4
- data/lib/cuprum/collections/rspec/contracts/repository_contracts.rb +18 -0
- data/lib/cuprum/collections/rspec/contracts/scope_contracts.rb +51 -0
- data/lib/cuprum/collections/rspec/contracts/scopes/builder_contracts.rb +10 -0
- data/lib/cuprum/collections/rspec/contracts/scopes/composition_contracts.rb +8 -0
- data/lib/cuprum/collections/rspec/contracts/scopes/criteria_contracts.rb +18 -366
- data/lib/cuprum/collections/rspec/contracts/scopes/logical_contracts.rb +30 -0
- data/lib/cuprum/collections/rspec/contracts/scopes.rb +2 -0
- data/lib/cuprum/collections/rspec/contracts.rb +2 -10
- data/lib/cuprum/collections/rspec/deferred/adapter_examples.rb +1077 -0
- data/lib/cuprum/collections/rspec/deferred/collection_examples.rb +27 -7
- data/lib/cuprum/collections/rspec/deferred/commands/assign_one_examples.rb +4 -4
- data/lib/cuprum/collections/rspec/deferred/commands/build_one_examples.rb +2 -2
- data/lib/cuprum/collections/rspec/deferred/commands/destroy_one_examples.rb +2 -2
- data/lib/cuprum/collections/rspec/deferred/commands/find_many_examples.rb +5 -5
- data/lib/cuprum/collections/rspec/deferred/commands/find_matching_examples.rb +45 -12
- data/lib/cuprum/collections/rspec/deferred/commands/find_one_examples.rb +2 -2
- data/lib/cuprum/collections/rspec/deferred/commands/insert_one_examples.rb +1 -1
- data/lib/cuprum/collections/rspec/deferred/commands/update_one_examples.rb +1 -1
- data/lib/cuprum/collections/rspec/deferred/query_examples.rb +930 -0
- data/lib/cuprum/collections/rspec/deferred/relation_examples.rb +48 -17
- data/lib/cuprum/collections/rspec/deferred/repository_examples.rb +961 -0
- data/lib/cuprum/collections/rspec/deferred/scope_examples.rb +598 -0
- data/lib/cuprum/collections/rspec/deferred/scopes/all_examples.rb +391 -0
- data/lib/cuprum/collections/rspec/deferred/scopes/builder_examples.rb +857 -0
- data/lib/cuprum/collections/rspec/deferred/scopes/composition_examples.rb +93 -0
- data/lib/cuprum/collections/rspec/deferred/scopes/conjunction_examples.rb +438 -0
- data/lib/cuprum/collections/rspec/deferred/scopes/criteria_examples.rb +1941 -0
- data/lib/cuprum/collections/rspec/deferred/scopes/disjunction_examples.rb +415 -0
- data/lib/cuprum/collections/rspec/deferred/scopes/none_examples.rb +385 -0
- data/lib/cuprum/collections/rspec/deferred/scopes/parser_examples.rb +740 -0
- data/lib/cuprum/collections/rspec/deferred/scopes.rb +8 -0
- data/lib/cuprum/collections/scope.rb +2 -2
- data/lib/cuprum/collections/scopes/container.rb +5 -4
- data/lib/cuprum/collections/scopes/criteria/parser.rb +24 -48
- data/lib/cuprum/collections/scopes/criteria.rb +7 -6
- data/lib/cuprum/collections/version.rb +4 -4
- data/lib/cuprum/collections.rb +5 -1
- metadata +47 -11
- data/lib/cuprum/collections/rspec/contracts/association_contracts.rb +0 -2127
- data/lib/cuprum/collections/rspec/contracts/basic.rb +0 -11
- data/lib/cuprum/collections/rspec/contracts/collection_contracts.rb +0 -387
- data/lib/cuprum/collections/rspec/contracts/command_contracts.rb +0 -169
- data/lib/cuprum/collections/rspec/contracts/relation_contracts.rb +0 -1264
|
@@ -0,0 +1,930 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'cuprum/collections/rspec/deferred'
|
|
4
|
+
|
|
5
|
+
module Cuprum::Collections::RSpec::Deferred
|
|
6
|
+
# Deferred examples for testing queries.
|
|
7
|
+
module QueryExamples
|
|
8
|
+
include RSpec::SleepingKingStudios::Deferred::Provider
|
|
9
|
+
|
|
10
|
+
BOOKS_FIXTURES = Cuprum::Collections::RSpec::Fixtures::BOOKS_FIXTURES
|
|
11
|
+
private_constant :BOOKS_FIXTURES
|
|
12
|
+
|
|
13
|
+
OPERATORS = Cuprum::Collections::Queries::Operators
|
|
14
|
+
private_constant :OPERATORS
|
|
15
|
+
|
|
16
|
+
deferred_examples 'should be a Query' do |**deferred_options|
|
|
17
|
+
shared_context 'when initialized with a Hash' do
|
|
18
|
+
let(:initial_scope) do
|
|
19
|
+
{ 'author' => 'Ursula K. LeGuin' }
|
|
20
|
+
end
|
|
21
|
+
let(:filtered_data) do
|
|
22
|
+
super().select { |item| item['author'] == 'Ursula K. LeGuin' }
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
shared_context 'when initialized with a Proc' do
|
|
27
|
+
let(:initial_scope) do
|
|
28
|
+
->(scope) { { 'published_at' => scope.less_than('1973-01-01') } }
|
|
29
|
+
end
|
|
30
|
+
let(:filtered_data) do
|
|
31
|
+
super().select { |item| item['published_at'] < '1973-01-01' }
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
shared_context 'when initialized with a scope' do
|
|
36
|
+
let(:initial_scope) do
|
|
37
|
+
Cuprum::Collections::Scope.new do |scope|
|
|
38
|
+
{ 'published_at' => scope.less_than('1973-01-01') }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
let(:filtered_data) do
|
|
42
|
+
super().select { |item| item['published_at'] < '1973-01-01' }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
shared_context 'when the query has composed filters' do
|
|
47
|
+
let(:scoped_query) do
|
|
48
|
+
super()
|
|
49
|
+
.where { { author: 'Ursula K. LeGuin' } }
|
|
50
|
+
.where { |scope| { series: scope.not_equal('Earthsea') } }
|
|
51
|
+
end
|
|
52
|
+
let(:filtered_data) do
|
|
53
|
+
super()
|
|
54
|
+
.select { |item| item['author'] == 'Ursula K. LeGuin' }
|
|
55
|
+
.reject { |item| item['series'] == 'Earthsea' }
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
let(:filter) { nil }
|
|
60
|
+
let(:limit) { nil }
|
|
61
|
+
let(:offset) { nil }
|
|
62
|
+
let(:order) { nil }
|
|
63
|
+
let(:scoped_query) do
|
|
64
|
+
scoped =
|
|
65
|
+
if filter.is_a?(Proc)
|
|
66
|
+
subject.where(&filter)
|
|
67
|
+
elsif filter
|
|
68
|
+
subject.where(filter)
|
|
69
|
+
else
|
|
70
|
+
subject
|
|
71
|
+
end
|
|
72
|
+
scoped = scoped.limit(limit) if limit
|
|
73
|
+
scoped = scoped.offset(offset) if offset
|
|
74
|
+
scoped = scoped.order(order) if order
|
|
75
|
+
|
|
76
|
+
scoped
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'should be enumerable' do
|
|
80
|
+
expect(described_class).to be < Enumerable
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
describe '#count' do
|
|
84
|
+
it { expect(query).to respond_to(:count).with(0).arguments }
|
|
85
|
+
|
|
86
|
+
next if deferred_options.fetch(:abstract, false)
|
|
87
|
+
|
|
88
|
+
it { expect(query.count).to be 0 }
|
|
89
|
+
|
|
90
|
+
context 'when the collection data changes' do
|
|
91
|
+
let(:item) { BOOKS_FIXTURES.first }
|
|
92
|
+
|
|
93
|
+
before(:example) do
|
|
94
|
+
query.count # Cache query results.
|
|
95
|
+
|
|
96
|
+
add_item_to_collection(item)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it { expect(query.count).to be 0 }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
context 'when the collection has many items' do
|
|
103
|
+
let(:data) { BOOKS_FIXTURES }
|
|
104
|
+
|
|
105
|
+
include_deferred 'should query the collection', ignore_order: true \
|
|
106
|
+
do
|
|
107
|
+
it { expect(scoped_query.count).to be == expected_data.count }
|
|
108
|
+
|
|
109
|
+
wrap_context 'when the query has composed filters' do
|
|
110
|
+
it { expect(scoped_query.count).to be == expected_data.count }
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
wrap_context 'when initialized with a Hash' do
|
|
114
|
+
it { expect(scoped_query.count).to be == expected_data.count }
|
|
115
|
+
|
|
116
|
+
wrap_context 'when the query has composed filters' do
|
|
117
|
+
it { expect(scoped_query.count).to be == expected_data.count }
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
wrap_context 'when initialized with a Proc' do
|
|
122
|
+
it { expect(scoped_query.count).to be == expected_data.count }
|
|
123
|
+
|
|
124
|
+
wrap_context 'when the query has composed filters' do
|
|
125
|
+
it { expect(scoped_query.count).to be == expected_data.count }
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
wrap_context 'when initialized with a scope' do
|
|
130
|
+
it { expect(scoped_query.count).to be == expected_data.count }
|
|
131
|
+
|
|
132
|
+
wrap_context 'when the query has composed filters' do
|
|
133
|
+
it { expect(scoped_query.count).to be == expected_data.count }
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
context 'when the collection data changes' do
|
|
139
|
+
let(:data) { BOOKS_FIXTURES[0...-1] }
|
|
140
|
+
let(:item) { BOOKS_FIXTURES.last }
|
|
141
|
+
|
|
142
|
+
before(:example) do
|
|
143
|
+
query.count # Cache query results.
|
|
144
|
+
|
|
145
|
+
add_item_to_collection(item)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it { expect(query.count).to be == expected_data.count }
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
describe '#each' do
|
|
154
|
+
shared_examples 'should enumerate the matching data' do
|
|
155
|
+
describe 'with no arguments' do
|
|
156
|
+
it { expect(scoped_query.each).to be_a Enumerator }
|
|
157
|
+
|
|
158
|
+
it { expect(scoped_query.each.count).to be == expected_data.size }
|
|
159
|
+
|
|
160
|
+
it { expect(scoped_query.each.to_a).to deep_match expected_data }
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
describe 'with a block' do
|
|
164
|
+
it 'should yield each matching item' do
|
|
165
|
+
expect { |block| scoped_query.each(&block) }
|
|
166
|
+
.to yield_successive_args(*expected_data)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
next if deferred_options.fetch(:abstract, false)
|
|
172
|
+
|
|
173
|
+
it { expect(query).to respond_to(:each).with(0).arguments }
|
|
174
|
+
|
|
175
|
+
include_examples 'should enumerate the matching data'
|
|
176
|
+
|
|
177
|
+
context 'when the collection data changes' do
|
|
178
|
+
let(:item) { BOOKS_FIXTURES.first }
|
|
179
|
+
|
|
180
|
+
before(:example) do
|
|
181
|
+
query.each {} # Cache query results.
|
|
182
|
+
|
|
183
|
+
add_item_to_collection(item)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
include_examples 'should enumerate the matching data'
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
context 'when the collection has many items' do
|
|
190
|
+
let(:data) { BOOKS_FIXTURES }
|
|
191
|
+
|
|
192
|
+
include_deferred 'should query the collection' do
|
|
193
|
+
include_examples 'should enumerate the matching data'
|
|
194
|
+
|
|
195
|
+
wrap_context 'when the query has composed filters' do
|
|
196
|
+
include_examples 'should enumerate the matching data'
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
wrap_context 'when initialized with a scope' do
|
|
200
|
+
include_examples 'should enumerate the matching data'
|
|
201
|
+
|
|
202
|
+
wrap_context 'when the query has composed filters' do
|
|
203
|
+
include_examples 'should enumerate the matching data'
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
context 'when the collection data changes' do
|
|
209
|
+
let(:data) { BOOKS_FIXTURES[0...-1] }
|
|
210
|
+
let(:item) { BOOKS_FIXTURES.last }
|
|
211
|
+
|
|
212
|
+
before(:example) do
|
|
213
|
+
query.each {} # Cache query results.
|
|
214
|
+
|
|
215
|
+
add_item_to_collection(item)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
include_examples 'should enumerate the matching data'
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
describe '#exists?' do
|
|
224
|
+
shared_examples 'should check the existence of matching data' do
|
|
225
|
+
let(:data) { [] }
|
|
226
|
+
let(:expected_data) { defined?(super()) ? super() : data }
|
|
227
|
+
|
|
228
|
+
it { expect(query.exists?).to be == !expected_data.empty? }
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
next if deferred_options.fetch(:abstract, false)
|
|
232
|
+
|
|
233
|
+
include_examples 'should define predicate', :exists?
|
|
234
|
+
|
|
235
|
+
include_examples 'should check the existence of matching data'
|
|
236
|
+
|
|
237
|
+
context 'when the collection has many items' do
|
|
238
|
+
let(:data) { BOOKS_FIXTURES }
|
|
239
|
+
|
|
240
|
+
include_deferred 'should query the collection', ignore_order: true \
|
|
241
|
+
do
|
|
242
|
+
include_examples 'should check the existence of matching data'
|
|
243
|
+
|
|
244
|
+
wrap_context 'when the query has composed filters' do
|
|
245
|
+
include_examples 'should check the existence of matching data'
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
wrap_context 'when initialized with a scope' do
|
|
249
|
+
include_examples 'should check the existence of matching data'
|
|
250
|
+
|
|
251
|
+
wrap_context 'when the query has composed filters' do
|
|
252
|
+
include_examples 'should check the existence of matching data'
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
describe '#limit' do
|
|
260
|
+
it { expect(query).to respond_to(:limit).with(0..1).arguments }
|
|
261
|
+
|
|
262
|
+
describe 'with no arguments' do
|
|
263
|
+
it { expect(query.limit).to be nil }
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
describe 'with nil' do
|
|
267
|
+
let(:error_message) { 'limit must be a non-negative integer' }
|
|
268
|
+
|
|
269
|
+
it 'should raise an exception' do
|
|
270
|
+
expect { query.limit nil }
|
|
271
|
+
.to raise_error ArgumentError, error_message
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
describe 'with an object' do
|
|
276
|
+
let(:error_message) { 'limit must be a non-negative integer' }
|
|
277
|
+
|
|
278
|
+
it 'should raise an exception' do
|
|
279
|
+
expect { query.limit Object.new.freeze }
|
|
280
|
+
.to raise_error ArgumentError, error_message
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
describe 'with a negative integer' do
|
|
285
|
+
let(:error_message) { 'limit must be a non-negative integer' }
|
|
286
|
+
|
|
287
|
+
it 'should raise an exception' do
|
|
288
|
+
expect { query.limit(-1) }
|
|
289
|
+
.to raise_error ArgumentError, error_message
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
describe 'with zero' do
|
|
294
|
+
it { expect(query.limit(0)).to be_a described_class }
|
|
295
|
+
|
|
296
|
+
it { expect(query.limit(0)).not_to be query }
|
|
297
|
+
|
|
298
|
+
it { expect(query.limit(0).limit).to be 0 }
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
describe 'with a positive integer' do
|
|
302
|
+
it { expect(query.limit(3)).to be_a described_class }
|
|
303
|
+
|
|
304
|
+
it { expect(query.limit(3)).not_to be query }
|
|
305
|
+
|
|
306
|
+
it { expect(query.limit(3).limit).to be 3 }
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
describe '#offset' do
|
|
311
|
+
it { expect(query).to respond_to(:offset).with(0..1).argument }
|
|
312
|
+
|
|
313
|
+
describe 'with no arguments' do
|
|
314
|
+
it { expect(query.offset).to be nil }
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
describe 'with nil' do
|
|
318
|
+
let(:error_message) { 'offset must be a non-negative integer' }
|
|
319
|
+
|
|
320
|
+
it 'should raise an exception' do
|
|
321
|
+
expect { query.offset nil }
|
|
322
|
+
.to raise_error ArgumentError, error_message
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
describe 'with an object' do
|
|
327
|
+
let(:error_message) { 'offset must be a non-negative integer' }
|
|
328
|
+
|
|
329
|
+
it 'should raise an exception' do
|
|
330
|
+
expect { query.offset Object.new.freeze }
|
|
331
|
+
.to raise_error ArgumentError, error_message
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
describe 'with a negative integer' do
|
|
336
|
+
let(:error_message) { 'offset must be a non-negative integer' }
|
|
337
|
+
|
|
338
|
+
it 'should raise an exception' do
|
|
339
|
+
expect { query.offset(-1) }
|
|
340
|
+
.to raise_error ArgumentError, error_message
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
describe 'with zero' do
|
|
345
|
+
it { expect(query.offset(0)).to be_a described_class }
|
|
346
|
+
|
|
347
|
+
it { expect(query.offset(0)).not_to be query }
|
|
348
|
+
|
|
349
|
+
it { expect(query.offset(0).offset).to be 0 }
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
describe 'with a positive integer' do
|
|
353
|
+
it { expect(query.offset(3)).to be_a described_class }
|
|
354
|
+
|
|
355
|
+
it { expect(query.offset(3)).not_to be query }
|
|
356
|
+
|
|
357
|
+
it { expect(query.offset(3).offset).to be 3 }
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
describe '#order' do
|
|
362
|
+
let(:default_order) { defined?(super()) ? super() : {} }
|
|
363
|
+
let(:error_message) do
|
|
364
|
+
'order must be a list of attribute names and/or a hash of ' \
|
|
365
|
+
'attribute names with values :asc or :desc'
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
it 'should define the method' do
|
|
369
|
+
expect(query)
|
|
370
|
+
.to respond_to(:order)
|
|
371
|
+
.with(0).arguments
|
|
372
|
+
.and_unlimited_arguments
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
it { expect(query).to have_aliased_method(:order).as(:order_by) }
|
|
376
|
+
|
|
377
|
+
describe 'with no arguments' do
|
|
378
|
+
it { expect(query.order).to be == default_order }
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
describe 'with a hash with invalid keys' do
|
|
382
|
+
it 'should raise an exception' do
|
|
383
|
+
expect { query.order({ nil => :asc }) }
|
|
384
|
+
.to raise_error ArgumentError, error_message
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
describe 'with a hash with empty string keys' do
|
|
389
|
+
it 'should raise an exception' do
|
|
390
|
+
expect { query.order({ '' => :asc }) }
|
|
391
|
+
.to raise_error ArgumentError, error_message
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
describe 'with a hash with empty symbol keys' do
|
|
396
|
+
it 'should raise an exception' do
|
|
397
|
+
expect { query.order({ '': :asc }) }
|
|
398
|
+
.to raise_error ArgumentError, error_message
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
describe 'with a hash with nil value' do
|
|
403
|
+
it 'should raise an exception' do
|
|
404
|
+
expect { query.order({ title: nil }) }
|
|
405
|
+
.to raise_error ArgumentError, error_message
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
describe 'with a hash with object value' do
|
|
410
|
+
it 'should raise an exception' do
|
|
411
|
+
expect { query.order({ title: Object.new.freeze }) }
|
|
412
|
+
.to raise_error ArgumentError, error_message
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
describe 'with a hash with empty value' do
|
|
417
|
+
it 'should raise an exception' do
|
|
418
|
+
expect { query.order({ title: '' }) }
|
|
419
|
+
.to raise_error ArgumentError, error_message
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
describe 'with a hash with invalid value' do
|
|
424
|
+
it 'should raise an exception' do
|
|
425
|
+
expect { query.order({ title: 'wibbly' }) }
|
|
426
|
+
.to raise_error ArgumentError, error_message
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
describe 'with a valid ordering' do
|
|
431
|
+
let(:expected) do
|
|
432
|
+
{ title: :asc }
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
it { expect(query.order(:title)).to be_a described_class }
|
|
436
|
+
|
|
437
|
+
it { expect(query.order(:title)).not_to be query }
|
|
438
|
+
|
|
439
|
+
it { expect(query.order(:title).order).to be == expected }
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
describe '#reset' do
|
|
444
|
+
let(:data) { [] }
|
|
445
|
+
let(:matching_data) { data }
|
|
446
|
+
let(:expected_data) do
|
|
447
|
+
defined?(super()) ? super() : matching_data
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
it { expect(query).to respond_to(:reset).with(0).arguments }
|
|
451
|
+
|
|
452
|
+
it { expect(query.reset).to be_a query.class }
|
|
453
|
+
|
|
454
|
+
it { expect(query.reset).not_to be query }
|
|
455
|
+
|
|
456
|
+
next if deferred_options.fetch(:abstract, false)
|
|
457
|
+
|
|
458
|
+
it { expect(query.reset.to_a).to be == query.to_a }
|
|
459
|
+
|
|
460
|
+
context 'when the collection data changes' do
|
|
461
|
+
let(:item) { BOOKS_FIXTURES.first }
|
|
462
|
+
let(:matching_data) { [item] }
|
|
463
|
+
|
|
464
|
+
before(:example) do
|
|
465
|
+
query.to_a # Cache query results.
|
|
466
|
+
|
|
467
|
+
add_item_to_collection(item)
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
it { expect(query.reset.count).to be expected_data.size }
|
|
471
|
+
|
|
472
|
+
it { expect(query.reset.to_a).to deep_match expected_data }
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
context 'when the collection has many items' do
|
|
476
|
+
let(:data) { BOOKS_FIXTURES }
|
|
477
|
+
|
|
478
|
+
it { expect(query.reset).to be_a query.class }
|
|
479
|
+
|
|
480
|
+
it { expect(query.reset).not_to be query }
|
|
481
|
+
|
|
482
|
+
it { expect(query.reset.to_a).to be == query.to_a }
|
|
483
|
+
|
|
484
|
+
context 'when the collection data changes' do
|
|
485
|
+
let(:data) { BOOKS_FIXTURES[0...-1] }
|
|
486
|
+
let(:item) { BOOKS_FIXTURES.last }
|
|
487
|
+
let(:matching_data) { [*data, item] }
|
|
488
|
+
|
|
489
|
+
before(:example) do
|
|
490
|
+
query.to_a # Cache query results.
|
|
491
|
+
|
|
492
|
+
add_item_to_collection(item)
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
it { expect(query.reset.count).to be expected_data.size }
|
|
496
|
+
|
|
497
|
+
it { expect(query.reset.to_a).to deep_match expected_data }
|
|
498
|
+
end
|
|
499
|
+
end
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
describe '#scope' do
|
|
503
|
+
include_examples 'should define reader', :scope
|
|
504
|
+
|
|
505
|
+
it { expect(query.scope).to be_a Cuprum::Collections::Scopes::Base }
|
|
506
|
+
|
|
507
|
+
it { expect(query.scope.type).to be :all }
|
|
508
|
+
|
|
509
|
+
wrap_context 'when initialized with a scope' do
|
|
510
|
+
let(:expected) do
|
|
511
|
+
Cuprum::Collections::Scope.new do |scope|
|
|
512
|
+
{
|
|
513
|
+
'published_at' => scope.less_than('1973-01-01')
|
|
514
|
+
}
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
it { expect(scoped_query.scope).to be == expected }
|
|
519
|
+
|
|
520
|
+
wrap_context 'when the query has composed filters' do
|
|
521
|
+
let(:expected) do
|
|
522
|
+
Cuprum::Collections::Scope.new do |scope|
|
|
523
|
+
{
|
|
524
|
+
'published_at' => scope.less_than('1973-01-01'),
|
|
525
|
+
'author' => 'Ursula K. LeGuin',
|
|
526
|
+
'series' => scope.not_equal('Earthsea')
|
|
527
|
+
}
|
|
528
|
+
end
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
it { expect(scoped_query.scope).to be == expected }
|
|
532
|
+
end
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
wrap_context 'when the query has composed filters' do
|
|
536
|
+
let(:expected) do
|
|
537
|
+
Cuprum::Collections::Scope.new do |scope|
|
|
538
|
+
{
|
|
539
|
+
'author' => 'Ursula K. LeGuin',
|
|
540
|
+
'series' => scope.not_equal('Earthsea')
|
|
541
|
+
}
|
|
542
|
+
end
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
it { expect(scoped_query.scope).to be == expected }
|
|
546
|
+
end
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
describe '#to_a' do
|
|
550
|
+
let(:data) { [] }
|
|
551
|
+
let(:queried_data) { scoped_query.to_a }
|
|
552
|
+
let(:expected_data) { defined?(super()) ? super() : data }
|
|
553
|
+
|
|
554
|
+
it { expect(query).to respond_to(:to_a).with(0).arguments }
|
|
555
|
+
|
|
556
|
+
next if deferred_options.fetch(:abstract, false)
|
|
557
|
+
|
|
558
|
+
it { expect(queried_data).to be == [] }
|
|
559
|
+
|
|
560
|
+
context 'when the collection data changes' do
|
|
561
|
+
let(:item) { BOOKS_FIXTURES.first }
|
|
562
|
+
|
|
563
|
+
before(:example) do
|
|
564
|
+
scoped_query.to_a # Cache query results.
|
|
565
|
+
|
|
566
|
+
add_item_to_collection(item)
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
it { expect(queried_data).to be == [] }
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
context 'when the collection has many items' do
|
|
573
|
+
let(:data) { BOOKS_FIXTURES }
|
|
574
|
+
|
|
575
|
+
include_deferred 'should query the collection' do
|
|
576
|
+
it { expect(queried_data).to be == expected_data }
|
|
577
|
+
|
|
578
|
+
wrap_context 'when the query has composed filters' do
|
|
579
|
+
it { expect(queried_data).to be == expected_data }
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
wrap_context 'when initialized with a scope' do
|
|
583
|
+
it { expect(queried_data).to be == expected_data }
|
|
584
|
+
|
|
585
|
+
wrap_context 'when the query has composed filters' do
|
|
586
|
+
it { expect(queried_data).to be == expected_data }
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
context 'when the collection data changes' do
|
|
592
|
+
let(:data) { BOOKS_FIXTURES[0...-1] }
|
|
593
|
+
let(:item) { BOOKS_FIXTURES.last }
|
|
594
|
+
|
|
595
|
+
before(:example) do
|
|
596
|
+
scoped_query.to_a # Cache query results.
|
|
597
|
+
|
|
598
|
+
add_item_to_collection(item)
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
it { expect(queried_data).to deep_match expected_data }
|
|
602
|
+
end
|
|
603
|
+
end
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
describe '#where' do
|
|
607
|
+
let(:block) { -> { { title: 'Gideon the Ninth' } } }
|
|
608
|
+
|
|
609
|
+
it 'should define the method' do
|
|
610
|
+
expect(subject)
|
|
611
|
+
.to respond_to(:where)
|
|
612
|
+
.with(0..1).arguments
|
|
613
|
+
.and_a_block
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
it { expect(subject.where(&block)).to be_a described_class }
|
|
617
|
+
|
|
618
|
+
it { expect(subject.where(&block)).not_to be subject }
|
|
619
|
+
|
|
620
|
+
it 'should set the scope' do
|
|
621
|
+
expect(subject.where(&block).scope)
|
|
622
|
+
.to be_a Cuprum::Collections::Scopes::Base
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
it 'should not change the original query scope' do
|
|
626
|
+
expect { subject.where(&block) }
|
|
627
|
+
.not_to change(subject, :scope)
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
context 'when the query does not have a scope' do
|
|
631
|
+
let(:expected) do
|
|
632
|
+
Cuprum::Collections::Scope.new({ 'title' => 'Gideon the Ninth' })
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
describe 'with a block' do
|
|
636
|
+
let(:block) { -> { { 'title' => 'Gideon the Ninth' } } }
|
|
637
|
+
|
|
638
|
+
it { expect(subject.where(&block).scope).to be == expected }
|
|
639
|
+
end
|
|
640
|
+
|
|
641
|
+
describe 'with a hash' do
|
|
642
|
+
let(:value) { { 'title' => 'Gideon the Ninth' } }
|
|
643
|
+
|
|
644
|
+
it { expect(subject.where(value).scope).to be == expected }
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
describe 'with a basic scope' do
|
|
648
|
+
let(:value) do
|
|
649
|
+
Cuprum::Collections::Scope
|
|
650
|
+
.new({ 'title' => 'Gideon the Ninth' })
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
it { expect(subject.where(value).scope).to be == value }
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
describe 'with a complex scope' do
|
|
657
|
+
let(:value) do
|
|
658
|
+
Cuprum::Collections::Scope
|
|
659
|
+
.new({ 'title' => 'Gideon the Ninth' })
|
|
660
|
+
.or({ 'title' => 'Harrow the Ninth' })
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
it { expect(subject.where(value).scope).to be == value }
|
|
664
|
+
end
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
context 'when the query has a scope' do
|
|
668
|
+
let(:initial_scope) do
|
|
669
|
+
Cuprum::Collections::Scope.new({ 'author' => 'Tamsyn Muir' })
|
|
670
|
+
end
|
|
671
|
+
let(:expected) do
|
|
672
|
+
operators = Cuprum::Collections::Queries::Operators
|
|
673
|
+
|
|
674
|
+
[
|
|
675
|
+
[
|
|
676
|
+
'author',
|
|
677
|
+
operators::EQUAL,
|
|
678
|
+
'Tamsyn Muir'
|
|
679
|
+
],
|
|
680
|
+
[
|
|
681
|
+
'title',
|
|
682
|
+
operators::EQUAL,
|
|
683
|
+
'Gideon the Ninth'
|
|
684
|
+
]
|
|
685
|
+
]
|
|
686
|
+
end
|
|
687
|
+
|
|
688
|
+
describe 'with a block' do
|
|
689
|
+
let(:block) { -> { { 'title' => 'Gideon the Ninth' } } }
|
|
690
|
+
let(:scope) { subject.where(&block).scope }
|
|
691
|
+
|
|
692
|
+
it { expect(scope).to be_a Cuprum::Collections::Scopes::Base }
|
|
693
|
+
|
|
694
|
+
it { expect(scope.type).to be :criteria }
|
|
695
|
+
|
|
696
|
+
it { expect(scope.criteria).to be == expected }
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
describe 'with a value' do
|
|
700
|
+
let(:value) { { 'title' => 'Gideon the Ninth' } }
|
|
701
|
+
let(:scope) { subject.where(value).scope }
|
|
702
|
+
|
|
703
|
+
it { expect(scope).to be_a Cuprum::Collections::Scopes::Base }
|
|
704
|
+
|
|
705
|
+
it { expect(scope.type).to be :criteria }
|
|
706
|
+
|
|
707
|
+
it { expect(scope.criteria).to be == expected }
|
|
708
|
+
end
|
|
709
|
+
|
|
710
|
+
describe 'with a basic scope' do
|
|
711
|
+
let(:value) do
|
|
712
|
+
Cuprum::Collections::Scope
|
|
713
|
+
.new({ 'title' => 'Gideon the Ninth' })
|
|
714
|
+
end
|
|
715
|
+
let(:scope) { subject.where(value).scope }
|
|
716
|
+
|
|
717
|
+
it { expect(scope).to be_a Cuprum::Collections::Scopes::Base }
|
|
718
|
+
|
|
719
|
+
it { expect(scope.type).to be :criteria }
|
|
720
|
+
|
|
721
|
+
it { expect(scope.criteria).to be == expected }
|
|
722
|
+
end
|
|
723
|
+
|
|
724
|
+
describe 'with a complex scope' do
|
|
725
|
+
let(:value) do
|
|
726
|
+
Cuprum::Collections::Scope
|
|
727
|
+
.new({ 'title' => 'Gideon the Ninth' })
|
|
728
|
+
.or({ 'title' => 'Harrow the Ninth' })
|
|
729
|
+
end
|
|
730
|
+
let(:scope) { subject.where(value).scope }
|
|
731
|
+
let(:outer) { scope.scopes.last }
|
|
732
|
+
let(:expected) do
|
|
733
|
+
operators = Cuprum::Collections::Queries::Operators
|
|
734
|
+
|
|
735
|
+
[
|
|
736
|
+
[
|
|
737
|
+
'author',
|
|
738
|
+
operators::EQUAL,
|
|
739
|
+
'Tamsyn Muir'
|
|
740
|
+
]
|
|
741
|
+
]
|
|
742
|
+
end
|
|
743
|
+
let(:expected_first) do
|
|
744
|
+
operators = Cuprum::Collections::Queries::Operators
|
|
745
|
+
|
|
746
|
+
[
|
|
747
|
+
[
|
|
748
|
+
'title',
|
|
749
|
+
operators::EQUAL,
|
|
750
|
+
'Gideon the Ninth'
|
|
751
|
+
]
|
|
752
|
+
]
|
|
753
|
+
end
|
|
754
|
+
let(:expected_second) do
|
|
755
|
+
operators = Cuprum::Collections::Queries::Operators
|
|
756
|
+
|
|
757
|
+
[
|
|
758
|
+
[
|
|
759
|
+
'title',
|
|
760
|
+
operators::EQUAL,
|
|
761
|
+
'Harrow the Ninth'
|
|
762
|
+
]
|
|
763
|
+
]
|
|
764
|
+
end
|
|
765
|
+
|
|
766
|
+
it { expect(scope).to be_a Cuprum::Collections::Scopes::Base }
|
|
767
|
+
|
|
768
|
+
it { expect(scope.type).to be :conjunction }
|
|
769
|
+
|
|
770
|
+
it { expect(scope.scopes.size).to be 2 }
|
|
771
|
+
|
|
772
|
+
it { expect(scope.scopes.first.type).to be :criteria }
|
|
773
|
+
|
|
774
|
+
it { expect(scope.scopes.first.criteria).to be == expected }
|
|
775
|
+
|
|
776
|
+
it { expect(outer).to be_a Cuprum::Collections::Scopes::Base }
|
|
777
|
+
|
|
778
|
+
it { expect(outer.type).to be :disjunction }
|
|
779
|
+
|
|
780
|
+
it { expect(outer.scopes.size).to be 2 }
|
|
781
|
+
|
|
782
|
+
it { expect(outer.scopes.first.criteria).to be == expected_first }
|
|
783
|
+
|
|
784
|
+
it { expect(outer.scopes.last.criteria).to be == expected_second }
|
|
785
|
+
end
|
|
786
|
+
end
|
|
787
|
+
end
|
|
788
|
+
end
|
|
789
|
+
|
|
790
|
+
deferred_examples 'should query the collection' \
|
|
791
|
+
do |**deferred_options, &examples|
|
|
792
|
+
shared_examples 'should query the collection' do
|
|
793
|
+
# :nocov:
|
|
794
|
+
if examples
|
|
795
|
+
instance_exec(&examples)
|
|
796
|
+
else
|
|
797
|
+
it { expect(queried_data).to be == expected_data }
|
|
798
|
+
end
|
|
799
|
+
# :nocov:
|
|
800
|
+
end
|
|
801
|
+
|
|
802
|
+
shared_examples 'should apply limit and offset' do
|
|
803
|
+
include_examples 'should query the collection'
|
|
804
|
+
|
|
805
|
+
context 'with limit: value' do
|
|
806
|
+
let(:limit) { 3 }
|
|
807
|
+
|
|
808
|
+
include_examples 'should query the collection'
|
|
809
|
+
end
|
|
810
|
+
|
|
811
|
+
context 'with offset: value' do
|
|
812
|
+
let(:offset) { 2 }
|
|
813
|
+
|
|
814
|
+
include_examples 'should query the collection'
|
|
815
|
+
end
|
|
816
|
+
|
|
817
|
+
describe 'with limit: value and offset: value' do
|
|
818
|
+
let(:limit) { 3 }
|
|
819
|
+
let(:offset) { 2 }
|
|
820
|
+
|
|
821
|
+
include_examples 'should query the collection'
|
|
822
|
+
end
|
|
823
|
+
end
|
|
824
|
+
|
|
825
|
+
shared_examples 'should order the results' do
|
|
826
|
+
include_examples 'should apply limit and offset'
|
|
827
|
+
|
|
828
|
+
next if deferred_options.fetch(:ignore_order, false)
|
|
829
|
+
|
|
830
|
+
describe 'with a simple ordering' do
|
|
831
|
+
let(:order) { 'title' }
|
|
832
|
+
let(:ordered_data) do
|
|
833
|
+
filtered_data.sort_by { |item| item['title'] }
|
|
834
|
+
end
|
|
835
|
+
|
|
836
|
+
include_examples 'should apply limit and offset'
|
|
837
|
+
end
|
|
838
|
+
|
|
839
|
+
describe 'with a complex ordering' do
|
|
840
|
+
let(:order) do
|
|
841
|
+
{
|
|
842
|
+
'author' => :desc,
|
|
843
|
+
'published_at' => :asc
|
|
844
|
+
}
|
|
845
|
+
end
|
|
846
|
+
let(:ordered_data) do
|
|
847
|
+
filtered_data.sort do |u, v|
|
|
848
|
+
compare = u['author'] <=> v['author']
|
|
849
|
+
|
|
850
|
+
next -compare unless compare.zero?
|
|
851
|
+
|
|
852
|
+
u['published_at'] <=> v['published_at']
|
|
853
|
+
end
|
|
854
|
+
end
|
|
855
|
+
|
|
856
|
+
include_examples 'should apply limit and offset'
|
|
857
|
+
end
|
|
858
|
+
end
|
|
859
|
+
|
|
860
|
+
let(:filter) { defined?(super()) ? super() : nil }
|
|
861
|
+
let(:limit) { defined?(super()) ? super() : nil }
|
|
862
|
+
let(:offset) { defined?(super()) ? super() : nil }
|
|
863
|
+
let(:mapped_data) { defined?(super()) ? super() : data }
|
|
864
|
+
let(:filtered_data) { mapped_data }
|
|
865
|
+
let(:ordered_data) do
|
|
866
|
+
return super() if defined?(super())
|
|
867
|
+
|
|
868
|
+
attr_name = defined?(default_order) ? default_order : 'id'
|
|
869
|
+
|
|
870
|
+
filtered_data.sort_by { |item| item[attr_name] }
|
|
871
|
+
end
|
|
872
|
+
let(:matching_data) do
|
|
873
|
+
data = ordered_data
|
|
874
|
+
data = data[offset..] || [] if offset
|
|
875
|
+
data = data[...limit] || [] if limit
|
|
876
|
+
|
|
877
|
+
data
|
|
878
|
+
end
|
|
879
|
+
let(:expected_data) do
|
|
880
|
+
defined?(super()) ? super() : matching_data
|
|
881
|
+
end
|
|
882
|
+
|
|
883
|
+
include_examples 'should order the results'
|
|
884
|
+
|
|
885
|
+
describe 'with a block filter' do
|
|
886
|
+
let(:filter) { -> { { 'author' => 'Ursula K. LeGuin' } } }
|
|
887
|
+
let(:filtered_data) do
|
|
888
|
+
super().select { |item| item['author'] == 'Ursula K. LeGuin' }
|
|
889
|
+
end
|
|
890
|
+
|
|
891
|
+
include_examples 'should order the results'
|
|
892
|
+
end
|
|
893
|
+
|
|
894
|
+
describe 'with a hash filter' do
|
|
895
|
+
let(:filter) { { 'author' => 'Ursula K. LeGuin' } }
|
|
896
|
+
let(:filtered_data) do
|
|
897
|
+
super().select { |item| item['author'] == 'Ursula K. LeGuin' }
|
|
898
|
+
end
|
|
899
|
+
|
|
900
|
+
include_examples 'should order the results'
|
|
901
|
+
end
|
|
902
|
+
|
|
903
|
+
describe 'with a basic scope filter' do
|
|
904
|
+
let(:filter) do
|
|
905
|
+
Cuprum::Collections::Scope.new({ 'author' => 'Ursula K. LeGuin' })
|
|
906
|
+
end
|
|
907
|
+
let(:filtered_data) do
|
|
908
|
+
super().select { |item| item['author'] == 'Ursula K. LeGuin' }
|
|
909
|
+
end
|
|
910
|
+
|
|
911
|
+
include_examples 'should order the results'
|
|
912
|
+
end
|
|
913
|
+
|
|
914
|
+
describe 'with a complex scope filter' do
|
|
915
|
+
let(:filter) do
|
|
916
|
+
Cuprum::Collections::Scope
|
|
917
|
+
.new({ 'author' => 'Ursula K. LeGuin' })
|
|
918
|
+
.or({ 'series' => nil })
|
|
919
|
+
end
|
|
920
|
+
let(:filtered_data) do
|
|
921
|
+
super().select do |item|
|
|
922
|
+
item['author'] == 'Ursula K. LeGuin' || item['series'].nil?
|
|
923
|
+
end
|
|
924
|
+
end
|
|
925
|
+
|
|
926
|
+
include_examples 'should order the results'
|
|
927
|
+
end
|
|
928
|
+
end
|
|
929
|
+
end
|
|
930
|
+
end
|