pagy 43.2.3 → 43.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/apps/calendar.ru +5 -6
  3. data/apps/demo.ru +1 -1
  4. data/apps/enable_rails_page_segment.rb +6 -2
  5. data/apps/keynav+root_key.ru +4 -5
  6. data/apps/keynav.ru +6 -7
  7. data/apps/keyset.ru +3 -5
  8. data/apps/keyset_sequel.ru +3 -5
  9. data/apps/rails.ru +3 -4
  10. data/apps/repro.ru +5 -6
  11. data/config/pagy.rb +1 -1
  12. data/javascripts/pagy.js +2 -2
  13. data/javascripts/pagy.js.map +2 -2
  14. data/javascripts/pagy.min.js +1 -1
  15. data/javascripts/pagy.mjs +1 -1
  16. data/lib/pagy/classes/calendar/calendar.rb +31 -25
  17. data/lib/pagy/classes/calendar/unit.rb +7 -4
  18. data/lib/pagy/classes/exceptions.rb +1 -0
  19. data/lib/pagy/classes/keyset/adapters/active_record.rb +3 -1
  20. data/lib/pagy/classes/keyset/adapters/sequel.rb +3 -1
  21. data/lib/pagy/classes/keyset/keynav.rb +3 -0
  22. data/lib/pagy/classes/keyset/keyset.rb +13 -17
  23. data/lib/pagy/classes/offset/countless.rb +10 -3
  24. data/lib/pagy/classes/offset/offset.rb +6 -1
  25. data/lib/pagy/classes/request.rb +10 -7
  26. data/lib/pagy/modules/abilities/configurable.rb +1 -1
  27. data/lib/pagy/modules/abilities/countable.rb +1 -0
  28. data/lib/pagy/modules/abilities/linkable.rb +19 -12
  29. data/lib/pagy/modules/abilities/rangeable.rb +0 -1
  30. data/lib/pagy/modules/b64.rb +8 -2
  31. data/lib/pagy/modules/console.rb +15 -6
  32. data/lib/pagy/modules/i18n/i18n.rb +11 -4
  33. data/lib/pagy/modules/searcher.rb +8 -4
  34. data/lib/pagy/toolbox/helpers/data_hash.rb +1 -0
  35. data/lib/pagy/toolbox/helpers/headers_hash.rb +2 -1
  36. data/lib/pagy/toolbox/helpers/info_tag.rb +2 -0
  37. data/lib/pagy/toolbox/helpers/input_nav_js.rb +1 -0
  38. data/lib/pagy/toolbox/helpers/page_url.rb +1 -0
  39. data/lib/pagy/toolbox/helpers/series_nav.rb +1 -0
  40. data/lib/pagy/toolbox/helpers/series_nav_js.rb +1 -0
  41. data/lib/pagy/toolbox/helpers/support/a_lambda.rb +1 -1
  42. data/lib/pagy/toolbox/paginators/calendar.rb +9 -6
  43. data/lib/pagy/toolbox/paginators/countish.rb +6 -3
  44. data/lib/pagy/toolbox/paginators/countless.rb +5 -2
  45. data/lib/pagy/toolbox/paginators/elasticsearch_rails.rb +12 -6
  46. data/lib/pagy/toolbox/paginators/keynav_js.rb +5 -3
  47. data/lib/pagy/toolbox/paginators/keyset.rb +2 -1
  48. data/lib/pagy/toolbox/paginators/meilisearch.rb +10 -7
  49. data/lib/pagy/toolbox/paginators/method.rb +7 -5
  50. data/lib/pagy/toolbox/paginators/offset.rb +9 -2
  51. data/lib/pagy/toolbox/paginators/searchkick.rb +12 -9
  52. data/lib/pagy.rb +1 -1
  53. metadata +1 -1
@@ -13,7 +13,7 @@ class Pagy
13
13
  autoload :Sequel, path.join('adapters/sequel')
14
14
  end
15
15
 
16
- autoload :Keynav, Pathname.new(__dir__).join('keynav')
16
+ autoload :Keynav, Pathname.new(__dir__).join('keynav')
17
17
 
18
18
  # Define empty subclasses to allow specific typing without triggering autoload
19
19
  class ActiveRecord < self; end
@@ -27,28 +27,24 @@ class Pagy
27
27
  if /::(?:ActiveRecord|Sequel)$/.match?(name)
