README.md

# 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>.