# Compile-time macro for generating a Plain implementation of Port.Repo # that delegates to a specific Ecto Repo module. # # ## Usage # # defmodule MyApp.Repo.Port do # use Skuld.Repo.Ecto, repo: MyApp.Repo # end # # # Then wire it up: # comp # |> Port.with_handler(%{Port.Repo => MyApp.Repo.Port}) # |> Comp.run!() # defmodule Skuld.Repo.Ecto do @moduledoc """ Macro for generating a `Port.Repo.Behaviour` implementation that delegates to a specific Ecto Repo module. Each operation in the `Port.Repo` contract is implemented by calling the corresponding function on the configured Repo module with the same arguments. ## Usage defmodule MyApp.Repo.Port do use Skuld.Repo.Ecto, repo: MyApp.Repo end This generates a module satisfying `Skuld.Repo.Behaviour` with functions like: def insert(changeset), do: MyApp.Repo.insert(changeset) def update(changeset), do: MyApp.Repo.update(changeset) # ... etc. ## Handler Installation alias Skuld.Effects.Port comp |> Port.with_handler(%{Port.Repo => MyApp.Repo.Port}) |> Comp.run!() """ defmacro __using__(opts) do repo = Keyword.fetch!(opts, :repo) operations = Skuld.Repo.Contract.__callbacks__() delegations = Enum.map(operations, fn %{name: name, params: params, arity: arity} -> param_vars = Enum.map(params, fn p -> Macro.var(p, nil) end) quote do @impl true def unquote(name)(unquote_splicing(param_vars)) do unquote(repo).unquote(name)(unquote_splicing(param_vars)) end defoverridable [{unquote(name), unquote(arity)}] end end) quote do @behaviour Skuld.Repo.Contract unquote_splicing(delegations) end end end