defmodule PotionIngredients.CQRS.Query 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.Query @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)) headers = conn.req_headers queried = apply(&unquote(caller).query/1, [to_map(transformed), headers]) handle(queried, unquote(presenter), conn) end defp parse_input(input) do Casefy.snake_case(input) end def query(input, headers \\ nil), 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) 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 query: 2 end end end