2020-01-01 13:55:28 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module Gitlab
|
|
|
|
module Pagination
|
|
|
|
module Keyset
|
|
|
|
class RequestContext
|
|
|
|
attr_reader :request
|
|
|
|
|
|
|
|
DEFAULT_SORT_DIRECTION = :desc
|
|
|
|
PRIMARY_KEY = :id
|
|
|
|
|
|
|
|
# A tie breaker is added as an additional order-by column
|
|
|
|
# to establish a well-defined order. We use the primary key
|
|
|
|
# column here.
|
|
|
|
TIE_BREAKER = { PRIMARY_KEY => DEFAULT_SORT_DIRECTION }.freeze
|
|
|
|
|
|
|
|
def initialize(request)
|
|
|
|
@request = request
|
|
|
|
end
|
|
|
|
|
|
|
|
# extracts Paging information from request parameters
|
|
|
|
def page
|
|
|
|
@page ||= Page.new(order_by: order_by, per_page: params[:per_page])
|
|
|
|
end
|
|
|
|
|
|
|
|
def apply_headers(next_page)
|
2020-06-23 00:09:42 +05:30
|
|
|
link = pagination_links(next_page)
|
|
|
|
request.header('Links', link)
|
|
|
|
request.header('Link', link)
|
2020-01-01 13:55:28 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def order_by
|
|
|
|
return TIE_BREAKER.dup unless params[:order_by]
|
|
|
|
|
|
|
|
order_by = { params[:order_by].to_sym => params[:sort]&.to_sym || DEFAULT_SORT_DIRECTION }
|
|
|
|
|
|
|
|
# Order by an additional unique key, we use the primary key here
|
|
|
|
order_by = order_by.merge(TIE_BREAKER) unless order_by[PRIMARY_KEY]
|
|
|
|
|
|
|
|
order_by
|
|
|
|
end
|
|
|
|
|
|
|
|
def params
|
|
|
|
@params ||= request.params
|
|
|
|
end
|
|
|
|
|
|
|
|
def lower_bounds_params(page)
|
|
|
|
page.lower_bounds.each_with_object({}) do |(column, value), params|
|
|
|
|
filter = filter_with_comparator(page, column)
|
|
|
|
params[filter] = value
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def filter_with_comparator(page, column)
|
|
|
|
direction = page.order_by[column]
|
|
|
|
|
|
|
|
if direction&.to_sym == :desc
|
|
|
|
"#{column}_before"
|
|
|
|
else
|
|
|
|
"#{column}_after"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def page_href(page)
|
|
|
|
base_request_uri.tap do |uri|
|
|
|
|
uri.query = query_params_for(page).to_query
|
|
|
|
end.to_s
|
|
|
|
end
|
|
|
|
|
|
|
|
def pagination_links(next_page)
|
|
|
|
%(<#{page_href(next_page)}>; rel="next")
|
|
|
|
end
|
|
|
|
|
|
|
|
def base_request_uri
|
|
|
|
@base_request_uri ||= URI.parse(request.request.url).tap do |uri|
|
|
|
|
uri.host = Gitlab.config.gitlab.host
|
|
|
|
uri.port = Gitlab.config.gitlab.port
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def query_params_for(page)
|
|
|
|
request.params.merge(lower_bounds_params(page))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|