Skip to content

Commit

Permalink
Reorganize the keyset docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ddnexus committed Jul 23, 2024
1 parent a455d79 commit 76ffd63
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 26 deletions.
58 changes: 36 additions & 22 deletions docs/api/keyset.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,63 +47,79 @@ less convenient for UIs.

### Keyset or Offset pagination?

+++ Keyset
!!!success Use Keyset pagination with large dataset and API
You will get the fastest pagination, regardless the table size and the relative position of the page

!!!warning Limited use for UIs
Only useful when you don't need any frontend (e.g. infinite pagination)
!!!

+++ Offset
!!!success Use Offset pagination with UIs even with large datasets
- You will get all the frontend features
- It will be easier to maintain because it requires almost no knowledge of SQL
- You can avoid the slowness on big tables by simply limiting the `:max_pages` pages: the users would not browse thousands of
records deep into your collection anyway

!!!warning Limited use for APIs
Your server will suffer on big data and your API will be slower for no good reasons
!!!
+++

## Overview

Pagy Keyset pagination does not waste resources and code complexity checking your set and your table config at every request.

That means that you have to be sure that your set is `uniquely ordered` and that your tables have the right indexes (for
performance). You do it once during development, and pagy will be fast at each request. ;)

!!!success Quick Tip: Order by primary key for instant success
If you don't have any particular order requirements, `order(:id)` is the best choice, because it's unique and already indexed.
!!!
## Usage

### Constraints

!!!warning With the keyset pagination technique...
- You don't know the record count nor the page count
- You cannot jump to an arbitrary page (no numbereed pages)
- You can only paginate from one page to the next (in either directions)
- You can only paginate from one page to the next: no jumping to arbitrary pages
- The `set` must be `uniquely ordered`. Add the primary key (usually `:id`) as the last order column to be sure
- You should add the best DB index for your ordering strategy for performance. The keyset pagination would work even without
any index, but that would defeat its purpose (performance).
!!!
!!!

!!!warning With Pagy::Keyset...
You don't know the `previous` and the `last` page, you only know the `first` and `next` pages, for performance and simplicity

!!!success
If you want to paginate backward like: `last` ... `prev` ... `prev` ... just call `reverse_order` on your set and go forward
like: `first` ... `next` ... `next` ... It does exactly the same: just faster and simpler.
If you want to paginate backward like: `last` ... `prev` ... `prev` ... just call `reverse_order` on your set and go forward
like: `first` ... `next` ... `next` ... It does exactly the same: just faster and simpler.
!!!

## How Pagy::Keyset works
### Setup

Pagy Keyset pagination does not waste resources and code complexity checking your set and your table config at every request.

That means that you have to be sure that your set is `uniquely ordered` and that your tables have the right indexes.

**You do it once during development, and pagy will be fast at each request.**

Depending on your order requirements, here is how you set it up:

+++ No order requirements
!!!success
If you don't need any ordering, `order(:id)` is the simplest choice, because it's unique and already indexed. It works fast out of the box without any setup.
!!!

+++ Specific order requirements
!!!success
If you need a specific order:
- **In order to make it work**...<br/>
Ensure that at least one of your ordered columns is unique OR append your primary keys to your order
- **In order to make it fast**...<br/>
Ensure to create a unique composite DB index, including the exact same columns and ordering direction of your set
!!!
+++

### How Pagy::Keyset works

- You pass an `uniquely ordered` `set` and `Pagy::Keyset` queries the page of records.
- It keeps track of the `latest` fetched ecord by encoding its `keyset` attributes into the `page` query string param of the
- It keeps track of the `latest` fetched record by encoding its `keyset` attributes into the `page` query string param of the
`next` URL.
- At each request, the `:page` is decoded and used to prepare a `when` clause that filters out the records already fetched, and
the `:limit` of requested records is pulled.
- You know that you reached the end of the collection when `pagy.next.nil?`.

### ORMs
## ORMs

`Pagy::Keyset` implements the subclasses for `ActiveRecord::Relation` and `Sequel::Dataset` sets and instantiate them internally:

Expand Down Expand Up @@ -192,8 +208,6 @@ Pagy::Keyset(set, typecast_latest:)

!!!danger Your set is not `uniquely ordered`

Pagy does not check if your set is `uniquely ordered` (read why in the [overview](#overview))

```rb
# Neither columns are unique
Product.order(:name, :production_date)
Expand Down
4 changes: 0 additions & 4 deletions docs/extras/keyset.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ pagy_keyset_next_url_page(@pagy)
#=> "/foo?page=eyJpZCI6MzB9"
```

!!!success Quick Tip: Order by primary key for instant success
If you don't have any particular order requirements, `order(:id)` is the best choice, because it's unique and already indexed.
!!!

## Variables

See the [Pagy::Keyset variables](/docs/api/keyset.md#variables)
Expand Down

0 comments on commit 76ffd63

Please sign in to comment.