Skuld.Effects.Port.EffectfulFacade (skuld v0.27.1)

View Source

Generates an effectful dispatch facade for a port contract.

use Skuld.Effects.Port.EffectfulFacade reads a contract's metadata and generates effectful caller functions (returning computations) and __key__ helpers for test stub matching.

Single-module (simplest)

With no options, the module is both the contract and the dispatch facade:

defmodule MyApp.Todos do
  use Skuld.Effects.Port.EffectfulFacade

  defcallback get_todo(id :: String.t()) :: {:ok, Todo.t()} | {:error, term()}
  defcallback list_todos() :: [Todo.t()]
end

MyApp.Todos has effectful @callbacks, __callbacks__/0, __port_effectful__?/0, and facade dispatch functions — all in one module.

From an existing DoubleDown Contract

When you have a separate contract module, use the :double_down_contract option:

defmodule MyApp.Todos.Contract do
  use DoubleDown.Contract

  defcallback get_todo(id :: String.t()) :: {:ok, Todo.t()} | {:error, term()}
  defcallback list_todos() :: [Todo.t()]
end

defmodule MyApp.Todos do
  use Skuld.Effects.Port.EffectfulFacade,
    double_down_contract: MyApp.Todos.Contract
end

MyApp.Todos is both the effectful contract (has effectful @callbacks, __callbacks__/0, __port_effectful__?/0) and the dispatch facade.

Separate effectful contract and facade

For cases where you want them in different modules:

defmodule MyApp.Todos.Effectful do
  use Skuld.Adapter.EffectfulContract,
    double_down_contract: MyApp.Todos.Contract
end

defmodule MyApp.Todos do
  use Skuld.Effects.Port.EffectfulFacade, contract: MyApp.Todos.Effectful
end

Handler Installation

comp do
  todo <- MyApp.Todos.get_todo("42")
  todo
end
|> Port.with_handler(%{MyApp.Todos => MyApp.Todos.Ecto})
|> Throw.with_handler()
|> Comp.run!()

Options

  • :contract — the effectful contract module. Defaults to __MODULE__.
  • :double_down_contract — the DoubleDown contract module. When given (and :contract is not), implicitly issues use Skuld.Adapter.EffectfulContract and sets :contract to __MODULE__. Cannot be combined with :contract.
  • Without options: single-module pattern — use DoubleDown.Contract is issued implicitly and everything is generated on the same module.