diff options
Diffstat (limited to 'lib/gitlab/pagination')
-rw-r--r-- | lib/gitlab/pagination/gitaly_keyset_pager.rb | 21 | ||||
-rw-r--r-- | lib/gitlab/pagination/offset_header_builder.rb | 65 | ||||
-rw-r--r-- | lib/gitlab/pagination/offset_pagination.rb | 54 |
3 files changed, 96 insertions, 44 deletions
diff --git a/lib/gitlab/pagination/gitaly_keyset_pager.rb b/lib/gitlab/pagination/gitaly_keyset_pager.rb index 651e3d5a807..1350168967e 100644 --- a/lib/gitlab/pagination/gitaly_keyset_pager.rb +++ b/lib/gitlab/pagination/gitaly_keyset_pager.rb @@ -15,6 +15,7 @@ module Gitlab # and supports pagination via gitaly. def paginate(finder) return paginate_via_gitaly(finder) if keyset_pagination_enabled? + return paginate_first_page_via_gitaly(finder) if paginate_first_page? branches = ::Kaminari.paginate_array(finder.execute) Gitlab::Pagination::OffsetPagination @@ -25,7 +26,11 @@ module Gitlab private def keyset_pagination_enabled? - Feature.enabled?(:branch_list_keyset_pagination, project) && params[:pagination] == 'keyset' + Feature.enabled?(:branch_list_keyset_pagination, project, default_enabled: true) && params[:pagination] == 'keyset' + end + + def paginate_first_page? + Feature.enabled?(:branch_list_keyset_pagination, project, default_enabled: true) && (params[:page].blank? || params[:page].to_i == 1) end def paginate_via_gitaly(finder) @@ -34,6 +39,20 @@ module Gitlab end end + # When first page is requested, we paginate the data via Gitaly + # Headers are added to immitate offset pagination, while it is the default option + def paginate_first_page_via_gitaly(finder) + finder.execute(gitaly_pagination: true).tap do |records| + total = project.repository.branch_count + per_page = params[:per_page].presence || Kaminari.config.default_per_page + + Gitlab::Pagination::OffsetHeaderBuilder.new( + request_context: request_context, per_page: per_page, page: 1, next_page: 2, + total: total, total_pages: total / per_page + 1 + ).execute + end + end + def apply_headers(records) if records.count == params[:per_page] Gitlab::Pagination::Keyset::HeaderBuilder diff --git a/lib/gitlab/pagination/offset_header_builder.rb b/lib/gitlab/pagination/offset_header_builder.rb new file mode 100644 index 00000000000..32089e40932 --- /dev/null +++ b/lib/gitlab/pagination/offset_header_builder.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +module Gitlab + module Pagination + class OffsetHeaderBuilder + attr_reader :request_context, :per_page, :page, :next_page, :prev_page, :total, :total_pages + + delegate :params, :header, :request, to: :request_context + + def initialize(request_context:, per_page:, page:, next_page:, prev_page: nil, total:, total_pages:) + @request_context = request_context + @per_page = per_page + @page = page + @next_page = next_page + @prev_page = prev_page + @total = total + @total_pages = total_pages + end + + def execute(exclude_total_headers: false, data_without_counts: false) + header 'X-Per-Page', per_page.to_s + header 'X-Page', page.to_s + header 'X-Next-Page', next_page.to_s + header 'X-Prev-Page', prev_page.to_s + header 'Link', pagination_links(data_without_counts) + + return if exclude_total_headers || data_without_counts + + header 'X-Total', total.to_s + header 'X-Total-Pages', total_pages.to_s + end + + private + + def pagination_links(data_without_counts) + [].tap do |links| + links << %(<#{page_href(page: prev_page)}>; rel="prev") if prev_page + links << %(<#{page_href(page: next_page)}>; rel="next") if next_page + links << %(<#{page_href(page: 1)}>; rel="first") + + links << %(<#{page_href(page: total_pages)}>; rel="last") unless data_without_counts + end.join(', ') + end + + def base_request_uri + @base_request_uri ||= URI.parse(request.url).tap do |uri| + uri.host = Gitlab.config.gitlab.host + uri.port = Gitlab.config.gitlab.port + end + end + + def build_page_url(query_params:) + base_request_uri.tap do |uri| + uri.query = query_params + end.to_s + end + + def page_href(next_page_params = {}) + query_params = params.merge(**next_page_params, per_page: params[:per_page]).to_query + + build_page_url(query_params: query_params) + end + end + end +end diff --git a/lib/gitlab/pagination/offset_pagination.rb b/lib/gitlab/pagination/offset_pagination.rb index 46c74b8fe3c..2805b12d95d 100644 --- a/lib/gitlab/pagination/offset_pagination.rb +++ b/lib/gitlab/pagination/offset_pagination.rb @@ -48,58 +48,26 @@ module Gitlab end def add_pagination_headers(paginated_data, exclude_total_headers) - header 'X-Per-Page', paginated_data.limit_value.to_s - header 'X-Page', paginated_data.current_page.to_s - header 'X-Next-Page', paginated_data.next_page.to_s - header 'X-Prev-Page', paginated_data.prev_page.to_s - header 'Link', pagination_links(paginated_data) - - return if exclude_total_headers || data_without_counts?(paginated_data) - - header 'X-Total', paginated_data.total_count.to_s - header 'X-Total-Pages', total_pages(paginated_data).to_s - end - - def pagination_links(paginated_data) - [].tap do |links| - links << %(<#{page_href(page: paginated_data.prev_page)}>; rel="prev") if paginated_data.prev_page - links << %(<#{page_href(page: paginated_data.next_page)}>; rel="next") if paginated_data.next_page - links << %(<#{page_href(page: 1)}>; rel="first") - - links << %(<#{page_href(page: total_pages(paginated_data))}>; rel="last") unless data_without_counts?(paginated_data) - end.join(', ') - end - - def total_pages(paginated_data) - # Ensure there is in total at least 1 page - [paginated_data.total_pages, 1].max + Gitlab::Pagination::OffsetHeaderBuilder.new( + request_context: self, per_page: paginated_data.limit_value, page: paginated_data.current_page, + next_page: paginated_data.next_page, prev_page: paginated_data.prev_page, + total: total_count(paginated_data), total_pages: total_pages(paginated_data) + ).execute(exclude_total_headers: exclude_total_headers, data_without_counts: data_without_counts?(paginated_data)) end def data_without_counts?(paginated_data) paginated_data.is_a?(Kaminari::PaginatableWithoutCount) end - def base_request_uri - @base_request_uri ||= URI.parse(request.url).tap do |uri| - uri.host = Gitlab.config.gitlab.host - uri.port = Gitlab.config.gitlab.port - end + def total_count(paginated_data) + paginated_data.total_count unless data_without_counts?(paginated_data) end - def build_page_url(query_params:) - base_request_uri.tap do |uri| - uri.query = query_params - end.to_s - end - - def page_href(next_page_params = {}) - query_params = params.merge(**next_page_params, per_page: per_page).to_query - - build_page_url(query_params: query_params) - end + def total_pages(paginated_data) + return if data_without_counts?(paginated_data) - def per_page - @per_page ||= params[:per_page] + # Ensure there is in total at least 1 page + [paginated_data.total_pages, 1].max end end end |