28
28
  # Ensure the adapter is mixed in (lazy load)
29
29
  mix_in_adapter(name.split('::').last)
30
- return allocate.tap { |instance| instance.send(:initialize, set, **) }
30
+ return allocate.tap { _1.send(:initialize, set, **) }
31
31
  end
32
32
 
33
33
  # 2. Handle Factory usage (Pagy::Keyset.new)
34
- orm_name = if defined?(::ActiveRecord) && set.is_a?(::ActiveRecord::Relation)
35
- :ActiveRecord
36
- elsif defined?(::Sequel) && set.is_a?(::Sequel::Dataset)
37
- :Sequel
38
- else
39
- raise TypeError, "expected an ActiveRecord::Relation or Sequel::Dataset; got #{set.class}"
40
- end
41
-
42
- # Get the specific subclass (self::ActiveRecord)
43
- subclass = const_get(orm_name)
44
- # Ensure the adapter is mixed in (lazy load)
45
- subclass.mix_in_adapter(orm_name)
46
- subclass.new(set, **)
34
+ adapter = if defined?(::ActiveRecord) && set.is_a?(::ActiveRecord::Relation)
35
+ :ActiveRecord
36
+ elsif defined?(::Sequel) && set.is_a?(::Sequel::Dataset)
37
+ :Sequel
38
+ else
39
+ raise TypeError, "expected an ActiveRecord::Relation or Sequel::Dataset; got #{set.class}"
40
+ end
41
+
42
+ const_get(adapter).tap { _1.mix_in_adapter(adapter) }.new(set, **)
47
43
  end
48
44
 
49
45
  # Helper to lazy-include the adapter module
50
- def self.mix_in_adapter(orm_name)
51
- adapter_module = Pagy::Keyset::Adapters.const_get(orm_name)
46
+ def self.mix_in_adapter(adapter)
47
+ adapter_module = Adapters.const_get(adapter)
52
48
  include(adapter_module) unless self < adapter_module
53
49
  end
54
50
 
@@ -34,15 +34,20 @@ class Pagy
34
34
  def finalize(fetched_size)
35
35
  # empty records (trigger the right info message for known 0 count)
36
36
  @count = 0 if fetched_size.zero? && @page == 1
37
- return self unless in_range? { fetched_size.positive? || @page == 1 }
38
37
 
39
- past = @last && @page < @last # this page has been past
38
+ unless in_range? { fetched_size.positive? || @page == 1 }
39
+ assign_empty_page_variables
40
+ return self
41
+ end
42
+
43
+ past = @last && @page < @last # current page is before the known last page
40
44
  more = fetched_size > @limit # more pages after this one
41
45
  @last = upto_max_pages(more ? @page + 1 : @page) unless past && more
42
46
  @in = [fetched_size, @limit].min
43
47
  @from = @in.zero? ? 0 : @offset + 1
44
48
  @to = @offset + @in
45
49
  assign_previous_and_next
50
+
46
51
  self
47
52
  end
48
53
 
@@ -55,7 +60,9 @@ class Pagy
55
60
  end
56
61
 
57
62
  # Support easy countless page param overriding (for legacy param and behavior)
58
- def compose_page_param(page) = EscapedValue.new("#{page || 1}+#{@last}")
63
+ def compose_page_param(page)
64
+ EscapedValue.new("#{page || 1}+#{@last}")
65
+ end
59
66
  end
60
67
  end
61
68
  end
@@ -19,11 +19,16 @@ class Pagy
19
19
  assign_and_check(limit: 1, count: 0, page: 1)
20
20
  assign_last
21
21
  assign_offset
22
- return unless in_range? { @page <= @last }
22
+
23
+ unless in_range? { @page <= @last }
24
+ assign_empty_page_variables
25
+ return
26
+ end
23
27
 
24
28
  @from = [@offset + 1, @count].min
25
29
  @to = [@offset + @limit, @count].min
26
30
  @in = [@to - @from + 1, @count].min
31
+
27
32
  assign_previous_and_next
28
33
  end
29
34
 
@@ -13,6 +13,7 @@ class Pagy
13
13
  else
14
14
  [request.base_url, request.path, get_params(request), request.cookies['pagy']]
15
15
  end
16
+ freeze
16
17
  end
