Fable.Events behaviour (Fable v0.0.1-alpha.2)

View Source

Fable.Events is the repository for Fable.Events.

When used it expects a :repo key to be set as an option:

defmodule MyApp.Events do
  use Fable.Events, repo: MyApp.Repo
end

Options

  • :registry - The name of the registry used for the process managers. Defaults to Fable. + repo name
  • :router - The module responsible for defining the routing of events. Defaults to __MODULE__ to their handlers
  • :event_schema - The schema to be used for persisting events. Defaults to Fable.Event
  • :process_manager_schema - The schema to be used for persisting process managers' state. Defaults to Fable.ProcessManager.State
  • :json_library - The library used for json encoding. Defaults to Jason

Emitting events

You can emit events as a standalone action or as part of an Ecto.Multi pipeline. For both ways you need to pass the resulting term to Repo.transaction for it to be applied.

Standalone action:

def create_aggregate(user, args) do
  %MyApp.Aggregate{id: uuid}
  |> MyApp.Events.emit(fn aggregate, repo, _changes ->
    with {:ok, _} <- can(user, :create_aggregate) do
      %MyApp.Aggregate.Created{args: args, user: user}
    end
  end)
  |> Repo.transaction
end

As part of Ecto.Multi:

def create_child_on_aggregate(aggregate, user, args) do
  multi =
    Ecto.Multi.new
    |> MyApp.Events.emit(aggregate, :aggregate, fn aggregate, repo, _changes ->
      with {:ok, _} <- can(user, :create_child) do
        %MyApp.Aggregate.ChildCreated{args: args, user: user}
      end
    end)
    |> Ecto.Multi.run(:child, fn repo, %{aggregate: aggregate} ->
      get_latest_child(aggregate, repo)
    end)

  case Repo.transaction(multi) do
    {:ok, %{child: child}} -> {:ok, child}
    {:error, :aggregate, error, _} -> {:error, error}
  end
end

Handling events

By default MyApp.Events will also be your router module. Look at Fable.Router for more information on that.

Summary

Callbacks

Creates a function, which emits events for an aggregate when passed to Repo.transaction.

Emit events as step within an Ecto.Multi pipeline.

Lists all the events of the aggregate in order.

Delete the given aggregate and replay all its events, building a new aggregate.

Types

emit_callback()

event_or_events()

@type event_or_events() :: Fable.Event.t() | [Fable.Event.t()]

handler()

@type handler() :: (Fable.aggregate(), Fable.Event.t() ->
                {:ok, Fable.aggregate()} | {:error, term()})

transation_fun()

@type transation_fun() :: (Ecto.Repo.t() -> any())

Callbacks

emit(aggregate, emit_callback, t)

@callback emit(Fable.aggregate(), emit_callback(), Keyword.t()) :: transation_fun()

Creates a function, which emits events for an aggregate when passed to Repo.transaction.

emit(t, aggregate, name, emit_callback, t)

Emit events as step within an Ecto.Multi pipeline.

log(aggregate)

@callback log(Fable.aggregate()) :: [Fable.Event.t()]

Lists all the events of the aggregate in order.

replay(repo, aggregate)

@callback replay(repo :: Ecto.Repo.t(), Fable.aggregate()) ::
  {:ok, Fable.aggregate()} | {:error, term()}

Delete the given aggregate and replay all its events, building a new aggregate.