# Fob

![Actions CI](

A minimalistic keyset pagination library for Ecto queries

**N.B.**: you probably don't want to use Fob. Fob makes a number of assumptions
about the queries passed to it, such as:

- they'll be run against a modern PostgreSQL database
    - fob uses the `-infinity` and `infinity` features of PostgreSQL
- each schema will have only one primary key
- each query must be ordered by at least the schema's primary key
- the primary keys is always the final ordering condition
- associations are untested and probably do not work

## Usage

Fob works primarily by composing Ecto queries with `Ecto.Query.where/3` and
`Ecto.Query.limit/2`. In general, the tracking of page breaks is left to any
consuming library/application, but Fob provides a convenience tool which it
uses internally for easy testing: `Fob.Cursor`.

A `Fob.Cursor` is a similar idea to a standard elixir `Stream` except that it
does not represent an active connection to a resource (some but not all Elixir
`Stream`s open a process or port and therefore represent a connection to
resource. This disallows some functionality which is desirable for Fob, such
as [`Stream.split/2`](

With the cursor, you may walk through the pages of a dataset with
`` and take multiple pages with `Fob.Cursor.split/2`

iex> alias Fob.Cursor
iex> import Ecto.Query, only: [order_by: 2]
iex> cursor =, asc: :id), MyApp.Repo, _initial_pagination = nil, _page_size = 3)
iex> {_records, cursor} =
{[%{id: 1}, %{id: 2}, %{id: 3}], #Fob.Cursor<...>}
iex> {_records, cursor} =
{[%{id: 4}, %{id: 5}, %{id: 6}], #Fob.Cursor<...>}
iex> {_records, cursor} = Cursor.split(cursor, 2)
{[%{id: 7}, %{id: 8}, %{id: 9}, %{id: 10}, %{id: 11}, %{id: 12}], #Fob.Cursor<...>}

## Why?

Why build an incomplete and minimal keyset pagination
library when there are already workable implementations in
[Paginator]( and
[Quarto]( Fob was originally cut
out of another library called Haste which we intend on open sourcing soon.
In our setup, Haste only uses postgres and satisfies the above assumptions.

## Installation

def deps do
    {:fob, "~> 0.1"}

Check out the docs here: