Commit dff3ba49 authored by Andreas Brandl's avatar Andreas Brandl

Check availability of keyset pagination

We specifically only enable keyset pagination for reviewed endpoints and
order-by combinations (in this case Project and only ordering by id).
parent 879b8e84
......@@ -4,8 +4,13 @@ module API
module Helpers
module Pagination
def paginate(relation)
if params[:pagination] == "keyset"
if params[:pagination] == "keyset" && Feature.enabled?(:api_keyset_pagination)
request_context = Gitlab::Pagination::Keyset::RequestContext.new(self)
unless Gitlab::Pagination::Keyset.available?(request_context, relation)
return error!('Keyset pagination is not yet available for this type of request', 501)
end
Gitlab::Pagination::Keyset.paginate(request_context, relation)
else
Gitlab::Pagination::OffsetPagination.new(self).paginate(relation)
......
......@@ -6,6 +6,16 @@ module Gitlab
def self.paginate(request_context, relation)
Gitlab::Pagination::Keyset::Pager.new(request_context).paginate(relation)
end
def self.available?(request_context, relation)
order_by = request_context.page.order_by
# This is only available for Project and order-by id (asc/desc)
return false unless relation.klass == Project
return false unless order_by[:id]
true
end
end
end
end
......@@ -31,14 +31,26 @@ describe API::Helpers::Pagination do
let(:params) { { pagination: 'keyset' } }
let(:request_context) { double('request context') }
before do
allow(Gitlab::Pagination::Keyset::RequestContext).to receive(:new).with(subject).and_return(request_context)
allow(Gitlab::Pagination::Keyset).to receive(:available?).and_return(true)
end
it 'delegates to KeysetPagination' do
expect(Gitlab::Pagination::Keyset::RequestContext).to receive(:new).with(subject).and_return(request_context)
expect(Gitlab::Pagination::Keyset).to receive(:paginate).with(request_context, relation).and_return(expected_result)
result = subject.paginate(relation)
expect(result).to eq(expected_result)
end
it 'renders a 501 error if keyset pagination isnt available yet' do
expect(Gitlab::Pagination::Keyset).to receive(:available?).with(request_context, relation).and_return(false)
expect(Gitlab::Pagination::Keyset).not_to receive(:paginate)
expect(subject).to receive(:error!).with(/not yet available/, 501)
subject.paginate(relation)
end
end
end
end
......@@ -18,4 +18,44 @@ describe Gitlab::Pagination::Keyset do
expect(subject).to eq(result)
end
end
describe '.available?' do
subject { described_class }
let(:request_context) { double("request context", page: page)}
let(:page) { double("page", order_by: order_by) }
shared_examples_for 'keyset pagination is available' do
it 'returns true for Project' do
expect(subject.available?(request_context, Project.all)).to be_truthy
end
it 'return false for other types of relations' do
expect(subject.available?(request_context, User.all)).to be_falsey
end
end
context 'with order-by id asc' do
let(:order_by) { { id: :asc } }
it_behaves_like 'keyset pagination is available'
end
context 'with order-by id desc' do
let(:order_by) { { id: :desc } }
it_behaves_like 'keyset pagination is available'
end
context 'with other order-by columns' do
let(:order_by) { { created_at: :desc } }
it 'returns false for Project' do
expect(subject.available?(request_context, Project.all)).to be_falsey
end
it 'return false for other types of relations' do
expect(subject.available?(request_context, User.all)).to be_falsey
end
end
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