mongoid-scroll 1.0.1 → 2.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.
- 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
|