Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
### 2.0.1 (Next)

* [#48](https://github.com/mongoid/mongoid-scroll/issues/48): Raise `NoSuchFieldError` when a sort or cursor refers to a field no longer defined on the model - [@dblock](https://github.com/dblock).
* [#51](https://github.com/mongoid/mongoid-scroll/pull/51): Report SimpleCov coverage to Coveralls once per build without duplicate gem uploads and refresh CI and coverage badges - [@dblock](https://github.com/dblock).
* [#50](https://github.com/mongoid/mongoid-scroll/pull/50): Modernize CI through Ruby 4.0, Mongoid 9 and MongoDB 8; fix Mongoid 9 dependency selection, database cleaner compatibility and invalid Danger workflow references - [@dblock](https://github.com/dblock).
* [#49](https://github.com/mongoid/mongoid-scroll/pull/49): Migrate Danger to danger-pr-comment workflow - [@dblock](https://github.com/dblock).
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ end

Resume iterating using the saved cursor and save the cursor to go backwards.

If the sort field or a saved cursor's field is no longer defined on the model, `scroll` raises `Mongoid::Scroll::Errors::NoSuchFieldError`. A defined field with a `nil` value is not considered missing.

```ruby
Feed::Item.desc(:position).limit(5).scroll(saved_iterator.next_cursor) do |record, iterator|
# each record, one-by-one
Expand Down
2 changes: 1 addition & 1 deletion lib/mongoid/criteria/scrollable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def cursor_from_record(cursor_type, record, cursor_options)

def scroll_field_type(criteria)
scroll_field = scroll_field(criteria)
field = criteria.klass.fields[scroll_field.to_s]
field = scroll_model_field(scroll_field)
field.foreign_key? && field.object_id_field? ? BSON::ObjectId : field.type
end
end
Expand Down
6 changes: 6 additions & 0 deletions lib/mongoid/criteria/scrollable/fields.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@ module Scrollable
module Fields
private

def scroll_model_field(field_name)
klass.fields[field_name.to_s] ||
raise(Mongoid::Scroll::Errors::NoSuchFieldError.new(field: field_name))
end

def raise_mismatched_sort_fields_error!(cursor, criteria_cursor_options)
diff = cursor.sort_options.reject { |k, v| criteria_cursor_options[k] == v }
raise Mongoid::Scroll::Errors::MismatchedSortFieldsError.new(diff: diff)
end

def different_sort_fields?(cursor, criteria_cursor_options)
scroll_model_field(cursor.field_name)
criteria_cursor_options[:field_type] = criteria_cursor_options[:field_type].to_s
criteria_cursor_options[:field_name] = criteria_cursor_options[:field_name].to_s
criteria_cursor_options != cursor.sort_options
Expand Down
31 changes: 31 additions & 0 deletions spec/mongoid/criteria_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,37 @@
end
end

context 'with a missing field' do
it 'rejects a sort field that is not defined on the model' do
expect do
Feed::Item.asc(:removed_field).scroll(cursor_type)
end.to raise_error Mongoid::Scroll::Errors::NoSuchFieldError, /does not exist: removed_field/
end

it 'rejects a cursor whose field is no longer defined on the model' do
cursor = cursor_type.new(nil, field_name: 'removed_field', field_type: String)
expect do
Feed::Item.asc(:name).scroll(cursor)
end.to raise_error Mongoid::Scroll::Errors::NoSuchFieldError, /does not exist: removed_field/
end

it 'does not confuse a nil field value with a missing field' do
record = Feed::Item.create!
cursor = cursor_type.from_record(record, field: record.fields['name'])
expect { Feed::Item.asc(:name).scroll(cursor) }.not_to raise_error
end

if cursor_type == Mongoid::Scroll::Base64EncodedCursor
it 'rejects a serialized cursor whose field is no longer defined on the model' do
cursor = cursor_type.new(nil, field_name: 'removed_field', field_type: String)
saved_cursor = cursor_type.new(cursor.to_s)
expect do
Feed::Item.asc(:name).scroll(saved_cursor)
end.to raise_error Mongoid::Scroll::Errors::NoSuchFieldError, /does not exist: removed_field/
end
end
end

context 'with data' do
before do
10.times do |i|
Expand Down
Loading