mongoid-scroll 0.3.7 → 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 (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,45 +0,0 @@
1
- require 'bundler'
2
- Bundler.setup(:default, :development)
3
-
4
- require 'mongoid-scroll'
5
- require 'faker'
6
-
7
- Mongoid.connect_to 'mongoid_scroll_demo'
8
- Mongoid.purge!
9
-
10
- raise 'No Moped' unless Object.const_defined?(:Moped)
11
-
12
- # total items to insert
13
- total_items = 20
14
- # a MongoDB query will be executed every scroll_by items
15
- scroll_by = 7
16
-
17
- # insert items with a position out-of-order
18
- rands = (0..total_items).to_a.sort { rand }[0..total_items]
19
- total_items.times do
20
- Mongoid.default_session['feed_items'].insert(title: Faker::Lorem.sentence, position: rands.pop)
21
- end
22
-
23
- Mongoid.default_session['feed_items'].indexes.create(position: 1, _id: 1)
24
-
25
- Moped.logger = Logger.new($stdout)
26
- Moped.logger.level = Logger::DEBUG
27
-
28
- total_shown = 0
29
- next_cursor = nil
30
- loop do
31
- current_cursor = next_cursor
32
- next_cursor = nil
33
- Mongoid.default_session['feed_items'].find.limit(scroll_by).sort(position: 1).scroll(current_cursor, field_type: Integer, field_name: 'position') do |item, cursor|
34
- puts "#{item['position']}: #{item['title']}"
35
- next_cursor = cursor
36
- total_shown += 1
37
- end
38
- break unless next_cursor
39
- # destroy an item just for the heck of it, scroll is not affected
40
- item = Mongoid.default_session['feed_items'].find.sort(position: 1).first
41
- Mongoid.default_session['feed_items'].find(_id: item['_id']).remove
42
- end
43
-
44
- # this will be 20
45
- puts "Shown #{total_shown} items."
@@ -1,38 +0,0 @@
1
- module Moped
2
- module Scrollable
3
- def scroll(cursor = nil, options = nil, &_block)
4
- unless options
5
- bson_type = Mongoid::Compatibility::Version.mongoid3? ? Moped::BSON::ObjectId : BSON::ObjectId
6
- options = { field_type: bson_type }
7
- end
8
- query = Query.new(collection, operation.selector.dup)
9
- query.operation.skip = operation.skip
10
- query.operation.limit = operation.limit
11
- # we don't support scrolling over a criteria with multiple fields
12
- if query.operation.selector['$orderby'] && query.operation.selector['$orderby'].keys.size != 1
13
- raise Mongoid::Scroll::Errors::MultipleSortFieldsError.new(sort: query.operation.selector['$orderby'])
14
- elsif !query.operation.selector.key?('$orderby') || query.operation.selector['$orderby'].empty?
15
- # introduce a default sort order if there's none
16
- query.sort(_id: 1)
17
- end
18
- # scroll field and direction
19
- scroll_field = query.operation.selector['$orderby'].keys.first
20
- scroll_direction = query.operation.selector['$orderby'].values.first.to_i
21
- # scroll cursor from the parameter, with value and tiebreak_id
22
- cursor_options = { field_name: scroll_field, field_type: options[:field_type], direction: scroll_direction }
23
- cursor = cursor.is_a?(Mongoid::Scroll::Cursor) ? cursor : Mongoid::Scroll::Cursor.new(cursor, cursor_options)
24
- query.operation.selector['$query'] = query.operation.selector['$query'].merge(cursor.criteria)
25
- query.operation.selector['$orderby'] = query.operation.selector['$orderby'].merge(_id: scroll_direction)
26
- # scroll
27
- if block_given?
28
- query.each do |record|
29
- yield record, Mongoid::Scroll::Cursor.from_record(record, cursor_options)
30
- end
31
- else
32
- query
33
- end
34
- end
35
- end
36
- end
37
-
38
- Moped::Query.send(:include, Moped::Scrollable)
@@ -1,126 +0,0 @@
1
- require 'spec_helper'
2
-
3
- if Object.const_defined?(:Moped)
4
- describe Moped::Query do
5
- context 'scrollable' do
6
- subject do
7
- Mongoid.default_session['feed_items'].find
8
- end
9
- it ':scroll' do
10
- expect(subject).to respond_to(:scroll)
11
- end
12
- end
13
- context 'with multiple sort fields' do
14
- subject do
15
- Mongoid.default_session['feed_items'].find.sort(name: 1, value: -1)
16
- end
17
- it 'raises Mongoid::Scroll::Errors::MultipleSortFieldsError' do
18
- expect { subject.scroll }.to raise_error Mongoid::Scroll::Errors::MultipleSortFieldsError,
19
- /You're attempting to scroll over data with a sort order that includes multiple fields: name, value./
20
- end
21
- end
22
- context 'with no sort' do
23
- subject do
24
- Mongoid.default_session['feed_items'].find
25
- end
26
- it 'adds a default sort by _id' do
27
- expect(subject.scroll.operation.selector['$orderby']).to eq(_id: 1)
28
- end
29
- end
30
- context 'with data' do
31
- before :each do
32
- 10.times do |i|
33
- Mongoid.default_session['feed_items'].insert(
34
- a_string: i.to_s,
35
- a_integer: i,
36
- a_datetime: DateTime.mongoize(DateTime.new(2013, i + 1, 21, 1, 42, 3, 'UTC')),
37
- a_date: Date.mongoize(Date.new(2013, i + 1, 21)),
38
- a_time: Time.mongoize(Time.at(Time.now.to_i + i))
39
- )
40
- end
41
- end
42
- context 'default' do
43
- it 'scrolls all' do
44
- records = []
45
- Mongoid.default_session['feed_items'].find.scroll do |record, _next_cursor|
46
- records << record
47
- end
48
- expect(records.size).to eq 10
49
- expect(records).to eq Mongoid.default_session['feed_items'].find.to_a
50
- end
51
- end
52
- { a_string: String, a_integer: Integer, a_date: Date, a_datetime: DateTime }.each_pair do |field_name, field_type|
53
- context field_type do
54
- it 'scrolls all with a block' do
55
- records = []
56
- Mongoid.default_session['feed_items'].find.sort(field_name => 1).scroll(nil, field_type: field_type) do |record, _next_cursor|
57
- records << record
58
- end
59
- expect(records.size).to eq 10
60
- expect(records).to eq Mongoid.default_session['feed_items'].find.to_a
61
- end
62
- it 'scrolls all with a break' do
63
- records = []
64
- cursor = nil
65
- Mongoid.default_session['feed_items'].find.sort(field_name => 1).limit(5).scroll(nil, field_type: field_type) do |record, next_cursor|
66
- records << record
67
- cursor = next_cursor
68
- end
69
- expect(records.size).to eq 5
70
- Mongoid.default_session['feed_items'].find.sort(field_name => 1).scroll(cursor, field_type: field_type) do |record, next_cursor|
71
- records << record
72
- cursor = next_cursor
73
- end
74
- expect(records.size).to eq 10
75
- expect(records).to eq Mongoid.default_session['feed_items'].find.to_a
76
- end
77
- it 'scrolls in descending order' do
78
- records = []
79
- Mongoid.default_session['feed_items'].find.sort(field_name => -1).limit(3).scroll(nil, field_type: field_type, field_name: field_name) do |record, _next_cursor|
80
- records << record
81
- end
82
- expect(records.size).to eq 3
83
- expect(records).to eq Mongoid.default_session['feed_items'].find.sort(field_name => -1).limit(3).to_a
84
- end
85
- it 'map' do
86
- record = Mongoid.default_session['feed_items'].find.limit(3).scroll(nil, field_type: field_type, field_name: field_name).map { |r| r }.last
87
- cursor = Mongoid::Scroll::Cursor.from_record(record, field_type: field_type, field_name: field_name)
88
- expect(cursor).to_not be nil
89
- expect(cursor.to_s.split(':')).to eq [
90
- Mongoid::Scroll::Cursor.transform_field_value(field_type, field_name, record[field_name.to_s]).to_s,
91
- record['_id'].to_s
92
- ]
93
- end
94
- end
95
- end
96
- end
97
- context 'with overlapping data', if: MongoDB.mmapv1? do
98
- before :each do
99
- 3.times { Feed::Item.create! a_integer: 5 }
100
- Feed::Item.first.update_attributes!(name: Array(1000).join('a'))
101
- end
102
- it 'natural order is different from order by id' do
103
- # natural order isn't necessarily going to be the same as _id order
104
- # if a document is updated and grows in size, it may need to be relocated and
105
- # thus cause the natural order to change
106
- expect(Feed::Item.order_by('$natural' => 1).to_a).to_not eq Feed::Item.order_by(_id: 1).to_a
107
- end
108
- [{ a_integer: 1 }, { a_integer: -1 }].each do |sort_order|
109
- it "scrolls by #{sort_order}" do
110
- records = []
111
- cursor = nil
112
- Mongoid.default_session['feed_items'].find.sort(sort_order).limit(2).scroll do |record, next_cursor|
113
- records << record
114
- cursor = next_cursor
115
- end
116
- expect(records.size).to eq 2
117
- Mongoid.default_session['feed_items'].find.sort(sort_order).scroll(cursor) do |record, _next_cursor|
118
- records << record
119
- end
120
- expect(records.size).to eq 3
121
- expect(records).to eq Mongoid.default_session['feed_items'].find.sort(sort_order.merge(_id: sort_order[:a_integer])).to_a
122
- end
123
- end
124
- end
125
- end
126
- end