mongoid-scroll 0.3.6 → 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 (38) hide show
  1. checksums.yaml +5 -5
  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 +10 -16
  7. data/LICENSE.md +1 -1
  8. data/README.md +59 -46
  9. data/RELEASING.md +4 -4
  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/spec_helper.rb +1 -1
  33. data/spec/support/feed/item.rb +1 -1
  34. metadata +19 -13
  35. data/.travis.yml +0 -35
  36. data/examples/moped_scroll_feed.rb +0 -45
  37. data/lib/moped/scrollable.rb +0 -38
  38. 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) { 'eyJ2YWx1ZSI6MTM4NzU5MDEyMywiZmllbGRfdHlwZSI6IkRhdGVUaW1lIiwiZmllbGRfbmFtZSI6ImFfZGF0ZXRpbWUiLCJkaXJlY3Rpb24iOjEsImluY2x1ZGVfY3VycmVudCI6ZmFsc2UsInRpZWJyZWFrX2lkIjoiNjQwNjQzYTcwOTQ0MzQyMzlmMmRiZjg2In0=' }
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) { 'eyJ2YWx1ZSI6MTM4NzYwNTcyMywiZmllbGRfdHlwZSI6IlRpbWUiLCJmaWVsZF9uYW1lIjoiYV90aW1lIiwiZGlyZWN0aW9uIjoxLCJpbmNsdWRlX2N1cnJlbnQiOmZhbHNlLCJ0aWVicmVha19pZCI6IjY0MDYzZDRhMDk0NDM0MTY2YmQwNTNlZCJ9' }
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