File: pagination.rb

package info (click to toggle)
ruby-sequel 5.63.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 10,408 kB
  • sloc: ruby: 113,747; makefile: 3
file content (140 lines) | stat: -rw-r--r-- 4,592 bytes parent folder | download | duplicates (2)
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