mongoid-scroll 0.3.2 → 0.3.7
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/.rubocop.yml +0 -2
- data/.rubocop_todo.yml +38 -17
- data/.travis.yml +31 -12
- data/CHANGELOG.md +32 -16
- data/Dangerfile +1 -0
- data/Gemfile +13 -10
- data/LICENSE.md +1 -1
- data/README.md +31 -11
- data/RELEASING.md +67 -0
- data/Rakefile +1 -1
- data/examples/mongo_ruby_driver_scroll_feed.rb +45 -0
- data/examples/mongoid_scroll_feed.rb +8 -3
- data/examples/moped_scroll_feed.rb +2 -0
- data/lib/config/locales/en.yml +1 -1
- data/lib/mongo/scrollable.rb +34 -0
- data/lib/mongoid-scroll.rb +3 -6
- data/lib/mongoid/criteria/scrollable.rb +81 -0
- data/lib/mongoid/scroll/cursor.rb +15 -11
- data/lib/mongoid/scroll/errors/base.rb +1 -1
- data/lib/mongoid/scroll/version.rb +1 -1
- data/lib/moped/scrollable.rb +7 -6
- data/mongoid-scroll.gemspec +2 -1
- data/spec/mongo/collection_view_spec.rb +126 -0
- data/spec/mongoid/criteria_spec.rb +39 -4
- data/spec/mongoid/scroll_cursor_spec.rb +25 -25
- data/spec/moped/query_spec.rb +100 -98
- data/spec/spec_helper.rb +6 -1
- data/spec/support/feed/item.rb +5 -1
- data/spec/support/feed/publisher.rb +9 -0
- data/spec/support/mongodb.rb +9 -0
- metadata +30 -11
- data/lib/mongoid/criterion/scrollable.rb +0 -33
- data/lib/mongoid/scroll/mongoid.rb +0 -7
|
@@ -4,6 +4,14 @@ Bundler.setup(:default, :development)
|
|
|
4
4
|
require 'mongoid-scroll'
|
|
5
5
|
require 'faker'
|
|
6
6
|
|
|
7
|
+
if defined?(Moped)
|
|
8
|
+
Moped.logger = Logger.new($stdout)
|
|
9
|
+
Moped.logger.level = Logger::DEBUG
|
|
10
|
+
else
|
|
11
|
+
Mongoid.logger.level = Logger::INFO
|
|
12
|
+
Mongo::Logger.logger.level = Logger::INFO if Mongoid::Compatibility::Version.mongoid5?
|
|
13
|
+
end
|
|
14
|
+
|
|
7
15
|
Mongoid.connect_to 'mongoid_scroll_demo'
|
|
8
16
|
Mongoid.purge!
|
|
9
17
|
|
|
@@ -27,9 +35,6 @@ total_items.times do |_i|
|
|
|
27
35
|
Feed::Item.create! title: Faker::Lorem.sentence, position: rands.pop
|
|
28
36
|
end
|
|
29
37
|
|
|
30
|
-
Moped.logger = Logger.new($stdout)
|
|
31
|
-
Moped.logger.level = Logger::DEBUG
|
|
32
|
-
|
|
33
38
|
Feed::Item.create_indexes
|
|
34
39
|
|
|
35
40
|
total_shown = 0
|
data/lib/config/locales/en.yml
CHANGED
|
@@ -18,5 +18,5 @@ en:
|
|
|
18
18
|
unsupported_field_type:
|
|
19
19
|
message: "Unsupported field type."
|
|
20
20
|
summary: "The type of the field '%{field}' is not supported: %{type}."
|
|
21
|
-
resolution: "Please open a feature request in https://github.com/
|
|
21
|
+
resolution: "Please open a feature request in https://github.com/mongoid/mongoid-scroll."
|
|
22
22
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Mongo
|
|
2
|
+
module Scrollable
|
|
3
|
+
def scroll(cursor = nil, options = nil, &_block)
|
|
4
|
+
view = self
|
|
5
|
+
# we don't support scrolling over a view with multiple fields
|
|
6
|
+
raise Mongoid::Scroll::Errors::MultipleSortFieldsError.new(sort: view.sort) if view.sort && view.sort.keys.size != 1
|
|
7
|
+
# scroll field and direction
|
|
8
|
+
scroll_field = view.sort ? view.sort.keys.first : :_id
|
|
9
|
+
scroll_direction = view.sort ? view.sort.values.first.to_i : 1
|
|
10
|
+
# scroll cursor from the parameter, with value and tiebreak_id
|
|
11
|
+
options = { field_type: BSON::ObjectId } unless options
|
|
12
|
+
cursor_options = { field_name: scroll_field, direction: scroll_direction }.merge(options)
|
|
13
|
+
cursor = cursor.is_a?(Mongoid::Scroll::Cursor) ? cursor : Mongoid::Scroll::Cursor.new(cursor, cursor_options)
|
|
14
|
+
# make a view
|
|
15
|
+
view = Mongo::Collection::View.new(
|
|
16
|
+
view.collection,
|
|
17
|
+
view.selector.merge(cursor.criteria),
|
|
18
|
+
sort: (view.sort || {}).merge(_id: scroll_direction),
|
|
19
|
+
skip: skip,
|
|
20
|
+
limit: limit
|
|
21
|
+
)
|
|
22
|
+
# scroll
|
|
23
|
+
if block_given?
|
|
24
|
+
view.each do |record|
|
|
25
|
+
yield record, Mongoid::Scroll::Cursor.from_record(record, cursor_options)
|
|
26
|
+
end
|
|
27
|
+
else
|
|
28
|
+
view
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
Mongo::Collection::View.send(:include, Mongo::Scrollable)
|
data/lib/mongoid-scroll.rb
CHANGED
|
@@ -3,13 +3,10 @@ require 'i18n'
|
|
|
3
3
|
I18n.load_path << File.join(File.dirname(__FILE__), 'config', 'locales', 'en.yml')
|
|
4
4
|
|
|
5
5
|
require 'mongoid'
|
|
6
|
+
require 'mongoid-compatibility'
|
|
6
7
|
require 'mongoid/scroll/version'
|
|
7
|
-
require 'mongoid/scroll/mongoid'
|
|
8
8
|
require 'mongoid/scroll/errors'
|
|
9
9
|
require 'mongoid/scroll/cursor'
|
|
10
|
-
|
|
11
10
|
require 'moped/scrollable' if Object.const_defined?(:Moped)
|
|
12
|
-
require '
|
|
13
|
-
|
|
14
|
-
Moped::Query.send(:include, Moped::Scrollable) if Object.const_defined?(:Moped)
|
|
15
|
-
Mongoid::Criteria.send(:include, Mongoid::Criterion::Scrollable)
|
|
11
|
+
require 'mongo/scrollable' if Object.const_defined?(:Mongo)
|
|
12
|
+
require 'mongoid/criteria/scrollable'
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
module Mongoid
|
|
2
|
+
class Criteria
|
|
3
|
+
module Scrollable
|
|
4
|
+
def scroll(cursor = nil, &_block)
|
|
5
|
+
raise_multiple_sort_fields_error if multiple_sort_fields?
|
|
6
|
+
criteria = dup
|
|
7
|
+
criteria.merge!(default_sort) if no_sort_option?
|
|
8
|
+
cursor_options = build_cursor_options(criteria)
|
|
9
|
+
cursor = cursor.is_a?(Mongoid::Scroll::Cursor) ? cursor : new_cursor(cursor, cursor_options)
|
|
10
|
+
cursor_criteria = build_cursor_criteria(criteria, cursor)
|
|
11
|
+
if block_given?
|
|
12
|
+
cursor_criteria.order_by(_id: scroll_direction(criteria)).each do |record|
|
|
13
|
+
yield record, cursor_from_record(record, cursor_options)
|
|
14
|
+
end
|
|
15
|
+
else
|
|
16
|
+
cursor_criteria
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def raise_multiple_sort_fields_error
|
|
23
|
+
raise Mongoid::Scroll::Errors::MultipleSortFieldsError.new(sort: criteria.options.sort)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def multiple_sort_fields?
|
|
27
|
+
options.sort && options.sort.keys.size != 1
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def no_sort_option?
|
|
31
|
+
options.sort.blank? || options.sort.empty?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def default_sort
|
|
35
|
+
asc(:_id)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def scroll_field(criteria)
|
|
39
|
+
criteria.options.sort.keys.first
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def scroll_direction(criteria)
|
|
43
|
+
criteria.options.sort.values.first.to_i
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def build_cursor_options(criteria)
|
|
47
|
+
{
|
|
48
|
+
field_type: scroll_field_type(criteria),
|
|
49
|
+
field_name: scroll_field(criteria),
|
|
50
|
+
direction: scroll_direction(criteria)
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def new_cursor(cursor, cursor_options)
|
|
55
|
+
Mongoid::Scroll::Cursor.new(cursor, cursor_options)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def build_cursor_criteria(criteria, cursor)
|
|
59
|
+
cursor_criteria = criteria.dup
|
|
60
|
+
cursor_criteria.selector = { '$and' => [criteria.selector, cursor.criteria] }
|
|
61
|
+
cursor_criteria
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def cursor_from_record(record, cursor_options)
|
|
65
|
+
Mongoid::Scroll::Cursor.from_record(record, cursor_options)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def scroll_field_type(criteria)
|
|
69
|
+
scroll_field = scroll_field(criteria)
|
|
70
|
+
field = criteria.klass.fields[scroll_field.to_s]
|
|
71
|
+
field.foreign_key? && field.object_id_field? ? bson_type : field.type
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def bson_type
|
|
75
|
+
Mongoid::Compatibility::Version.mongoid3? ? Moped::BSON::ObjectId : BSON::ObjectId
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
Mongoid::Criteria.send(:include, Mongoid::Criteria::Scrollable)
|
|
@@ -14,8 +14,12 @@ module Mongoid
|
|
|
14
14
|
compare_direction = direction == 1 ? '$gt' : '$lt'
|
|
15
15
|
cursor_criteria = { field_name => { compare_direction => mongo_value } } if mongo_value
|
|
16
16
|
tiebreak_criteria = { field_name => mongo_value, :_id => { compare_direction => tiebreak_id } } if mongo_value && tiebreak_id
|
|
17
|
-
cursor_selector =
|
|
18
|
-
|
|
17
|
+
cursor_selector = if Mongoid::Compatibility::Version.mongoid6? || Mongoid::Compatibility::Version.mongoid7?
|
|
18
|
+
Mongoid::Criteria::Queryable::Selector.new
|
|
19
|
+
else
|
|
20
|
+
Origin::Selector.new
|
|
21
|
+
end
|
|
22
|
+
cursor_selector['$or'] = [cursor_criteria, tiebreak_criteria].compact if cursor_criteria || tiebreak_criteria
|
|
19
23
|
cursor_selector.__evolve_object_id__
|
|
20
24
|
end
|
|
21
25
|
|
|
@@ -39,16 +43,16 @@ module Mongoid
|
|
|
39
43
|
return unless value
|
|
40
44
|
parts = value.split(':')
|
|
41
45
|
unless parts.length >= 2
|
|
42
|
-
|
|
46
|
+
raise Mongoid::Scroll::Errors::InvalidCursorError.new(cursor: value)
|
|
43
47
|
end
|
|
44
48
|
id = parts[-1]
|
|
45
49
|
value = parts[0...-1].join(':')
|
|
46
50
|
@value = Mongoid::Scroll::Cursor.parse_field_value(field_type, field_name, value)
|
|
47
|
-
if Mongoid::
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
@tiebreak_id = if Mongoid::Compatibility::Version.mongoid3?
|
|
52
|
+
Moped::BSON::ObjectId(id)
|
|
53
|
+
else
|
|
54
|
+
BSON::ObjectId.from_string(id)
|
|
55
|
+
end
|
|
52
56
|
end
|
|
53
57
|
|
|
54
58
|
class << self
|
|
@@ -58,7 +62,7 @@ module Mongoid
|
|
|
58
62
|
elsif options && (field = options[:field])
|
|
59
63
|
[field.type.to_s, field.name.to_s]
|
|
60
64
|
else
|
|
61
|
-
|
|
65
|
+
raise ArgumentError.new 'Missing options[:field_name] and/or options[:field_type].'
|
|
62
66
|
end
|
|
63
67
|
end
|
|
64
68
|
|
|
@@ -72,7 +76,7 @@ module Mongoid
|
|
|
72
76
|
when 'Float' then value.to_f
|
|
73
77
|
when 'Integer' then value.to_i
|
|
74
78
|
else
|
|
75
|
-
|
|
79
|
+
raise Mongoid::Scroll::Errors::UnsupportedFieldTypeError.new(field: field_name, type: field_type)
|
|
76
80
|
end
|
|
77
81
|
end
|
|
78
82
|
|
|
@@ -85,7 +89,7 @@ module Mongoid
|
|
|
85
89
|
when 'Float' then value.to_f
|
|
86
90
|
when 'Integer' then value.to_i
|
|
87
91
|
else
|
|
88
|
-
|
|
92
|
+
raise Mongoid::Scroll::Errors::UnsupportedFieldTypeError.new(field: field_name, type: field_type)
|
|
89
93
|
end
|
|
90
94
|
end
|
|
91
95
|
end
|
data/lib/moped/scrollable.rb
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
module Moped
|
|
2
2
|
module Scrollable
|
|
3
3
|
def scroll(cursor = nil, options = nil, &_block)
|
|
4
|
-
options
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
end unless options
|
|
4
|
+
unless options
|
|
5
|
+
bson_type = Mongoid::Compatibility::Version.mongoid3? ? Moped::BSON::ObjectId : BSON::ObjectId
|
|
6
|
+
options = { field_type: bson_type }
|
|
7
|
+
end
|
|
9
8
|
query = Query.new(collection, operation.selector.dup)
|
|
10
9
|
query.operation.skip = operation.skip
|
|
11
10
|
query.operation.limit = operation.limit
|
|
12
11
|
# we don't support scrolling over a criteria with multiple fields
|
|
13
12
|
if query.operation.selector['$orderby'] && query.operation.selector['$orderby'].keys.size != 1
|
|
14
|
-
|
|
13
|
+
raise Mongoid::Scroll::Errors::MultipleSortFieldsError.new(sort: query.operation.selector['$orderby'])
|
|
15
14
|
elsif !query.operation.selector.key?('$orderby') || query.operation.selector['$orderby'].empty?
|
|
16
15
|
# introduce a default sort order if there's none
|
|
17
16
|
query.sort(_id: 1)
|
|
@@ -35,3 +34,5 @@ module Moped
|
|
|
35
34
|
end
|
|
36
35
|
end
|
|
37
36
|
end
|
|
37
|
+
|
|
38
|
+
Moped::Query.send(:include, Moped::Scrollable)
|
data/mongoid-scroll.gemspec
CHANGED
|
@@ -10,9 +10,10 @@ Gem::Specification.new do |s|
|
|
|
10
10
|
s.required_rubygems_version = '>= 1.3.6'
|
|
11
11
|
s.files = `git ls-files`.split("\n")
|
|
12
12
|
s.require_paths = ['lib']
|
|
13
|
-
s.homepage = 'http://github.com/
|
|
13
|
+
s.homepage = 'http://github.com/mongoid/mongoid-scroll'
|
|
14
14
|
s.licenses = ['MIT']
|
|
15
15
|
s.summary = 'Mongoid extensions to enable infinite scroll.'
|
|
16
16
|
s.add_dependency 'mongoid', '>= 3.0'
|
|
17
|
+
s.add_dependency 'mongoid-compatibility'
|
|
17
18
|
s.add_dependency 'i18n'
|
|
18
19
|
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
if Object.const_defined?(:Mongo)
|
|
4
|
+
describe Mongo::Collection::View do
|
|
5
|
+
context 'scrollable' do
|
|
6
|
+
subject do
|
|
7
|
+
Mongoid.default_client['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_client['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_client['feed_items'].find
|
|
25
|
+
end
|
|
26
|
+
it 'adds a default sort by _id' do
|
|
27
|
+
expect(subject.scroll.sort).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_client['feed_items'].insert_one(
|
|
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_client['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_client['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_client['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_client['feed_items'].find.to_a
|
|
61
|
+
end
|
|
62
|
+
it 'scrolls all with a break' do
|
|
63
|
+
records = []
|
|
64
|
+
cursor = nil
|
|
65
|
+
Mongoid.default_client['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_client['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_client['feed_items'].find.to_a
|
|
76
|
+
end
|
|
77
|
+
it 'scrolls in descending order' do
|
|
78
|
+
records = []
|
|
79
|
+
Mongoid.default_client['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_client['feed_items'].find.sort(field_name => -1).limit(3).to_a
|
|
84
|
+
end
|
|
85
|
+
it 'map' do
|
|
86
|
+
record = Mongoid.default_client['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_client['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_client['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_client['feed_items'].find.sort(sort_order.merge(_id: sort_order[:a_integer])).to_a
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -13,6 +13,7 @@ describe Mongoid::Criteria do
|
|
|
13
13
|
/You're attempting to scroll over data with a sort order that includes multiple fields: name, value./
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
|
+
|
|
16
17
|
context 'with no sort' do
|
|
17
18
|
subject do
|
|
18
19
|
Feed::Item.all
|
|
@@ -42,7 +43,30 @@ describe Mongoid::Criteria do
|
|
|
42
43
|
expect(records.size).to eq 10
|
|
43
44
|
expect(records).to eq Feed::Item.all.to_a
|
|
44
45
|
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
|
|
59
|
+
end
|
|
45
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
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
46
70
|
{ a_string: String, a_integer: Integer, a_date: Date, a_datetime: DateTime }.each_pair do |field_name, field_type|
|
|
47
71
|
context field_type do
|
|
48
72
|
it 'scrolls all with a block' do
|
|
@@ -68,6 +92,17 @@ describe Mongoid::Criteria do
|
|
|
68
92
|
expect(records.size).to eq 10
|
|
69
93
|
expect(records).to eq Feed::Item.all.to_a
|
|
70
94
|
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
|
|
105
|
+
end
|
|
71
106
|
it 'scrolls in descending order' do
|
|
72
107
|
records = []
|
|
73
108
|
Feed::Item.desc(field_name).limit(3).scroll do |record, _next_cursor|
|
|
@@ -132,9 +167,9 @@ describe Mongoid::Criteria do
|
|
|
132
167
|
end
|
|
133
168
|
it 'merges cursor criteria when no sort field is given' do
|
|
134
169
|
criteria = Feed::Item.where(:a_time.gt => Time.new(2013, 7, 22, 1, 2, 3))
|
|
135
|
-
|
|
136
|
-
cursor_input = "#{
|
|
137
|
-
field_type = Mongoid::
|
|
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
|
|
138
173
|
cursor_options = { field_type: field_type, field_name: '_id', direction: 1 }
|
|
139
174
|
cursor = Mongoid::Scroll::Cursor.new(cursor_input, cursor_options)
|
|
140
175
|
records = []
|
|
@@ -160,7 +195,7 @@ describe Mongoid::Criteria do
|
|
|
160
195
|
expect(records.map(&:name)).to eq ['embedded']
|
|
161
196
|
end
|
|
162
197
|
end
|
|
163
|
-
context 'with overlapping data' do
|
|
198
|
+
context 'with overlapping data', if: MongoDB.mmapv1? do
|
|
164
199
|
before :each do
|
|
165
200
|
3.times { Feed::Item.create! a_integer: 5 }
|
|
166
201
|
Feed::Item.first.update_attributes!(name: Array(1000).join('a'))
|