module PgORM::Pagination(T)

Overview

Pagination module providing offset-based and cursor-based pagination.

Offset-Based Pagination

Traditional page-number based pagination. Easy to use but can be slow for large datasets or high page numbers.

# Page 2, 20 records per page
result = User.paginate(page: 2, limit: 20)

# Or use offset directly
result = User.paginate_by_offset(offset: 40, limit: 20)

Cursor-Based Pagination

More efficient for large datasets. Uses a cursor (usually the primary key) to fetch the next/previous page.

# First page
result = User.order(:id).paginate_cursor(limit: 20)

# Next page
result = User.order(:id).paginate_cursor(after: cursor, limit: 20)

Direct including types

Defined in:

pg-orm/pagination.cr

Instance Method Summary

Instance Method Detail

def paginate(page : Int32 = 1, limit : Int32 = 25) : PaginatedResult(T) #

Paginates results using page number (1-indexed).

This is the most common pagination method. It calculates the offset automatically based on the page number and limit.

Parameters

  • page: Page number (1-indexed, defaults to 1)
  • limit: Records per page (defaults to 25)

Example

# Get page 2 with 20 records per page
result = Article.where(published: true).paginate(page: 2, limit: 20)

# With ordering
result = Article.order(:created_at).paginate(page: 1, limit: 10)

# Works with joins (uses DISTINCT count automatically)
result = Article.join(:left, Comment, :article_id).paginate(page: 1, limit: 10)

# Access metadata
puts "Page #{result.page} of #{result.total_pages}"
puts "Showing #{result.from}-#{result.to} of #{result.total}"

# Iterate records
result.records.each do |article|
  puts article.title
end

Returns a PaginatedResult with records and metadata.


[View source]
def paginate_by_offset(offset : Int32 = 0, limit : Int32 = 25) : PaginatedResult(T) #

Paginates results using offset and limit directly.

Use this when you want to control the offset manually instead of using page numbers. Useful for custom pagination logic.

Parameters

  • offset: Number of records to skip (defaults to 0)
  • limit: Number of records to return (defaults to 25)

Example

# Skip first 40 records, get next 20
result = Article.paginate_by_offset(offset: 40, limit: 20)

# Custom pagination logic
offset = calculate_custom_offset()
result = Article.paginate_by_offset(offset: offset, limit: 20)

Returns a PaginatedResult with records and metadata.


[View source]
def paginate_cursor(after : String | Nil = nil, before : String | Nil = nil, limit : Int32 = 25, cursor_column : Symbol = :id) : CursorPaginatedResult(T) #

Cursor-based pagination for efficient large dataset traversal.

This method uses a cursor (typically the primary key) to fetch pages without using OFFSET, making it much more efficient for large datasets.

Parameters

  • after: Cursor to fetch records after (for next page)
  • before: Cursor to fetch records before (for previous page)
  • limit: Number of records to return (defaults to 25)
  • cursor_column: Column to use as cursor (defaults to :id)

Example

# First page
result = Article.order(:id).paginate_cursor(limit: 20)

result.records.each { |article| puts article.title }

# Next page using cursor from previous result
if result.has_next?
  next_result = Article.order(:id).paginate_cursor(
    after: result.next_cursor,
    limit: 20
  )
end

# Previous page using cursor
if result.has_prev?
  prev_result = Article.order(:id).paginate_cursor(
    before: result.prev_cursor,
    limit: 20
  )
end

# Custom cursor column
result = Article.order(:created_at).paginate_cursor(
  limit: 20,
  cursor_column: :created_at
)

Important Notes

  • Always use .order() with the same column as cursor_column
  • The cursor column should be indexed for performance
  • Don't use both after and before at the same time

Returns a CursorPaginatedResult with records and cursor metadata.


[View source]