# PipelineFlow
Magic macro that defines a PipelineFlow struct for you. Comparable with Plug.Conn.
You can define functions that will be wrapped by the macro that will automatically
merge results, halt on execution and log their steps.
## Example with single execution string
```elixir
defmodule Payment do
use PipelineFlow
attributes(user: nil, user_id: nil, api_config: %{}, api_session_token: nil, api_result: nil, product: nil)
def_step get_user(pipeline) do
case Users.get_user(pipeline.user_id) do
{:ok, user} -> {:ok, %{user: user}
{:error, :not_found} -> {:error, :not_found}
end
end
def_step get_api_config(pipeline) do
Application.get_env(:test_app, :api_config)
end
def_step get_api_session_token(pipeline), requires: [:get_user] do
case PaymentApi.get_api_token(user: pipeline.api_config[:user], password: pipeline.api_config[:password]) do
{:ok, %{token: token}} -> {:ok, %{api_session_token: token}}
{:error, error} -> {:error, error}
end
end
def_step pay_for_product(pipeline), requires: [:get_api_session_token] do
case PaymentApi.pay(pipeline.api_session_token, pipeline.product) do
{:ok, %{status: "paid"}} -> {:ok, %{payment_result: status}}
{:ok, %{status: "pending"}} -> {:error, :payment_pending}
{:error, error} -> {:error, error}
end
end
def_step set_product_status(pipeline), requires: [:pay_for_product] do
case Products.update_status(pipeline.user, pipeline.product, "paid") do
{:ok, _} -> {:ok, pipeline}
{:error, error} -> {:error, error}
end
end
def value(pipeline), do: pipeline.product
end
```
You can now execute the entire chain by just calling `exec`:
```elixir
result =
%{user_id: user_id}
|> Payment.new()
|> Payment.exec()
```
The result in the example above will be `{:ok, product}` or `{:error, :atom_of_step_where_it_went_wrong, error}`
## Example with steps with arguments
A defined flow with steps that expect function arguments, cannot be called in one go. However, you can still call the steps individually.
```elixir
defmodule ComplexExample do
use PipelineFlow
attributes(user: nil)
def_step get_user(pipeline, user_id) when is_binary(user_id) do
case Users.get_user(user_id) do
{:ok, user} -> {:ok, %{user: user, user_id: user_id}}
{:error, error} -> {:error, error}
end
end
end
```
```elixir
pipeline =
ComplexExample.new()
|> ComplexExample.get_user(user_id)
```
## Installation
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `pipeline` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:pipeline, "~> 0.1.0"}
]
end
```
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at <https://hexdocs.pm/pipeline>.