Current section
Files
Jump to
Current section
Files
lib/ex_runner.ex
defmodule ExRunner do
@moduledoc false
@doc false
defmacro __using__(_) do
quote do
import ExRunner, only: [input: 1, output: 1, embed_object: 2]
import Ecto.Changeset
import Ecto.Query
@before_compile unquote(__MODULE__)
end
end
@doc false
defmacro input(schema) do
quote do
defmodule Input do
@moduledoc false
use Ecto.Schema
@primary_key false
embedded_schema unquote(schema)
end
end
end
@doc false
defmacro output(schema) do
quote do
defmodule Output do
@moduledoc false
use Ecto.Schema
@primary_key false
embedded_schema unquote(schema)
end
end
end
@doc false
defmacro embed_object(name, schema) do
quote do
defmodule unquote(name) do
@moduledoc false
use Ecto.Schema
@primary_key false
embedded_schema unquote(schema)
end
end
end
@doc false
defmacro __before_compile__(_) do
quote do
def run(params) when is_list(params) do
params |> Enum.into(%{}) |> run()
end
def run(params) when is_nil(params) do
run(%{})
end
def run(%_{} = params) do
params |> Map.from_struct() |> run()
end
@doc """
Runs the operation. Argument can be a map, a keyword list or a struct. If the operation is successful, it returns {:ok, output}. In other cases, it returns {:error, changeset}
"""
def run(%{} = params) do
input = ExRunner.Parser.parse(__MODULE__.Input, params)
changeset = EctoMorph.generate_changeset(input, __MODULE__.Input)
changeset = Map.put(changeset, :params, input)
if changeset.valid? do
changeset = validate(changeset)
if changeset.valid? do
response = execute(changeset)
cond do
is_nil(response) -> {:ok, %{}}
is_nil(Map.get(response, :valid?)) ->
output = ExRunner.Parser.parse(__MODULE__.Output, response)
changeset = EctoMorph.generate_changeset(output, __MODULE__.Output)
if changeset.valid?, do: {:ok, output}, else: raise Ecto.InvalidChangesetError, changeset: changeset
true -> {:error, response}
end
else
{:error, changeset}
end
else
{:error, changeset}
end
end
@doc """
Implements the bang for run function. Argument can be a map, a keyword list or a struct. If the operation is successful, it returns output. In other cases, it raises Ecto.InvalidChangesetError.
"""
def run!(params) do
case run(params) do
{:ok, response} -> response
{:error, changeset} -> raise Ecto.InvalidChangesetError, changeset: changeset
end
end
end
end
end