Sumup.Pagination (Sumup v1.0.0)

Copy Markdown View Source

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

Functions

Builds a lazy Stream over paginated results.

Types

fetch_fun()

@type fetch_fun() :: (state :: term() ->
                  {:ok, {items :: [term()], next_state :: term() | nil}}
                  | {:error, Sumup.Error.t()})

Functions

stream(initial_state, fetch_fun)

@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 emit items and continue with next_state
  • {:ok, {items, nil}} to emit a final page of items and stop
  • {:error, error} to halt the stream and raise a Sumup.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()