Welcome to mirror list, hosted at ThFree Co, Russian Federation.

request_context.rb « keyset « pagination « gitlab « lib - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 070fa844347c8937351335b2fc9525c43613ac13 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# 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)
          link = pagination_links(next_page)
          request.header('Links', link)
          request.header('Link', link)
        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