mongoid-scroll 0.3.6 → 1.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 +5 -5
- data/.github/workflows/ci.yml +36 -0
- data/.github/workflows/danger.yml +17 -0
- data/.rubocop_todo.yml +24 -19
- data/CHANGELOG.md +14 -0
- data/Gemfile +10 -16
- data/LICENSE.md +1 -1
- data/README.md +59 -46
- data/RELEASING.md +4 -4
- data/UPGRADING.md +14 -0
- data/examples/mongoid_scroll_feed.rb +2 -8
- data/lib/config/locales/en.yml +8 -0
- data/lib/mongo/scrollable.rb +8 -3
- data/lib/mongoid/criteria/scrollable/cursors.rb +18 -0
- data/lib/mongoid/criteria/scrollable/fields.rb +21 -0
- data/lib/mongoid/criteria/scrollable.rb +13 -12
- data/lib/mongoid/scroll/base64_encoded_cursor.rb +40 -0
- data/lib/mongoid/scroll/base_cursor.rb +123 -0
- data/lib/mongoid/scroll/cursor.rb +24 -87
- data/lib/mongoid/scroll/errors/base.rb +1 -1
- data/lib/mongoid/scroll/errors/invalid_base64_cursor_error.rb +11 -0
- data/lib/mongoid/scroll/errors/invalid_base_cursor_error.rb +8 -0
- data/lib/mongoid/scroll/errors/invalid_cursor_error.rb +1 -1
- data/lib/mongoid/scroll/errors/mismatched_sort_fields_error.rb +15 -0
- data/lib/mongoid/scroll/errors.rb +3 -0
- data/lib/mongoid/scroll/version.rb +1 -1
- data/lib/mongoid-scroll.rb +4 -1
- data/spec/mongo/collection_view_spec.rb +122 -105
- data/spec/mongoid/base64_encoded_cursor_spec.rb +233 -0
- data/spec/mongoid/criteria_spec.rb +236 -197
- data/spec/mongoid/{scroll_cursor_spec.rb → cursor_spec.rb} +48 -12
- data/spec/spec_helper.rb +1 -1
- data/spec/support/feed/item.rb +1 -1
- metadata +19 -13
- data/.travis.yml +0 -35
- data/examples/moped_scroll_feed.rb +0 -45
- data/lib/moped/scrollable.rb +0 -38
- data/spec/moped/query_spec.rb +0 -126
@@ -1,225 +1,264 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Mongoid::Criteria do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
subject do
|
19
|
-
Feed::Item.all
|
20
|
-
end
|
21
|
-
it 'adds a default sort by _id' do
|
22
|
-
expect(subject.scroll.options[:sort]).to eq('_id' => 1)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
context 'with data' do
|
26
|
-
before :each do
|
27
|
-
10.times do |i|
|
28
|
-
Feed::Item.create!(
|
29
|
-
a_string: i.to_s,
|
30
|
-
a_integer: i,
|
31
|
-
a_datetime: DateTime.new(2013, i + 1, 21, 1, 42, 3, 'UTC'),
|
32
|
-
a_date: Date.new(2013, i + 1, 21),
|
33
|
-
a_time: Time.at(Time.now.to_i + i)
|
34
|
-
)
|
4
|
+
[Mongoid::Scroll::Cursor, Mongoid::Scroll::Base64EncodedCursor].each do |cursor_type|
|
5
|
+
context cursor_type do
|
6
|
+
context 'with multiple sort fields' do
|
7
|
+
subject do
|
8
|
+
Feed::Item.desc(:name).asc(:value)
|
9
|
+
end
|
10
|
+
it ':scroll' do
|
11
|
+
expect(subject).to respond_to(:scroll)
|
12
|
+
end
|
13
|
+
it 'raises Mongoid::Scroll::Errors::MultipleSortFieldsError' do
|
14
|
+
expect do
|
15
|
+
subject.scroll(cursor_type)
|
16
|
+
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
|
+
end
|
35
18
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
19
|
+
context 'with different sort fields between the cursor and the criteria' do
|
20
|
+
subject do
|
21
|
+
Feed::Item.desc(:name)
|
22
|
+
end
|
23
|
+
it 'raises Mongoid::Scroll::Errors::MismatchedSortFieldsError' do
|
24
|
+
record = Feed::Item.create!
|
25
|
+
cursor = cursor_type.from_record(record, field: record.fields['a_string'])
|
26
|
+
error_string = /You're attempting to scroll over data with a sort order that differs between the cursor and the original criteria: field_name, direction./
|
27
|
+
expect { subject.scroll(cursor) }.to raise_error Mongoid::Scroll::Errors::MismatchedSortFieldsError, error_string
|
28
|
+
end
|
45
29
|
end
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
cursor = next_cursor
|
54
|
-
end
|
55
|
-
criteria.scroll(cursor) do |_record, next_cursor|
|
56
|
-
cursor = next_cursor
|
57
|
-
end
|
58
|
-
expect(criteria).to eq original_criteria
|
30
|
+
context 'with no sort' do
|
31
|
+
subject do
|
32
|
+
Feed::Item.all
|
33
|
+
end
|
34
|
+
it 'adds a default sort by _id' do
|
35
|
+
expect(subject.scroll(cursor_type).options[:sort]).to eq('_id' => 1)
|
36
|
+
end
|
59
37
|
end
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
38
|
+
context 'with data' do
|
39
|
+
before :each do
|
40
|
+
10.times do |i|
|
41
|
+
Feed::Item.create!(
|
42
|
+
name: i.to_s,
|
43
|
+
a_string: i.to_s,
|
44
|
+
a_integer: i,
|
45
|
+
a_datetime: DateTime.new(2013, i + 1, 21, 1, 42, 3, 'UTC'),
|
46
|
+
a_date: Date.new(2013, i + 1, 21),
|
47
|
+
a_time: Time.at(Time.now.to_i + i)
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
context 'default' do
|
52
|
+
it 'scrolls all' do
|
53
|
+
records = []
|
54
|
+
Feed::Item.all.scroll(cursor_type) do |record, _next_cursor|
|
55
|
+
records << record
|
56
|
+
end
|
57
|
+
expect(records.size).to eq 10
|
58
|
+
expect(records).to eq Feed::Item.all.to_a
|
59
|
+
end
|
60
|
+
it 'does not change original criteria' do
|
61
|
+
criteria = Feed::Item.where(:a_time.gt => Time.new(2013, 7, 22, 1, 2, 3))
|
62
|
+
original_criteria = criteria.dup
|
63
|
+
criteria.limit(2).scroll(cursor_type)
|
64
|
+
expect(criteria).to eq original_criteria
|
65
|
+
cursor = nil
|
66
|
+
criteria.limit(2).scroll(cursor) do |_record, next_cursor|
|
67
|
+
cursor = next_cursor
|
68
|
+
end
|
69
|
+
criteria.scroll(cursor) do |_record, next_cursor|
|
70
|
+
cursor = next_cursor
|
71
|
+
end
|
72
|
+
expect(criteria).to eq original_criteria
|
73
|
+
end
|
74
|
+
end
|
75
|
+
context 'with a foreign key' do
|
76
|
+
it 'sorts by object id' do
|
77
|
+
records = []
|
78
|
+
Feed::Item.asc('publisher_id').scroll(cursor_type) { |r, _| records << r }
|
79
|
+
expect(records).not_to be_empty
|
80
|
+
end
|
81
|
+
end
|
82
|
+
{ a_string: String, a_integer: Integer, a_date: Date, a_datetime: DateTime }.each_pair do |field_name, field_type|
|
83
|
+
context field_type do
|
84
|
+
it 'scrolls all with a block' do
|
85
|
+
records = []
|
86
|
+
Feed::Item.asc(field_name).scroll(cursor_type) do |record, _next_cursor|
|
87
|
+
records << record
|
88
|
+
end
|
89
|
+
expect(records.size).to eq 10
|
90
|
+
expect(records).to eq Feed::Item.all.to_a
|
91
|
+
end
|
92
|
+
it 'scrolls all with a break' do
|
93
|
+
records = []
|
94
|
+
cursor = nil
|
95
|
+
Feed::Item.asc(field_name).limit(5).scroll(cursor_type) do |record, next_cursor|
|
96
|
+
records << record
|
97
|
+
cursor = next_cursor
|
98
|
+
end
|
99
|
+
expect(records.size).to eq 5
|
100
|
+
Feed::Item.asc(field_name).scroll(cursor) do |record, next_cursor|
|
101
|
+
records << record
|
102
|
+
cursor = next_cursor
|
103
|
+
end
|
104
|
+
expect(records.size).to eq 10
|
105
|
+
expect(records).to eq Feed::Item.all.to_a
|
106
|
+
end
|
107
|
+
it 'scrolls from a cursor' do
|
108
|
+
last_record = nil
|
109
|
+
cursor = nil
|
110
|
+
Feed::Item.asc(field_name).limit(5).scroll(cursor_type) do |record, next_cursor|
|
111
|
+
last_record = record
|
112
|
+
cursor = next_cursor
|
113
|
+
end
|
114
|
+
sixth_item = Feed::Item.asc(field_name).to_a[5]
|
115
|
+
from_item = Feed::Item.asc(field_name).scroll(cursor).to_a.first
|
116
|
+
expect(from_item).to eq sixth_item
|
117
|
+
end
|
118
|
+
it 'includes the current record when Mongoid::Scroll::Cursor#include_current is true' do
|
119
|
+
last_record = nil
|
120
|
+
cursor = nil
|
121
|
+
Feed::Item.asc(field_name).limit(5).scroll(cursor_type) do |record, next_cursor|
|
122
|
+
last_record = record
|
123
|
+
cursor = next_cursor
|
124
|
+
end
|
125
|
+
fifth_item = last_record
|
126
|
+
cursor.include_current = true
|
127
|
+
from_item = Feed::Item.asc(field_name).scroll(cursor).to_a.first
|
128
|
+
expect(from_item).to eq fifth_item
|
129
|
+
end
|
130
|
+
it 'scrolls in descending order' do
|
131
|
+
records = []
|
132
|
+
Feed::Item.desc(field_name).limit(3).scroll(cursor_type) do |record, _next_cursor|
|
133
|
+
records << record
|
134
|
+
end
|
135
|
+
expect(records.size).to eq 3
|
136
|
+
expect(records).to eq Feed::Item.desc(field_name).limit(3).to_a
|
137
|
+
end
|
138
|
+
it 'map' do
|
139
|
+
record = Feed::Item.desc(field_name).limit(3).scroll(cursor_type).map { |r| r }.last
|
140
|
+
expect(record).to_not be nil
|
141
|
+
cursor = cursor_type.from_record(record, field_type: field_type, field_name: field_name)
|
142
|
+
expect(cursor).to_not be nil
|
143
|
+
expect(cursor.tiebreak_id).to eq record.id
|
144
|
+
expect(cursor.value).to eq record.send(field_name)
|
145
|
+
end
|
146
|
+
it 'can be reused' do
|
147
|
+
ids = Feed::Item.asc(field_name).limit(2).map(&:id)
|
148
|
+
Feed::Item.asc(field_name).limit(2).scroll(cursor_type) do |_, cursor|
|
149
|
+
cursor.include_current = true
|
150
|
+
expect(Feed::Item.asc(field_name).limit(2).scroll(cursor).pluck(:id)).to eq ids
|
151
|
+
break
|
152
|
+
end
|
153
|
+
end
|
154
|
+
it 'can be re-created and reused' do
|
155
|
+
ids = Feed::Item.asc(field_name).limit(2).map(&:id)
|
156
|
+
Feed::Item.asc(field_name).limit(2).scroll(cursor_type) do |_, cursor|
|
157
|
+
new_cursor = cursor_type.new(cursor.to_s, field_type: field_type, field_name: field_name)
|
158
|
+
new_cursor.include_current = true
|
159
|
+
expect(Feed::Item.asc(field_name).limit(2).scroll(new_cursor).pluck(:id)).to eq ids
|
160
|
+
break
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
67
165
|
end
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
166
|
+
context 'with logic in initial criteria' do
|
167
|
+
before :each do
|
168
|
+
3.times do |i|
|
169
|
+
Feed::Item.create!(
|
170
|
+
name: "Feed Item #{i}",
|
171
|
+
a_string: i.to_s,
|
172
|
+
a_integer: i,
|
173
|
+
a_datetime: DateTime.new(2015, i + 1, 21, 1, 42, 3, 'UTC'),
|
174
|
+
a_date: Date.new(2016, i + 1, 21),
|
175
|
+
a_time: Time.new(2015, i + 1, 22, 1, 2, 3)
|
176
|
+
)
|
76
177
|
end
|
77
|
-
|
78
|
-
|
178
|
+
Feed::Item.create!(
|
179
|
+
name: 'Feed Item 3',
|
180
|
+
a_string: '3',
|
181
|
+
a_integer: 3,
|
182
|
+
a_datetime: DateTime.new(2015, 3, 2, 1, 2, 3),
|
183
|
+
a_date: Date.new(2012, 2, 3),
|
184
|
+
a_time: Time.new(2014, 2, 2, 1, 2, 3)
|
185
|
+
)
|
79
186
|
end
|
80
|
-
it '
|
187
|
+
it 'respects original criteria with OR logic' do
|
188
|
+
criteria = Feed::Item.where(
|
189
|
+
'$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
|
+
).asc(:a_time)
|
81
191
|
records = []
|
82
192
|
cursor = nil
|
83
|
-
|
193
|
+
criteria.limit(2).scroll(cursor_type) do |record, next_cursor|
|
84
194
|
records << record
|
85
195
|
cursor = next_cursor
|
86
196
|
end
|
87
|
-
expect(records.size).to eq
|
88
|
-
|
197
|
+
expect(records.size).to eq 2
|
198
|
+
expect(records.map(&:name)).to eq ['Feed Item 0', 'Feed Item 1']
|
199
|
+
records = []
|
200
|
+
criteria.limit(2).scroll(cursor) do |record, next_cursor|
|
89
201
|
records << record
|
90
202
|
cursor = next_cursor
|
91
203
|
end
|
92
|
-
expect(records.size).to eq
|
93
|
-
expect(records).to eq Feed
|
204
|
+
expect(records.size).to eq 1
|
205
|
+
expect(records.map(&:name)).to eq ['Feed Item 2']
|
94
206
|
end
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
Feed::Item.
|
99
|
-
|
100
|
-
cursor = next_cursor
|
101
|
-
end
|
102
|
-
sixth_item = Feed::Item.asc(field_name).to_a[5]
|
103
|
-
from_item = Feed::Item.asc(field_name).scroll(cursor).to_a.first
|
104
|
-
expect(from_item).to eq sixth_item
|
207
|
+
end
|
208
|
+
context 'with embeddable objects' do
|
209
|
+
before do
|
210
|
+
@item = Feed::Item.create! a_integer: 1, name: 'item'
|
211
|
+
@embedded_item = Feed::EmbeddedItem.create! name: 'embedded', item: @item
|
105
212
|
end
|
106
|
-
it '
|
213
|
+
it 'respects embedded queries' do
|
107
214
|
records = []
|
108
|
-
|
215
|
+
criteria = @item.embedded_items.limit(2)
|
216
|
+
criteria.scroll(cursor_type) do |record, _next_cursor|
|
109
217
|
records << record
|
110
218
|
end
|
111
|
-
expect(records.size).to eq
|
112
|
-
expect(records).to eq
|
113
|
-
end
|
114
|
-
it 'map' do
|
115
|
-
record = Feed::Item.desc(field_name).limit(3).scroll.map { |r| r }.last
|
116
|
-
expect(record).to_not be nil
|
117
|
-
cursor = Mongoid::Scroll::Cursor.from_record(record, field_type: field_type, field_name: field_name)
|
118
|
-
expect(cursor).to_not be nil
|
119
|
-
expect(cursor.to_s.split(':')).to eq [
|
120
|
-
Mongoid::Scroll::Cursor.transform_field_value(field_type, field_name, record.send(field_name)).to_s,
|
121
|
-
record.id.to_s
|
122
|
-
]
|
219
|
+
expect(records.size).to eq 1
|
220
|
+
expect(records.map(&:name)).to eq ['embedded']
|
123
221
|
end
|
124
222
|
end
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
records = []
|
153
|
-
cursor = nil
|
154
|
-
criteria.limit(2).scroll do |record, next_cursor|
|
155
|
-
records << record
|
156
|
-
cursor = next_cursor
|
157
|
-
end
|
158
|
-
expect(records.size).to eq 2
|
159
|
-
expect(records.map(&:name)).to eq ['Feed Item 0', 'Feed Item 1']
|
160
|
-
records = []
|
161
|
-
criteria.limit(2).scroll(cursor) do |record, next_cursor|
|
162
|
-
records << record
|
163
|
-
cursor = next_cursor
|
164
|
-
end
|
165
|
-
expect(records.size).to eq 1
|
166
|
-
expect(records.map(&:name)).to eq ['Feed Item 2']
|
167
|
-
end
|
168
|
-
it 'merges cursor criteria when no sort field is given' do
|
169
|
-
criteria = Feed::Item.where(:a_time.gt => Time.new(2013, 7, 22, 1, 2, 3))
|
170
|
-
feed_item = Feed::Item.where(name: 'Feed Item 1').first
|
171
|
-
cursor_input = "#{feed_item.id}:#{feed_item.id}"
|
172
|
-
field_type = Mongoid::Compatibility::Version.mongoid3? ? Moped::BSON::ObjectId : BSON::ObjectId
|
173
|
-
cursor_options = { field_type: field_type, field_name: '_id', direction: 1 }
|
174
|
-
cursor = Mongoid::Scroll::Cursor.new(cursor_input, cursor_options)
|
175
|
-
records = []
|
176
|
-
criteria.limit(2).scroll(cursor) do |record, next_cursor|
|
177
|
-
records << record
|
178
|
-
cursor = next_cursor
|
179
|
-
end
|
180
|
-
expect(records.size).to eq 2
|
181
|
-
end
|
182
|
-
end
|
183
|
-
context 'with embeddable objects' do
|
184
|
-
before do
|
185
|
-
@item = Feed::Item.create! a_integer: 1, name: 'item'
|
186
|
-
@embedded_item = Feed::EmbeddedItem.create! name: 'embedded', item: @item
|
187
|
-
end
|
188
|
-
it 'respects embedded queries' do
|
189
|
-
records = []
|
190
|
-
criteria = @item.embedded_items.limit(2)
|
191
|
-
criteria.scroll do |record, _next_cursor|
|
192
|
-
records << record
|
223
|
+
context 'with overlapping data', if: MongoDB.mmapv1? do
|
224
|
+
before :each do
|
225
|
+
3.times { Feed::Item.create! a_integer: 5 }
|
226
|
+
Feed::Item.first.update_attributes!(name: Array(1000).join('a'))
|
227
|
+
end
|
228
|
+
it 'natural order is different from order by id' do
|
229
|
+
# natural order isn't necessarily going to be the same as _id order
|
230
|
+
# if a document is updated and grows in size, it may need to be relocated and
|
231
|
+
# thus cause the natural order to change
|
232
|
+
expect(Feed::Item.order_by('$natural' => 1).to_a).to_not eq(Feed::Item.order_by(_id: 1).to_a)
|
233
|
+
end
|
234
|
+
[{ a_integer: 1 }, { a_integer: -1 }].each do |sort_order|
|
235
|
+
it "scrolls by #{sort_order}" do
|
236
|
+
records = []
|
237
|
+
cursor = nil
|
238
|
+
Feed::Item.order_by(sort_order).limit(2).scroll(cursor_type) do |record, next_cursor|
|
239
|
+
records << record
|
240
|
+
cursor = next_cursor
|
241
|
+
end
|
242
|
+
expect(records.size).to eq 2
|
243
|
+
Feed::Item.order_by(sort_order).scroll(cursor) do |record, _next_cursor|
|
244
|
+
records << record
|
245
|
+
end
|
246
|
+
expect(records.size).to eq 3
|
247
|
+
expect(records).to eq Feed::Item.all.sort(_id: sort_order[:a_integer]).to_a
|
248
|
+
end
|
249
|
+
end
|
193
250
|
end
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
# if a document is updated and grows in size, it may need to be relocated and
|
206
|
-
# thus cause the natural order to change
|
207
|
-
expect(Feed::Item.order_by('$natural' => 1).to_a).to_not eq(Feed::Item.order_by(_id: 1).to_a)
|
208
|
-
end
|
209
|
-
[{ a_integer: 1 }, { a_integer: -1 }].each do |sort_order|
|
210
|
-
it "scrolls by #{sort_order}" do
|
211
|
-
records = []
|
212
|
-
cursor = nil
|
213
|
-
Feed::Item.order_by(sort_order).limit(2).scroll do |record, next_cursor|
|
214
|
-
records << record
|
215
|
-
cursor = next_cursor
|
216
|
-
end
|
217
|
-
expect(records.size).to eq 2
|
218
|
-
Feed::Item.order_by(sort_order).scroll(cursor) do |record, _next_cursor|
|
219
|
-
records << record
|
220
|
-
end
|
221
|
-
expect(records.size).to eq 3
|
222
|
-
expect(records).to eq Feed::Item.all.sort(_id: sort_order[:a_integer]).to_a
|
251
|
+
context 'with several records having the same value' do
|
252
|
+
before :each do
|
253
|
+
3.times { Feed::Item.create! a_integer: 5 }
|
254
|
+
end
|
255
|
+
it 'returns records from the current one when Mongoid::Scroll::Cursor#include_current is true' do
|
256
|
+
_first_item, second_item, third_item = Feed::Item.asc(:a_integer).to_a
|
257
|
+
cursor = Mongoid::Scroll::Cursor.from_record(second_item, field: Feed::Item.fields['a_integer'])
|
258
|
+
cursor.include_current = true
|
259
|
+
items = Feed::Item.asc(:a_integer).limit(2).scroll(cursor).to_a
|
260
|
+
expect(items).to eq([second_item, third_item])
|
261
|
+
end
|
223
262
|
end
|
224
263
|
end
|
225
264
|
end
|
@@ -17,22 +17,15 @@ describe Mongoid::Scroll::Cursor do
|
|
17
17
|
end
|
18
18
|
context 'an id field cursor' do
|
19
19
|
let(:feed_item) { Feed::Item.create!(a_string: 'astring') }
|
20
|
-
field_type = Mongoid::Compatibility::Version.mongoid3? ? Moped::BSON::ObjectId : BSON::ObjectId
|
21
20
|
subject do
|
22
|
-
Mongoid::Scroll::Cursor.new "#{feed_item.id}:#{feed_item.id}", field_name: '_id', field_type:
|
21
|
+
Mongoid::Scroll::Cursor.new "#{feed_item.id}:#{feed_item.id}", field_name: '_id', field_type: BSON::ObjectId, direction: 1
|
23
22
|
end
|
24
|
-
its(:value) { should eq feed_item.id
|
23
|
+
its(:value) { should eq feed_item.id }
|
25
24
|
its(:tiebreak_id) { should eq feed_item.id }
|
26
25
|
its(:criteria) do
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
])
|
31
|
-
else
|
32
|
-
should eq('$or' => [
|
33
|
-
{ '_id' => { '$gt' => BSON::ObjectId(feed_item.id.to_s) } }
|
34
|
-
])
|
35
|
-
end
|
26
|
+
should eq('$or' => [
|
27
|
+
{ '_id' => { '$gt' => BSON::ObjectId(feed_item.id.to_s) } }
|
28
|
+
])
|
36
29
|
end
|
37
30
|
end
|
38
31
|
context 'a string field cursor' do
|
@@ -138,4 +131,47 @@ describe Mongoid::Scroll::Cursor do
|
|
138
131
|
end.to raise_error ArgumentError
|
139
132
|
end
|
140
133
|
end
|
134
|
+
context 'a cursor with include_current set to true' do
|
135
|
+
let(:feed_item) { Feed::Item.create!(a_string: 'astring') }
|
136
|
+
subject do
|
137
|
+
Mongoid::Scroll::Cursor.new "#{feed_item.a_string}:#{feed_item.id}", field_name: 'a_string', field_type: String, include_current: true
|
138
|
+
end
|
139
|
+
its(:value) { should eq 'astring' }
|
140
|
+
its(:tiebreak_id) { should eq feed_item.id }
|
141
|
+
its(:criteria) do
|
142
|
+
should eq('$or' => [
|
143
|
+
{ 'a_string' => { '$gt' => 'astring' } },
|
144
|
+
{ '_id' => { '$gte' => BSON::ObjectId(feed_item.id.to_s) }, 'a_string' => 'astring' }
|
145
|
+
])
|
146
|
+
end
|
147
|
+
end
|
148
|
+
context 'criteria' do
|
149
|
+
context 'with data' do
|
150
|
+
before :each do
|
151
|
+
3.times do |i|
|
152
|
+
Feed::Item.create!(
|
153
|
+
name: "Feed Item #{i}",
|
154
|
+
a_time: Time.new(2015, i + 1, 22, 1, 2, 3)
|
155
|
+
)
|
156
|
+
end
|
157
|
+
Feed::Item.create!(
|
158
|
+
name: 'Feed Item 3',
|
159
|
+
a_time: Time.new(2014, 2, 2, 1, 2, 3)
|
160
|
+
)
|
161
|
+
end
|
162
|
+
it 'merges cursor criteria when no sort field is given' do
|
163
|
+
criteria = Feed::Item.where(:a_time.gt => Time.new(2013, 7, 22, 1, 2, 3))
|
164
|
+
feed_item = Feed::Item.where(name: 'Feed Item 1').first
|
165
|
+
cursor_input = "#{feed_item.id}:#{feed_item.id}"
|
166
|
+
cursor_options = { field_type: BSON::ObjectId, field_name: '_id', direction: 1 }
|
167
|
+
cursor = Mongoid::Scroll::Cursor.new(cursor_input, cursor_options)
|
168
|
+
records = []
|
169
|
+
criteria.limit(2).scroll(cursor) do |record, next_cursor|
|
170
|
+
records << record
|
171
|
+
cursor = next_cursor
|
172
|
+
end
|
173
|
+
expect(records.size).to eq 2
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
141
177
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -18,7 +18,7 @@ end
|
|
18
18
|
RSpec.configure do |config|
|
19
19
|
config.before :all do
|
20
20
|
Mongoid.logger.level = Logger::INFO
|
21
|
-
Mongo::Logger.logger.level = Logger::INFO if Mongoid::Compatibility::Version.
|
21
|
+
Mongo::Logger.logger.level = Logger::INFO if Mongoid::Compatibility::Version.mongoid5_or_newer?
|
22
22
|
end
|
23
23
|
config.before :each do
|
24
24
|
DatabaseCleaner.clean
|
data/spec/support/feed/item.rb
CHANGED
@@ -13,7 +13,7 @@ module Feed
|
|
13
13
|
embeds_many :embedded_items, class_name: 'Feed::EmbeddedItem'
|
14
14
|
|
15
15
|
publisher_options = { class_name: 'Feed::Publisher' }
|
16
|
-
publisher_options[:optional] = true if Mongoid::Compatibility::Version.
|
16
|
+
publisher_options[:optional] = true if Mongoid::Compatibility::Version.mongoid6_or_newer?
|
17
17
|
belongs_to :publisher, publisher_options
|
18
18
|
end
|
19
19
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid-scroll
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Doubrovkine
|
8
8
|
- Frank Macreery
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-03-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: mongoid
|
@@ -53,17 +53,18 @@ dependencies:
|
|
53
53
|
- - ">="
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '0'
|
56
|
-
description:
|
56
|
+
description:
|
57
57
|
email: dblock@dblock.org
|
58
58
|
executables: []
|
59
59
|
extensions: []
|
60
60
|
extra_rdoc_files: []
|
61
61
|
files:
|
62
|
+
- ".github/workflows/ci.yml"
|
63
|
+
- ".github/workflows/danger.yml"
|
62
64
|
- ".gitignore"
|
63
65
|
- ".rspec"
|
64
66
|
- ".rubocop.yml"
|
65
67
|
- ".rubocop_todo.yml"
|
66
|
-
- ".travis.yml"
|
67
68
|
- CHANGELOG.md
|
68
69
|
- Dangerfile
|
69
70
|
- Gemfile
|
@@ -71,29 +72,35 @@ files:
|
|
71
72
|
- README.md
|
72
73
|
- RELEASING.md
|
73
74
|
- Rakefile
|
75
|
+
- UPGRADING.md
|
74
76
|
- examples/mongo_ruby_driver_scroll_feed.rb
|
75
77
|
- examples/mongoid_scroll_feed.rb
|
76
|
-
- examples/moped_scroll_feed.rb
|
77
78
|
- lib/config/locales/en.yml
|
78
79
|
- lib/mongo/scrollable.rb
|
79
80
|
- lib/mongoid-scroll.rb
|
80
81
|
- lib/mongoid/criteria/scrollable.rb
|
82
|
+
- lib/mongoid/criteria/scrollable/cursors.rb
|
83
|
+
- lib/mongoid/criteria/scrollable/fields.rb
|
84
|
+
- lib/mongoid/scroll/base64_encoded_cursor.rb
|
85
|
+
- lib/mongoid/scroll/base_cursor.rb
|
81
86
|
- lib/mongoid/scroll/cursor.rb
|
82
87
|
- lib/mongoid/scroll/errors.rb
|
83
88
|
- lib/mongoid/scroll/errors/base.rb
|
89
|
+
- lib/mongoid/scroll/errors/invalid_base64_cursor_error.rb
|
90
|
+
- lib/mongoid/scroll/errors/invalid_base_cursor_error.rb
|
84
91
|
- lib/mongoid/scroll/errors/invalid_cursor_error.rb
|
92
|
+
- lib/mongoid/scroll/errors/mismatched_sort_fields_error.rb
|
85
93
|
- lib/mongoid/scroll/errors/multiple_sort_fields_error.rb
|
86
94
|
- lib/mongoid/scroll/errors/no_such_field_error.rb
|
87
95
|
- lib/mongoid/scroll/errors/unsupported_field_type_error.rb
|
88
96
|
- lib/mongoid/scroll/version.rb
|
89
97
|
- lib/mongoid_scroll.rb
|
90
|
-
- lib/moped/scrollable.rb
|
91
98
|
- mongoid-scroll.gemspec
|
92
99
|
- spec/mongo/collection_view_spec.rb
|
100
|
+
- spec/mongoid/base64_encoded_cursor_spec.rb
|
93
101
|
- spec/mongoid/criteria_spec.rb
|
94
|
-
- spec/mongoid/
|
102
|
+
- spec/mongoid/cursor_spec.rb
|
95
103
|
- spec/mongoid/scroll_spec.rb
|
96
|
-
- spec/moped/query_spec.rb
|
97
104
|
- spec/spec_helper.rb
|
98
105
|
- spec/support/feed/embedded_item.rb
|
99
106
|
- spec/support/feed/item.rb
|
@@ -103,7 +110,7 @@ homepage: http://github.com/mongoid/mongoid-scroll
|
|
103
110
|
licenses:
|
104
111
|
- MIT
|
105
112
|
metadata: {}
|
106
|
-
post_install_message:
|
113
|
+
post_install_message:
|
107
114
|
rdoc_options: []
|
108
115
|
require_paths:
|
109
116
|
- lib
|
@@ -118,9 +125,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
125
|
- !ruby/object:Gem::Version
|
119
126
|
version: 1.3.6
|
120
127
|
requirements: []
|
121
|
-
|
122
|
-
|
123
|
-
signing_key:
|
128
|
+
rubygems_version: 3.2.32
|
129
|
+
signing_key:
|
124
130
|
specification_version: 4
|
125
131
|
summary: Mongoid extensions to enable infinite scroll.
|
126
132
|
test_files: []
|