Current section

Files

Jump to
retort lib retort client stream.ex
Raw

lib/retort/client/stream.ex

defmodule Retort.Client.Stream do
@moduledoc """
Streams the resources from all the pages available on an `Retort.Client.index/3`.
"""
alias Alembic.Pagination
alias Alembic.Pagination.Page
alias Retort.Client
# CONSTANTS
@default_timeout 5000
# Struct
defstruct pagination: nil,
params: %{},
pid: nil,
timeout: @default_timeout
# Types
@typedoc """
The internal state of stream produced by `new/3`.
* `params` - the params passed to `Retort.Client.index/3`. After the initial call, `"page[number]"`
and `"page[size]"` will be overridden with the `Alembic.Pagination.t` `next` `Alembic.Pagination.Page.t` `number`
and `size`.
* `pid` - the `pid` of an `Retort.Client`
* `timeout` - the timeout for each `Retort.Client.index/3` call
"""
@type t :: %__MODULE__{
pagination: Pagination.t,
params: map,
pid: pid,
timeout: timeout
}
# Functions
@doc """
A new stream of `pid`'s `Retort.Client.index/3` starting with the given `params` and `timeout` for
each request.
"""
@spec new(pid) :: Enumerable.t
@spec new(pid, map) :: Enumerable.t
@spec new(pid, map, timeout) :: Enumerable.t
def new(pid, params \\ %{}, timeout \\ @default_timeout) when is_pid(pid) and is_map(params) do
Elixir.Stream.resource(
fn -> %__MODULE__{params: params, pid: pid, timeout: timeout} end,
&page/1,
fn _ -> :ok end
)
end
## Private Functions
### next
# pagination not supported
defp next(state = %__MODULE__{}, nil), do: next(state, %Pagination{next: nil})
# pagination supplies next page
defp next(state = %__MODULE__{}, pagination = %Pagination{}), do: %{state | pagination: pagination}
### page
# no next page: the previous page was the last page
defp page(state = %__MODULE__{pagination: %Pagination{next: nil}}) do
{:halt, state}
end
# first through last page
defp page(state = %__MODULE__{pagination: pagination, params: params, pid: pid, timeout: timeout}) do
{:ok, resources, pagination} = Client.Generic.index(pid, page_params(params, pagination), timeout)
{resources, next(state, pagination)}
end
### page_params
# first page
defp page_params(params, nil), do: params
# second through last page
defp page_params(params, %Pagination{next: next_page = %Page{}}), do: Map.merge(params, Page.to_params(next_page))
end