-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a new subclass of the `Cursor` class to encode/decode cursors using a timestamp column (such as `created_at`) as order field. It encodes the value of the field as a number with microsecond resolution (the default for MySQL). This cursor class is instantiated instead of the regular `Cursor` when an `order_field` of a compatible type is used to configure the paginator.
- Loading branch information
Showing
7 changed files
with
424 additions
and
268 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# frozen_string_literal: true | ||
|
||
module RailsCursorPagination | ||
# Cursor class that's used to uniquely identify a record and serialize and | ||
# deserialize this cursor so that it can be used for pagination. | ||
# This class expects the `order_field` of the record to be a timestamp and is | ||
# to be used only when sorting a | ||
class TimestampCursor < Cursor | ||
class << self | ||
# Decode the provided encoded cursor. Returns an instance of this | ||
# +RailsCursorPagination::Cursor+ class containing both the ID and the | ||
# ordering field value. The ordering field is expected to be a timestamp | ||
# and is always decoded in the UTC timezone. | ||
# | ||
# @param encoded_string [String] | ||
# The encoded cursor | ||
# @param order_field [Symbol] | ||
# The column that is being ordered on. It needs to be a timestamp of a | ||
# class that responds to `#strftime`. | ||
def decode(encoded_string:, order_field:) | ||
decoded = JSON.parse(Base64.strict_decode64(encoded_string)) | ||
|
||
new( | ||
id: decoded[1], | ||
order_field: order_field, | ||
order_field_value: Time.at(decoded[0].to_r / (10**6)).utc | ||
) | ||
rescue ArgumentError, JSON::ParserError | ||
raise InvalidCursorError, | ||
"The given cursor `#{encoded_string}` " \ | ||
'could not be decoded to a timestamp' | ||
end | ||
end | ||
|
||
# Encodes the cursor as an array containing the timestamp as microseconds | ||
# from UNIX epoch and the id of the object | ||
# | ||
# @return [String] | ||
def encode | ||
unless @order_field_value.respond_to?(:strftime) | ||
raise ParameterError, | ||
"Could not encode #{@order_field} " \ | ||
"with value #{@order_field_value}." \ | ||
'It does not respond to #strftime. Is it a timestamp?' | ||
end | ||
|
||
Base64.strict_encode64( | ||
[ | ||
@order_field_value.strftime('%s%6N').to_i, | ||
@id | ||
].to_json | ||
) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.