Commit eb1db88f authored by Aleksei Lipniagov's avatar Aleksei Lipniagov

Merge branch 'keyset-iterator-pass-cursor' into 'master'

Allow passing the cursor to Keyset::Iterator

See merge request gitlab-org/gitlab!71292
parents 304003f2 0db7486e
...@@ -6,10 +6,11 @@ module Gitlab ...@@ -6,10 +6,11 @@ module Gitlab
class Iterator class Iterator
UnsupportedScopeOrder = Class.new(StandardError) UnsupportedScopeOrder = Class.new(StandardError)
def initialize(scope:, use_union_optimization: true, in_operator_optimization_options: nil) def initialize(scope:, cursor: {}, use_union_optimization: true, in_operator_optimization_options: nil)
@scope, success = Gitlab::Pagination::Keyset::SimpleOrderBuilder.build(scope) @scope, success = Gitlab::Pagination::Keyset::SimpleOrderBuilder.build(scope)
raise(UnsupportedScopeOrder, 'The order on the scope does not support keyset pagination') unless success raise(UnsupportedScopeOrder, 'The order on the scope does not support keyset pagination') unless success
@cursor = cursor
@order = Gitlab::Pagination::Keyset::Order.extract_keyset_order_object(scope) @order = Gitlab::Pagination::Keyset::Order.extract_keyset_order_object(scope)
@use_union_optimization = in_operator_optimization_options ? false : use_union_optimization @use_union_optimization = in_operator_optimization_options ? false : use_union_optimization
@in_operator_optimization_options = in_operator_optimization_options @in_operator_optimization_options = in_operator_optimization_options
...@@ -17,11 +18,9 @@ module Gitlab ...@@ -17,11 +18,9 @@ module Gitlab
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def each_batch(of: 1000) def each_batch(of: 1000)
cursor_attributes = {}
loop do loop do
current_scope = scope.dup current_scope = scope.dup
relation = order.apply_cursor_conditions(current_scope, cursor_attributes, keyset_options) relation = order.apply_cursor_conditions(current_scope, cursor, keyset_options)
relation = relation.reorder(order) unless @in_operator_optimization_options relation = relation.reorder(order) unless @in_operator_optimization_options
relation = relation.limit(of) relation = relation.limit(of)
...@@ -30,14 +29,14 @@ module Gitlab ...@@ -30,14 +29,14 @@ module Gitlab
last_record = relation.last last_record = relation.last
break unless last_record break unless last_record
cursor_attributes = order.cursor_attributes_for_node(last_record) @cursor = order.cursor_attributes_for_node(last_record)
end end
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
private private
attr_reader :scope, :order attr_reader :scope, :cursor, :order
def keyset_options def keyset_options
{ {
......
...@@ -32,8 +32,11 @@ RSpec.describe Gitlab::Pagination::Keyset::Iterator do ...@@ -32,8 +32,11 @@ RSpec.describe Gitlab::Pagination::Keyset::Iterator do
]) ])
end end
let(:iterator_params) { nil }
let(:scope) { project.issues.reorder(custom_reorder) } let(:scope) { project.issues.reorder(custom_reorder) }
subject(:iterator) { described_class.new(**iterator_params) }
shared_examples 'iterator examples' do shared_examples 'iterator examples' do
describe '.each_batch' do describe '.each_batch' do
it 'yields an ActiveRecord::Relation when a block is given' do it 'yields an ActiveRecord::Relation when a block is given' do
...@@ -56,6 +59,30 @@ RSpec.describe Gitlab::Pagination::Keyset::Iterator do ...@@ -56,6 +59,30 @@ RSpec.describe Gitlab::Pagination::Keyset::Iterator do
expect(count).to eq(9) expect(count).to eq(9)
end end
it 'continues after the cursor' do
loaded_records = []
cursor = nil
# stopping the iterator after the first batch and storing the cursor
iterator.each_batch(of: 2) do |relation| # rubocop: disable Lint/UnreachableLoop
loaded_records.concat(relation.to_a)
record = loaded_records.last
cursor = custom_reorder.cursor_attributes_for_node(record)
break
end
expect(loaded_records).to eq(project.issues.order(custom_reorder).take(2))
# continuing the iteration
new_iterator = described_class.new(**iterator_params.merge(cursor: cursor))
new_iterator.each_batch(of: 2) do |relation|
loaded_records.concat(relation.to_a)
end
expect(loaded_records).to eq(project.issues.order(custom_reorder))
end
it 'allows updating of the yielded relations' do it 'allows updating of the yielded relations' do
time = Time.current time = Time.current
...@@ -131,13 +158,13 @@ RSpec.describe Gitlab::Pagination::Keyset::Iterator do ...@@ -131,13 +158,13 @@ RSpec.describe Gitlab::Pagination::Keyset::Iterator do
end end
context 'when use_union_optimization is used' do context 'when use_union_optimization is used' do
subject(:iterator) { described_class.new(scope: scope, use_union_optimization: true) } let(:iterator_params) { { scope: scope, use_union_optimization: true } }
include_examples 'iterator examples' include_examples 'iterator examples'
end end
context 'when use_union_optimization is not used' do context 'when use_union_optimization is not used' do
subject(:iterator) { described_class.new(scope: scope, use_union_optimization: false) } let(:iterator_params) { { scope: scope, use_union_optimization: false } }
include_examples 'iterator examples' include_examples 'iterator examples'
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment