diff --git a/CHANGELOG.md b/CHANGELOG.md index a79e0c1..9b12393 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * [#38](https://github.com/mongoid/mongoid-scroll/pull/38): Add `previous_cursor` - [@GCorbel](https://github.com/GCorbel). * [#42](https://github.com/mongoid/mongoid-scroll/pull/42): Add `first_cursor` - [@GCorbel](https://github.com/GCorbel). +* [#43](https://github.com/mongoid/mongoid-scroll/pull/43): Add `current_cursor` - [@GCorbel](https://github.com/GCorbel). * Your contribution here. ### 1.0.1 (2023/03/15) diff --git a/README.md b/README.md index c55fa61..e25ac0c 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ Feed::Item.desc(:position).limit(5).scroll(saved_iterator.previous_cursor) do |r end ``` -Use `saved_iterator.first_cursor` to loop over the first records. +Use `saved_iterator.first_cursor` to loop over the first records or `saved_iterator.current_cursor` to loop over the same records again. The iteration finishes when no more records are available. You can also finish iterating over the remaining records by omitting the query limit. @@ -161,7 +161,7 @@ end ## Cursors -You can use `Mongoid::Scroll::Cursor.from_record` to generate a cursor. A cursor points at the last record of the previous iteration and unlike MongoDB cursors will not expire. +You can use `Mongoid::Scroll::Cursor.from_record` to generate a cursor. A cursor points at the last record of the iteration and unlike MongoDB cursors will not expire. ```ruby record = Feed::Item.desc(:position).limit(3).last diff --git a/lib/mongo/scrollable.rb b/lib/mongo/scrollable.rb index 1f40b59..a6bed88 100644 --- a/lib/mongo/scrollable.rb +++ b/lib/mongo/scrollable.rb @@ -41,11 +41,14 @@ def scroll(cursor_or_type = nil, options = nil, &_block) # scroll if block_given? previous_cursor = nil + current_cursor = nil records.each do |record| previous_cursor ||= cursor_type.from_record(record, cursor_options.merge(type: :previous)) + current_cursor ||= cursor_type.from_record(record, cursor_options.merge(include_current: true)) iterator = Mongoid::Criteria::Scrollable::Iterator.new( previous_cursor: previous_cursor, - next_cursor: cursor_type.from_record(record, cursor_options) + next_cursor: cursor_type.from_record(record, cursor_options), + current_cursor: current_cursor ) yield record, iterator end diff --git a/lib/mongoid/criteria/scrollable.rb b/lib/mongoid/criteria/scrollable.rb index 3e89327..724074c 100644 --- a/lib/mongoid/criteria/scrollable.rb +++ b/lib/mongoid/criteria/scrollable.rb @@ -15,11 +15,14 @@ def scroll(cursor_or_type = nil, &_block) records = find_records(criteria, cursor) if block_given? previous_cursor = nil + current_cursor = nil records.each do |record| previous_cursor ||= cursor_from_record(cursor_type, record, cursor_options.merge(type: :previous)) + current_cursor ||= cursor_from_record(cursor_type, record, cursor_options.merge(include_current: true)) iterator = Mongoid::Criteria::Scrollable::Iterator.new( previous_cursor: previous_cursor, - next_cursor: cursor_from_record(cursor_type, record, cursor_options) + next_cursor: cursor_from_record(cursor_type, record, cursor_options), + current_cursor: current_cursor ) yield record, iterator end diff --git a/lib/mongoid/criteria/scrollable/iterator.rb b/lib/mongoid/criteria/scrollable/iterator.rb index 8cad507..282364e 100644 --- a/lib/mongoid/criteria/scrollable/iterator.rb +++ b/lib/mongoid/criteria/scrollable/iterator.rb @@ -2,10 +2,11 @@ module Mongoid class Criteria module Scrollable class Iterator - attr_accessor :previous_cursor, :next_cursor + attr_accessor :previous_cursor, :current_cursor, :next_cursor - def initialize(previous_cursor:, next_cursor:) + def initialize(previous_cursor:, current_cursor:, next_cursor:) @previous_cursor = previous_cursor + @current_cursor = current_cursor @next_cursor = next_cursor end diff --git a/spec/mongo/collection_view_spec.rb b/spec/mongo/collection_view_spec.rb index 323140e..6144a42 100644 --- a/spec/mongo/collection_view_spec.rb +++ b/spec/mongo/collection_view_spec.rb @@ -127,6 +127,17 @@ expect(Mongoid.default_client['feed_items'].find.sort(field_name => 1).limit(2).scroll(second_iterator.previous_cursor, field_type: field_type).to_a).to eq(records.limit(2).to_a) expect(Mongoid.default_client['feed_items'].find.sort(field_name => 1).limit(2).scroll(third_iterator.previous_cursor, field_type: field_type).to_a).to eq(records.skip(2).limit(2).to_a) end + it 'can loop over the same records with the current cursor' do + current_cursor = nil + records = Mongoid.default_client['feed_items'].find.sort(field_name => 1) + cursor = cursor_type.from_record records.skip(4).first, field_name: field_name, field_type: field_type, include_current: true + + records.limit(2).scroll(cursor, field_type: field_type) do |record, iterator| + current_cursor = iterator.current_cursor + end + + expect(records.limit(2).scroll(current_cursor, field_type: field_type).to_a).to eq(records.skip(4).limit(2).to_a) + end it 'can loop over the first records with the first cursor' do first_cursor = nil records = Mongoid.default_client['feed_items'].find.sort(field_name => 1) diff --git a/spec/mongoid/criteria_spec.rb b/spec/mongoid/criteria_spec.rb index 53f5cef..2b30853 100644 --- a/spec/mongoid/criteria_spec.rb +++ b/spec/mongoid/criteria_spec.rb @@ -181,6 +181,16 @@ expect(Feed::Item.asc(field_name).limit(2).scroll(second_iterator.previous_cursor)).to eq(records.limit(2)) expect(Feed::Item.asc(field_name).limit(2).scroll(third_iterator.previous_cursor)).to eq(records.skip(2).limit(2)) end + it 'can loop over the same records with the current cursor' do + current_cursor = nil + cursor = cursor_type.from_record Feed::Item.skip(4).first, field_name: field_name, field_type: field_type, include_current: true + + Feed::Item.asc(field_name).limit(2).scroll(cursor) do |_, iterator| + current_cursor = iterator.current_cursor + end + + expect(Feed::Item.asc(field_name).limit(2).scroll(current_cursor).to_a).to eq(Feed::Item.asc(field_name).skip(4).limit(2).to_a) + end it 'can loop over the first records with the first page cursor' do first_cursor = nil