# A simple paginator based on page numbers. # # Example: http://example.com/api/users/?page=3&page_size=50 class RESTFramework::Paginators::PageNumberPaginator < RESTFramework::Paginators::BasePaginator def initialize(**kwargs) super # Exclude any `select` clauses since that would cause `count` to fail with a SQL `SyntaxError`. @count = @data.except(:select).count @page_size = self._page_size @total_pages = @count / @page_size @total_pages += 1 if @count % @page_size != 0 end def _page_size page_size = nil # Get from context, if allowed. if @controller.page_size_query_param if page_size = @controller.params[@controller.page_size_query_param].presence page_size = page_size.to_i end end # Otherwise, get from config. if !page_size && @controller.page_size page_size = @controller.page_size end # Ensure we don't exceed the max page size. if @controller.max_page_size && page_size > @controller.max_page_size page_size = @controller.max_page_size end # Ensure we return at least 1. return page_size.zero? ? 1 : page_size end # Get the page and return it so the caller can serialize it. def get_page(page_number=nil) # If page number isn't provided, infer from the params or use 1 as a fallback value. unless page_number page_number = @controller&.params&.[](@controller.page_query_param&.to_sym) if page_number.blank? page_number = 1 else page_number = page_number.to_i if page_number.zero? page_number = 1 end end end @page_number = page_number # Get the data page and return it so the caller can serialize the data in the proper format. page_index = @page_number - 1 return @data.limit(@page_size).offset(page_index * @page_size) end # Wrap the serialized page with appropriate metadata. TODO: include links. def get_paginated_response(serialized_page) return { count: @count, page: @page_number, page_size: @page_size, total_pages: @total_pages, results: serialized_page, } end end # Alias for convenience. RESTFramework::PageNumberPaginator = RESTFramework::Paginators::PageNumberPaginator