defmodule PotionIngredients.CQRS.Command do @callback changeset(Map.t()) :: Map.t() defmacro __using__(opts) do import PotionIngredients.CQRS.Handler import PotionIngredients.Utils, only: [to_map: 1] caller = __CALLER__.module [presenter: presenter] = opts quote do @behaviour PotionIngredients.CQRS.Command @spec init(Atom.t()) :: Atom.t() def init(i), do: i @spec call(Plug.Conn.t(), any) :: Plug.Conn.t() def call(conn, fun) do transformed = changeset(parse_input(conn.params)) queried = apply(&unquote(caller).execute/1, [to_map(transformed)]) handle(queried, unquote(presenter), conn) end defp parse_input(input) do Casefy.snake_case(input) end def execute(input), do: input def success(output) when is_map(output) do {:ok, :ok, output} end def success(output, status) when is_map(output) and is_atom(status) and status in [:ok, :created, :no_content] do {:ok, status, output} end def error(reason) when is_map(reason) do {:error, :bad_request, reason} end def error(reason, status) when is_map(reason) and is_atom(status) do {:error, status, reason} end defoverridable execute: 1 end end end