class Onsi::Paginate
Pagination handles cursor pagination.
It handles setting up a cursor and ordering the query. The next cursor will be added to the response's meta object.
@example Controller
Action def index
render_resource(Onsi::Paginate.perform(person.messages, 'messages', params))
end
@author Maddie Schipper @since 1.4.0
Constants
- Result
Public Class Methods
cursor_for_query(query, type)
click to toggle source
@private
# File lib/onsi/paginate.rb, line 58 def cursor_for_query(query, type) obj = query.last return nil if obj.nil? Base64.strict_encode64([ type.to_s, obj.id.to_s ].join(':')) end
cursor_offset(query, cursor_type, cursor)
click to toggle source
@private
# File lib/onsi/paginate.rb, line 71 def cursor_offset(query, cursor_type, cursor) type, id = Base64.strict_decode64(cursor).split(':', 2) raise Onsi::Errors::PaginationError, 'invalid cursor type' unless cursor_type.to_s == type query.where(id: (id.to_i + 1)...Float::INFINITY) rescue ArgumentError => e raise e if e.message.downcase != 'invalid base64' raise Onsi::Errors::PaginationError, 'invalid cursor format' end
perform(query, type, params, options = {})
click to toggle source
Modify the query based on the pagination options
@param query [#reorder, limit, where, last] The query to modify
@param type [#to_s] The type of the pagination. This us used to verify the cursor
@param params [#fetch] The request params.
@return [Onsi::Paginate::Result]
# File lib/onsi/paginate.rb, line 31 def perform(query, type, params, options = {}) cursor_type = type.to_s cursor_param = options.fetch(:cursor_param, :cursor) max_per_page = options.fetch(:max_per_page, 100) per_page_param = options.fetch(:per_page_param, :per_page) cursor_generator = options.fetch(:cursor, lambda { |query, type| Paginate.cursor_for_query(query, type) }) cursor_offset = options.fetch(:offset, lambda { |query, type, cursor| Paginate.cursor_offset(query, type, cursor) }) order_by = options.fetch(:order_by, id: :asc) per_page = params.fetch(per_page_param, 25).to_i raise Onsi::Errors::PaginationError, "too many objects per page, max #{max_per_page}" if per_page > max_per_page query = query.reorder(order_by) query = query.limit(per_page) query = cursor_offset.call(query, cursor_type, params.fetch(cursor_param)) if params.fetch(cursor_param, nil).present? response_params = {}.tap do |rp| rp[per_page_param] = per_page value = cursor_generator.call(query, cursor_type) rp[cursor_param] = value unless value.nil? end Result.new(query, response_params) end