17
18
 
18
19
  attr_reader :base_url, :path, :params, :cookie
@@ -20,21 +21,23 @@ class Pagy
20
21
  def resolve_page(force_integer: true)
21
22
  page_key = @options[:page_key] || DEFAULT[:page_key]
22
23
  page = @params.dig(@options[:root_key], page_key) || @params[page_key]
23
- page = nil if page == '' # fix for app-generated queries like ?page=
24
- force_integer ? (page || 1).to_i : page
24
+ force_integer ? [page.to_i, 1].max : page
25
25
  end
26
26
 
27
27
  def resolve_limit
28
28
  limit_key = @options[:limit_key] || DEFAULT[:limit_key]
29
- return @options[:limit] || DEFAULT[:limit] \
30
- unless @options[:client_max_limit] &&
31
- (requested_limit = @params.dig(@options[:root_key], limit_key) || @params[limit_key])
29
+ default = @options[:limit] || DEFAULT[:limit]
30
+ max_limit = @options[:client_max_limit]
31
+ return default unless max_limit
32
32
 
33
- [requested_limit.to_i, @options[:client_max_limit]].min
33
+ limit = @params.dig(@options[:root_key], limit_key) || @params[limit_key]
34
+ limit ? [limit.to_i, max_limit].min : default
34
35
  end
35
36
 
36
37
  private
37
38
 
38
- def get_params(request) = request.GET.merge(request.POST).to_h
39
+ def get_params(request)
40
+ request.GET.merge(request.POST).to_h.freeze
41
+ end
39
42
  end
40
43
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Pagy
4
- # Add configurstion methods
4
+ # Add configuration methods
5
5
  module Configurable
6
6
  # Sync the pagy javascript targets
7
7
  def sync_javascript(destination, *targets)
@@ -17,6 +17,7 @@ class Pagy
17
17
  else
18
18
  collection.count(:all)
19
19
  end
20
+
20
21
  count.is_a?(Hash) ? count.size : count
21
22
  end
22
23
  end
@@ -38,26 +38,33 @@ class Pagy
38
38
 
39
39
  protected
40
40
 
41
- # Overriddable by classes with composite page param
41
+ # Overridable by classes with composite page param
42
42
  def compose_page_param(page) = page
43
43
 
44
44
  # Return the URL for the page, relying on the Pagy::Request
45
45
  def compose_page_url(page, **options)
46
- root_key, page_key, limit_key, client_max_limit, limit, querify, absolute, path, fragment =
47
- @options.merge(options)
48
- .values_at(:root_key, :page_key, :limit_key, :client_max_limit, :limit, :querify, :absolute, :path, :fragment)
49
- params = @request.params.clone(freeze: false)
50
- (root_key ? params[root_key] = params[root_key]&.clone(freeze: false) || {} : params).tap do |h|
51
- { page_key => compose_page_param(page),
52
- limit_key => client_max_limit && limit }.each { |k, v| v ? h[k] = v : h.delete(k) }
46
+ opts = @options.merge(options)
47
+ params = @request.params.clone(freeze: false)
48
+ root_key = opts[:root_key]
49
+ container = if root_key
50
+ params[root_key] = params[root_key]&.clone(freeze: false) || {}
51
+ else
52
+ params
53
+ end
54
+
55
+ { opts[:page_key] => compose_page_param(page),
56
+ opts[:limit_key] => opts[:client_max_limit] && opts[:limit] }.each do |k, v|
57
+ v ? container[k] = v : container.delete(k)
53
58
  end
