mongoid-scroll 0.3.7 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +36 -0
  3. data/.github/workflows/danger.yml +17 -0
  4. data/.rubocop_todo.yml +24 -19
  5. data/CHANGELOG.md +10 -0
  6. data/Gemfile +6 -5
  7. data/LICENSE.md +1 -1
  8. data/README.md +59 -46
  9. data/RELEASING.md +1 -1
  10. data/UPGRADING.md +14 -0
  11. data/examples/mongoid_scroll_feed.rb +2 -8
  12. data/lib/config/locales/en.yml +8 -0
  13. data/lib/mongo/scrollable.rb +8 -3
  14. data/lib/mongoid/criteria/scrollable/cursors.rb +18 -0
  15. data/lib/mongoid/criteria/scrollable/fields.rb +21 -0
  16. data/lib/mongoid/criteria/scrollable.rb +13 -12
  17. data/lib/mongoid/scroll/base64_encoded_cursor.rb +40 -0
  18. data/lib/mongoid/scroll/base_cursor.rb +123 -0
  19. data/lib/mongoid/scroll/cursor.rb +24 -87
  20. data/lib/mongoid/scroll/errors/base.rb +1 -1
  21. data/lib/mongoid/scroll/errors/invalid_base64_cursor_error.rb +11 -0
  22. data/lib/mongoid/scroll/errors/invalid_base_cursor_error.rb +8 -0
  23. data/lib/mongoid/scroll/errors/invalid_cursor_error.rb +1 -1
  24. data/lib/mongoid/scroll/errors/mismatched_sort_fields_error.rb +15 -0
  25. data/lib/mongoid/scroll/errors.rb +3 -0
  26. data/lib/mongoid/scroll/version.rb +1 -1
  27. data/lib/mongoid-scroll.rb +4 -1
  28. data/spec/mongo/collection_view_spec.rb +122 -105
  29. data/spec/mongoid/base64_encoded_cursor_spec.rb +233 -0
  30. data/spec/mongoid/criteria_spec.rb +236 -197
  31. data/spec/mongoid/{scroll_cursor_spec.rb → cursor_spec.rb} +48 -12
  32. data/spec/support/feed/item.rb +1 -1
  33. metadata +15 -8
  34. data/.travis.yml +0 -37
  35. data/examples/moped_scroll_feed.rb +0 -45
  36. data/lib/moped/scrollable.rb +0 -38
  37. 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
- context 'with multiple sort fields' do
5
- subject do
6
- Feed::Item.desc(:name).asc(:value)
7
- end
8
- it ':scroll' do
9
- expect(subject).to respond_to(:scroll)
10
- end
11
- it 'raises Mongoid::Scroll::Errors::MultipleSortFieldsError' do
12
- expect { subject.scroll }.to raise_error Mongoid::Scroll::Errors::MultipleSortFieldsError,
13
- /You're attempting to scroll over data with a sort order that includes multiple fields: name, value./
14
- end
15
- end
16
-
17
- context 'with no sort' do
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
- end
37
- context 'default' do
38
- it 'scrolls all' do
39
- records = []
40
- Feed::Item.all.scroll do |record, _next_cursor|
41
- records << record
42
- end
43
- expect(records.size).to eq 10
44
- expect(records).to eq Feed::Item.all.to_a
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
- it 'does not change original criteria' do
47
- criteria = Feed::Item.where(:a_time.gt => Time.new(2013, 7, 22, 1, 2, 3))
48
- original_criteria = criteria.dup
49
- criteria.limit(2).scroll
50
- expect(criteria).to eq original_criteria
51
- cursor = nil
52
- criteria.limit(2).scroll(cursor) do |_record, next_cursor|
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
- end
61
-
62
- context 'with a foreign key' do
63
- it 'sorts by object id' do
64
- records = []
65
- Feed::Item.asc('publisher_id').scroll { |r, _| records << r }
66
- expect(records).not_to be_empty
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
- end
69
-
70
- { a_string: String, a_integer: Integer, a_date: Date, a_datetime: DateTime }.each_pair do |field_name, field_type|
71
- context field_type do
72
- it 'scrolls all with a block' do
73
- records = []
74
- Feed::Item.asc(field_name).scroll do |record, _next_cursor|
75
- records << record
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
- expect(records.size).to eq 10
78
- expect(records).to eq Feed::Item.all.to_a
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 'scrolls all with a break' do
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
- Feed::Item.asc(field_name).limit(5).scroll do |record, next_cursor|
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 5
88
- Feed::Item.asc(field_name).scroll(cursor) do |record, next_cursor|
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 10
93
- expect(records).to eq Feed::Item.all.to_a
204
+ expect(records.size).to eq 1
205
+ expect(records.map(&:name)).to eq ['Feed Item 2']
94
206
  end
95
- it 'scrolls from a cursor' do
96
- last_record = nil
97
- cursor = nil
98
- Feed::Item.asc(field_name).limit(5).scroll do |record, next_cursor|
99
- last_record = record
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 'scrolls in descending order' do
213
+ it 'respects embedded queries' do
107
214
  records = []
108
- Feed::Item.desc(field_name).limit(3).scroll do |record, _next_cursor|
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 3
112
- expect(records).to eq Feed::Item.desc(field_name).limit(3).to_a
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
- end
126
- end
127
- context 'with logic in initial criteria' do
128
- before :each do
129
- 3.times do |i|
130
- Feed::Item.create!(
131
- name: "Feed Item #{i}",
132
- a_string: i.to_s,
133
- a_integer: i,
134
- a_datetime: DateTime.new(2015, i + 1, 21, 1, 42, 3, 'UTC'),
135
- a_date: Date.new(2016, i + 1, 21),
136
- a_time: Time.new(2015, i + 1, 22, 1, 2, 3)
137
- )
138
- end
139
- Feed::Item.create!(
140
- name: 'Feed Item 3',
141
- a_string: '3',
142
- a_integer: 3,
143
- a_datetime: DateTime.new(2015, 3, 2, 1, 2, 3),
144
- a_date: Date.new(2012, 2, 3),
145
- a_time: Time.new(2014, 2, 2, 1, 2, 3)
146
- )
147
- end
148
- it 'respects original criteria with OR logic' do
149
- criteria = Feed::Item.where(
150
- '$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) }]
151
- ).asc(:a_time)
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
- expect(records.size).to eq 1
195
- expect(records.map(&:name)).to eq ['embedded']
196
- end
197
- end
198
- context 'with overlapping data', if: MongoDB.mmapv1? do
199
- before :each do
200
- 3.times { Feed::Item.create! a_integer: 5 }
201
- Feed::Item.first.update_attributes!(name: Array(1000).join('a'))
202
- end
203
- it 'natural order is different from order by id' do
204
- # natural order isn't necessarily going to be the same as _id order
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: field_type, direction: 1
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.to_s }
23
+ its(:value) { should eq feed_item.id }
25
24
  its(:tiebreak_id) { should eq feed_item.id }
26
25
  its(:criteria) do
27
- if Mongoid::Compatibility::Version.mongoid3?
28
- should eq('$or' => [
29
- { '_id' => { '$gt' => Moped::BSON::ObjectId(feed_item.id.to_s) } }
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
@@ -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.mongoid6? || Mongoid::Compatibility::Version.mongoid7?
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,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-scroll
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.7
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Doubrovkine
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-06-01 00:00:00.000000000 Z
12
+ date: 2023-03-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mongoid
@@ -59,11 +59,12 @@ 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/scroll_cursor_spec.rb
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
@@ -118,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
125
  - !ruby/object:Gem::Version
119
126
  version: 1.3.6
120
127
  requirements: []
121
- rubygems_version: 3.1.3
128
+ rubygems_version: 3.2.32
122
129
  signing_key:
123
130
  specification_version: 4
124
131
  summary: Mongoid extensions to enable infinite scroll.
data/.travis.yml DELETED
@@ -1,37 +0,0 @@
1
- services:
2
- - mongodb
3
-
4
- language: ruby
5
-
6
- cache: bundler
7
-
8
- before_install:
9
- - gem update --system
10
- - gem install bundler
11
-
12
- matrix:
13
- include:
14
- - rvm: 2.3.1
15
- env: MONGOID_VERSION=3
16
- - rvm: 2.3.1
17
- env: MONGOID_VERSION=4
18
- - rvm: 2.3.1
19
- env: MONGOID_VERSION=5
20
- - rvm: 2.3.1
21
- env: MONGOID_VERSION=6
22
- - rvm: 2.3.1
23
- env: MONGOID_VERSION=7
24
- - rvm: 2.3.1
25
- env: MONGOID_VERSION=HEAD
26
- - rvm: 2.3.1
27
- script:
28
- - bundle exec danger
29
-
30
- bundler_args: --without development
31
-
32
- addons:
33
- apt:
34
- sources:
35
- - mongodb-3.4-precise
36
- packages:
37
- - mongodb-org-server