Class: RailsCursorPagination::Cursor

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_cursor_pagination/cursor.rb

Overview

Cursor class that’s used to uniquely identify a record and serialize and deserialize this cursor so that it can be used for pagination.

Direct Known Subclasses

TimestampCursor

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id:, order_field: :id, order_field_value: nil) ⇒ Cursor

Initializes the record

Parameters:

  • id (Integer)

    The ID of the cursor record

  • order_field (Symbol) (defaults to: :id)

    The column or virtual column for ordering

  • order_field_value (Object) (defaults to: nil)

    Optional. The value that the order_field of the record contains in case that the order field is not the ID

Raises:



70
71
72
73
74
75
76
77
78
79
80
# File 'lib/rails_cursor_pagination/cursor.rb', line 70

def initialize(id:, order_field: :id, order_field_value: nil)
  @id = id
  @order_field = order_field
  @order_field_value = order_field_value

  return if !custom_order_field? || !order_field_value.nil?

  raise ParameterError, 'The `order_field` was set to ' \
                        "`#{@order_field.inspect}` but " \
                        'no `order_field_value` was set'
end

Instance Attribute Details

#idObject (readonly)

Returns the value of attribute id.



9
10
11
# File 'lib/rails_cursor_pagination/cursor.rb', line 9

def id
  @id
end

#order_field_valueObject (readonly)

Returns the value of attribute order_field_value.



9
10
11
# File 'lib/rails_cursor_pagination/cursor.rb', line 9

def order_field_value
  @order_field_value
end

Class Method Details

.decode(encoded_string:, order_field: :id) ⇒ RailsCursorPagination::Cursor

Decode the provided encoded cursor. Returns an instance of this RailsCursorPagination::Cursor class containing either just the cursor’s ID or in case of pagination on any other field, containing both the ID and the ordering field value.

Parameters:

  • encoded_string (String)

    The encoded cursor

  • order_field (Symbol) (defaults to: :id)

    Optional. The column that is being ordered on in case it’s not the ID column

Returns:



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/rails_cursor_pagination/cursor.rb', line 37

def decode(encoded_string:, order_field: :id)
  decoded = JSON.parse(Base64.strict_decode64(encoded_string))
  if order_field == :id
    if decoded.is_a?(Array)
      raise InvalidCursorError,
            "The given cursor `#{encoded_string}` was decoded as " \
            "`#{decoded}` but could not be parsed"
    end
    new(id: decoded, order_field: :id)
  else
    unless decoded.is_a?(Array) && decoded.size == 2
      raise InvalidCursorError,
            "The given cursor `#{encoded_string}` was decoded as " \
            "`#{decoded}` but could not be parsed"
    end
    new(id: decoded[1], order_field: order_field,
        order_field_value: decoded[0])
  end
rescue ArgumentError, JSON::ParserError
  raise InvalidCursorError,
        "The given cursor `#{encoded_string}` could not be decoded"
end

.from_record(record:, order_field: :id) ⇒ Cursor

Generate a cursor for the given record and ordering field. The cursor encodes all the data required to then paginate based on it with the given ordering field.

Parameters:

  • record (ActiveRecord)

    Model instance for which we want the cursor

  • order_field (Symbol) (defaults to: :id)

    Column or virtual column of the record that the relation is ordered by

Returns:



21
22
23
24
# File 'lib/rails_cursor_pagination/cursor.rb', line 21

def from_record(record:, order_field: :id)
  new(id: record.id, order_field: order_field,
      order_field_value: record[order_field])
end

Instance Method Details

#encodeString

Generate an encoded string for this cursor. The cursor encodes all the data required to then paginate based on it with the given ordering field.

If we only order by ID, the cursor doesn’t need to include any other data. But if we order by any other field, the cursor needs to include both the value from this other field as well as the records ID to resolve the order of duplicates in the non-ID field.

Returns:

  • (String)


91
92
93
94
95
96
97
98
99
# File 'lib/rails_cursor_pagination/cursor.rb', line 91

def encode
  unencoded_cursor =
    if custom_order_field?
      [@order_field_value, @id]
    else
      @id
    end
  Base64.strict_encode64(unencoded_cursor.to_json)
end