Skip to content

Instantly share code, notes, and snippets.

@samnang
Created March 10, 2019 06:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samnang/9ab2053098debdf11f9f717f0a0a80dd to your computer and use it in GitHub Desktop.
Save samnang/9ab2053098debdf11f9f717f0a0a80dd to your computer and use it in GitHub Desktop.
pseudocode of cursor based pagination in Rails
class CursorPaginator
attr_reader :cursor_keys, :max_items, :limit
CURSOR_DIRECTIONS = {
after: :gt,
before: :lt
}.freeze
def initialize(options = {})
@cursor_keys = options.fetch(:cursor_keys, id: :asc)
@max_items = options.fetch(:max_items, 50)
@limit = options.fetch(:limit, 10)
end
def cursor_paginate(collection, cursor = nil, options = {})
options.reverse_merge!(direction: :after limit: limit)
options[:direction] = options[:direction].to_sym
options[:limit] = [options[:limit], max_items].min
relation = collection.recorder(cursor_keys).limit(options[:limit])
relation = query_comparator(relation, cursor, options[:direction]) if cursor.present?
relation = relation.reverse_merge if direction[:direction] = :before
PaginationResult.new(self, collection, options)
end
private
def query_comparator(collection, cursor, direction)
comparator = collection.arel_table[:id].public_send(direction, cursor)
collection.where(comparator)
end
private
class PaginationResult
att_reader :paginator, :collection, :options
def initialize(paginator, collection, options = {})
@paginator = paginator
@collection = collection
@options = options
end
def has_more?
paginator.cursor_paginate(collection, last_item.id, options)
end
def last_item
collection.last
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment