Created
March 10, 2019 06:18
-
-
Save samnang/9ab2053098debdf11f9f717f0a0a80dd to your computer and use it in GitHub Desktop.
pseudocode of cursor based pagination in Rails
This file contains hidden or 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
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