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.
Files changed (38) hide show
  1. checksums.yaml +5 -5
  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 +14 -0
  6. data/Gemfile +10 -16
  7. data/LICENSE.md +1 -1
  8. data/README.md +59 -46
  9. data/RELEASING.md +4 -4
  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/spec_helper.rb +1 -1
  33. data/spec/support/feed/item.rb +1 -1
  34. metadata +19 -13
  35. data/.travis.yml +0 -35
  36. data/examples/moped_scroll_feed.rb +0 -45
  37. data/lib/moped/scrollable.rb +0 -38
  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
- 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
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.mongoid5? || Mongoid::Compatibility::Version.mongoid6?
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
@@ -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,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-scroll
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.6
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: 2018-05-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
@@ -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/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
@@ -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
- rubyforge_project:
122
- rubygems_version: 2.6.12
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: []