mongoid-scroll 1.0.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +20 -2
- data/.gitignore +1 -0
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +153 -35
- data/CHANGELOG.md +15 -5
- data/Gemfile +4 -4
- data/README.md +24 -36
- data/RELEASING.md +1 -4
- data/Rakefile +3 -3
- data/UPGRADING.md +21 -1
- data/examples/{mongoid_scroll_feed.rb → feed.rb} +3 -3
- data/lib/config/locales/en.yml +4 -1
- data/lib/mongoid/criteria/scrollable/iterator.rb +19 -0
- data/lib/mongoid/criteria/scrollable.rb +28 -8
- data/lib/mongoid/scroll/base64_encoded_cursor.rb +8 -6
- data/lib/mongoid/scroll/base_cursor.rb +12 -11
- data/lib/mongoid/scroll/cursor.rb +5 -5
- data/lib/mongoid/scroll/errors/base.rb +4 -4
- data/lib/mongoid/scroll/errors/mismatched_sort_fields_error.rb +1 -3
- data/lib/mongoid/scroll/errors/multiple_sort_fields_error.rb +1 -3
- data/lib/mongoid/scroll/errors/unsupported_type_error.rb +11 -0
- data/lib/mongoid/scroll/errors.rb +1 -0
- data/lib/mongoid/scroll/version.rb +1 -1
- data/lib/mongoid-scroll.rb +1 -2
- data/mongoid-scroll.gemspec +3 -3
- data/spec/mongoid/base64_encoded_cursor_spec.rb +148 -77
- data/spec/mongoid/criteria_spec.rb +108 -37
- data/spec/mongoid/cursor_spec.rb +112 -63
- data/spec/mongoid/scroll_spec.rb +1 -1
- data/spec/spec_helper.rb +9 -2
- data/spec/support/feed/embedded_item.rb +2 -0
- data/spec/support/feed/item.rb +1 -1
- metadata +12 -26
- data/examples/mongo_ruby_driver_scroll_feed.rb +0 -45
- data/lib/mongo/scrollable.rb +0 -39
- data/spec/mongo/collection_view_spec.rb +0 -143
@@ -10,15 +10,24 @@ module Mongoid
|
|
10
10
|
criteria = dup
|
11
11
|
criteria.merge!(default_sort) if no_sort_option?
|
12
12
|
cursor_options = build_cursor_options(criteria)
|
13
|
-
cursor =
|
13
|
+
cursor = new_cursor(cursor_type, cursor, cursor_options) unless cursor.is_a?(cursor_type)
|
14
14
|
raise_mismatched_sort_fields_error!(cursor, cursor_options) if different_sort_fields?(cursor, cursor_options)
|
15
|
-
|
15
|
+
records = find_records(criteria, cursor)
|
16
16
|
if block_given?
|
17
|
-
|
18
|
-
|
17
|
+
previous_cursor = nil
|
18
|
+
current_cursor = nil
|
19
|
+
records.each do |record|
|
20
|
+
previous_cursor ||= cursor_from_record(cursor_type, record, cursor_options.merge(type: :previous))
|
21
|
+
current_cursor ||= cursor_from_record(cursor_type, record, cursor_options.merge(include_current: true))
|
22
|
+
iterator = Mongoid::Criteria::Scrollable::Iterator.new(
|
23
|
+
previous_cursor: previous_cursor,
|
24
|
+
next_cursor: cursor_from_record(cursor_type, record, cursor_options),
|
25
|
+
current_cursor: current_cursor
|
26
|
+
)
|
27
|
+
yield record, iterator
|
19
28
|
end
|
20
29
|
else
|
21
|
-
|
30
|
+
records
|
22
31
|
end
|
23
32
|
end
|
24
33
|
|
@@ -60,10 +69,21 @@ module Mongoid
|
|
60
69
|
cursor_type.new(cursor, cursor_options)
|
61
70
|
end
|
62
71
|
|
63
|
-
def
|
72
|
+
def find_records(criteria, cursor)
|
64
73
|
cursor_criteria = criteria.dup
|
65
74
|
cursor_criteria.selector = { '$and' => [criteria.selector, cursor.criteria] }
|
66
|
-
|
75
|
+
if cursor.type == :previous
|
76
|
+
pipeline = [
|
77
|
+
{ '$match' => cursor_criteria.selector },
|
78
|
+
{ '$sort' => { cursor.field_name => -cursor.direction } },
|
79
|
+
{ '$limit' => criteria.options[:limit] },
|
80
|
+
{ '$sort' => { cursor.field_name => cursor.direction } }
|
81
|
+
]
|
82
|
+
aggregation = cursor_criteria.view.aggregate(pipeline)
|
83
|
+
aggregation.map { |record| Mongoid::Factory.from_db(cursor_criteria.klass, record) }
|
84
|
+
else
|
85
|
+
cursor_criteria.order_by(_id: scroll_direction(criteria))
|
86
|
+
end
|
67
87
|
end
|
68
88
|
|
69
89
|
def cursor_from_record(cursor_type, record, cursor_options)
|
@@ -79,4 +99,4 @@ module Mongoid
|
|
79
99
|
end
|
80
100
|
end
|
81
101
|
|
82
|
-
Mongoid::Criteria.
|
102
|
+
Mongoid::Criteria.include Mongoid::Criteria::Scrollable
|
@@ -10,18 +10,19 @@ module Mongoid
|
|
10
10
|
if value
|
11
11
|
begin
|
12
12
|
parsed = ::JSON.parse(::Base64.strict_decode64(value))
|
13
|
-
rescue
|
13
|
+
rescue StandardError
|
14
14
|
raise Mongoid::Scroll::Errors::InvalidBase64CursorError.new(cursor: value)
|
15
15
|
end
|
16
|
-
super
|
16
|
+
super(parse_field_value(parsed['field_type'], parsed['field_name'], parsed['value']), {
|
17
17
|
field_type: parsed['field_type'],
|
18
18
|
field_name: parsed['field_name'],
|
19
19
|
direction: parsed['direction'],
|
20
20
|
include_current: parsed['include_current'],
|
21
|
-
tiebreak_id: parsed['tiebreak_id'] && !parsed['tiebreak_id'].empty? ? BSON::ObjectId.from_string(parsed['tiebreak_id']) : nil
|
22
|
-
|
21
|
+
tiebreak_id: parsed['tiebreak_id'] && !parsed['tiebreak_id'].empty? ? BSON::ObjectId.from_string(parsed['tiebreak_id']) : nil,
|
22
|
+
type: parsed['type'].try(:to_sym)
|
23
|
+
})
|
23
24
|
else
|
24
|
-
super
|
25
|
+
super(nil, options)
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
@@ -32,7 +33,8 @@ module Mongoid
|
|
32
33
|
field_name: field_name,
|
33
34
|
direction: direction,
|
34
35
|
include_current: include_current,
|
35
|
-
tiebreak_id: tiebreak_id && tiebreak_id.to_s
|
36
|
+
tiebreak_id: tiebreak_id && tiebreak_id.to_s,
|
37
|
+
type: type
|
36
38
|
}.to_json)
|
37
39
|
end
|
38
40
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Mongoid
|
2
2
|
module Scroll
|
3
3
|
class BaseCursor
|
4
|
-
attr_accessor :value, :tiebreak_id, :field_type, :field_name, :direction, :include_current
|
4
|
+
attr_accessor :value, :tiebreak_id, :field_type, :field_name, :direction, :include_current, :type
|
5
5
|
|
6
6
|
def initialize(value, options = {})
|
7
7
|
@value = value
|
@@ -10,17 +10,16 @@ module Mongoid
|
|
10
10
|
@field_name = options[:field_name]
|
11
11
|
@direction = options[:direction] || 1
|
12
12
|
@include_current = options[:include_current] || false
|
13
|
+
@type = options[:type] || :next
|
14
|
+
|
15
|
+
raise Mongoid::Scroll::Errors::UnsupportedTypeError.new(type: @type) unless %i[previous next].include?(@type)
|
13
16
|
end
|
14
17
|
|
15
18
|
def criteria
|
16
19
|
mongo_value = value.class.mongoize(value) if value
|
17
20
|
cursor_criteria = { field_name => { compare_direction => mongo_value } } if mongo_value
|
18
21
|
tiebreak_criteria = { field_name => mongo_value, :_id => { tiebreak_compare_direction => tiebreak_id } } if mongo_value && tiebreak_id
|
19
|
-
cursor_selector =
|
20
|
-
Mongoid::Criteria::Queryable::Selector.new
|
21
|
-
else
|
22
|
-
Origin::Selector.new
|
23
|
-
end
|
22
|
+
cursor_selector = Mongoid::Criteria::Queryable::Selector.new
|
24
23
|
cursor_selector['$or'] = [cursor_criteria, tiebreak_criteria].compact if cursor_criteria || tiebreak_criteria
|
25
24
|
cursor_selector.__evolve_object_id__
|
26
25
|
end
|
@@ -69,8 +68,7 @@ module Mongoid
|
|
69
68
|
return nil unless value
|
70
69
|
|
71
70
|
case field_type.to_s
|
72
|
-
when 'BSON::ObjectId' then value.to_s
|
73
|
-
when 'String' then value.to_s
|
71
|
+
when 'BSON::ObjectId', 'String' then value.to_s
|
74
72
|
when 'Date' then Time.utc(value.year, value.month, value.day).to_i
|
75
73
|
when 'DateTime', 'Time' then value.utc.to_f.round(3)
|
76
74
|
when 'Float' then value.to_f
|
@@ -86,20 +84,23 @@ module Mongoid
|
|
86
84
|
field_type: field_type.to_s,
|
87
85
|
field_name: field_name.to_s,
|
88
86
|
direction: options[:direction] || 1,
|
89
|
-
include_current: options[:include_current] || false
|
87
|
+
include_current: options[:include_current] || false,
|
88
|
+
type: options[:type].try(:to_sym) || :next
|
90
89
|
}
|
91
90
|
elsif options && (field = options[:field])
|
92
91
|
{
|
93
92
|
field_type: field.type.to_s,
|
94
93
|
field_name: field.name.to_s,
|
95
94
|
direction: options[:direction] || 1,
|
96
|
-
include_current: options[:include_current] || false
|
95
|
+
include_current: options[:include_current] || false,
|
96
|
+
type: options[:type].try(:to_sym) || :next
|
97
97
|
}
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
101
|
def compare_direction
|
102
|
-
|
102
|
+
dir = type == :previous ? -direction : direction
|
103
|
+
dir == 1 ? '$gt' : '$lt'
|
103
104
|
end
|
104
105
|
|
105
106
|
def tiebreak_compare_direction
|
@@ -4,20 +4,20 @@ module Mongoid
|
|
4
4
|
def initialize(value = nil, options = {})
|
5
5
|
options = extract_field_options(options)
|
6
6
|
raise ArgumentError.new 'Missing options[:field_name] and/or options[:field_type].' unless options
|
7
|
+
|
7
8
|
if value
|
8
9
|
parts = value.split(':') if value
|
9
|
-
unless parts && parts.length >= 2
|
10
|
-
|
11
|
-
end
|
10
|
+
raise Mongoid::Scroll::Errors::InvalidCursorError.new(cursor: value) unless parts && parts.length >= 2
|
11
|
+
|
12
12
|
value = parse_field_value(
|
13
13
|
options[:field_type],
|
14
14
|
options[:field_name],
|
15
15
|
parts[0...-1].join(':')
|
16
16
|
)
|
17
17
|
options[:tiebreak_id] = BSON::ObjectId.from_string(parts[-1])
|
18
|
-
super
|
18
|
+
super
|
19
19
|
else
|
20
|
-
super
|
20
|
+
super(nil, options)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -21,13 +21,13 @@ module Mongoid
|
|
21
21
|
@resolution = create_resolution(key, attributes)
|
22
22
|
|
23
23
|
"\nProblem:\n #{@problem}" \
|
24
|
-
|
25
|
-
|
24
|
+
"\nSummary:\n #{@summary}" \
|
25
|
+
"\nResolution:\n #{@resolution}"
|
26
26
|
end
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
-
BASE_KEY = 'mongoid.scroll.errors.messages'.freeze
|
30
|
+
BASE_KEY = 'mongoid.scroll.errors.messages'.freeze # :nodoc:
|
31
31
|
|
32
32
|
# Given the key of the specific error and the options hash, translate the
|
33
33
|
# message.
|
@@ -38,7 +38,7 @@ module Mongoid
|
|
38
38
|
#
|
39
39
|
# Returns a localized error message string.
|
40
40
|
def translate(key, options)
|
41
|
-
::I18n.translate("#{BASE_KEY}.#{key}",
|
41
|
+
::I18n.translate("#{BASE_KEY}.#{key}", locale: :en, **options).strip
|
42
42
|
end
|
43
43
|
|
44
44
|
# Create the problem.
|
@@ -4,9 +4,7 @@ module Mongoid
|
|
4
4
|
# Raised when the original sort params and the cursor sort params are different
|
5
5
|
class MismatchedSortFieldsError < Mongoid::Scroll::Errors::Base
|
6
6
|
def initialize(opts = {})
|
7
|
-
if opts[:diff] && opts[:diff].is_a?(Hash)
|
8
|
-
opts = opts.merge(diff: opts[:diff].keys.join(', '))
|
9
|
-
end
|
7
|
+
opts = opts.merge(diff: opts[:diff].keys.join(', ')) if opts[:diff] && opts[:diff].is_a?(Hash)
|
10
8
|
super(compose_message('mismatched_sort_fields', opts))
|
11
9
|
end
|
12
10
|
end
|
@@ -3,9 +3,7 @@ module Mongoid
|
|
3
3
|
module Errors
|
4
4
|
class MultipleSortFieldsError < Mongoid::Scroll::Errors::Base
|
5
5
|
def initialize(opts = {})
|
6
|
-
if opts[:sort] && opts[:sort].is_a?(Hash)
|
7
|
-
opts = opts.merge(sort: opts[:sort].keys.join(', '))
|
8
|
-
end
|
6
|
+
opts = opts.merge(sort: opts[:sort].keys.join(', ')) if opts[:sort] && opts[:sort].is_a?(Hash)
|
9
7
|
super(compose_message('multiple_sort_fields', opts))
|
10
8
|
end
|
11
9
|
end
|
@@ -6,3 +6,4 @@ require 'mongoid/scroll/errors/invalid_cursor_error'
|
|
6
6
|
require 'mongoid/scroll/errors/invalid_base64_cursor_error'
|
7
7
|
require 'mongoid/scroll/errors/no_such_field_error'
|
8
8
|
require 'mongoid/scroll/errors/unsupported_field_type_error'
|
9
|
+
require 'mongoid/scroll/errors/unsupported_type_error'
|
data/lib/mongoid-scroll.rb
CHANGED
@@ -3,7 +3,6 @@ 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'
|
7
6
|
require 'mongoid/scroll/version'
|
8
7
|
require 'mongoid/scroll/errors'
|
9
8
|
require 'mongoid/scroll/base_cursor'
|
@@ -11,5 +10,5 @@ require 'mongoid/scroll/cursor'
|
|
11
10
|
require 'mongoid/scroll/base64_encoded_cursor'
|
12
11
|
require 'mongoid/criteria/scrollable/fields'
|
13
12
|
require 'mongoid/criteria/scrollable/cursors'
|
14
|
-
require '
|
13
|
+
require 'mongoid/criteria/scrollable/iterator'
|
15
14
|
require 'mongoid/criteria/scrollable'
|
data/mongoid-scroll.gemspec
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
$LOAD_PATH.push File.expand_path('
|
1
|
+
$LOAD_PATH.push File.expand_path('lib', __dir__)
|
2
2
|
require 'mongoid/scroll/version'
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
|
|
13
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
|
-
s.add_dependency 'mongoid', '>= 3.0'
|
17
|
-
s.add_dependency 'mongoid-compatibility'
|
18
16
|
s.add_dependency 'i18n'
|
17
|
+
s.add_dependency 'mongoid', '>= 6.0'
|
18
|
+
s.metadata['rubygems_mfa_required'] = 'true'
|
19
19
|
end
|
@@ -3,17 +3,25 @@ require 'spec_helper'
|
|
3
3
|
describe Mongoid::Scroll::Base64EncodedCursor do
|
4
4
|
context 'new' do
|
5
5
|
context 'an empty cursor' do
|
6
|
-
let(:base64_string) { 'eyJ2YWx1ZSI6bnVsbCwiZmllbGRfdHlwZSI6IlN0cmluZyIsImZpZWxkX25hbWUiOiJhX3N0cmluZyIsImRpcmVjdGlvbiI6MSwiaW5jbHVkZV9jdXJyZW50IjpmYWxzZSwidGllYnJlYWtfaWQiOm51bGx9' }
|
7
6
|
subject do
|
8
7
|
Mongoid::Scroll::Base64EncodedCursor.new base64_string
|
9
8
|
end
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
its(:
|
9
|
+
|
10
|
+
let(:base64_string) { 'eyJ2YWx1ZSI6bnVsbCwiZmllbGRfdHlwZSI6IlN0cmluZyIsImZpZWxkX25hbWUiOiJhX3N0cmluZyIsImRpcmVjdGlvbiI6MSwiaW5jbHVkZV9jdXJyZW50IjpmYWxzZSwidGllYnJlYWtfaWQiOm51bGwsInR5cGUiOiJuZXh0In0=' }
|
11
|
+
|
12
|
+
its(:tiebreak_id) { is_expected.to be_nil }
|
13
|
+
its(:value) { is_expected.to be_nil }
|
14
|
+
its(:criteria) { is_expected.to eq({}) }
|
15
|
+
its(:type) { is_expected.to eq(:next) }
|
16
|
+
its(:to_s) { is_expected.to eq(base64_string) }
|
14
17
|
end
|
18
|
+
|
15
19
|
context 'a string field cursor' do
|
16
|
-
|
20
|
+
subject do
|
21
|
+
Mongoid::Scroll::Base64EncodedCursor.new base64_string
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:base64_string) { 'eyJ2YWx1ZSI6ImEgc3RyaW5nIiwiZmllbGRfdHlwZSI6IlN0cmluZyIsImZpZWxkX25hbWUiOiJhX3N0cmluZyIsImRpcmVjdGlvbiI6MSwiaW5jbHVkZV9jdXJyZW50IjpmYWxzZSwidGllYnJlYWtfaWQiOiI2NDA2M2RmODA5NDQzNDE3YzdkMmIxMDIiLCJ0eXBlIjoibmV4dCJ9' }
|
17
25
|
let(:a_value) { 'a string' }
|
18
26
|
let(:tiebreak_id) { BSON::ObjectId.from_string('64063df809443417c7d2b102') }
|
19
27
|
let(:criteria) do
|
@@ -24,18 +32,24 @@ describe Mongoid::Scroll::Base64EncodedCursor do
|
|
24
32
|
]
|
25
33
|
}
|
26
34
|
end
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
its(:value) { should eq a_value }
|
35
|
+
|
36
|
+
its(:value) { is_expected.to eq a_value }
|
31
37
|
its(:tiebreak_id) { tiebreak_id }
|
32
|
-
its(:value) {
|
33
|
-
its(:tiebreak_id) {
|
34
|
-
its(:criteria) {
|
35
|
-
its(:
|
38
|
+
its(:value) { is_expected.to eq a_value }
|
39
|
+
its(:tiebreak_id) { is_expected.to eq tiebreak_id }
|
40
|
+
its(:criteria) { is_expected.to eq(criteria) }
|
41
|
+
its(:type) { is_expected.to eq(:next) }
|
42
|
+
its(:to_s) { is_expected.to eq(base64_string) }
|
36
43
|
end
|
44
|
+
|
37
45
|
context 'an id field cursor' do
|
38
|
-
|
46
|
+
subject do
|
47
|
+
Mongoid::Scroll::Base64EncodedCursor.new base64_string
|
48
|
+
end
|
49
|
+
|
50
|
+
let(:base64_string) do
|
51
|
+
'eyJ2YWx1ZSI6IjY0MDY0NTg0MDk0NDM0MjgxZmE3MWFiMiIsImZpZWxkX3R5cGUiOiJCU09OOjpPYmplY3RJZCIsImZpZWxkX25hbWUiOiJpZCIsImRpcmVjdGlvbiI6MSwiaW5jbHVkZV9jdXJyZW50IjpmYWxzZSwidGllYnJlYWtfaWQiOiI2NDA2NDU4NDA5NDQzNDI4MWZhNzFhYjIiLCJ0eXBlIjoibmV4dCJ9'
|
52
|
+
end
|
39
53
|
let(:a_value) { BSON::ObjectId('64064584094434281fa71ab2') }
|
40
54
|
let(:tiebreak_id) { a_value }
|
41
55
|
let(:criteria) do
|
@@ -46,16 +60,20 @@ describe Mongoid::Scroll::Base64EncodedCursor do
|
|
46
60
|
]
|
47
61
|
}
|
48
62
|
end
|
63
|
+
|
64
|
+
its(:value) { is_expected.to eq a_value }
|
65
|
+
its(:tiebreak_id) { is_expected.to eq tiebreak_id }
|
66
|
+
its(:criteria) { is_expected.to eq(criteria) }
|
67
|
+
its(:type) { is_expected.to eq(:next) }
|
68
|
+
its(:to_s) { is_expected.to eq(base64_string) }
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'an integer field cursor' do
|
49
72
|
subject do
|
50
73
|
Mongoid::Scroll::Base64EncodedCursor.new base64_string
|
51
74
|
end
|
52
|
-
|
53
|
-
|
54
|
-
its(:criteria) { should eq(criteria) }
|
55
|
-
its(:to_s) { should eq(base64_string) }
|
56
|
-
end
|
57
|
-
context 'an integer field cursor' do
|
58
|
-
let(:base64_string) { 'eyJ2YWx1ZSI6MTAsImZpZWxkX3R5cGUiOiJJbnRlZ2VyIiwiZmllbGRfbmFtZSI6ImFfaW50ZWdlciIsImRpcmVjdGlvbiI6MSwiaW5jbHVkZV9jdXJyZW50IjpmYWxzZSwidGllYnJlYWtfaWQiOiI2NDA2M2RmODA5NDQzNDE3YzdkMmIxMDgifQ==' }
|
75
|
+
|
76
|
+
let(:base64_string) { 'eyJ2YWx1ZSI6MTAsImZpZWxkX3R5cGUiOiJJbnRlZ2VyIiwiZmllbGRfbmFtZSI6ImFfaW50ZWdlciIsImRpcmVjdGlvbiI6MSwiaW5jbHVkZV9jdXJyZW50IjpmYWxzZSwidGllYnJlYWtfaWQiOiI2NDA2M2RmODA5NDQzNDE3YzdkMmIxMDgiLCJ0eXBlIjoibmV4dCJ9' }
|
59
77
|
let(:a_value) { 10 }
|
60
78
|
let(:tiebreak_id) { BSON::ObjectId('64063df809443417c7d2b108') }
|
61
79
|
let(:criteria) do
|
@@ -66,18 +84,22 @@ describe Mongoid::Scroll::Base64EncodedCursor do
|
|
66
84
|
]
|
67
85
|
}
|
68
86
|
end
|
69
|
-
|
70
|
-
|
71
|
-
end
|
72
|
-
its(:value) { should eq a_value }
|
87
|
+
|
88
|
+
its(:value) { is_expected.to eq a_value }
|
73
89
|
its(:tiebreak_id) { tiebreak_id }
|
74
|
-
its(:value) {
|
75
|
-
its(:tiebreak_id) {
|
76
|
-
its(:criteria) {
|
77
|
-
its(:
|
90
|
+
its(:value) { is_expected.to eq a_value }
|
91
|
+
its(:tiebreak_id) { is_expected.to eq tiebreak_id }
|
92
|
+
its(:criteria) { is_expected.to eq(criteria) }
|
93
|
+
its(:type) { is_expected.to eq(:next) }
|
94
|
+
its(:to_s) { is_expected.to eq(base64_string) }
|
78
95
|
end
|
96
|
+
|
79
97
|
context 'a date/time field cursor' do
|
80
|
-
|
98
|
+
subject do
|
99
|
+
Mongoid::Scroll::Base64EncodedCursor.new base64_string
|
100
|
+
end
|
101
|
+
|
102
|
+
let(:base64_string) { 'eyJ2YWx1ZSI6MTM4NzU5MDEyMy4wLCJmaWVsZF90eXBlIjoiRGF0ZVRpbWUiLCJmaWVsZF9uYW1lIjoiYV9kYXRldGltZSIsImRpcmVjdGlvbiI6MSwiaW5jbHVkZV9jdXJyZW50IjpmYWxzZSwidGllYnJlYWtfaWQiOiI2NDA2NDNhNzA5NDQzNDIzOWYyZGJmODYiLCJ0eXBlIjoibmV4dCJ9' }
|
81
103
|
let(:a_value) { DateTime.new(2013, 12, 21, 1, 42, 3, 'UTC') }
|
82
104
|
let(:tiebreak_id) { BSON::ObjectId('640643a7094434239f2dbf86') }
|
83
105
|
let(:criteria) do
|
@@ -88,16 +110,20 @@ describe Mongoid::Scroll::Base64EncodedCursor do
|
|
88
110
|
]
|
89
111
|
}
|
90
112
|
end
|
113
|
+
|
114
|
+
its(:value) { is_expected.to eq a_value }
|
115
|
+
its(:tiebreak_id) { is_expected.to eq tiebreak_id }
|
116
|
+
its(:criteria) { is_expected.to eq(criteria) }
|
117
|
+
its(:type) { is_expected.to eq(:next) }
|
118
|
+
its(:to_s) { is_expected.to eq(base64_string) }
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'a date field cursor' do
|
91
122
|
subject do
|
92
123
|
Mongoid::Scroll::Base64EncodedCursor.new base64_string
|
93
124
|
end
|
94
|
-
|
95
|
-
|
96
|
-
its(:criteria) { should eq(criteria) }
|
97
|
-
its(:to_s) { should eq(base64_string) }
|
98
|
-
end
|
99
|
-
context 'a date field cursor' do
|
100
|
-
let(:base64_string) { 'eyJ2YWx1ZSI6MTM4NzU4NDAwMCwiZmllbGRfdHlwZSI6IkRhdGUiLCJmaWVsZF9uYW1lIjoiYV9kYXRlIiwiZGlyZWN0aW9uIjoxLCJpbmNsdWRlX2N1cnJlbnQiOmZhbHNlLCJ0aWVicmVha19pZCI6IjY0MDY0MmM5MDk0NDM0MjEyYzRkNDQyMCJ9' }
|
125
|
+
|
126
|
+
let(:base64_string) { 'eyJ2YWx1ZSI6MTM4NzU4NDAwMCwiZmllbGRfdHlwZSI6IkRhdGUiLCJmaWVsZF9uYW1lIjoiYV9kYXRlIiwiZGlyZWN0aW9uIjoxLCJpbmNsdWRlX2N1cnJlbnQiOmZhbHNlLCJ0aWVicmVha19pZCI6IjY0MDY0MmM5MDk0NDM0MjEyYzRkNDQyMCIsInR5cGUiOiJuZXh0In0=' }
|
101
127
|
let(:tiebreak_id) { BSON::ObjectId('640642c9094434212c4d4420') }
|
102
128
|
let(:a_value) { Date.new(2013, 12, 21) }
|
103
129
|
let(:criteria) do
|
@@ -108,16 +134,20 @@ describe Mongoid::Scroll::Base64EncodedCursor do
|
|
108
134
|
]
|
109
135
|
}
|
110
136
|
end
|
137
|
+
|
138
|
+
its(:value) { is_expected.to eq a_value }
|
139
|
+
its(:tiebreak_id) { is_expected.to eq tiebreak_id }
|
140
|
+
its(:criteria) { is_expected.to eq(criteria) }
|
141
|
+
its(:type) { is_expected.to eq(:next) }
|
142
|
+
its(:to_s) { is_expected.to eq(base64_string) }
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'a time field cursor' do
|
111
146
|
subject do
|
112
147
|
Mongoid::Scroll::Base64EncodedCursor.new base64_string
|
113
148
|
end
|
114
|
-
|
115
|
-
|
116
|
-
its(:criteria) { should eq(criteria) }
|
117
|
-
its(:to_s) { should eq(base64_string) }
|
118
|
-
end
|
119
|
-
context 'a time field cursor' do
|
120
|
-
let(:base64_string) { 'eyJ2YWx1ZSI6MTM4NzYwNTcyMy4wLCJmaWVsZF90eXBlIjoiVGltZSIsImZpZWxkX25hbWUiOiJhX3RpbWUiLCJkaXJlY3Rpb24iOjEsImluY2x1ZGVfY3VycmVudCI6ZmFsc2UsInRpZWJyZWFrX2lkIjoiNjQwNjNkNGEwOTQ0MzQxNjZiZDA1M2VkIn0=' }
|
149
|
+
|
150
|
+
let(:base64_string) { 'eyJ2YWx1ZSI6MTM4NzYwNTcyMy4wLCJmaWVsZF90eXBlIjoiVGltZSIsImZpZWxkX25hbWUiOiJhX3RpbWUiLCJkaXJlY3Rpb24iOjEsImluY2x1ZGVfY3VycmVudCI6ZmFsc2UsInRpZWJyZWFrX2lkIjoiNjQwNjNkNGEwOTQ0MzQxNjZiZDA1M2VkIiwidHlwZSI6Im5leHQifQ==' }
|
121
151
|
let(:item_id) { BSON::ObjectId('640636f209443407333b46d4') }
|
122
152
|
let(:a_value) { Time.new(2013, 12, 21, 6, 2, 3, '+00:00').utc }
|
123
153
|
let(:tiebreak_id) { BSON::ObjectId('64063d4a094434166bd053ed') }
|
@@ -129,15 +159,15 @@ describe Mongoid::Scroll::Base64EncodedCursor do
|
|
129
159
|
]
|
130
160
|
}
|
131
161
|
end
|
132
|
-
|
133
|
-
|
134
|
-
end
|
135
|
-
its(:value) { should eq a_value }
|
162
|
+
|
163
|
+
its(:value) { is_expected.to eq a_value }
|
136
164
|
its(:tiebreak_id) { tiebreak_id }
|
137
|
-
its(:tiebreak_id) {
|
138
|
-
its(:criteria) {
|
139
|
-
its(:
|
165
|
+
its(:tiebreak_id) { is_expected.to eq tiebreak_id }
|
166
|
+
its(:criteria) { is_expected.to eq(criteria) }
|
167
|
+
its(:type) { is_expected.to eq(:next) }
|
168
|
+
its(:to_s) { is_expected.to eq(base64_string) }
|
140
169
|
end
|
170
|
+
|
141
171
|
context 'an invalid field cursor' do
|
142
172
|
it 'raises ArgumentError' do
|
143
173
|
expect do
|
@@ -145,6 +175,7 @@ describe Mongoid::Scroll::Base64EncodedCursor do
|
|
145
175
|
end.to raise_error Mongoid::Scroll::Errors::InvalidBase64CursorError
|
146
176
|
end
|
147
177
|
end
|
178
|
+
|
148
179
|
context 'an invalid cursor' do
|
149
180
|
it 'raises a Mongoid::Scroll::Errors::InvalidBase64CursorError with an invalid Base64 string' do
|
150
181
|
expect { Mongoid::Scroll::Base64EncodedCursor.new 'invalid' }.to raise_error Mongoid::Scroll::Errors::InvalidBase64CursorError, /The cursor supplied is invalid: invalid./
|
@@ -155,79 +186,119 @@ describe Mongoid::Scroll::Base64EncodedCursor do
|
|
155
186
|
end
|
156
187
|
end
|
157
188
|
end
|
189
|
+
|
158
190
|
context 'from_record' do
|
159
191
|
context 'a string field cursor' do
|
192
|
+
subject do
|
193
|
+
Mongoid::Scroll::Base64EncodedCursor.from_record feed_item, field_name: field_name, field_type: field_type
|
194
|
+
end
|
195
|
+
|
160
196
|
let(:field_type) { String }
|
161
197
|
let(:field_value) { 'a string' }
|
162
198
|
let(:field_name) { 'a_string' }
|
163
199
|
let(:feed_item) { Feed::Item.create!(field_name => field_value) }
|
200
|
+
|
201
|
+
its(:value) { is_expected.to eq field_value }
|
202
|
+
its(:field_name) { is_expected.to eq field_name }
|
203
|
+
its(:field_type) { is_expected.to eq field_type.to_s }
|
204
|
+
end
|
205
|
+
|
206
|
+
context 'an id field cursor' do
|
164
207
|
subject do
|
165
208
|
Mongoid::Scroll::Base64EncodedCursor.from_record feed_item, field_name: field_name, field_type: field_type
|
166
209
|
end
|
167
|
-
|
168
|
-
its(:field_name) { should eq field_name }
|
169
|
-
its(:field_type) { should eq field_type.to_s }
|
170
|
-
end
|
171
|
-
context 'an id field cursor' do
|
210
|
+
|
172
211
|
let(:field_type) { BSON::ObjectId }
|
173
212
|
let(:field_name) { 'id' }
|
174
213
|
let(:feed_item) { Feed::Item.create! }
|
214
|
+
|
215
|
+
its(:value) { is_expected.to eq feed_item._id }
|
216
|
+
its(:field_type) { is_expected.to eq field_type.to_s }
|
217
|
+
end
|
218
|
+
|
219
|
+
context 'an integer field cursor' do
|
175
220
|
subject do
|
176
221
|
Mongoid::Scroll::Base64EncodedCursor.from_record feed_item, field_name: field_name, field_type: field_type
|
177
222
|
end
|
178
|
-
|
179
|
-
its(:field_type) { should eq field_type.to_s }
|
180
|
-
end
|
181
|
-
context 'an integer field cursor' do
|
223
|
+
|
182
224
|
let(:field_type) { Integer }
|
183
225
|
let(:field_value) { 10 }
|
184
226
|
let(:field_name) { 'a_integer' }
|
185
227
|
let(:feed_item) { Feed::Item.create!(field_name => field_value) }
|
228
|
+
|
229
|
+
its(:value) { is_expected.to eq field_value }
|
230
|
+
its(:field_type) { is_expected.to eq field_type.to_s }
|
231
|
+
end
|
232
|
+
|
233
|
+
context 'a date/time field cursor' do
|
186
234
|
subject do
|
187
235
|
Mongoid::Scroll::Base64EncodedCursor.from_record feed_item, field_name: field_name, field_type: field_type
|
188
236
|
end
|
189
|
-
|
190
|
-
its(:field_type) { should eq field_type.to_s }
|
191
|
-
end
|
192
|
-
context 'a date/time field cursor' do
|
237
|
+
|
193
238
|
let(:field_type) { DateTime }
|
194
239
|
let(:field_value) { DateTime.new(2013, 12, 21, 1, 42, 3, 'UTC') }
|
195
240
|
let(:field_name) { 'a_datetime' }
|
196
241
|
let(:feed_item) { Feed::Item.create!(field_name => field_value) }
|
242
|
+
|
243
|
+
its(:value) { is_expected.to eq field_value }
|
244
|
+
its(:field_type) { is_expected.to eq field_type.to_s }
|
245
|
+
end
|
246
|
+
|
247
|
+
context 'a date field cursor' do
|
197
248
|
subject do
|
198
249
|
Mongoid::Scroll::Base64EncodedCursor.from_record feed_item, field_name: field_name, field_type: field_type
|
199
250
|
end
|
200
|
-
|
201
|
-
its(:field_type) { should eq field_type.to_s }
|
202
|
-
end
|
203
|
-
context 'a date field cursor' do
|
251
|
+
|
204
252
|
let(:field_type) { Date }
|
205
253
|
let(:field_value) { Date.new(2013, 12, 21) }
|
206
254
|
let(:field_name) { 'a_date' }
|
207
255
|
let(:feed_item) { Feed::Item.create!(field_name => field_value) }
|
256
|
+
|
257
|
+
its(:value) { is_expected.to eq field_value }
|
258
|
+
end
|
259
|
+
|
260
|
+
context 'a time field cursor' do
|
208
261
|
subject do
|
209
262
|
Mongoid::Scroll::Base64EncodedCursor.from_record feed_item, field_name: field_name, field_type: field_type
|
210
263
|
end
|
211
|
-
|
212
|
-
end
|
213
|
-
context 'a time field cursor' do
|
264
|
+
|
214
265
|
let(:field_type) { Time }
|
215
266
|
let(:field_value) { Time.new(2013, 12, 21, 1, 2, 3) }
|
216
267
|
let(:field_name) { 'a_time' }
|
217
268
|
let(:feed_item) { Feed::Item.create!(field_name => field_value) }
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
its(:value) { should eq field_value }
|
222
|
-
its(:field_type) { should eq field_type.to_s }
|
269
|
+
|
270
|
+
its(:value) { is_expected.to eq field_value }
|
271
|
+
its(:field_type) { is_expected.to eq field_type.to_s }
|
223
272
|
end
|
273
|
+
|
224
274
|
context 'an array field cursor' do
|
225
275
|
let(:feed_item) { Feed::Item.create!(a_array: %w[x y]) }
|
276
|
+
|
226
277
|
it 'is not supported' do
|
227
278
|
expect do
|
228
279
|
Mongoid::Scroll::Base64EncodedCursor.from_record feed_item, field_name: 'a_array', field_type: Array
|
229
280
|
end.to raise_error Mongoid::Scroll::Errors::UnsupportedFieldTypeError, /The type of the field 'a_array' is not supported: Array./
|
230
281
|
end
|
231
282
|
end
|
283
|
+
|
284
|
+
it 'encode and decode type option' do
|
285
|
+
feed_item = Feed::Item.create!
|
286
|
+
cursor = Mongoid::Scroll::Base64EncodedCursor.from_record feed_item, field_name: 'id', field_type: BSON::ObjectId, type: :previous
|
287
|
+
expect(Mongoid::Scroll::Base64EncodedCursor.new(cursor.to_s).type).to eq(:previous)
|
288
|
+
end
|
289
|
+
|
290
|
+
context 'a cursor with previous set to true' do
|
291
|
+
subject do
|
292
|
+
Mongoid::Scroll::Base64EncodedCursor.from_record feed_item, field_name: field_name, field_type: field_type, type: :previous
|
293
|
+
end
|
294
|
+
|
295
|
+
let(:field_type) { BSON::ObjectId }
|
296
|
+
let(:field_name) { 'id' }
|
297
|
+
let(:feed_item) { Feed::Item.create! }
|
298
|
+
|
299
|
+
its(:value) { is_expected.to eq feed_item._id }
|
300
|
+
its(:field_type) { is_expected.to eq field_type.to_s }
|
301
|
+
its(:type) { is_expected.to eq(:previous) }
|
302
|
+
end
|
232
303
|
end
|
233
304
|
end
|