Skip to content

Commit

Permalink
Add a cursor for the current page. (#43)
Browse files Browse the repository at this point in the history
* Add a cursor for the current page.

* add a line in CHANGELOG

* fix Changelog

* add for mongo view

* Update CHANGELOG.md

Co-authored-by: Daniel (dB.) Doubrovkine <[email protected]>

* minor change

* try to fix specs on CI

* Update README.md

Co-authored-by: Daniel (dB.) Doubrovkine <[email protected]>

* remove extra spaces in the README

---------

Co-authored-by: Daniel (dB.) Doubrovkine <[email protected]>
  • Loading branch information
GCorbel and dblock authored Sep 4, 2024
1 parent a725ea5 commit 5f41285
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion lib/mongo/scrollable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion lib/mongoid/criteria/scrollable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions lib/mongoid/criteria/scrollable/iterator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
11 changes: 11 additions & 0 deletions spec/mongo/collection_view_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 10 additions & 0 deletions spec/mongoid/criteria_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit 5f41285

Please sign in to comment.