Class: Gitlab::Pagination::Keyset::Paginator

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/gitlab/pagination/keyset/paginator.rb

Defined Under Namespace

Modules: Base64CursorConverter

Constant Summary collapse

FORWARD_DIRECTION =
'n'
BACKWARD_DIRECTION =
'p'

Instance Method Summary collapse

Constructor Details

#initialize(scope:, cursor: nil, per_page: 20, cursor_converter: Base64CursorConverter, direction_key: :_kd, keyset_order_options: {}) ⇒ Paginator

scope - ActiveRecord::Relation object with order by clause cursor - Encoded cursor attributes as String. Empty value will requests the first page. per_page - Number of items per page. cursor_converter - Object that serializes and de-serializes the cursor attributes. Implements dump and parse methods. direction_key - Symbol that will be the hash key of the direction within the cursor. (default: _kd => keyset direction)



27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/gitlab/pagination/keyset/paginator.rb', line 27

def initialize(scope:, cursor: nil, per_page: 20, cursor_converter: Base64CursorConverter, direction_key: :_kd, keyset_order_options: {})
  @keyset_scope = build_scope(scope)
  @order = Gitlab::Pagination::Keyset::Order.extract_keyset_order_object(@keyset_scope)
  @per_page = per_page
  @cursor_converter = cursor_converter
  @direction_key = direction_key
  @has_another_page = false
  @at_last_page = false
  @at_first_page = false
  @cursor_attributes = decode_cursor_attributes(cursor)
  @keyset_order_options = keyset_order_options

  set_pagination_helper_flags!
end

Instance Method Details

#cursor_for_first_pageObject



108
109
110
# File 'lib/gitlab/pagination/keyset/paginator.rb', line 108

def cursor_for_first_page
  cursor_converter.dump({ direction_key => FORWARD_DIRECTION })
end

#cursor_for_last_pageObject



112
113
114
# File 'lib/gitlab/pagination/keyset/paginator.rb', line 112

def cursor_for_last_page
  cursor_converter.dump({ direction_key => BACKWARD_DIRECTION })
end

#cursor_for_next_pageObject



92
93
94
95
96
97
98
# File 'lib/gitlab/pagination/keyset/paginator.rb', line 92

def cursor_for_next_page
  if has_next_page?
    data = order.cursor_attributes_for_node(records.last)
    data[direction_key] = FORWARD_DIRECTION
    cursor_converter.dump(data)
  end
end

#cursor_for_previous_pageObject



100
101
102
103
104
105
106
# File 'lib/gitlab/pagination/keyset/paginator.rb', line 100

def cursor_for_previous_page
  if has_previous_page?
    data = order.cursor_attributes_for_node(records.first)
    data[direction_key] = BACKWARD_DIRECTION
    cursor_converter.dump(data)
  end
end

#has_next_page?Boolean

This and has_previous_page? methods are direction aware. In case we paginate backwards, has_next_page? will mean that we have a previous page.

Returns:

  • (Boolean)


68
69
70
71
72
73
74
75
76
77
78
# File 'lib/gitlab/pagination/keyset/paginator.rb', line 68

def has_next_page?
  records

  if at_last_page?
    false
  elsif paginate_forward?
    @has_another_page
  elsif paginate_backward?
    true
  end
end

#has_previous_page?Boolean

Returns:

  • (Boolean)


80
81
82
83
84
85
86
87
88
89
90
# File 'lib/gitlab/pagination/keyset/paginator.rb', line 80

def has_previous_page?
  records

  if at_first_page?
    false
  elsif paginate_backward?
    @has_another_page
  elsif paginate_forward?
    true
  end
end

#recordsObject

rubocop: disable CodeReuse/ActiveRecord



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/gitlab/pagination/keyset/paginator.rb', line 43

def records
  @records ||= begin
    items = if paginate_backward?
              reversed_order
                .apply_cursor_conditions(keyset_scope, cursor_attributes, keyset_order_options)
                .reorder(reversed_order)
                .limit(per_page_plus_one)
                .to_a
            else
              order
                .apply_cursor_conditions(keyset_scope, cursor_attributes, keyset_order_options)
                .limit(per_page_plus_one)
                .to_a
            end

    @has_another_page = items.size == per_page_plus_one
    items.pop if @has_another_page
    items.reverse! if paginate_backward?
    items
  end
end