mongoid-scroll 0.3.7 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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 +14 -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 +252 -196
  31. data/spec/mongoid/{scroll_cursor_spec.rb → cursor_spec.rb} +54 -18
  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
@@ -0,0 +1,233 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::Scroll::Base64EncodedCursor do
4
+ context 'new' do
5
+ context 'an empty cursor' do
6
+ let(:base64_string) { 'eyJ2YWx1ZSI6bnVsbCwiZmllbGRfdHlwZSI6IlN0cmluZyIsImZpZWxkX25hbWUiOiJhX3N0cmluZyIsImRpcmVjdGlvbiI6MSwiaW5jbHVkZV9jdXJyZW50IjpmYWxzZSwidGllYnJlYWtfaWQiOm51bGx9' }
7
+ subject do
8
+ Mongoid::Scroll::Base64EncodedCursor.new base64_string
9
+ end
10
+ its(:tiebreak_id) { should be_nil }
11
+ its(:value) { should be_nil }
12
+ its(:criteria) { should eq({}) }
13
+ its(:to_s) { should eq(base64_string) }
14
+ end
15
+ context 'a string field cursor' do
16
+ let(:base64_string) { 'eyJ2YWx1ZSI6ImEgc3RyaW5nIiwiZmllbGRfdHlwZSI6IlN0cmluZyIsImZpZWxkX25hbWUiOiJhX3N0cmluZyIsImRpcmVjdGlvbiI6MSwiaW5jbHVkZV9jdXJyZW50IjpmYWxzZSwidGllYnJlYWtfaWQiOiI2NDA2M2RmODA5NDQzNDE3YzdkMmIxMDIifQ==' }
17
+ let(:a_value) { 'a string' }
18
+ let(:tiebreak_id) { BSON::ObjectId.from_string('64063df809443417c7d2b102') }
19
+ let(:criteria) do
20
+ {
21
+ '$or' => [
22
+ { 'a_string' => { '$gt' => a_value } },
23
+ { 'a_string' => a_value, '_id' => { '$gt' => tiebreak_id } }
24
+ ]
25
+ }
26
+ end
27
+ subject do
28
+ Mongoid::Scroll::Base64EncodedCursor.new base64_string
29
+ end
30
+ its(:value) { should eq a_value }
31
+ its(:tiebreak_id) { tiebreak_id }
32
+ its(:value) { should eq a_value }
33
+ its(:tiebreak_id) { should eq tiebreak_id }
34
+ its(:criteria) { should eq(criteria) }
35
+ its(:to_s) { should eq(base64_string) }
36
+ end
37
+ context 'an id field cursor' do
38
+ let(:base64_string) { 'eyJ2YWx1ZSI6IjY0MDY0NTg0MDk0NDM0MjgxZmE3MWFiMiIsImZpZWxkX3R5cGUiOiJCU09OOjpPYmplY3RJZCIsImZpZWxkX25hbWUiOiJpZCIsImRpcmVjdGlvbiI6MSwiaW5jbHVkZV9jdXJyZW50IjpmYWxzZSwidGllYnJlYWtfaWQiOiI2NDA2NDU4NDA5NDQzNDI4MWZhNzFhYjIifQ==' }
39
+ let(:a_value) { BSON::ObjectId('64064584094434281fa71ab2') }
40
+ let(:tiebreak_id) { a_value }
41
+ let(:criteria) do
42
+ {
43
+ '$or' => [
44
+ { 'id' => { '$gt' => a_value } },
45
+ { 'id' => a_value, '_id' => { '$gt' => tiebreak_id } }
46
+ ]
47
+ }
48
+ end
49
+ subject do
50
+ Mongoid::Scroll::Base64EncodedCursor.new base64_string
51
+ end
52
+ its(:value) { should eq a_value }
53
+ its(:tiebreak_id) { should eq tiebreak_id }
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==' }
59
+ let(:a_value) { 10 }
60
+ let(:tiebreak_id) { BSON::ObjectId('64063df809443417c7d2b108') }
61
+ let(:criteria) do
62
+ {
63
+ '$or' => [
64
+ { 'a_integer' => { '$gt' => 10 } },
65
+ { 'a_integer' => 10, '_id' => { '$gt' => tiebreak_id } }
66
+ ]
67
+ }
68
+ end
69
+ subject do
70
+ Mongoid::Scroll::Base64EncodedCursor.new base64_string
71
+ end
72
+ its(:value) { should eq a_value }
73
+ its(:tiebreak_id) { tiebreak_id }
74
+ its(:value) { should eq a_value }
75
+ its(:tiebreak_id) { should eq tiebreak_id }
76
+ its(:criteria) { should eq(criteria) }
77
+ its(:to_s) { should eq(base64_string) }
78
+ end
79
+ context 'a date/time field cursor' do
80
+ let(:base64_string) { 'eyJ2YWx1ZSI6MTM4NzU5MDEyMy4wLCJmaWVsZF90eXBlIjoiRGF0ZVRpbWUiLCJmaWVsZF9uYW1lIjoiYV9kYXRldGltZSIsImRpcmVjdGlvbiI6MSwiaW5jbHVkZV9jdXJyZW50IjpmYWxzZSwidGllYnJlYWtfaWQiOiI2NDA2NDNhNzA5NDQzNDIzOWYyZGJmODYifQ==' }
81
+ let(:a_value) { DateTime.new(2013, 12, 21, 1, 42, 3, 'UTC') }
82
+ let(:tiebreak_id) { BSON::ObjectId('640643a7094434239f2dbf86') }
83
+ let(:criteria) do
84
+ {
85
+ '$or' => [
86
+ { 'a_datetime' => { '$gt' => a_value.utc } },
87
+ { 'a_datetime' => a_value.utc, '_id' => { '$gt' => tiebreak_id } }
88
+ ]
89
+ }
90
+ end
91
+ subject do
92
+ Mongoid::Scroll::Base64EncodedCursor.new base64_string
93
+ end
94
+ its(:value) { should eq a_value }
95
+ its(:tiebreak_id) { should eq tiebreak_id }
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' }
101
+ let(:tiebreak_id) { BSON::ObjectId('640642c9094434212c4d4420') }
102
+ let(:a_value) { Date.new(2013, 12, 21) }
103
+ let(:criteria) do
104
+ {
105
+ '$or' => [
106
+ { 'a_date' => { '$gt' => a_value.to_datetime.utc } },
107
+ { 'a_date' => a_value.to_datetime.utc, '_id' => { '$gt' => tiebreak_id } }
108
+ ]
109
+ }
110
+ end
111
+ subject do
112
+ Mongoid::Scroll::Base64EncodedCursor.new base64_string
113
+ end
114
+ its(:value) { should eq a_value }
115
+ its(:tiebreak_id) { should eq tiebreak_id }
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=' }
121
+ let(:item_id) { BSON::ObjectId('640636f209443407333b46d4') }
122
+ let(:a_value) { Time.new(2013, 12, 21, 6, 2, 3, '+00:00').utc }
123
+ let(:tiebreak_id) { BSON::ObjectId('64063d4a094434166bd053ed') }
124
+ let(:criteria) do
125
+ {
126
+ '$or' => [
127
+ { 'a_time' => { '$gt' => a_value } },
128
+ { 'a_time' => a_value, '_id' => { '$gt' => tiebreak_id } }
129
+ ]
130
+ }
131
+ end
132
+ subject do
133
+ Mongoid::Scroll::Base64EncodedCursor.new base64_string
134
+ end
135
+ its(:value) { should eq a_value }
136
+ its(:tiebreak_id) { tiebreak_id }
137
+ its(:tiebreak_id) { should eq tiebreak_id }
138
+ its(:criteria) { should eq(criteria) }
139
+ its(:to_s) { should eq(base64_string) }
140
+ end
141
+ context 'an invalid field cursor' do
142
+ it 'raises ArgumentError' do
143
+ expect do
144
+ Mongoid::Scroll::Base64EncodedCursor.new 'invalid', {}
145
+ end.to raise_error Mongoid::Scroll::Errors::InvalidBase64CursorError
146
+ end
147
+ end
148
+ context 'an invalid cursor' do
149
+ it 'raises a Mongoid::Scroll::Errors::InvalidBase64CursorError with an invalid Base64 string' do
150
+ expect { Mongoid::Scroll::Base64EncodedCursor.new 'invalid' }.to raise_error Mongoid::Scroll::Errors::InvalidBase64CursorError, /The cursor supplied is invalid: invalid./
151
+ end
152
+
153
+ it 'raises a Mongoid::Scroll::Errors::InvalidBase64CursorError with an invalid JSON string' do
154
+ expect { Mongoid::Scroll::Base64EncodedCursor.new 'aW52YWxpZA==' }.to raise_error Mongoid::Scroll::Errors::InvalidBase64CursorError, /The cursor supplied is invalid: aW52YWxpZA==./
155
+ end
156
+ end
157
+ end
158
+ context 'from_record' do
159
+ context 'a string field cursor' do
160
+ let(:field_type) { String }
161
+ let(:field_value) { 'a string' }
162
+ let(:field_name) { 'a_string' }
163
+ let(:feed_item) { Feed::Item.create!(field_name => field_value) }
164
+ subject do
165
+ Mongoid::Scroll::Base64EncodedCursor.from_record feed_item, field_name: field_name, field_type: field_type
166
+ end
167
+ its(:value) { should eq field_value }
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
172
+ let(:field_type) { BSON::ObjectId }
173
+ let(:field_name) { 'id' }
174
+ let(:feed_item) { Feed::Item.create! }
175
+ subject do
176
+ Mongoid::Scroll::Base64EncodedCursor.from_record feed_item, field_name: field_name, field_type: field_type
177
+ end
178
+ its(:value) { should eq feed_item._id }
179
+ its(:field_type) { should eq field_type.to_s }
180
+ end
181
+ context 'an integer field cursor' do
182
+ let(:field_type) { Integer }
183
+ let(:field_value) { 10 }
184
+ let(:field_name) { 'a_integer' }
185
+ let(:feed_item) { Feed::Item.create!(field_name => field_value) }
186
+ subject do
187
+ Mongoid::Scroll::Base64EncodedCursor.from_record feed_item, field_name: field_name, field_type: field_type
188
+ end
189
+ its(:value) { should eq field_value }
190
+ its(:field_type) { should eq field_type.to_s }
191
+ end
192
+ context 'a date/time field cursor' do
193
+ let(:field_type) { DateTime }
194
+ let(:field_value) { DateTime.new(2013, 12, 21, 1, 42, 3, 'UTC') }
195
+ let(:field_name) { 'a_datetime' }
196
+ let(:feed_item) { Feed::Item.create!(field_name => field_value) }
197
+ subject do
198
+ Mongoid::Scroll::Base64EncodedCursor.from_record feed_item, field_name: field_name, field_type: field_type
199
+ end
200
+ its(:value) { should eq field_value }
201
+ its(:field_type) { should eq field_type.to_s }
202
+ end
203
+ context 'a date field cursor' do
204
+ let(:field_type) { Date }
205
+ let(:field_value) { Date.new(2013, 12, 21) }
206
+ let(:field_name) { 'a_date' }
207
+ let(:feed_item) { Feed::Item.create!(field_name => field_value) }
208
+ subject do
209
+ Mongoid::Scroll::Base64EncodedCursor.from_record feed_item, field_name: field_name, field_type: field_type
210
+ end
211
+ its(:value) { should eq field_value }
212
+ end
213
+ context 'a time field cursor' do
214
+ let(:field_type) { Time }
215
+ let(:field_value) { Time.new(2013, 12, 21, 1, 2, 3) }
216
+ let(:field_name) { 'a_time' }
217
+ let(:feed_item) { Feed::Item.create!(field_name => field_value) }
218
+ subject do
219
+ Mongoid::Scroll::Base64EncodedCursor.from_record feed_item, field_name: field_name, field_type: field_type
220
+ end
221
+ its(:value) { should eq field_value }
222
+ its(:field_type) { should eq field_type.to_s }
223
+ end
224
+ context 'an array field cursor' do
225
+ let(:feed_item) { Feed::Item.create!(a_array: %w[x y]) }
226
+ it 'is not supported' do
227
+ expect do
228
+ Mongoid::Scroll::Base64EncodedCursor.from_record feed_item, field_name: 'a_array', field_type: Array
229
+ end.to raise_error Mongoid::Scroll::Errors::UnsupportedFieldTypeError, /The type of the field 'a_array' is not supported: Array./
230
+ end
231
+ end
232
+ end
233
+ end