Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
ddnexus committed Aug 20, 2021
2 parents bedb2d6 + a8d592b commit b941ab3
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 44 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# CHANGELOG

## Version 4.11.0

### Changes

- added countless_minimal feature
- added missing deprecation to countless class
- doc improvements

### Commits

- [5103ee9](http://github.com/ddnexus/pagy/commit/5103ee9): added countless_minimal feature
- [ed6bc0b](http://github.com/ddnexus/pagy/commit/ed6bc0b): added missing deprecation to countless class
- [bedb2d6](http://github.com/ddnexus/pagy/commit/bedb2d6): Fix - link directly to docs [ci-skip] (#328)
- [74aa300](http://github.com/ddnexus/pagy/commit/74aa300): Remove minor extra parenthesis in trim docs [ci-skip] (#326)
- [f8b96eb](http://github.com/ddnexus/pagy/commit/f8b96eb): docs - add links directly to docs page [ci-skip] (#324)

## Version 4.10.2

### Changes
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
pagy (4.10.2)
pagy (4.11.0)

GEM
remote: https://rubygems.org/
Expand Down
6 changes: 3 additions & 3 deletions docs/api/countless.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ The `pagy_info` and all the `*_combo_nav_js` helpers that use the total `count`

Instead of basing all the internal calculations on the `:count` variable (passed with the constructor), this class uses the number of actually retrieved items to deduce the pagination variables.

The retrieved items number is passed in a second step with the `finalize` method, and it allows to determine if there is a `next` page, or if the current page is the `last` page, or if the current request should raise a `Pagy::OverflowError` exception.

The trick is retrieving `items + 1`, and using the resulting number to calculate the variables, while eventually removing the extra item from the result. (see the [countless.rb extra](https://github.com/ddnexus/pagy/blob/master/lib/pagy/extras/countless.rb))
The retrieved items number can be passed in a second step to the `finalize` method, wich allows to determine if there is a `next` page, or if the current page is the `last` page, or if the current request should raise a `Pagy::OverflowError` exception.
Retrieving these variables may be useful to supply a UI as complete as possible, when used with classic helpers, and can be skipped when it's not needed (like for navless pagination, infinite-scroll, etc.). See the [countless.rb extra](https://github.com/ddnexus/pagy/blob/master/lib/pagy/extras/countless.rb) for more details.

## Methods

Expand Down
51 changes: 41 additions & 10 deletions docs/extras/countless.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ title: Countless
---
# Countless Extra

This extra uses the `Pagy::Countless` subclass in order to avoid to execute an otherwise needed count query. It is especially useful when used with large DB tables, where [Caching the count](../how-to.md#caching-the-count) may not be an option.

Its usage is practically the same as the regular `Pagy::Backend` module (see the [backend doc](../api/backend.md)).

The pagination resulting from this extra has some limitation as documented in the [Pagy::Countless Caveats doc](../api/countless.md#caveats).
This extra uses the `Pagy::Countless` subclass in order to save one count query per request. It is especially useful when used with large DB tables, where [Caching the count](../how-to.md#caching-the-count) may not be an option, or when there is no need to have a classic UI. Please read also the [Pagy::Countless doc](../api/countless.md) for a full understanding of its features and limitations.

## Synopsis

Expand All @@ -17,13 +13,51 @@ In the `pagy.rb` initializer:

```ruby
require 'pagy/extras/countless'
# optionally enable the minimal mode by default
# Pagy::VARS[:countless_minimal] = true
```

In a controller:

```ruby
@pagy, @records = pagy_countless(some_scope, ...)
# default mode (eager loading)
@pagy, @records = pagy_countless(some_scope, ...)

# OR
# enable minimal mode for this instance (lazy loading)
@pagy, @records = pagy_countless(some_scope, countless_minimal: true, ...)
```

## Modes
This extra can be used in two different modes by enabling or not the `:countless_minimal` variable.

### Default mode

This is the preferred automatic way to save one query per request, while keep using the classic pagination UI helpers.

By default this extra will try to finalize the `pagy` object with all the available variables in a countless pagination. It will do so by retrieving `items + 1`, and using the resulting number to calculate the variables, while eventually removing the extra item from the result.

That means:

- The `pagy` object will know whether the current page is the last one or there will be a next page so you can use it right away with any supported helper
- The returned paginated collection (`@records`) will be an `Array` instead of a scope (so the records are already eager-loaded from the DB)

### Minimal mode

This is the preferred mode used to implement navless and automatic incremental/infinite-scroll pagination, where there is no need to use any UI.

If you enable the `:countless_minimal` variable, then:

- The returned `pagy` object will contain just a handful of variables and will miss the finalization, so you cannnot use it with any helpers
- The returned paginated collection (`@records`) will be a regular scope (i.e. no record has been load yet) so an eventual fragment caching can work as expected
- You will need to check the size of the paginated collection (`@records`) in order to know if it is the last page or not. You can tell if it by checking `@records.size < @pagy.vars[:items]`. Notice that IF the last page has exactly the `@pagy.vars[:items]` in it you will not be able to know it. In infinite scroll that would just try to load the next page returning 0 items, so it will be perfectly acceptable anyway.

## Variables

| Variable | Description | Default |
|:---------------------|:----------------------------------|:--------|
| `:countless_minimal` | enable the countless minimal mode | `false` |

## Files

Expand All @@ -35,7 +69,7 @@ All the methods in this module are prefixed with the `"pagy_countless"` string,

### pagy_countless(collection, vars=nil)

This method is the same as the generic `pagy` method. (see the [pagy doc](../api/backend.md#pagycollection-varsnil))
This method is the same as the generic `pagy` method (see the [pagy doc](../api/backend.md#pagycollection-varsnil)), however its returned objects will depend on the value of the `:countless_minimal` variable (see [Modes](#modes))

### pagy_countless_get_vars(_collection, vars)

Expand All @@ -44,6 +78,3 @@ This sub-method is similar to the `pagy_get_vars` sub-method, but it is called o
### pagy_countless_get_items(collection, pagy)

This sub-method is similar to the `pagy_get_items` sub-method, but it is called only by the `pagy_countless` method. (see the [pagy_get_items doc](../api/backend.md#pagy_get_itemscollection-pagy)).

**Notice**: This method calls `to_a` on the collection in order to `pop` the eventual extra item from the result, so it returns an `Array`. That's different than the regular `pagy_get_items` method which doesn't need to call `to_a` on the collection.

3 changes: 2 additions & 1 deletion lib/config/pagy.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

# Pagy initializer file (4.10.2)
# Pagy initializer file (4.11.0)
# Customize only what you really need and notice that Pagy works also without any of the following lines.
# Should you just cherry pick part of this file, please maintain the require-order of the extras

Expand Down Expand Up @@ -42,6 +42,7 @@
# Countless extra: Paginate without any count, saving one query per rendering
# See https://ddnexus.github.io/pagy/extras/countless
# require 'pagy/extras/countless'
# Pagy::VARS[:countless_minimal] = false # default (eager loading)

# Elasticsearch Rails extra: Paginate `ElasticsearchRails::Results` objects
# See https://ddnexus.github.io/pagy/extras/elasticsearch_rails
Expand Down
2 changes: 1 addition & 1 deletion lib/javascripts/pagy.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

function Pagy(){}

Pagy.version = '4.10.2'
Pagy.version = '4.11.0'

Pagy.delay = 100

Expand Down
2 changes: 1 addition & 1 deletion lib/pagy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

# main class
class Pagy
VERSION = '4.10.2'
VERSION = '4.11.0'

# Root pathname to get the path of Pagy files like templates or dictionaries
def self.root
Expand Down
2 changes: 2 additions & 0 deletions lib/pagy/countless.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class Countless < Pagy
# Merge and validate the options, do some simple arithmetic and set a few instance variables
def initialize(vars={}) # rubocop:disable Lint/MissingSuper
@vars = VARS.merge(vars.delete_if{|_,v| v.nil? || v == '' }) # default vars + cleaned vars (can be overridden)
@vars[:fragment] = Pagy.deprecated_var(:anchor, @vars[:anchor], :fragment, @vars[:fragment]) if @vars[:anchor]

INSTANCE_VARS_MIN.each do |k,min| # validate instance variables
raise VariableError.new(self), "expected :#{k} >= #{min}; got #{@vars[k].inspect}" \
unless @vars[k] && instance_variable_set(:"@#{k}", @vars[k].to_i) >= min
Expand Down
6 changes: 5 additions & 1 deletion lib/pagy/extras/countless.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

class Pagy

VARS[:countless_minimal] = false

module Backend
private # the whole module is private so no problem with including it in a controller

Expand All @@ -17,13 +19,15 @@ def pagy_countless(collection, vars={})
# Sub-method called only by #pagy_countless: here for easy customization of variables by overriding
def pagy_countless_get_vars(_collection, vars)
pagy_set_items_from_params(vars) if defined?(UseItemsExtra)
vars[:page] ||= params[ vars[:page_param] || VARS[:page_param] ]
vars[:page] ||= params[ vars[:page_param] || VARS[:page_param] ]
vars
end

# Sub-method called only by #pagy_countless: here for easy customization of record-extraction by overriding
def pagy_countless_get_items(collection, pagy)
# This should work with ActiveRecord, Sequel, Mongoid...
return collection.offset(pagy.offset).limit(pagy.items) if pagy.vars[:countless_minimal]

items = collection.offset(pagy.offset).limit(pagy.items + 1).to_a
items_size = items.size
items.pop if items_size == pagy.items + 1
Expand Down
53 changes: 27 additions & 26 deletions test/pagy/extras/metadata_test.rb.rematch
Original file line number Diff line number Diff line change
@@ -1,30 +1,4 @@
---
"[1] pagy/extras/metadata::#pagy_metadata#test_0004_returns only specific metadata":
:scaffold_url: "/foo?page=__pagy_page__"
:page: 3
:count: 1000
:prev: 2
:next: 4
:pages: 50
"[1] pagy/extras/metadata::#pagy_metadata#test_0001_defines all metadata":
- :scaffold_url
- :first_url
- :prev_url
- :page_url
- :next_url
- :last_url
- :count
- :page
- :items
- :vars
- :pages
- :last
- :from
- :to
- :prev
- :next
- :series
- :sequels
"[1] pagy/extras/metadata::#pagy_metadata#test_0002_returns the full pagy metadata":
:scaffold_url: "/foo?page=__pagy_page__"
:first_url: "/foo?page=1"
Expand All @@ -50,6 +24,7 @@
:link_extra: ''
:i18n_key: pagy.item_name
:cycle: false
:countless_minimal: false
:steps: false
:metadata:
- :scaffold_url
Expand Down Expand Up @@ -98,3 +73,29 @@
- 7
- :gap
- 50
"[1] pagy/extras/metadata::#pagy_metadata#test_0001_defines all metadata":
- :scaffold_url
- :first_url
- :prev_url
- :page_url
- :next_url
- :last_url
- :count
- :page
- :items
- :vars
- :pages
- :last
- :from
- :to
- :prev
- :next
- :series
- :sequels
"[1] pagy/extras/metadata::#pagy_metadata#test_0004_returns only specific metadata":
:scaffold_url: "/foo?page=__pagy_page__"
:page: 3
:count: 1000
:prev: 2
:next: 4
:pages: 50

0 comments on commit b941ab3

Please sign in to comment.