mongoid-scroll 1.0.1 → 2.0.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/.github/workflows/ci.yml +20 -2
- data/.gitignore +1 -0
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +153 -35
- data/CHANGELOG.md +15 -5
- data/Gemfile +4 -4
- data/README.md +24 -36
- data/RELEASING.md +1 -4
- data/Rakefile +3 -3
- data/UPGRADING.md +21 -1
- data/examples/{mongoid_scroll_feed.rb → feed.rb} +3 -3
- data/lib/config/locales/en.yml +4 -1
- data/lib/mongoid/criteria/scrollable/iterator.rb +19 -0
- data/lib/mongoid/criteria/scrollable.rb +28 -8
- data/lib/mongoid/scroll/base64_encoded_cursor.rb +8 -6
- data/lib/mongoid/scroll/base_cursor.rb +12 -11
- data/lib/mongoid/scroll/cursor.rb +5 -5
- data/lib/mongoid/scroll/errors/base.rb +4 -4
- data/lib/mongoid/scroll/errors/mismatched_sort_fields_error.rb +1 -3
- data/lib/mongoid/scroll/errors/multiple_sort_fields_error.rb +1 -3
- data/lib/mongoid/scroll/errors/unsupported_type_error.rb +11 -0
- data/lib/mongoid/scroll/errors.rb +1 -0
- data/lib/mongoid/scroll/version.rb +1 -1
- data/lib/mongoid-scroll.rb +1 -2
- data/mongoid-scroll.gemspec +3 -3
- data/spec/mongoid/base64_encoded_cursor_spec.rb +148 -77
- data/spec/mongoid/criteria_spec.rb +108 -37
- data/spec/mongoid/cursor_spec.rb +112 -63
- data/spec/mongoid/scroll_spec.rb +1 -1
- data/spec/spec_helper.rb +9 -2
- data/spec/support/feed/embedded_item.rb +2 -0
- data/spec/support/feed/item.rb +1 -1
- metadata +12 -26
- data/examples/mongo_ruby_driver_scroll_feed.rb +0 -45
- data/lib/mongo/scrollable.rb +0 -39
- data/spec/mongo/collection_view_spec.rb +0 -143
@@ -7,19 +7,23 @@ describe Mongoid::Criteria do
|
|
7
7
|
subject do
|
8
8
|
Feed::Item.desc(:name).asc(:value)
|
9
9
|
end
|
10
|
+
|
10
11
|
it ':scroll' do
|
11
12
|
expect(subject).to respond_to(:scroll)
|
12
13
|
end
|
14
|
+
|
13
15
|
it 'raises Mongoid::Scroll::Errors::MultipleSortFieldsError' do
|
14
16
|
expect do
|
15
17
|
subject.scroll(cursor_type)
|
16
18
|
end.to raise_error Mongoid::Scroll::Errors::MultipleSortFieldsError, /You're attempting to scroll over data with a sort order that includes multiple fields: name, value./
|
17
19
|
end
|
18
20
|
end
|
21
|
+
|
19
22
|
context 'with different sort fields between the cursor and the criteria' do
|
20
23
|
subject do
|
21
24
|
Feed::Item.desc(:name)
|
22
25
|
end
|
26
|
+
|
23
27
|
it 'raises Mongoid::Scroll::Errors::MismatchedSortFieldsError' do
|
24
28
|
record = Feed::Item.create!
|
25
29
|
cursor = cursor_type.from_record(record, field: record.fields['a_string'])
|
@@ -27,16 +31,19 @@ describe Mongoid::Criteria do
|
|
27
31
|
expect { subject.scroll(cursor) }.to raise_error Mongoid::Scroll::Errors::MismatchedSortFieldsError, error_string
|
28
32
|
end
|
29
33
|
end
|
34
|
+
|
30
35
|
context 'with no sort' do
|
31
36
|
subject do
|
32
37
|
Feed::Item.all
|
33
38
|
end
|
39
|
+
|
34
40
|
it 'adds a default sort by _id' do
|
35
41
|
expect(subject.scroll(cursor_type).options[:sort]).to eq('_id' => 1)
|
36
42
|
end
|
37
43
|
end
|
44
|
+
|
38
45
|
context 'with data' do
|
39
|
-
before
|
46
|
+
before do
|
40
47
|
10.times do |i|
|
41
48
|
Feed::Item.create!(
|
42
49
|
name: i.to_s,
|
@@ -48,30 +55,33 @@ describe Mongoid::Criteria do
|
|
48
55
|
)
|
49
56
|
end
|
50
57
|
end
|
58
|
+
|
51
59
|
context 'default' do
|
52
60
|
it 'scrolls all' do
|
53
61
|
records = []
|
54
|
-
Feed::Item.all.scroll(cursor_type) do |record,
|
62
|
+
Feed::Item.all.scroll(cursor_type) do |record, _iterator|
|
55
63
|
records << record
|
56
64
|
end
|
57
65
|
expect(records.size).to eq 10
|
58
66
|
expect(records).to eq Feed::Item.all.to_a
|
59
67
|
end
|
68
|
+
|
60
69
|
it 'does not change original criteria' do
|
61
70
|
criteria = Feed::Item.where(:a_time.gt => Time.new(2013, 7, 22, 1, 2, 3))
|
62
71
|
original_criteria = criteria.dup
|
63
72
|
criteria.limit(2).scroll(cursor_type)
|
64
73
|
expect(criteria).to eq original_criteria
|
65
74
|
cursor = nil
|
66
|
-
criteria.limit(2).scroll(cursor) do |_record,
|
67
|
-
cursor = next_cursor
|
75
|
+
criteria.limit(2).scroll(cursor) do |_record, iterator|
|
76
|
+
cursor = iterator.next_cursor
|
68
77
|
end
|
69
|
-
criteria.scroll(cursor) do |_record,
|
70
|
-
cursor = next_cursor
|
78
|
+
criteria.scroll(cursor) do |_record, iterator|
|
79
|
+
cursor = iterator.next_cursor
|
71
80
|
end
|
72
81
|
expect(criteria).to eq original_criteria
|
73
82
|
end
|
74
83
|
end
|
84
|
+
|
75
85
|
context 'with a foreign key' do
|
76
86
|
it 'sorts by object id' do
|
77
87
|
records = []
|
@@ -79,92 +89,144 @@ describe Mongoid::Criteria do
|
|
79
89
|
expect(records).not_to be_empty
|
80
90
|
end
|
81
91
|
end
|
92
|
+
|
82
93
|
{ a_string: String, a_integer: Integer, a_date: Date, a_datetime: DateTime }.each_pair do |field_name, field_type|
|
83
94
|
context field_type do
|
84
95
|
it 'scrolls all with a block' do
|
85
96
|
records = []
|
86
|
-
Feed::Item.asc(field_name).scroll(cursor_type) do |record,
|
97
|
+
Feed::Item.asc(field_name).scroll(cursor_type) do |record, _iterator|
|
87
98
|
records << record
|
88
99
|
end
|
89
100
|
expect(records.size).to eq 10
|
90
101
|
expect(records).to eq Feed::Item.all.to_a
|
91
102
|
end
|
103
|
+
|
92
104
|
it 'scrolls all with a break' do
|
93
105
|
records = []
|
94
106
|
cursor = nil
|
95
|
-
Feed::Item.asc(field_name).limit(5).scroll(cursor_type) do |record,
|
107
|
+
Feed::Item.asc(field_name).limit(5).scroll(cursor_type) do |record, iterator|
|
96
108
|
records << record
|
97
|
-
cursor = next_cursor
|
109
|
+
cursor = iterator.next_cursor
|
98
110
|
end
|
99
111
|
expect(records.size).to eq 5
|
100
|
-
Feed::Item.asc(field_name).scroll(cursor) do |record,
|
112
|
+
Feed::Item.asc(field_name).scroll(cursor) do |record, iterator|
|
101
113
|
records << record
|
102
|
-
cursor = next_cursor
|
114
|
+
cursor = iterator.next_cursor
|
103
115
|
end
|
104
116
|
expect(records.size).to eq 10
|
105
117
|
expect(records).to eq Feed::Item.all.to_a
|
106
118
|
end
|
119
|
+
|
107
120
|
it 'scrolls from a cursor' do
|
108
121
|
last_record = nil
|
109
122
|
cursor = nil
|
110
|
-
Feed::Item.asc(field_name).limit(5).scroll(cursor_type) do |record,
|
123
|
+
Feed::Item.asc(field_name).limit(5).scroll(cursor_type) do |record, iterator|
|
111
124
|
last_record = record
|
112
|
-
cursor = next_cursor
|
125
|
+
cursor = iterator.next_cursor
|
113
126
|
end
|
114
127
|
sixth_item = Feed::Item.asc(field_name).to_a[5]
|
115
128
|
from_item = Feed::Item.asc(field_name).scroll(cursor).to_a.first
|
116
129
|
expect(from_item).to eq sixth_item
|
117
130
|
end
|
131
|
+
|
118
132
|
it 'includes the current record when Mongoid::Scroll::Cursor#include_current is true' do
|
119
133
|
last_record = nil
|
120
134
|
cursor = nil
|
121
|
-
Feed::Item.asc(field_name).limit(5).scroll(cursor_type) do |record,
|
135
|
+
Feed::Item.asc(field_name).limit(5).scroll(cursor_type) do |record, iterator|
|
122
136
|
last_record = record
|
123
|
-
cursor = next_cursor
|
137
|
+
cursor = iterator.next_cursor
|
124
138
|
end
|
125
139
|
fifth_item = last_record
|
126
140
|
cursor.include_current = true
|
127
141
|
from_item = Feed::Item.asc(field_name).scroll(cursor).to_a.first
|
128
142
|
expect(from_item).to eq fifth_item
|
129
143
|
end
|
144
|
+
|
130
145
|
it 'scrolls in descending order' do
|
131
146
|
records = []
|
132
|
-
Feed::Item.desc(field_name).limit(3).scroll(cursor_type) do |record,
|
147
|
+
Feed::Item.desc(field_name).limit(3).scroll(cursor_type) do |record, _iterator|
|
133
148
|
records << record
|
134
149
|
end
|
135
150
|
expect(records.size).to eq 3
|
136
151
|
expect(records).to eq Feed::Item.desc(field_name).limit(3).to_a
|
137
152
|
end
|
153
|
+
|
138
154
|
it 'map' do
|
139
155
|
record = Feed::Item.desc(field_name).limit(3).scroll(cursor_type).map { |r| r }.last
|
140
|
-
expect(record).
|
156
|
+
expect(record).not_to be_nil
|
141
157
|
cursor = cursor_type.from_record(record, field_type: field_type, field_name: field_name)
|
142
|
-
expect(cursor).
|
158
|
+
expect(cursor).not_to be_nil
|
143
159
|
expect(cursor.tiebreak_id).to eq record.id
|
144
160
|
expect(cursor.value).to eq record.send(field_name)
|
145
161
|
end
|
162
|
+
|
146
163
|
it 'can be reused' do
|
147
164
|
ids = Feed::Item.asc(field_name).limit(2).map(&:id)
|
148
|
-
Feed::Item.asc(field_name).limit(2).scroll(cursor_type) do |_,
|
149
|
-
|
150
|
-
expect(Feed::Item.asc(field_name).limit(2).scroll(
|
165
|
+
Feed::Item.asc(field_name).limit(2).scroll(cursor_type) do |_, iterator|
|
166
|
+
iterator.next_cursor.include_current = true
|
167
|
+
expect(Feed::Item.asc(field_name).limit(2).scroll(iterator.next_cursor).pluck(:id)).to eq ids
|
151
168
|
break
|
152
169
|
end
|
153
170
|
end
|
171
|
+
|
154
172
|
it 'can be re-created and reused' do
|
155
173
|
ids = Feed::Item.asc(field_name).limit(2).map(&:id)
|
156
|
-
Feed::Item.asc(field_name).limit(2).scroll(cursor_type) do |_,
|
157
|
-
new_cursor = cursor_type.new(
|
174
|
+
Feed::Item.asc(field_name).limit(2).scroll(cursor_type) do |_, iterator|
|
175
|
+
new_cursor = cursor_type.new(iterator.next_cursor.to_s, field_type: field_type, field_name: field_name)
|
158
176
|
new_cursor.include_current = true
|
159
177
|
expect(Feed::Item.asc(field_name).limit(2).scroll(new_cursor).pluck(:id)).to eq ids
|
160
178
|
break
|
161
179
|
end
|
162
180
|
end
|
181
|
+
|
182
|
+
it 'can scroll back with the previous cursor' do
|
183
|
+
first_iterator = nil
|
184
|
+
second_iterator = nil
|
185
|
+
third_iterator = nil
|
186
|
+
|
187
|
+
Feed::Item.asc(field_name).limit(2).scroll(cursor_type) do |_, iterator|
|
188
|
+
first_iterator = iterator
|
189
|
+
end
|
190
|
+
|
191
|
+
Feed::Item.asc(field_name).limit(2).scroll(first_iterator.next_cursor) do |_, iterator|
|
192
|
+
second_iterator = iterator
|
193
|
+
end
|
194
|
+
|
195
|
+
Feed::Item.asc(field_name).limit(2).scroll(second_iterator.next_cursor) do |_, iterator|
|
196
|
+
third_iterator = iterator
|
197
|
+
end
|
198
|
+
|
199
|
+
records = Feed::Item.asc(field_name)
|
200
|
+
expect(Feed::Item.asc(field_name).limit(2).scroll(second_iterator.previous_cursor)).to eq(records.limit(2))
|
201
|
+
expect(Feed::Item.asc(field_name).limit(2).scroll(third_iterator.previous_cursor)).to eq(records.skip(2).limit(2))
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'can loop over the same records with the current cursor' do
|
205
|
+
current_cursor = nil
|
206
|
+
cursor = cursor_type.from_record Feed::Item.skip(4).first, field_name: field_name, field_type: field_type, include_current: true
|
207
|
+
|
208
|
+
Feed::Item.asc(field_name).limit(2).scroll(cursor) do |_, iterator|
|
209
|
+
current_cursor = iterator.current_cursor
|
210
|
+
end
|
211
|
+
|
212
|
+
expect(Feed::Item.asc(field_name).limit(2).scroll(current_cursor).to_a).to eq(Feed::Item.asc(field_name).skip(4).limit(2).to_a)
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'can loop over the first records with the first page cursor' do
|
216
|
+
first_cursor = nil
|
217
|
+
|
218
|
+
Feed::Item.asc(field_name).limit(2).scroll(cursor_type) do |_, it|
|
219
|
+
first_cursor = it.first_cursor
|
220
|
+
end
|
221
|
+
|
222
|
+
expect(Feed::Item.asc(field_name).limit(2).scroll(first_cursor).to_a).to eq(Feed::Item.asc(field_name).limit(2).to_a)
|
223
|
+
end
|
163
224
|
end
|
164
225
|
end
|
165
226
|
end
|
227
|
+
|
166
228
|
context 'with logic in initial criteria' do
|
167
|
-
before
|
229
|
+
before do
|
168
230
|
3.times do |i|
|
169
231
|
Feed::Item.create!(
|
170
232
|
name: "Feed Item #{i}",
|
@@ -184,63 +246,69 @@ describe Mongoid::Criteria do
|
|
184
246
|
a_time: Time.new(2014, 2, 2, 1, 2, 3)
|
185
247
|
)
|
186
248
|
end
|
249
|
+
|
187
250
|
it 'respects original criteria with OR logic' do
|
188
251
|
criteria = Feed::Item.where(
|
189
252
|
'$or' => [{ :a_time.gt => Time.new(2015, 7, 22, 1, 2, 3) }, { :a_time.lte => Time.new(2015, 7, 22, 1, 2, 3), :a_date.gte => Date.new(2015, 7, 30) }]
|
190
253
|
).asc(:a_time)
|
191
254
|
records = []
|
192
255
|
cursor = nil
|
193
|
-
criteria.limit(2).scroll(cursor_type) do |record,
|
256
|
+
criteria.limit(2).scroll(cursor_type) do |record, iterator|
|
194
257
|
records << record
|
195
|
-
cursor = next_cursor
|
258
|
+
cursor = iterator.next_cursor
|
196
259
|
end
|
197
260
|
expect(records.size).to eq 2
|
198
261
|
expect(records.map(&:name)).to eq ['Feed Item 0', 'Feed Item 1']
|
199
262
|
records = []
|
200
|
-
criteria.limit(2).scroll(cursor) do |record,
|
263
|
+
criteria.limit(2).scroll(cursor) do |record, iterator|
|
201
264
|
records << record
|
202
|
-
cursor = next_cursor
|
265
|
+
cursor = iterator.next_cursor
|
203
266
|
end
|
204
267
|
expect(records.size).to eq 1
|
205
268
|
expect(records.map(&:name)).to eq ['Feed Item 2']
|
206
269
|
end
|
207
270
|
end
|
271
|
+
|
208
272
|
context 'with embeddable objects' do
|
209
273
|
before do
|
210
274
|
@item = Feed::Item.create! a_integer: 1, name: 'item'
|
211
275
|
@embedded_item = Feed::EmbeddedItem.create! name: 'embedded', item: @item
|
212
276
|
end
|
277
|
+
|
213
278
|
it 'respects embedded queries' do
|
214
279
|
records = []
|
215
280
|
criteria = @item.embedded_items.limit(2)
|
216
|
-
criteria.scroll(cursor_type) do |record,
|
281
|
+
criteria.scroll(cursor_type) do |record, _iterator|
|
217
282
|
records << record
|
218
283
|
end
|
219
284
|
expect(records.size).to eq 1
|
220
285
|
expect(records.map(&:name)).to eq ['embedded']
|
221
286
|
end
|
222
287
|
end
|
288
|
+
|
223
289
|
context 'with overlapping data', if: MongoDB.mmapv1? do
|
224
|
-
before
|
290
|
+
before do
|
225
291
|
3.times { Feed::Item.create! a_integer: 5 }
|
226
292
|
Feed::Item.first.update_attributes!(name: Array(1000).join('a'))
|
227
293
|
end
|
294
|
+
|
228
295
|
it 'natural order is different from order by id' do
|
229
296
|
# natural order isn't necessarily going to be the same as _id order
|
230
297
|
# if a document is updated and grows in size, it may need to be relocated and
|
231
298
|
# thus cause the natural order to change
|
232
|
-
expect(Feed::Item.order_by('$natural' => 1).to_a).
|
299
|
+
expect(Feed::Item.order_by('$natural' => 1).to_a).not_to eq(Feed::Item.order_by(_id: 1).to_a)
|
233
300
|
end
|
301
|
+
|
234
302
|
[{ a_integer: 1 }, { a_integer: -1 }].each do |sort_order|
|
235
303
|
it "scrolls by #{sort_order}" do
|
236
304
|
records = []
|
237
305
|
cursor = nil
|
238
|
-
Feed::Item.order_by(sort_order).limit(2).scroll(cursor_type) do |record,
|
306
|
+
Feed::Item.order_by(sort_order).limit(2).scroll(cursor_type) do |record, iterator|
|
239
307
|
records << record
|
240
|
-
cursor = next_cursor
|
308
|
+
cursor = iterator.next_cursor
|
241
309
|
end
|
242
310
|
expect(records.size).to eq 2
|
243
|
-
Feed::Item.order_by(sort_order).scroll(cursor) do |record,
|
311
|
+
Feed::Item.order_by(sort_order).scroll(cursor) do |record, _iterator|
|
244
312
|
records << record
|
245
313
|
end
|
246
314
|
expect(records.size).to eq 3
|
@@ -248,10 +316,12 @@ describe Mongoid::Criteria do
|
|
248
316
|
end
|
249
317
|
end
|
250
318
|
end
|
319
|
+
|
251
320
|
context 'with several records having the same value' do
|
252
|
-
before
|
321
|
+
before do
|
253
322
|
3.times { Feed::Item.create! a_integer: 5 }
|
254
323
|
end
|
324
|
+
|
255
325
|
it 'returns records from the current one when Mongoid::Scroll::Cursor#include_current is true' do
|
256
326
|
_first_item, second_item, third_item = Feed::Item.asc(:a_integer).to_a
|
257
327
|
cursor = Mongoid::Scroll::Cursor.from_record(second_item, field: Feed::Item.fields['a_integer'])
|
@@ -260,6 +330,7 @@ describe Mongoid::Criteria do
|
|
260
330
|
expect(items).to eq([second_item, third_item])
|
261
331
|
end
|
262
332
|
end
|
333
|
+
|
263
334
|
context 'with DateTime with a milisecond precision' do
|
264
335
|
let!(:item_1) { Feed::Item.create!(a_datetime: DateTime.new(2013, 1, 21, 1, 42, 3.1, 'UTC')) }
|
265
336
|
let!(:item_2) { Feed::Item.create!(a_datetime: DateTime.new(2013, 1, 21, 1, 42, 3.2, 'UTC')) }
|
@@ -268,9 +339,9 @@ describe Mongoid::Criteria do
|
|
268
339
|
it 'doesn\'t lose the precision when rebuilding the cursor' do
|
269
340
|
records = []
|
270
341
|
cursor = nil
|
271
|
-
Feed::Item.order_by(a_datetime: 1).limit(2).scroll(cursor_type) do |record,
|
342
|
+
Feed::Item.order_by(a_datetime: 1).limit(2).scroll(cursor_type) do |record, iterator|
|
272
343
|
records << record
|
273
|
-
cursor = next_cursor
|
344
|
+
cursor = iterator.next_cursor
|
274
345
|
end
|
275
346
|
expect(records).to eq [item_1, item_2]
|
276
347
|
cursor = cursor_type.new(cursor.to_s, field: Feed::Item.fields['a_datetime'])
|
data/spec/mongoid/cursor_spec.rb
CHANGED
@@ -5,125 +5,158 @@ describe Mongoid::Scroll::Cursor do
|
|
5
5
|
subject do
|
6
6
|
Mongoid::Scroll::Cursor.new nil, field_name: 'a_string', field_type: String
|
7
7
|
end
|
8
|
-
|
9
|
-
its(:
|
10
|
-
its(:
|
8
|
+
|
9
|
+
its(:tiebreak_id) { is_expected.to be_nil }
|
10
|
+
its(:value) { is_expected.to be_nil }
|
11
|
+
its(:criteria) { is_expected.to eq({}) }
|
11
12
|
end
|
13
|
+
|
12
14
|
context 'an invalid cursor' do
|
13
15
|
it 'raises InvalidCursorError' do
|
14
16
|
expect { Mongoid::Scroll::Cursor.new 'invalid', field_name: 'a_string', field_type: String }.to raise_error Mongoid::Scroll::Errors::InvalidCursorError,
|
15
17
|
/The cursor supplied is invalid: invalid./
|
16
18
|
end
|
17
19
|
end
|
20
|
+
|
18
21
|
context 'an id field cursor' do
|
19
|
-
let(:feed_item) { Feed::Item.create!(a_string: 'astring') }
|
20
22
|
subject do
|
21
23
|
Mongoid::Scroll::Cursor.new "#{feed_item.id}:#{feed_item.id}", field_name: '_id', field_type: BSON::ObjectId, direction: 1
|
22
24
|
end
|
23
|
-
|
24
|
-
|
25
|
+
|
26
|
+
let(:feed_item) { Feed::Item.create!(a_string: 'astring') }
|
27
|
+
|
28
|
+
its(:value) { is_expected.to eq feed_item.id }
|
29
|
+
its(:tiebreak_id) { is_expected.to eq feed_item.id }
|
30
|
+
|
25
31
|
its(:criteria) do
|
26
|
-
|
27
|
-
|
28
|
-
|
32
|
+
is_expected.to eq('$or' => [
|
33
|
+
{ '_id' => { '$gt' => BSON::ObjectId(feed_item.id.to_s) } }
|
34
|
+
])
|
29
35
|
end
|
30
36
|
end
|
37
|
+
|
31
38
|
context 'a string field cursor' do
|
32
|
-
let(:feed_item) { Feed::Item.create!(a_string: 'astring') }
|
33
39
|
subject do
|
34
40
|
Mongoid::Scroll::Cursor.new "#{feed_item.a_string}:#{feed_item.id}", field_name: 'a_string', field_type: String
|
35
41
|
end
|
36
|
-
|
37
|
-
|
42
|
+
|
43
|
+
let(:feed_item) { Feed::Item.create!(a_string: 'astring') }
|
44
|
+
|
45
|
+
its(:value) { is_expected.to eq feed_item.a_string }
|
46
|
+
its(:tiebreak_id) { is_expected.to eq feed_item.id }
|
47
|
+
|
38
48
|
its(:criteria) do
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
49
|
+
is_expected.to eq('$or' => [
|
50
|
+
{ 'a_string' => { '$gt' => feed_item.a_string } },
|
51
|
+
{ 'a_string' => feed_item.a_string, '_id' => { '$gt' => feed_item.id } }
|
52
|
+
])
|
43
53
|
end
|
44
54
|
end
|
55
|
+
|
45
56
|
context 'an integer field cursor' do
|
46
|
-
let(:feed_item) { Feed::Item.create!(a_integer: 10) }
|
47
57
|
subject do
|
48
58
|
Mongoid::Scroll::Cursor.new "#{feed_item.a_integer}:#{feed_item.id}", field_name: 'a_integer', field_type: Integer
|
49
59
|
end
|
50
|
-
|
51
|
-
|
60
|
+
|
61
|
+
let(:feed_item) { Feed::Item.create!(a_integer: 10) }
|
62
|
+
|
63
|
+
its(:value) { is_expected.to eq feed_item.a_integer }
|
64
|
+
its(:tiebreak_id) { is_expected.to eq feed_item.id }
|
65
|
+
|
52
66
|
its(:criteria) do
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
67
|
+
is_expected.to eq('$or' => [
|
68
|
+
{ 'a_integer' => { '$gt' => feed_item.a_integer } },
|
69
|
+
{ 'a_integer' => feed_item.a_integer, '_id' => { '$gt' => feed_item.id } }
|
70
|
+
])
|
57
71
|
end
|
58
72
|
end
|
73
|
+
|
59
74
|
context 'a date/time field cursor' do
|
60
|
-
let(:feed_item) { Feed::Item.create!(a_datetime: DateTime.new(2013, 12, 21, 1, 42, 3, 'UTC')) }
|
61
75
|
subject do
|
62
76
|
Mongoid::Scroll::Cursor.new "#{feed_item.a_datetime.utc.to_f.round(3)}:#{feed_item.id}", field_name: 'a_datetime', field_type: DateTime
|
63
77
|
end
|
64
|
-
|
65
|
-
|
66
|
-
|
78
|
+
|
79
|
+
let(:feed_item) { Feed::Item.create!(a_datetime: DateTime.new(2013, 12, 21, 1, 42, 3, 'UTC')) }
|
80
|
+
|
81
|
+
its(:value) { is_expected.to eq feed_item.a_datetime }
|
82
|
+
its(:tiebreak_id) { is_expected.to eq feed_item.id }
|
83
|
+
its(:to_s) { is_expected.to eq "#{feed_item.a_datetime.utc.to_f.round(3)}:#{feed_item.id}" }
|
84
|
+
|
67
85
|
its(:criteria) do
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
86
|
+
is_expected.to eq('$or' => [
|
87
|
+
{ 'a_datetime' => { '$gt' => feed_item.a_datetime } },
|
88
|
+
{ 'a_datetime' => feed_item.a_datetime, '_id' => { '$gt' => feed_item.id } }
|
89
|
+
])
|
72
90
|
end
|
73
91
|
end
|
92
|
+
|
74
93
|
context 'a date field cursor' do
|
75
|
-
let(:feed_item) { Feed::Item.create!(a_date: Date.new(2013, 12, 21)) }
|
76
94
|
subject do
|
77
95
|
Mongoid::Scroll::Cursor.new "#{feed_item.a_date.to_datetime.to_i}:#{feed_item.id}", field_name: 'a_date', field_type: Date
|
78
96
|
end
|
79
|
-
|
80
|
-
|
81
|
-
|
97
|
+
|
98
|
+
let(:feed_item) { Feed::Item.create!(a_date: Date.new(2013, 12, 21)) }
|
99
|
+
|
100
|
+
its(:value) { is_expected.to eq feed_item.a_date }
|
101
|
+
its(:tiebreak_id) { is_expected.to eq feed_item.id }
|
102
|
+
its(:to_s) { is_expected.to eq "#{feed_item.a_date.to_datetime.to_i}:#{feed_item.id}" }
|
103
|
+
|
82
104
|
its(:criteria) do
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
105
|
+
is_expected.to eq('$or' => [
|
106
|
+
{ 'a_date' => { '$gt' => feed_item.a_date.to_datetime } },
|
107
|
+
{ 'a_date' => feed_item.a_date.to_datetime, '_id' => { '$gt' => feed_item.id } }
|
108
|
+
])
|
87
109
|
end
|
88
110
|
end
|
111
|
+
|
89
112
|
context 'a time field cursor' do
|
90
|
-
let(:feed_item) { Feed::Item.create!(a_time: Time.new(2013, 12, 21, 1, 2, 3)) }
|
91
113
|
subject do
|
92
114
|
Mongoid::Scroll::Cursor.new "#{feed_item.a_time.to_f.round(3)}:#{feed_item.id}", field_name: 'a_time', field_type: Time
|
93
115
|
end
|
94
|
-
|
95
|
-
|
96
|
-
|
116
|
+
|
117
|
+
let(:feed_item) { Feed::Item.create!(a_time: Time.new(2013, 12, 21, 1, 2, 3)) }
|
118
|
+
|
119
|
+
its(:value) { is_expected.to eq feed_item.a_time }
|
120
|
+
its(:tiebreak_id) { is_expected.to eq feed_item.id }
|
121
|
+
its(:to_s) { is_expected.to eq "#{feed_item.a_time.to_f.round(3)}:#{feed_item.id}" }
|
122
|
+
|
97
123
|
its(:criteria) do
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
124
|
+
is_expected.to eq('$or' => [
|
125
|
+
{ 'a_time' => { '$gt' => feed_item.a_time } },
|
126
|
+
{ 'a_time' => feed_item.a_time, '_id' => { '$gt' => feed_item.id } }
|
127
|
+
])
|
102
128
|
end
|
103
129
|
end
|
130
|
+
|
104
131
|
context 'a time field cursor with a field option' do
|
105
|
-
let(:feed_item) { Feed::Item.create!(a_time: Time.new(2013, 12, 21, 1, 2, 3)) }
|
106
132
|
subject do
|
107
133
|
Mongoid::Scroll::Cursor.new "#{feed_item.a_time.to_f.round(3)}:#{feed_item.id}", field: Feed::Item.fields['a_time']
|
108
134
|
end
|
109
|
-
|
110
|
-
|
111
|
-
|
135
|
+
|
136
|
+
let(:feed_item) { Feed::Item.create!(a_time: Time.new(2013, 12, 21, 1, 2, 3)) }
|
137
|
+
|
138
|
+
its(:value) { is_expected.to eq feed_item.a_time }
|
139
|
+
its(:tiebreak_id) { is_expected.to eq feed_item.id }
|
140
|
+
its(:to_s) { is_expected.to eq "#{feed_item.a_time.to_f.round(3)}:#{feed_item.id}" }
|
141
|
+
|
112
142
|
its(:criteria) do
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
143
|
+
is_expected.to eq('$or' => [
|
144
|
+
{ 'a_time' => { '$gt' => feed_item.a_time } },
|
145
|
+
{ 'a_time' => feed_item.a_time, '_id' => { '$gt' => feed_item.id } }
|
146
|
+
])
|
117
147
|
end
|
118
148
|
end
|
149
|
+
|
119
150
|
context 'an array field cursor' do
|
120
151
|
let(:feed_item) { Feed::Item.create!(a_array: %w[x y]) }
|
152
|
+
|
121
153
|
it 'is not supported' do
|
122
154
|
expect do
|
123
155
|
Mongoid::Scroll::Cursor.from_record feed_item, field_name: 'a_array', field_type: Array
|
124
156
|
end.to raise_error Mongoid::Scroll::Errors::UnsupportedFieldTypeError, /The type of the field 'a_array' is not supported: Array./
|
125
157
|
end
|
126
158
|
end
|
159
|
+
|
127
160
|
context 'an invalid field cursor' do
|
128
161
|
it 'raises ArgumentError' do
|
129
162
|
expect do
|
@@ -131,23 +164,38 @@ describe Mongoid::Scroll::Cursor do
|
|
131
164
|
end.to raise_error ArgumentError
|
132
165
|
end
|
133
166
|
end
|
134
|
-
|
167
|
+
|
168
|
+
context 'an invalid type cursor' do
|
135
169
|
let(:feed_item) { Feed::Item.create!(a_string: 'astring') }
|
170
|
+
|
171
|
+
it 'raises Mongoid::Scroll::Errors::UnsupportedTypeError' do
|
172
|
+
expect do
|
173
|
+
Mongoid::Scroll::Cursor.new "#{feed_item.a_string}:#{feed_item.id}", field_name: 'a_string', field_type: String, include_current: true, type: :invalid
|
174
|
+
end.to raise_error Mongoid::Scroll::Errors::UnsupportedTypeError, /The type supplied in the cursor is not supported: invalid./
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'a cursor with include_current set to true' do
|
136
179
|
subject do
|
137
180
|
Mongoid::Scroll::Cursor.new "#{feed_item.a_string}:#{feed_item.id}", field_name: 'a_string', field_type: String, include_current: true
|
138
181
|
end
|
139
|
-
|
140
|
-
|
182
|
+
|
183
|
+
let(:feed_item) { Feed::Item.create!(a_string: 'astring') }
|
184
|
+
|
185
|
+
its(:value) { is_expected.to eq 'astring' }
|
186
|
+
its(:tiebreak_id) { is_expected.to eq feed_item.id }
|
187
|
+
|
141
188
|
its(:criteria) do
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
189
|
+
is_expected.to eq('$or' => [
|
190
|
+
{ 'a_string' => { '$gt' => 'astring' } },
|
191
|
+
{ '_id' => { '$gte' => BSON::ObjectId(feed_item.id.to_s) }, 'a_string' => 'astring' }
|
192
|
+
])
|
146
193
|
end
|
147
194
|
end
|
195
|
+
|
148
196
|
context 'criteria' do
|
149
197
|
context 'with data' do
|
150
|
-
before
|
198
|
+
before do
|
151
199
|
3.times do |i|
|
152
200
|
Feed::Item.create!(
|
153
201
|
name: "Feed Item #{i}",
|
@@ -159,6 +207,7 @@ describe Mongoid::Scroll::Cursor do
|
|
159
207
|
a_time: Time.new(2014, 2, 2, 1, 2, 3)
|
160
208
|
)
|
161
209
|
end
|
210
|
+
|
162
211
|
it 'merges cursor criteria when no sort field is given' do
|
163
212
|
criteria = Feed::Item.where(:a_time.gt => Time.new(2013, 7, 22, 1, 2, 3))
|
164
213
|
feed_item = Feed::Item.where(name: 'Feed Item 1').first
|
data/spec/mongoid/scroll_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,12 +1,19 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
2
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
3
|
|
4
|
+
require 'coveralls'
|
5
|
+
Coveralls.wear! do
|
6
|
+
add_filter 'spec'
|
7
|
+
end
|
8
|
+
|
4
9
|
require 'rubygems'
|
5
10
|
require 'rspec'
|
6
11
|
require 'rspec/its'
|
7
12
|
require 'database_cleaner'
|
8
13
|
require 'mongoid-scroll'
|
9
14
|
|
15
|
+
Time.zone ||= 'EST'
|
16
|
+
|
10
17
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each do |f|
|
11
18
|
require f
|
12
19
|
end
|
@@ -18,9 +25,9 @@ end
|
|
18
25
|
RSpec.configure do |config|
|
19
26
|
config.before :all do
|
20
27
|
Mongoid.logger.level = Logger::INFO
|
21
|
-
Mongo::Logger.logger.level = Logger::INFO
|
28
|
+
Mongo::Logger.logger.level = Logger::INFO
|
22
29
|
end
|
23
|
-
config.before
|
30
|
+
config.before do
|
24
31
|
DatabaseCleaner.clean
|
25
32
|
end
|
26
33
|
end
|