Module: Philiprehberger::Pagination

Defined in:
lib/philiprehberger/pagination.rb,
lib/philiprehberger/pagination/page.rb,
lib/philiprehberger/pagination/version.rb

Defined Under Namespace

Classes: Error, InvalidCursorError, InvalidPageSizeError, Page

Constant Summary collapse

DEFAULT_PER_PAGE =
25
VERSION =
'0.6.0'

Class Method Summary collapse

Class Method Details

.each_page(collection, strategy: :offset, per_page: DEFAULT_PER_PAGE, **opts) {|page| ... } ⇒ Enumerator?

Iterate every page of a collection in order, yielding each Page.

Drives paginate repeatedly using the previous page’s ‘next_cursor` (or next page number for offset strategy) until there are no further pages. Returns an Enumerator if no block is given. Useful for batch-processing idioms (export, ETL, slow report generation) where callers would otherwise have to thread cursors by hand.

Parameters:

  • collection (Array, #to_a)

    the collection to paginate

  • strategy (Symbol) (defaults to: :offset)

    :offset, :cursor, or :keyset

  • per_page (Integer) (defaults to: DEFAULT_PER_PAGE)

    items per page

  • opts (Hash)

    additional keyword args forwarded to paginate

Yields:

  • (page)

    each Page in order

Returns:

  • (Enumerator, nil)


64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/philiprehberger/pagination.rb', line 64

def self.each_page(collection, strategy: :offset, per_page: DEFAULT_PER_PAGE, **opts)
  unless block_given?
    return to_enum(:each_page, collection, strategy: strategy, per_page: per_page, **opts)
  end

  first_args = opts.dup
  page = paginate(collection, strategy: strategy, per_page: per_page, **first_args)
  yield page

  while page.has_next?
    loop_args = opts.dup
    if strategy.to_sym == :offset
      loop_args[:page] = page.current_page + 1
    else
      loop_args[:cursor] = page.next_cursor
    end
    page = paginate(collection, strategy: strategy, per_page: per_page, **loop_args)
    yield page
  end

  nil
end

.paginate(collection, strategy: :offset, per_page: DEFAULT_PER_PAGE, cursor: nil, page: nil, max_per_page: nil, min_per_page: nil, secret: nil) ⇒ Page

Paginate a collection using the specified strategy.

Parameters:

  • collection (Array, #to_a)

    the collection to paginate

  • strategy (Symbol) (defaults to: :offset)

    :offset, :cursor, or :keyset

  • per_page (Integer) (defaults to: DEFAULT_PER_PAGE)

    items per page

  • cursor (String, nil) (defaults to: nil)

    cursor for cursor-based pagination

  • page (Integer, nil) (defaults to: nil)

    page number for offset-based pagination

  • max_per_page (Integer, nil) (defaults to: nil)

    maximum allowed per_page value

  • min_per_page (Integer, nil) (defaults to: nil)

    minimum allowed per_page value

  • secret (String, nil) (defaults to: nil)

    HMAC secret for cursor signing (cursor/keyset strategies)

Returns:

  • (Page)

    the paginated result

Raises:



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/philiprehberger/pagination.rb', line 30

def self.paginate(collection, strategy: :offset, per_page: DEFAULT_PER_PAGE, cursor: nil, page: nil,
                  max_per_page: nil, min_per_page: nil, secret: nil)
  per_page = per_page.to_i
  validate_page_size!(per_page, min_per_page: min_per_page, max_per_page: max_per_page)
  per_page = [per_page, 1].max

  items = collection.to_a

  case strategy.to_sym
  when :offset
    paginate_offset(items, per_page: per_page, page: page)
  when :cursor
    paginate_cursor(items, per_page: per_page, cursor: cursor, secret: secret)
  when :keyset
    paginate_keyset(items, per_page: per_page, cursor: cursor, secret: secret)
  else
    raise Error, "unknown strategy: #{strategy}"
  end
end