Packages

DSpace client library for Elixir

Current section

Files

Jump to
dspace_ex lib dspace api stream_builder.ex
Raw

lib/dspace/api/stream_builder.ex

defmodule DSpace.API.StreamBuilder do
@moduledoc """
Default implementation for streaming of paginated collections from the API.
This module is usually not used directly. Streaming functionality is used through resource
modules:
items =
DSpace.API.Item.list()
|> DSpace.API.stream!(client)
# Yields: [item1, item2, item3], [item4, item5, item6], ...
"""
import DSpace.Utils, only: [is_nonempty_binary: 1]
alias DSpace.API
# Public API
@doc """
Creates a stream for paginated API responses.
## Parameters
* `client` - The `t:DSpace.API.t/0` client structure to use for the request.
* `operation` - The operation to perform, configured with a transformer that returns the
response as a tuple `{items, meta, next}` where `items` is a list of resources, `meta` is
metadata, and `next` is the URL for the next page or `nil` if there are no more pages.
* `options` - Keyword list of request options.
"""
@spec new(API.t(), struct(), keyword()) :: Enumerable.t()
def new(client, operation, options) do
Stream.resource(fn -> {operation, client, options} end, &fetch_page/1, & &1)
end
# Private helpers
@spec fetch_page({nil, client, opts}) :: {:halt, nil} when client: API.t(), opts: keyword()
@spec fetch_page({operation, client, opts}) :: {list(), {operation, client, opts}}
when operation: struct(), client: API.t(), opts: keyword()
defp fetch_page({nil, _client, _options}), do: {:halt, nil}
defp fetch_page({operation, client, options}) do
{items, _meta, next} = API.request!(operation, client, options)
if is_nonempty_binary(next) do
# `next` is already a fully built URL, so we drop the params of the initial operation
{items, {%{operation | path: next, params: []}, client, options}}
else
{items, {nil, client, options}}
end
end
end