1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
# frozen-string-literal: true
#
# The pagination extension adds the Sequel::Dataset#paginate and #each_page methods,
# which return paginated (limited and offset) datasets with the following methods
# added that make creating a paginated display easier:
#
# * +page_size+
# * +page_count+
# * +page_range+
# * +current_page+
# * +next_page+
# * +prev_page+
# * +first_page?+
# * +last_page?+
# * +pagination_record_count+
# * +current_page_record_count+
# * +current_page_record_range+
#
# This extension uses Object#extend at runtime, which can hurt performance.
#
# You can load this extension into specific datasets:
#
# ds = DB[:table]
# ds = ds.extension(:pagination)
#
# Or you can load it into all of a database's datasets, which
# is probably the desired behavior if you are using this extension:
#
# DB.extension(:pagination)
#
# Related modules: Sequel::DatasetPagination, Sequel::Dataset::Pagination
#
module Sequel
module DatasetPagination
# Returns a paginated dataset. The returned dataset is limited to
# the page size at the correct offset, and extended with the Pagination
# module. If a record count is not provided, does a count of total
# number of records for this dataset.
def paginate(page_no, page_size, record_count=nil)
raise(Error, "You cannot paginate a dataset that already has a limit") if @opts[:limit]
record_count ||= count
page_count = (record_count / page_size.to_f).ceil
page_count = 1 if page_count == 0
limit(page_size, (page_no - 1) * page_size).
with_extend(Dataset::Pagination).
clone(:page_size=>page_size, :current_page=>page_no, :pagination_record_count=>record_count, :page_count=>page_count)
end
# Yields a paginated dataset for each page and returns the receiver. Does
# a count to find the total number of records for this dataset. Returns
# an enumerator if no block is given.
def each_page(page_size)
raise(Error, "You cannot paginate a dataset that already has a limit") if @opts[:limit]
return to_enum(:each_page, page_size) unless defined?(yield)
record_count = count
total_pages = (record_count / page_size.to_f).ceil
(1..total_pages).each{|page_no| yield paginate(page_no, page_size, record_count)}
self
end
end
class Dataset
# Holds methods that only relate to paginated datasets. Paginated dataset
# have pages starting at 1 (page 1 is offset 0, page 2 is offset 1 * page_size).
module Pagination
# The number of records per page (the final page may have fewer than
# this number of records).
def page_size
@opts[:page_size]
end
# The number of pages in the dataset before pagination, of which
# this paginated dataset is one. Empty datasets are considered
# to have a single page.
def page_count
@opts[:page_count]
end
# The current page of the dataset, starting at 1 and not 0.
def current_page
@opts[:current_page]
end
# The total number of records in the dataset before pagination.
def pagination_record_count
@opts[:pagination_record_count]
end
# Returns the record range for the current page
def current_page_record_range
return (0..0) if current_page > page_count
a = 1 + (current_page - 1) * page_size
b = a + page_size - 1
b = pagination_record_count if b > pagination_record_count
a..b
end
# Returns the number of records in the current page
def current_page_record_count
return 0 if current_page > page_count
a = 1 + (current_page - 1) * page_size
b = a + page_size - 1
b = pagination_record_count if b > pagination_record_count
b - a + 1
end
# Returns true if the current page is the first page
def first_page?
current_page == 1
end
# Returns true if the current page is the last page
def last_page?
current_page == page_count
end
# Returns the next page number or nil if the current page is the last page
def next_page
current_page < page_count ? (current_page + 1) : nil
end
# Returns the page range
def page_range
1..page_count
end
# Returns the previous page number or nil if the current page is the first
def prev_page
current_page > 1 ? (current_page - 1) : nil
end
end
end
Dataset.register_extension(:pagination, DatasetPagination)
end
|