Generic lazy pagination built on Stream.resource/3, used by every
resource module that exposes a list_all/2-style function (e.g.
Sumup.Transactions.list_all/2, Sumup.Members.list_all/2).
SumUp itself is inconsistent about how it paginates: Transactions use
opaque ref cursors (newest_ref / oldest_ref), while some list
endpoints use limit/offset. This module doesn't care which scheme a
given resource uses — it just repeatedly calls a fetch_fun you provide
until it signals there's nothing left, and lazily streams the
concatenated items.
Summary
Types
@type fetch_fun() :: (state :: term() -> {:ok, {items :: [term()], next_state :: term() | nil}} | {:error, Sumup.Error.t()})
Functions
@spec stream(term(), fetch_fun()) :: Enumerable.t()
Builds a lazy Stream over paginated results.
initial_state is whatever your fetch_fun needs to make its first
call (often nil). fetch_fun is called with the current state and
must return:
{:ok, {items, next_state}}to emititemsand continue withnext_state{:ok, {items, nil}}to emit a final page ofitemsand stop{:error, error}to halt the stream and raise aSumup.RequestError
Example
Sumup.Pagination.stream(nil, fn cursor ->
with {:ok, %{"items" => items} = page} <-
Sumup.Transactions.list(config, oldest_ref: cursor) do
next = if items == [], do: nil, else: page["links"]["next_ref"]
{:ok, {items, next}}
end
end)
|> Stream.take(500)
|> Enum.to_list()