Generic, lazy pagination built on Stream.resource/3 for Monzo list
endpoints that are ordered oldest-first and support a since cursor
plus a page limit.
Summary
Functions
@spec stream( (String.t() | nil, pos_integer() -> {:ok, [item]} | {:error, term()}), (item -> String.t() | nil), keyword() ) :: Enumerable.t() when item: term()
Builds a lazy Stream that walks every page of a paginated endpoint,
yielding individual items.
fetch_page is called with since (a cursor string or nil) and
limit, and must return {:ok, items} or {:error, reason}. The last
item's cursor_fun.(item) becomes the next page's since value. A page
shorter than limit (or empty) ends the stream.
If fetch_page returns an error, the stream halts and raises that
error via Stream.resource/3's natural propagation - wrap consumption
in try/rescue or use Enum.reduce_while/3 if you need to handle
paging errors without an exception. Most callers will simply use
Enum.to_list/1, Enum.take/2, or a for comprehension.
Example
fetch_page = fn since, limit ->
Monzo.Transactions.list(client, %{account_id: account_id, since: since, limit: limit})
end
Monzo.Pagination.stream(fetch_page, &Monzo.Transaction.cursor_value/1, page_size: 100)
|> Enum.each(fn tx -> IO.inspect(tx.id) end)