54
- querify&.(params) # Must modify the params: the returned value is ignored
55
- fragment &&= "##{fragment.delete_prefix('#')}"
56
- compose_url(absolute, path, params, fragment)
59
+
60
+ opts[:querify]&.(params) # Must modify the params: the returned value is ignored
61
+ fragment = opts[:fragment].to_s.sub(/\A(?=[^#])/, '#') # conditionally prepend '#'
62
+
63
+ compose_url(opts[:absolute], opts[:path], params, fragment)
57
64
  end
58
65
 
59
66
  def compose_url(absolute, path, params, fragment)
60
- query_string = QueryUtils.build_nested_query(params).sub(/\A(?=.)/, '?')
67
+ query_string = QueryUtils.build_nested_query(params).sub(/\A(?=.)/, '?') # conditionally prepend '?'
61
68
  "#{@request.base_url if absolute}#{path || @request.path}#{query_string}#{fragment}"
62
69
  end
63
70
  end
@@ -9,7 +9,6 @@ class Pagy
9
9
  return true if (@in_range = yield)
10
10
  raise RangeError.new(self, :page, "in 1..#{@last}", @page) if @options[:raise_range_error]
11
11
 
12
- assign_empty_page_variables
13
12
  @in_range = false
14
13
  end
15
14
  end
@@ -5,14 +5,19 @@ class Pagy
5
5
  module B64
6
6
  module_function
7
7
 
8
- def encode(bin) = [bin].pack('m0')
8
+ def encode(bin)
9
+ [bin].pack('m0')
10
+ end
9
11
 
10
- def decode(str) = str.unpack1('m0')
12
+ def decode(str)
13
+ str.unpack1('m0')
14
+ end
11
15
 
12
16
  def urlsafe_encode(bin)
13
17
  str = encode(bin)
14
18
  str.chomp!('==') or str.chomp!('=')
15
19
  str.tr!('+/', '-_')
20
+
16
21
  str
17
22
  end
18
23
 
@@ -23,6 +28,7 @@ class Pagy
23
28
  else
24
29
  str = str.tr('-_', '+/')
25
30
  end
31
+
26
32
  decode(str)
27
33
  end
28
34
  end
@@ -9,16 +9,25 @@ class Pagy
9
9
  @collection = clone
10
10
  end
11
11
 
12
- def offset(value) = tap { @collection = self[value..] }
13
- def limit(value) = @collection[0, value]
14
- def count(*) = size
12
+ def offset(value)
13
+ tap { @collection = self[value..] }
14
+ end
15
+
16
+ def limit(value)
17
+ @collection[0, value]
18
+ end
19
+
20
+ def count(*) = size
15
21
  end
16
22
 
17
23
  include Method
18
24
 
19
- # Direct reference to request.params via a method
20
- def request = @request ||= { base_url: 'http://www.example.com', path: '/path', params: { example: '123' } }
21
- def params = request[:params]
25
+ def request
26
+ @request ||= { base_url: 'http://www.example.com', path: '/path', params: { example: '123' } }
27
+ end
28
+
29
+ def params = request[:params]
30
+
22
31
  def collection = Collection
23
32
  end
24
33
  end
@@ -8,15 +8,22 @@ class Pagy
8
8
  module I18n
9
9
  extend self
10
10
 
11
- def pathnames = @pathnames ||= [ROOT.join('locales')]
12
- def locales = @locales ||= {}
11
+ def pathnames
12
+ @pathnames ||= [ROOT.join('locales')]
13
+ end
14
+
15
+ def locales
16
+ @locales ||= {}
17
+ end
13
18
 
14
19
  # Store the variable for the duration of a single request
15
20
  def locale=(value)
16
- Thread.current[:pagy_locale] = value
21
+ Thread.current[:pagy_locale] = value.to_s
17
22
  end
18
23
 
19
- def locale = Thread.current[:pagy_locale] || 'en'
24
+ def locale
25
+ Thread.current[:pagy_locale] || 'en'
26
+ end
20
27
 
21
28
  # Translate and pluralize the key with the locale entries
22
29
  def translate(key, **options)
@@ -6,12 +6,16 @@ class Pagy
6
6
  module_function
7
7
 
8
8
  # Common search logic
9
- def wrap(pagy_search_args, options)
9
+ def wrap(search_arguments, options)
10
10
  options[:page] ||= options[:request].resolve_page
11
11
  options[:limit] = options[:request].resolve_limit
12
- pagy, results = yield
13
- calling = pagy_search_args[4..]
14
- [pagy, calling.empty? ? results : results.send(*calling)]
12
+
13
+ pagy, results = yield
14
+
15
+ arguments = search_arguments[4..]
16
+ results = results.send(*arguments) unless arguments.empty?
17
+
18
+ [pagy, results]
15
19
  end
16
20
  end
17
21
  end
@@ -9,6 +9,7 @@ class Pagy
9
9
  template = compose_page_url(PAGE_TOKEN, **)
10
10
  to_url = ->(page) { template.sub(PAGE_TOKEN, page.to_s) if page }
11
11
  data_keys -= %i[count limit] if calendar?
12
+
12
13
  data_keys.each_with_object({}) do |key, data|
13
14
  value = case key
14
15
  when :url_template then template
@@ -4,7 +4,7 @@ require_relative 'urls_hash'
4
4
 
5
5
  # Add pagination response headers
6
6
  class Pagy
7
- DEFAULT_HEADERS_MAP = { page: 'current-page',
7
+ DEFAULT_HEADERS_MAP = { page: 'current-page',
8
8
  limit: 'page-limit',
9
9
  count: 'total-count',
10
10
  pages: 'total-pages' }.freeze
@@ -12,6 +12,7 @@ class Pagy
12
12
  # Generate a hash of RFC-8288-compliant http headers
13
13
  def headers_hash(headers_map: @options[:headers_map] || DEFAULT_HEADERS_MAP, **)
14
14
  links = urls_hash(**, absolute: true).map { %(<#{_2}>; rel="#{_1}") }.join(', ')
15
+
15
16
  headers_map.each_with_object('link' => links) do |(key, name), hash|
16
17
  next unless name
17
18
 
@@ -13,6 +13,7 @@ class Pagy
13
13
  else
14
14
  'pagy.info_tag.multiple_pages'
15
15
  end
16
+
16
17
  info_data = if @count.nil?
17
18
  { page: @page, pages: @last }
18
19
  else
@@ -21,6 +22,7 @@ class Pagy
21
22
  from: @from,
22
23
  to: @to }
23
24
  end
25
+
24
26
  %(<span#{%( id="#{id}") if id} class="pagy info">#{I18n.translate(i18n_key, **info_data)}</span>)
25
27
  end
26
28
  end
@@ -13,6 +13,7 @@ class Pagy
13
13
  html = %(#{previous_tag(a_lambda)}<label>#{
14
14
  I18n.translate('pagy.input_nav_js', page_input: input, pages: @last)}</label>#{
15
15
  next_tag(a_lambda)})
16
+
16
17
  wrap_input_nav_js(html, 'pagy input-nav-js', **)
17
18
  end
18
19
  end
@@ -11,6 +11,7 @@ class Pagy
11
11
  when :last then @last
12
12
  else page
13
13
  end
14
+
14
15
  compose_page_url(target, **) if target || page == :first
15
16
  end
16
17
  end
@@ -23,6 +23,7 @@ class Pagy
23
23
  end
24
24
  end
25
25
  html << next_tag(a_lambda)
26
+
26
27
  wrap_series_nav(html, 'pagy series-nav', **)
27
28
  end
28
29
  end
@@ -13,6 +13,7 @@ class Pagy
13
13
  current: %(<a role="link" aria-current="page" aria-disabled="true">#{LABEL_TOKEN}</a>),
14
14
  gap: %(<a role="separator" aria-disabled="true">#{I18n.translate('pagy.gap')}</a>),
15
15
  after: next_tag(a_lambda) }
16
+
16
17
  wrap_series_nav_js(tokens, 'pagy series-nav-js', **)
17
18
  end
18
19
  end
@@ -13,7 +13,7 @@ class Pagy
13
13
 
14
14
  # Return a performance optimized lambda to generate the anchor tag
15
15
  # Benchmarked on a 20 link nav: it is ~22x faster and uses ~18x less memory than rails' link_to
16
- def a_lambda(anchor_string: nil, **)
16
+ def a_lambda(anchor_string: @options[:anchor_string], **)
17
17
  left, right = %(<a href="#{compose_page_url(PAGE_TOKEN, **)}"#{
18
18
  %( #{anchor_string}) if anchor_string}).split(PAGE_TOKEN, 2)
19
19
 
@@ -12,15 +12,18 @@ class Pagy
12
12
  unless config.is_a?(Hash) && (config.keys - allowed_options).empty?
13
13
 
14
14
  config[:offset] ||= {}
15
+
15
16
  unless config[:disabled]
16
- calendar, from, to =
17
- Calendar.send(:init, config,
18
- pagy_calendar_period(collection),
19
- config[:request].params) do |unit, period|
20
- pagy_calendar_counts(collection, unit, *period) if respond_to?(:pagy_calendar_counts)
21
- end
17
+ period = pagy_calendar_period(collection)
18
+ params = config[:request].params
19
+
20
+ calendar, from, to = Calendar.send(:init, config, period, params) do |unit, unit_period|
21
+ pagy_calendar_counts(collection, unit, *unit_period) if respond_to?(:pagy_calendar_counts)
22
+ end
23
+
22
24
  collection = pagy_calendar_filter(collection, from, to)
23
25
  end
26
+
24
27
  pagy, records = pagy(:offset, collection, **config[:offset])
25
28
  [calendar, pagy, records]
26
29
  end
@@ -9,26 +9,29 @@ class Pagy
9
9
  # Return the Offset::Countish instance and records
10
10
  def paginate(collection, options)
11
11
  options[:page] ||= options[:request].resolve_page(force_integer: false)
12
+
12
13
  if options[:page].is_a?(String)
13
14
  page, count, epoch = options[:page].split.map(&:to_i)
14
15
  options[:page] = page
15
16
  end
17
+
16
18
  setup_options(count, epoch, collection, options)
17
19
  options[:limit] = options[:request].resolve_limit
18
- pagy = Offset::Countish.new(**options)
20
+
21
+ pagy = Offset::Countish.new(**options)
19
22
  [pagy, pagy.records(collection)]
20
23
  end
21
24
 
22
25
  # Get the count from the page and set epoch when ttl (Time To Live) requires it
23
26
  def setup_options(count, epoch, collection, options)
24
27
  now = Time.now.to_i
28
+
25
29
  if !options[:count] && count && (!options[:ttl] ||
26
30
  (epoch && epoch <= now && now < (epoch + options[:ttl]))) # ongoing
27
- # puts 'ongoing'
28
31
  options[:count] = count
29
32
  options[:epoch] = epoch if options[:ttl]
33
+
30
34
  else # recount
31
- # puts 'recount'
32
35
  options[:count] ||= Countable.get_count(collection, options)
33
36
  options[:epoch] = now if options[:ttl]
34
37
  end
@@ -7,13 +7,16 @@ class Pagy
7
7
  # Return the Offset::Countless instance and records
8
8
  def paginate(collection, options)
9
9
  options[:page] ||= options[:request].resolve_page(force_integer: false) # accept nil and strings
10
+
10
11
  if options[:page].is_a?(String)
11
- page, last = options[:page].split.map(&:to_i) # decoded '+' added by the compose_page_url
12
+ page, last = options[:page].split.map(&:to_i) # ' ' separator, (encoded as '+' by Countless#compose_page_param)
12
13
  options[:page] = page
13
14
  options[:last] = last if last&.positive?
14
15
  end
16
+
15
17
  options[:limit] = options[:request].resolve_limit
16
- pagy = Offset::Countless.new(**options)
18
+
19
+ pagy = Offset::Countless.new(**options)
17
20
  [pagy, pagy.records(collection)]
18
21
  end
19
22
  end
@@ -8,22 +8,26 @@ class Pagy
8
8
 
9
9
  # Paginate from the search object
10
10
  def paginate(search, options)
11
- if search.is_a?(Search::Arguments)
12
- # The search is the array of pagy_search arguments
11
+ if search.is_a?(Search::Arguments) # Active mode
12
+
13
13
  Searcher.wrap(search, options) do
14
14
  model, query_or_payload, search_options = search
15
15
  search_options[:size] = options[:limit]
16
16
  search_options[:from] = options[:limit] * ((options[:page] || 1) - 1)
17
- response_object = model.send(options[:search_method] || ElasticsearchRails::DEFAULT[:search_method],
18
- query_or_payload, **search_options)
19
- options[:count] = total_count_from(response_object)
17
+
18
+ method = options[:search_method] || ElasticsearchRails::DEFAULT[:search_method]
19
+ response_object = model.send(method, query_or_payload, **search_options)
20
+ options[:count] = total_count_from(response_object)
21
+
20
22
  [ElasticsearchRails.new(**options), response_object]
21
23
  end
22
- else
24
+
25
+ else # Passive mode
23
26
  from, size = pagination_params_from(search)
24
27
  options[:limit] = size
25
28
  options[:page] = ((from || 0) / options[:limit]) + 1
26
29
  options[:count] = total_count_from(search)
30
+
27
31
  ElasticsearchRails.new(**options)
28
32
  end
29
33
  end
@@ -36,6 +40,7 @@ class Pagy
36
40
  from = (container[:from] || container['from']).to_i
37
41
  size = (container[:size] || container['size']).to_i
38
42
  size = 10 if size.zero?
43
+
39
44
  [from, size]
40
45
  end
41
46
 
@@ -44,6 +49,7 @@ class Pagy
44
49
  total = response_object.instance_eval do
45
50
  respond_to?(:response) ? response['hits']['total'] : raw_response['hits']['total']
46
51
  end
52
+
47
53
  total.is_a?(Hash) ? total['value'] : total
48
54
  end
49
55
  end
@@ -10,15 +10,17 @@ class Pagy
10
10
  # Fall back to :countless if the :page has no client data.
11
11
  def paginate(set, options)
12
12
  page = options[:request].resolve_page(force_integer: false) # allow nil
13
- if page&.match(' ') # countless page -> no augmentation -> fallback
14
- return CountlessPaginator.paginate(set, page:, **options)
15
- elsif page.is_a?(String) # keynav page param
13
+
14
+ return CountlessPaginator.paginate(set, page:, **options) if page&.match(' ') # countless fallback
15
+
16
+ if page.is_a?(String) # keynav page param
16
17
  page_arguments = JSON.parse(B64.urlsafe_decode(page))
17
18
  # Restart the pagination from page 1/nil if the url has been requested from another browser
18
19
  options[:page] = page_arguments if options[:request].cookie == page_arguments.shift
19
20
  end
20
21
 
21
22
  options[:limit] = options[:request].resolve_limit
23
+
22
24
  pagy = Keyset::Keynav.new(set, **options)
23
25
  [pagy, pagy.records]
24
26
  end
@@ -8,7 +8,8 @@ class Pagy
8
8
  def paginate(set, options)
9
9
  options[:page] ||= options[:request].resolve_page(force_integer: false) # allow nil
10
10
  options[:limit] = options[:request].resolve_limit
11
- pagy = Keyset.new(set, **options)
11
+ pagy = Keyset.new(set, **options)
12
+
12
13
  [pagy, pagy.records]
13
14
  end
14
15
  end
@@ -8,22 +8,25 @@ class Pagy
8
8
 
9
9
  # Paginate from the search object
10
10
  def paginate(search, options)
11
- if search.is_a?(Search::Arguments)
12
- # The search is the array of pagy_search arguments
11
+ if search.is_a?(Search::Arguments) # Active mode
12
+
13
13
  Searcher.wrap(search, options) do
14
14
  model, term, search_options = search
15
15
  search_options[:hits_per_page] = options[:limit]
16
16
  search_options[:page] = options[:page]
17
- results = model.send(options[:search_method] || Meilisearch::DEFAULT[:search_method],
18
- term, search_options)
19
- options[:count] = results.raw_answer['totalHits']
17
+
18
+ method = options[:search_method] || Meilisearch::DEFAULT[:search_method]
19
+ results = model.send(method, term, search_options)
20
+ options[:count] = results.raw_answer['totalHits']
21
+
20
22
  [Meilisearch.new(**options), results]
21
23
  end
22
- else
23
- # The search is a meilisearch results object
24
+
25
+ else # Passive mode
24
26
  options[:limit] = search.raw_answer['hitsPerPage']
25
27
  options[:page] = search.raw_answer['page']
26
28
  options[:count] = search.raw_answer['totalHits']
29
+
27
30
  Meilisearch.new(**options)
28
31
  end
29
32
  end
@@ -21,14 +21,16 @@ class Pagy
21
21
  protected
22
22
 
23
23
  define_method :pagy do |paginator = :offset, collection, **options|
24
- arguments = if paginator == :calendar
25
- [self, collection, options]
26
- else
27
- [collection, options = Pagy.options.merge(options)]
28
- end
24
+ arguments = if paginator == :calendar
25
+ [self, collection, options]
26
+ else
27
+ [collection, options = Pagy.options.merge(options)]
28
+ end
29
+
29
30
  options[:root_key] = 'page' if options[:jsonapi] # enforce 'page' root_key for JSON:API
30
31
  options[:request] ||= request # user set request or self.request
31
32
  options[:request] = Request.new(options) # Pagy::Request
33
+
32
34
  Pagy.const_get(paginators[paginator]).paginate(*arguments)
33
35
  end
34
36
  end