defmodule PipeHelpers.Flow do
def new() do
{:ok, %{}}
end
def start(name, fun) do
start(name, %{}, fun)
end
def start(name, init, fun) do
then_ok({:ok, init}, name, fun)
end
def then_ok({:ok, state}, name, fun) do
if Map.has_key?(state, name) do
raise ArgumentError, message: "name #{name} is already used in flow"
end
fun
|> Function.info()
|> Keyword.get(:arity)
|> case do
0 -> fun.()
1 -> fun.(state)
_ -> raise "then_ok function arity can only be 0 or 1"
end
|> case do
{:ok, val} ->
if is_nil(name) do
state
else
Map.put(state, name, val)
end
|> PipeHelpers.ok()
{:error, e} ->
{:error, state, name, e}
e ->
{:error, state, name, e}
end
end
def then_ok(result, _, _fun), do: result
def tap_ok(result, fun) do
then_ok(result, nil, fun)
result
end
def map_ok({:ok, state}, fun) do
fun
|> Function.info()
|> Keyword.get(:arity)
|> case do
0 -> fun.()
1 -> fun.(state)
_ -> raise "then_ok function arity can only be 0 or 1"
end
end
def map_ok(result, _fun), do: result
def finish({:ok, state}, key) do
if Map.has_key?(state, key) do
{:ok, Map.get(state, key)}
else
{:error, :key_undefined}
end
end
def finish({:error, _state, k, err}, _key) do
{:error, {k, err}}
end
def finish(result, _key), do: result
end