Shell layer cursor encoding/decoding for cursor-based pagination.
SIDE EFFECTS:
Cursors are opaque tokens that encode:
Format: Base64(JSON({:id ... :sort-value ... :sort-field ... :sort-direction ...}))
Shell layer cursor encoding/decoding for cursor-based pagination.
SIDE EFFECTS:
- JSON encoding/decoding
- Base64 encoding/decoding
- Exception throwing on invalid cursors
Cursors are opaque tokens that encode:
- Item ID (for stable ordering)
- Sort field value (for comparison)
- Sort direction (asc/desc)
- Optional timestamp (for expiry)
Format: Base64(JSON({:id ... :sort-value ... :sort-field ... :sort-direction ...}))(create-cursor item sort-field sort-direction)(create-cursor item sort-field sort-direction include-timestamp?)Create cursor data from an item.
Helper function to extract cursor data from a paginated item.
Args: item - Map containing the item data sort-field - Keyword of field used for sorting sort-direction - :asc or :desc include-timestamp? - (optional) Include cursor creation timestamp (default: false)
Returns: Cursor data map ready for encoding
Side Effects:
Example: (create-cursor {:id #uuid "123..." :created-at #inst "2024-01-04" :name "Alice"} :created-at :desc true) ;;=> {:id #uuid "123..." ;; :sort-value #inst "2024-01-04" ;; :sort-field "created-at" ;; :sort-direction :desc ;; :timestamp #inst "2024-01-04T12:00:00Z"}
Create cursor data from an item.
Helper function to extract cursor data from a paginated item.
Args:
item - Map containing the item data
sort-field - Keyword of field used for sorting
sort-direction - :asc or :desc
include-timestamp? - (optional) Include cursor creation timestamp (default: false)
Returns:
Cursor data map ready for encoding
Side Effects:
- Current time retrieval (if include-timestamp? is true)
Example:
(create-cursor
{:id #uuid "123..." :created-at #inst "2024-01-04" :name "Alice"}
:created-at
:desc
true)
;;=> {:id #uuid "123..."
;; :sort-value #inst "2024-01-04"
;; :sort-field "created-at"
;; :sort-direction :desc
;; :timestamp #inst "2024-01-04T12:00:00Z"}(cursor-expired? cursor-data ttl-seconds)Check if cursor has expired based on TTL.
Args: cursor-data - Decoded cursor data with :timestamp ttl-seconds - Time-to-live in seconds
Returns: Boolean - true if cursor is expired, false otherwise
Side Effects:
Example: (cursor-expired? {:id #uuid "..." :timestamp #inst "2024-01-04T10:00:00Z" ...} 3600) ; 1 hour TTL ;;=> false (if current time is within 1 hour of timestamp)
Check if cursor has expired based on TTL.
Args:
cursor-data - Decoded cursor data with :timestamp
ttl-seconds - Time-to-live in seconds
Returns:
Boolean - true if cursor is expired, false otherwise
Side Effects:
- Current time retrieval
Example:
(cursor-expired?
{:id #uuid "..." :timestamp #inst "2024-01-04T10:00:00Z" ...}
3600) ; 1 hour TTL
;;=> false (if current time is within 1 hour of timestamp)(decode-cursor cursor-str)Decode Base64 cursor string to cursor data.
Takes an opaque cursor token and returns structured data for pagination.
Args: cursor-str - Base64-encoded cursor string
Returns: Map with keys: :id - UUID of the item :sort-value - Value of the sort field :sort-field - Name of field used for sorting :sort-direction - :asc or :desc :timestamp - (optional) Instant when cursor was created
Side Effects:
Example: (decode-cursor "eyJpZCI6IjEyM2U0NTY3LWU4OWItMTJkMy1hNDU2LTQyNjYxNDE3NDAwMCI...") ;;=> {:id #uuid "123e4567-e89b-12d3-a456-426614174000" ;; :sort-value #inst "2024-01-04T10:00:00Z" ;; :sort-field "created_at" ;; :sort-direction :desc ;; :timestamp #inst "2024-01-04T12:00:00Z"}
Throws: ex-info with :type :invalid-cursor if:
Decode Base64 cursor string to cursor data.
Takes an opaque cursor token and returns structured data for pagination.
Args:
cursor-str - Base64-encoded cursor string
Returns:
Map with keys:
:id - UUID of the item
:sort-value - Value of the sort field
:sort-field - Name of field used for sorting
:sort-direction - :asc or :desc
:timestamp - (optional) Instant when cursor was created
Side Effects:
- Base64 decoding
- JSON parsing
- Logging
Example:
(decode-cursor "eyJpZCI6IjEyM2U0NTY3LWU4OWItMTJkMy1hNDU2LTQyNjYxNDE3NDAwMCI...")
;;=> {:id #uuid "123e4567-e89b-12d3-a456-426614174000"
;; :sort-value #inst "2024-01-04T10:00:00Z"
;; :sort-field "created_at"
;; :sort-direction :desc
;; :timestamp #inst "2024-01-04T12:00:00Z"}
Throws:
ex-info with :type :invalid-cursor if:
- Cursor is not valid Base64
- Cursor does not contain valid JSON
- Cursor is missing required fields
- Cursor contains invalid data types(encode-cursor cursor-data)Encode cursor data to Base64 string.
Takes structured cursor data and returns an opaque Base64-encoded token suitable for pagination.
Args: cursor-data - Map with keys: :id - UUID of the item :sort-value - Value of the sort field (any type) :sort-field - Name of field used for sorting :sort-direction - :asc or :desc :timestamp - (optional) Instant when cursor was created
Returns: Base64-encoded cursor string (opaque token)
Side Effects:
Example: (encode-cursor {:id #uuid "123e4567-e89b-12d3-a456-426614174000" :sort-value #inst "2024-01-04T10:00:00Z" :sort-field "created_at" :sort-direction :desc :timestamp #inst "2024-01-04T12:00:00Z"}) ;;=> "eyJpZCI6IjEyM2U0NTY3LWU4OWItMTJkMy1hNDU2LTQyNjYxNDE3NDAwMCI..."
Throws: ex-info if encoding fails
Encode cursor data to Base64 string.
Takes structured cursor data and returns an opaque Base64-encoded token
suitable for pagination.
Args:
cursor-data - Map with keys:
:id - UUID of the item
:sort-value - Value of the sort field (any type)
:sort-field - Name of field used for sorting
:sort-direction - :asc or :desc
:timestamp - (optional) Instant when cursor was created
Returns:
Base64-encoded cursor string (opaque token)
Side Effects:
- JSON encoding
- Base64 encoding
- Logging
Example:
(encode-cursor
{:id #uuid "123e4567-e89b-12d3-a456-426614174000"
:sort-value #inst "2024-01-04T10:00:00Z"
:sort-field "created_at"
:sort-direction :desc
:timestamp #inst "2024-01-04T12:00:00Z"})
;;=> "eyJpZCI6IjEyM2U0NTY3LWU4OWItMTJkMy1hNDU2LTQyNjYxNDE3NDAwMCI..."
Throws:
ex-info if encoding fails(valid-cursor? cursor-str)Check if cursor string is valid without throwing.
Attempts to decode the cursor and returns true if successful.
Args: cursor-str - Base64-encoded cursor string
Returns: Boolean - true if cursor is valid, false otherwise
Side Effects:
Example: (valid-cursor? "eyJpZCI6IjEyM2U0NTY3...") ;;=> true
(valid-cursor? "invalid-cursor") ;;=> false
Check if cursor string is valid without throwing. Attempts to decode the cursor and returns true if successful. Args: cursor-str - Base64-encoded cursor string Returns: Boolean - true if cursor is valid, false otherwise Side Effects: - Cursor decoding (if successful) - Logging Example: (valid-cursor? "eyJpZCI6IjEyM2U0NTY3...") ;;=> true (valid-cursor? "invalid-cursor") ;;=> false
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |