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



115
116
117
# File 'lib/gitlab/pagination/keyset/paginator.rb', line 115

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

#cursor_for_last_pageObject



119
120
121
# File 'lib/gitlab/pagination/keyset/paginator.rb', line 119

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

#cursor_for_next_pageObject



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

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



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

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)


75
76
77
78
79
80
81
82
83
84
85
# File 'lib/gitlab/pagination/keyset/paginator.rb', line 75

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)


87
88
89
90
91
92
93
94
95
96
97
# File 'lib/gitlab/pagination/keyset/paginator.rb', line 87

def has_previous_page?
  records

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

#keyset_relationObject

rubocop: disable CodeReuse/ActiveRecord – This is a reusable module. Defining these scopes on the model would encourage duplication.



59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/gitlab/pagination/keyset/paginator.rb', line 59

def keyset_relation
  if paginate_backward?
    reversed_order
      .apply_cursor_conditions(keyset_scope, cursor_attributes, keyset_order_options)
      .reorder(reversed_order)
      .limit(per_page_plus_one)
  else
    order
      .apply_cursor_conditions(keyset_scope, cursor_attributes, keyset_order_options)
      .limit(per_page_plus_one)
  end
end

#recordsObject



42
43
44
45
46
47
48
49
50
51
# File 'lib/gitlab/pagination/keyset/paginator.rb', line 42

def records
  @records ||= begin
    items = keyset_relation.to_a

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

#to_sqlObject



53
54
55
# File 'lib/gitlab/pagination/keyset/paginator.rb', line 53

def to_sql
  keyset_relation.to_sql
end