File: api-pagination.rb

package info (click to toggle)
ruby-api-pagination 4.8.2-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 272 kB
  • sloc: ruby: 1,125; makefile: 3
file content (142 lines) | stat: -rw-r--r-- 4,724 bytes parent folder | download
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
141
142
require 'api-pagination/configuration'
require 'api-pagination/version'

module ApiPagination
  class << self
    def paginate(collection, options = {})
      options[:page]     = options[:page].to_i
      options[:page]     = 1 if options[:page] <= 0
      options[:per_page] = options[:per_page].to_i

      case ApiPagination.config.paginator
      when :pagy
        paginate_with_pagy(collection, options)
      when :kaminari
        paginate_with_kaminari(collection, options, options[:paginate_array_options] || {})
      when :will_paginate
        paginate_with_will_paginate(collection, options)
      else
        raise StandardError, "Unknown paginator: #{ApiPagination.config.paginator}"
      end
    end

    def pages_from(collection, options = {})
      return pagy_pages_from(collection) if ApiPagination.config.paginator == :pagy && collection.is_a?(Pagy)

      {}.tap do |pages|
        unless collection.first_page?
          pages[:first] = 1
          pages[:prev]  = collection.current_page - 1
        end

        unless collection.last_page? || (ApiPagination.config.paginator == :kaminari && collection.out_of_range?)
          pages[:last] = collection.total_pages if ApiPagination.config.include_total
          pages[:next] = collection.current_page + 1
        end
      end
    end

    def total_from(collection)
      case ApiPagination.config.paginator
        when :pagy          then collection.count.to_s
        when :kaminari      then collection.total_count.to_s
        when :will_paginate then collection.total_entries.to_s
      end
    end

    private

    def paginate_with_pagy(collection, options)
      if Pagy::DEFAULT[:max_per_page] && options[:per_page] > Pagy::DEFAULT[:max_per_page]
        options[:per_page] = Pagy::DEFAULT[:max_per_page]
      elsif options[:per_page] <= 0
        options[:per_page] = Pagy::DEFAULT[:items]
      end

      pagy = pagy_from(collection, options)
      collection = if collection.respond_to?(:offset) && collection.respond_to?(:limit)
        collection.offset(pagy.offset).limit(pagy.items)
      else
        collection[pagy.offset, pagy.items]
      end

      return [collection, pagy]
    end

    def pagy_from(collection, options)
      if options[:count]
        count = options[:count]
      else
        count = collection.is_a?(Array) ? collection.count : collection.count(:all)
      end

      Pagy.new(count: count, items: options[:per_page], page: options[:page])
    end

    def pagy_pages_from(pagy)
      {}.tap do |pages|
        unless pagy.page == 1
          pages[:first] = 1
          pages[:prev]  = pagy.prev
        end

        unless pagy.page == pagy.pages
          pages[:last] = pagy.pages if ApiPagination.config.include_total
          pages[:next] = pagy.next
        end
      end
    end

    def paginate_with_kaminari(collection, options, paginate_array_options = {})
      if Kaminari.config.max_per_page && options[:per_page] > Kaminari.config.max_per_page
        options[:per_page] = Kaminari.config.max_per_page
      elsif options[:per_page] <= 0
        options[:per_page] = get_default_per_page_for_kaminari(collection)
      end

      collection = Kaminari.paginate_array(collection, **paginate_array_options) if collection.is_a?(Array)
      collection = collection.page(options[:page]).per(options[:per_page])
      collection.without_count if !collection.is_a?(Array) && !ApiPagination.config.include_total
      [collection, nil]
    end

    def paginate_with_will_paginate(collection, options)
      if options[:per_page] <= 0
        options[:per_page] = default_per_page_for_will_paginate(collection)
      end

      collection = if defined?(Sequel::Dataset) && collection.kind_of?(Sequel::Dataset)
        collection.paginate(options[:page], options[:per_page])
      else
        supported_options = [:page, :per_page, :total_entries]
        options = options.dup.keep_if { |k,v| supported_options.include?(k.to_sym) }
        collection.paginate(options)
      end

      [collection, nil]
    end

    def get_default_per_page_for_kaminari(collection)
      default = Kaminari.config.default_per_page
      extract_per_page_from_model(collection, :default_per_page) || default
    end

    def default_per_page_for_will_paginate(collection)
      default = WillPaginate.per_page
      extract_per_page_from_model(collection, :per_page) || default
    end

    def extract_per_page_from_model(collection, accessor)
      klass = if collection.respond_to?(:klass)
        collection.klass
      else
        collection.first.class
      end

      return unless klass.respond_to?(accessor)
      klass.send(accessor)
    end
  end
end

require 'api-pagination/hooks'