Skip to content

Instantly share code, notes, and snippets.

@hl
Last active August 28, 2021 04:55
Show Gist options
  • Save hl/c535b594b24e858d0e5ccfff29280c7a to your computer and use it in GitHub Desktop.
Save hl/c535b594b24e858d0e5ccfff29280c7a to your computer and use it in GitHub Desktop.

Revisions

  1. hl revised this gist Jul 18, 2019. 1 changed file with 26 additions and 26 deletions.
    52 changes: 26 additions & 26 deletions context.ex
    Original file line number Diff line number Diff line change
    @@ -79,8 +79,8 @@ defmodule Context do
    ## Examples
    iex> #{__MODULE__}.get_#{unquote(name)}(1)
    %#{unquote(schema)}{}
    iex> #{__MODULE__}.get_#{unquote(name)}(1)
    %#{unquote(schema)}{}
    """
    @spec unquote(:"get_#{name}")(String.t()) :: unquote(schema).t() | nil
    def unquote(:"get_#{name}")(id) when is_binary(id) do
    @@ -102,8 +102,8 @@ defmodule Context do
    ## Examples
    iex> #{__MODULE__}.get_#{unquote(name)}!(1)
    %#{unquote(schema)}{}
    iex> #{__MODULE__}.get_#{unquote(name)}!(1)
    %#{unquote(schema)}{}
    """
    @spec unquote(:"get_#{name}!")(String.t()) :: unquote(schema).t()
    def unquote(:"get_#{name}!")(id) when is_binary(id) do
    @@ -125,8 +125,8 @@ defmodule Context do
    ## Examples
    iex> #{__MODULE__}.get_#{unquote(name)}_by(title: "title")
    %#{unquote(schema)}{}
    iex> #{__MODULE__}.get_#{unquote(name)}_by(title: "title")
    %#{unquote(schema)}{}
    """
    @spec unquote(:"get_#{name}_by")(keyword) :: unquote(schema).t() | nil
    def unquote(:"get_#{name}_by")(clauses) do
    @@ -148,8 +148,8 @@ defmodule Context do
    ## Examples
    iex> #{__MODULE__}.get_#{unquote(name)}_by!(title: "title")
    %#{unquote(schema)}{}
    iex> #{__MODULE__}.get_#{unquote(name)}_by!(title: "title")
    %#{unquote(schema)}{}
    """
    @spec unquote(:"get_#{name}_by!")(keyword) :: unquote(schema).t()
    def unquote(:"get_#{name}_by!")(clauses) do
    @@ -171,8 +171,8 @@ defmodule Context do
    ## Examples
    iex> #{__MODULE__}.find_#{unquote(name)}(1)
    {:ok, %#{unquote(schema)}{}}
    iex> #{__MODULE__}.find_#{unquote(name)}(1)
    {:ok, %#{unquote(schema)}{}}
    """
    @spec unquote(:"find_#{name}")(String.t()) ::
    {:ok, unquote(schema).t()} | {:error, {unquote(schema), :not_found}}
    @@ -198,8 +198,8 @@ defmodule Context do
    ## Examples
    iex> #{__MODULE__}.find_#{unquote(name)}_by(title: "title")
    {:ok, %#{unquote(schema)}{}}
    iex> #{__MODULE__}.find_#{unquote(name)}_by(title: "title")
    {:ok, %#{unquote(schema)}{}}
    """
    @spec unquote(:"find_#{name}_by")(keyword) ::
    {:ok, unquote(schema).t()} | {:error, {unquote(schema), :not_found}}
    @@ -225,8 +225,8 @@ defmodule Context do
    ## Examples
    iex> #{__MODULE__}.create_#{unquote(name)}(%{})
    {:ok, %#{unquote(schema)}{}}
    iex> #{__MODULE__}.create_#{unquote(name)}(%{})
    {:ok, %#{unquote(schema)}{}}
    """
    @spec unquote(:"create_#{name}")(map) ::
    {:ok, unquote(schema).t()} | {:error, Ecto.Changeset.t()}
    @@ -250,8 +250,8 @@ defmodule Context do
    ## Examples
    iex> #{__MODULE__}.create_#{unquote(name)}(%{})
    %#{unquote(schema)}{}
    iex> #{__MODULE__}.create_#{unquote(name)}(%{})
    %#{unquote(schema)}{}
    """
    @spec unquote(:"create_#{name}!")(map) :: unquote(schema).t()
    def unquote(:"create_#{name}!")(args) when is_map(args) do
    @@ -275,8 +275,8 @@ defmodule Context do
    ## Examples
    iex> #{__MODULE__}.update_#{unquote(name)}!(%#{unquote(schema)}{}, %{})
    {:ok, %#{unquote(schema)}{}}
    iex> #{__MODULE__}.update_#{unquote(name)}!(%#{unquote(schema)}{}, %{})
    {:ok, %#{unquote(schema)}{}}
    """
    @spec unquote(:"update_#{name}")(unquote(schema).t(), map) ::
    {:ok, unquote(schema).t()} | {:error, Ecto.Changeset.t()}
    @@ -308,8 +308,8 @@ defmodule Context do
    ## Examples
    iex> #{__MODULE__}.update_#{unquote(name)}!(%#{unquote(schema)}{}, %{})
    %#{unquote(schema)}{}
    iex> #{__MODULE__}.update_#{unquote(name)}!(%#{unquote(schema)}{}, %{})
    %#{unquote(schema)}{}
    """
    @spec unquote(:"update_#{name}!")(unquote(schema).t(), map) :: unquote(schema).t()
    def unquote(:"update_#{name}!")(%unquote(schema){} = struct, args) when is_map(args) do
    @@ -339,8 +339,8 @@ defmodule Context do
    ## Examples
    iex> #{__MODULE__}.delete_#{unquote(name)}(%#{unquote(name)}{})
    {:ok, %#{unquote(schema)}{}}
    iex> #{__MODULE__}.delete_#{unquote(name)}(%#{unquote(name)}{})
    {:ok, %#{unquote(schema)}{}}
    """
    @spec unquote(:"delete_#{name}")(unquote(schema).t()) ::
    {:ok, unquote(schema).t()} | {:error, Ecto.Changeset.t()}
    @@ -363,8 +363,8 @@ defmodule Context do
    ## Examples
    iex> #{__MODULE__}.delete_#{unquote(name)}(%#{unquote(name)}{})
    {:ok, %#{unquote(schema)}{}}
    iex> #{__MODULE__}.delete_#{unquote(name)}(%#{unquote(name)}{})
    {:ok, %#{unquote(schema)}{}}
    """
    @spec unquote(:"delete_#{name}!")(unquote(schema).t()) :: unquote(schema).t()
    def unquote(:"delete_#{name}!")(%unquote(schema){} = struct) do
    @@ -382,8 +382,8 @@ defmodule Context do
    ## Examples
    iex> #{__MODULE__}.change_#{unquote(name)}(%#{__MODULE__}{}, %{})
    %Ecto.Changeset{}
    iex> #{__MODULE__}.change_#{unquote(name)}(%#{__MODULE__}{}, %{})
    %Ecto.Changeset{}
    """
    @spec unquote(:"change_#{name}")(map) :: Ecto.Changeset.t()
    def unquote(:"change_#{name}")(%unquote(schema){} = schema, args \\ %{}) do
  2. hl revised this gist Jun 24, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion context.ex
    Original file line number Diff line number Diff line change
    @@ -390,7 +390,7 @@ defmodule Context do
    unquote(schema).changeset(schema, args)
    end

    defoverridable [{unquote(:"change_#{name}"), 1}]
    defoverridable [{unquote(:"change_#{name}"), 2}]
    end
    end
    end
  3. hl revised this gist Jun 24, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion context.ex
    Original file line number Diff line number Diff line change
    @@ -382,7 +382,7 @@ defmodule Context do
    ## Examples
    iex> #{__MODULE__}.change_#{unquote(name)}(#{__MODULE__}, %{})
    iex> #{__MODULE__}.change_#{unquote(name)}(%#{__MODULE__}{}, %{})
    %Ecto.Changeset{}
    """
    @spec unquote(:"change_#{name}")(map) :: Ecto.Changeset.t()
  4. hl revised this gist Jun 24, 2019. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions context.ex
    Original file line number Diff line number Diff line change
    @@ -60,7 +60,7 @@ defmodule Context do
    {:"create_#{name}!", 1},
    {:"update_#{name}!", 2},
    {:"delete_#{name}!", 1},
    {:"change_#{name}", 1}
    {:"change_#{name}", 2}
    ]
    end

    @@ -375,19 +375,19 @@ defmodule Context do
    end
    end

    def gen_fun({:change, 1}, name, schema) do
    def gen_fun({:change, 2}, name, schema) do
    quote do
    @doc """
    Returns an #{unquote(schema)} changeset
    ## Examples
    iex> #{__MODULE__}.change_#{unquote(name)}(%{})
    iex> #{__MODULE__}.change_#{unquote(name)}(#{__MODULE__}, %{})
    %Ecto.Changeset{}
    """
    @spec unquote(:"change_#{name}")(map) :: Ecto.Changeset.t()
    def unquote(:"change_#{name}")(args \\ %{}) do
    unquote(schema).changeset(%unquote(schema){}, args)
    def unquote(:"change_#{name}")(%unquote(schema){} = schema, args \\ %{}) do
    unquote(schema).changeset(schema, args)
    end

    defoverridable [{unquote(:"change_#{name}"), 1}]
  5. hl revised this gist Jun 22, 2019. 1 changed file with 53 additions and 19 deletions.
    72 changes: 53 additions & 19 deletions context.ex
    Original file line number Diff line number Diff line change
    @@ -27,7 +27,7 @@ defmodule Context do
    end)
    end

    @spec parse_name(atom(), any()) :: String.t()
    @spec parse_name(atom, any) :: String.t()
    defp parse_name(schema, caller) do
    schema
    |> Macro.expand_once(caller)
    @@ -37,15 +37,15 @@ defmodule Context do
    |> Macro.underscore()
    end

    @spec build_functions(String.t(), keyword()) :: [{atom(), non_neg_integer()}]
    @spec build_functions(String.t(), keyword) :: [{atom, non_neg_integer}]
    defp build_functions(name, opts) do
    only = Keyword.get(opts, :only, default_functions(name))
    except = Keyword.get(opts, :except, [])

    only -- except
    end

    @spec default_functions(String.t()) :: [{atom(), non_neg_integer()}]
    @spec default_functions(String.t()) :: [{atom, non_neg_integer}]
    defp default_functions(name) do
    [
    {:"get_#{name}", 1},
    @@ -59,12 +59,13 @@ defmodule Context do
    {:"delete_#{name}", 1},
    {:"create_#{name}!", 1},
    {:"update_#{name}!", 2},
    {:"delete_#{name}!", 1}
    {:"delete_#{name}!", 1},
    {:"change_#{name}", 1}
    ]
    end

    @doc false
    @spec gen_fun(tuple(), String.t(), atom()) :: tuple()
    @spec gen_fun(tuple, String.t(), atom) :: tuple
    def gen_fun(fun_and_arity, name, schema)

    def gen_fun({:get, 1}, name, schema) do
    @@ -81,8 +82,8 @@ defmodule Context do
    iex> #{__MODULE__}.get_#{unquote(name)}(1)
    %#{unquote(schema)}{}
    """
    @spec unquote(:"get_#{name}")(integer()) :: unquote(schema).t() | nil
    def unquote(:"get_#{name}")(id) do
    @spec unquote(:"get_#{name}")(String.t()) :: unquote(schema).t() | nil
    def unquote(:"get_#{name}")(id) when is_binary(id) do
    @__repo__.get(unquote(schema), id)
    end

    @@ -104,8 +105,8 @@ defmodule Context do
    iex> #{__MODULE__}.get_#{unquote(name)}!(1)
    %#{unquote(schema)}{}
    """
    @spec unquote(:"get_#{name}!")(integer()) :: unquote(schema).t()
    def unquote(:"get_#{name}!")(id) do
    @spec unquote(:"get_#{name}!")(String.t()) :: unquote(schema).t()
    def unquote(:"get_#{name}!")(id) when is_binary(id) do
    @__repo__.get!(unquote(schema), id)
    end

    @@ -127,7 +128,7 @@ defmodule Context do
    iex> #{__MODULE__}.get_#{unquote(name)}_by(title: "title")
    %#{unquote(schema)}{}
    """
    @spec unquote(:"get_#{name}_by")(keyword()) :: unquote(schema).t() | nil
    @spec unquote(:"get_#{name}_by")(keyword) :: unquote(schema).t() | nil
    def unquote(:"get_#{name}_by")(clauses) do
    @__repo__.get_by(unquote(schema), clauses)
    end
    @@ -150,7 +151,7 @@ defmodule Context do
    iex> #{__MODULE__}.get_#{unquote(name)}_by!(title: "title")
    %#{unquote(schema)}{}
    """
    @spec unquote(:"get_#{name}_by!")(keyword()) :: unquote(schema).t()
    @spec unquote(:"get_#{name}_by!")(keyword) :: unquote(schema).t()
    def unquote(:"get_#{name}_by!")(clauses) do
    @__repo__.get_by!(unquote(schema), clauses)
    end
    @@ -173,9 +174,9 @@ defmodule Context do
    iex> #{__MODULE__}.find_#{unquote(name)}(1)
    {:ok, %#{unquote(schema)}{}}
    """
    @spec unquote(:"find_#{name}")(integer()) ::
    @spec unquote(:"find_#{name}")(String.t()) ::
    {:ok, unquote(schema).t()} | {:error, {unquote(schema), :not_found}}
    def unquote(:"find_#{name}")(id) do
    def unquote(:"find_#{name}")(id) when is_binary(id) do
    case @__repo__.get(unquote(schema), id) do
    nil -> {:error, {unquote(schema), :not_found}}
    term -> {:ok, term}
    @@ -200,7 +201,7 @@ defmodule Context do
    iex> #{__MODULE__}.find_#{unquote(name)}_by(title: "title")
    {:ok, %#{unquote(schema)}{}}
    """
    @spec unquote(:"find_#{name}_by")(keyword()) ::
    @spec unquote(:"find_#{name}_by")(keyword) ::
    {:ok, unquote(schema).t()} | {:error, {unquote(schema), :not_found}}
    def unquote(:"find_#{name}_by")(clauses) do
    case @__repo__.get_by(unquote(schema), clauses) do
    @@ -227,7 +228,7 @@ defmodule Context do
    iex> #{__MODULE__}.create_#{unquote(name)}(%{})
    {:ok, %#{unquote(schema)}{}}
    """
    @spec unquote(:"create_#{name}")(map()) ::
    @spec unquote(:"create_#{name}")(map) ::
    {:ok, unquote(schema).t()} | {:error, Ecto.Changeset.t()}
    def unquote(:"create_#{name}")(args) when is_map(args) do
    changeset = unquote(schema).changeset(%unquote(schema){}, args)
    @@ -252,7 +253,7 @@ defmodule Context do
    iex> #{__MODULE__}.create_#{unquote(name)}(%{})
    %#{unquote(schema)}{}
    """
    @spec unquote(:"create_#{name}!")(map()) :: unquote(schema).t()
    @spec unquote(:"create_#{name}!")(map) :: unquote(schema).t()
    def unquote(:"create_#{name}!")(args) when is_map(args) do
    changeset = unquote(schema).changeset(%unquote(schema){}, args)
    @__repo__.insert!(changeset)
    @@ -277,10 +278,17 @@ defmodule Context do
    iex> #{__MODULE__}.update_#{unquote(name)}!(%#{unquote(schema)}{}, %{})
    {:ok, %#{unquote(schema)}{}}
    """
    @spec unquote(:"update_#{name}")(unquote(schema).t(), map()) ::
    @spec unquote(:"update_#{name}")(unquote(schema).t(), map) ::
    {:ok, unquote(schema).t()} | {:error, Ecto.Changeset.t()}
    def unquote(:"update_#{name}")(%unquote(schema){} = struct, args) when is_map(args) do
    struct =
    case Keyword.has_key?(unquote(schema).__info__(:functions), :preload) do
    true -> @__repo__.preload(struct, apply(unquote(schema), :preload, []))
    false -> struct
    end

    changeset = unquote(schema).changeset(struct, args)

    @__repo__.update(changeset)
    end

    @@ -303,9 +311,16 @@ defmodule Context do
    iex> #{__MODULE__}.update_#{unquote(name)}!(%#{unquote(schema)}{}, %{})
    %#{unquote(schema)}{}
    """
    @spec unquote(:"update_#{name}!")(unquote(schema).t(), map()) :: unquote(schema).t()
    @spec unquote(:"update_#{name}!")(unquote(schema).t(), map) :: unquote(schema).t()
    def unquote(:"update_#{name}!")(%unquote(schema){} = struct, args) when is_map(args) do
    struct =
    case Keyword.has_key?(unquote(schema).__info__(:functions), :preload) do
    true -> @__repo__.preload(struct, apply(unquote(schema), :preload, []))
    false -> struct
    end

    changeset = unquote(schema).changeset(struct, args)

    @__repo__.update!(changeset)
    end

    @@ -359,4 +374,23 @@ defmodule Context do
    defoverridable [{unquote(:"delete_#{name}!"), 1}]
    end
    end
    end

    def gen_fun({:change, 1}, name, schema) do
    quote do
    @doc """
    Returns an #{unquote(schema)} changeset
    ## Examples
    iex> #{__MODULE__}.change_#{unquote(name)}(%{})
    %Ecto.Changeset{}
    """
    @spec unquote(:"change_#{name}")(map) :: Ecto.Changeset.t()
    def unquote(:"change_#{name}")(args \\ %{}) do
    unquote(schema).changeset(%unquote(schema){}, args)
    end

    defoverridable [{unquote(:"change_#{name}"), 1}]
    end
    end
    end
  6. hl created this gist Jun 19, 2019.
    362 changes: 362 additions & 0 deletions context.ex
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,362 @@
    defmodule Context do
    @moduledoc false

    defmacro __using__(opts) do
    repo = Keyword.fetch!(opts, :repo)

    quote do
    import Context, only: [context: 1, context: 2]

    Module.put_attribute(__MODULE__, :__repo__, unquote(repo))
    end
    end

    @doc false
    defmacro context(schema, opts \\ []) do
    name = Keyword.get(opts, :name, parse_name(schema, __CALLER__))
    funs = build_functions(name, opts)

    Enum.reduce(funs, [], fn {fun_name, arity}, acc ->
    fun =
    fun_name
    |> Atom.to_string()
    |> String.replace("_#{name}", "")
    |> String.to_existing_atom()

    [Kernel.apply(__MODULE__, :gen_fun, [{fun, arity}, name, schema]) | acc]
    end)
    end

    @spec parse_name(atom(), any()) :: String.t()
    defp parse_name(schema, caller) do
    schema
    |> Macro.expand_once(caller)
    |> Atom.to_string()
    |> String.split(".")
    |> List.last()
    |> Macro.underscore()
    end

    @spec build_functions(String.t(), keyword()) :: [{atom(), non_neg_integer()}]
    defp build_functions(name, opts) do
    only = Keyword.get(opts, :only, default_functions(name))
    except = Keyword.get(opts, :except, [])

    only -- except
    end

    @spec default_functions(String.t()) :: [{atom(), non_neg_integer()}]
    defp default_functions(name) do
    [
    {:"get_#{name}", 1},
    {:"get_#{name}!", 1},
    {:"get_#{name}_by", 1},
    {:"get_#{name}_by!", 1},
    {:"find_#{name}", 1},
    {:"find_#{name}_by", 1},
    {:"create_#{name}", 1},
    {:"update_#{name}", 2},
    {:"delete_#{name}", 1},
    {:"create_#{name}!", 1},
    {:"update_#{name}!", 2},
    {:"delete_#{name}!", 1}
    ]
    end

    @doc false
    @spec gen_fun(tuple(), String.t(), atom()) :: tuple()
    def gen_fun(fun_and_arity, name, schema)

    def gen_fun({:get, 1}, name, schema) do
    quote do
    @doc """
    Get a #{unquote(schema)} by ID
    ## Parameters
    - id: Valid ID
    ## Examples
    iex> #{__MODULE__}.get_#{unquote(name)}(1)
    %#{unquote(schema)}{}
    """
    @spec unquote(:"get_#{name}")(integer()) :: unquote(schema).t() | nil
    def unquote(:"get_#{name}")(id) do
    @__repo__.get(unquote(schema), id)
    end

    defoverridable [{unquote(:"get_#{name}"), 1}]
    end
    end

    def gen_fun({:get!, 1}, name, schema) do
    quote do
    @doc """
    Find a #{unquote(schema)} by ID
    ## Parameters
    - id: Valid ID
    ## Examples
    iex> #{__MODULE__}.get_#{unquote(name)}!(1)
    %#{unquote(schema)}{}
    """
    @spec unquote(:"get_#{name}!")(integer()) :: unquote(schema).t()
    def unquote(:"get_#{name}!")(id) do
    @__repo__.get!(unquote(schema), id)
    end

    defoverridable [{unquote(:"get_#{name}!"), 1}]
    end
    end

    def gen_fun({:get_by, 1}, name, schema) do
    quote do
    @doc """
    Find a #{unquote(schema)} by clauses
    ## Parameters
    - clauses: keyword list
    ## Examples
    iex> #{__MODULE__}.get_#{unquote(name)}_by(title: "title")
    %#{unquote(schema)}{}
    """
    @spec unquote(:"get_#{name}_by")(keyword()) :: unquote(schema).t() | nil
    def unquote(:"get_#{name}_by")(clauses) do
    @__repo__.get_by(unquote(schema), clauses)
    end

    defoverridable [{unquote(:"get_#{name}_by"), 1}]
    end
    end

    def gen_fun({:get_by!, 1}, name, schema) do
    quote do
    @doc """
    Find a #{unquote(schema)} by clauses
    ## Parameters
    - clauses: keyword list
    ## Examples
    iex> #{__MODULE__}.get_#{unquote(name)}_by!(title: "title")
    %#{unquote(schema)}{}
    """
    @spec unquote(:"get_#{name}_by!")(keyword()) :: unquote(schema).t()
    def unquote(:"get_#{name}_by!")(clauses) do
    @__repo__.get_by!(unquote(schema), clauses)
    end

    defoverridable [{unquote(:"get_#{name}_by!"), 1}]
    end
    end

    def gen_fun({:find, 1}, name, schema) do
    quote do
    @doc """
    Find a #{unquote(schema)} by ID
    ## Parameters
    - id: Valid ID
    ## Examples
    iex> #{__MODULE__}.find_#{unquote(name)}(1)
    {:ok, %#{unquote(schema)}{}}
    """
    @spec unquote(:"find_#{name}")(integer()) ::
    {:ok, unquote(schema).t()} | {:error, {unquote(schema), :not_found}}
    def unquote(:"find_#{name}")(id) do
    case @__repo__.get(unquote(schema), id) do
    nil -> {:error, {unquote(schema), :not_found}}
    term -> {:ok, term}
    end
    end

    defoverridable [{unquote(:"find_#{name}"), 1}]
    end
    end

    def gen_fun({:find_by, 1}, name, schema) do
    quote do
    @doc """
    Find a #{unquote(schema)} by clauses
    ## Parameters
    - clauses: keyword list
    ## Examples
    iex> #{__MODULE__}.find_#{unquote(name)}_by(title: "title")
    {:ok, %#{unquote(schema)}{}}
    """
    @spec unquote(:"find_#{name}_by")(keyword()) ::
    {:ok, unquote(schema).t()} | {:error, {unquote(schema), :not_found}}
    def unquote(:"find_#{name}_by")(clauses) do
    case @__repo__.get_by(unquote(schema), clauses) do
    nil -> {:error, {unquote(schema), :not_found}}
    term -> {:ok, term}
    end
    end

    defoverridable [{unquote(:"find_#{name}_by"), 1}]
    end
    end

    def gen_fun({:create, 1}, name, schema) do
    quote do
    @doc """
    Create a new #{unquote(schema)}
    ## Parameters
    - args: map
    ## Examples
    iex> #{__MODULE__}.create_#{unquote(name)}(%{})
    {:ok, %#{unquote(schema)}{}}
    """
    @spec unquote(:"create_#{name}")(map()) ::
    {:ok, unquote(schema).t()} | {:error, Ecto.Changeset.t()}
    def unquote(:"create_#{name}")(args) when is_map(args) do
    changeset = unquote(schema).changeset(%unquote(schema){}, args)
    @__repo__.insert(changeset)
    end

    defoverridable [{unquote(:"create_#{name}"), 1}]
    end
    end

    def gen_fun({:create!, 1}, name, schema) do
    quote do
    @doc """
    Create a new #{unquote(schema)}
    ## Parameters
    - args: map
    ## Examples
    iex> #{__MODULE__}.create_#{unquote(name)}(%{})
    %#{unquote(schema)}{}
    """
    @spec unquote(:"create_#{name}!")(map()) :: unquote(schema).t()
    def unquote(:"create_#{name}!")(args) when is_map(args) do
    changeset = unquote(schema).changeset(%unquote(schema){}, args)
    @__repo__.insert!(changeset)
    end

    defoverridable [{unquote(:"create_#{name}!"), 1}]
    end
    end

    def gen_fun({:update, 2}, name, schema) do
    quote do
    @doc """
    Update an existing #{unquote(schema)}
    ## Parameters
    - struct: %#{unquote(schema)}{}
    - args: map
    ## Examples
    iex> #{__MODULE__}.update_#{unquote(name)}!(%#{unquote(schema)}{}, %{})
    {:ok, %#{unquote(schema)}{}}
    """
    @spec unquote(:"update_#{name}")(unquote(schema).t(), map()) ::
    {:ok, unquote(schema).t()} | {:error, Ecto.Changeset.t()}
    def unquote(:"update_#{name}")(%unquote(schema){} = struct, args) when is_map(args) do
    changeset = unquote(schema).changeset(struct, args)
    @__repo__.update(changeset)
    end

    defoverridable [{unquote(:"update_#{name}"), 2}]
    end
    end

    def gen_fun({:update!, 2}, name, schema) do
    quote do
    @doc """
    Update an existing #{unquote(schema)}
    ## Parameters
    - struct: %#{unquote(schema)}{}
    - args: map
    ## Examples
    iex> #{__MODULE__}.update_#{unquote(name)}!(%#{unquote(schema)}{}, %{})
    %#{unquote(schema)}{}
    """
    @spec unquote(:"update_#{name}!")(unquote(schema).t(), map()) :: unquote(schema).t()
    def unquote(:"update_#{name}!")(%unquote(schema){} = struct, args) when is_map(args) do
    changeset = unquote(schema).changeset(struct, args)
    @__repo__.update!(changeset)
    end

    defoverridable [{unquote(:"update_#{name}!"), 2}]
    end
    end

    def gen_fun({:delete, 1}, name, schema) do
    quote do
    @doc """
    Delete an existing #{unquote(schema)}
    ## Parameters
    - struct: %#{unquote(schema)}{}
    ## Examples
    iex> #{__MODULE__}.delete_#{unquote(name)}(%#{unquote(name)}{})
    {:ok, %#{unquote(schema)}{}}
    """
    @spec unquote(:"delete_#{name}")(unquote(schema).t()) ::
    {:ok, unquote(schema).t()} | {:error, Ecto.Changeset.t()}
    def unquote(:"delete_#{name}")(%unquote(schema){} = struct) do
    @__repo__.delete(struct)
    end

    defoverridable [{unquote(:"delete_#{name}"), 1}]
    end
    end

    def gen_fun({:delete!, 1}, name, schema) do
    quote do
    @doc """
    Delete an existing #{unquote(schema)}
    ## Parameters
    - struct: %#{unquote(schema)}{}
    ## Examples
    iex> #{__MODULE__}.delete_#{unquote(name)}(%#{unquote(name)}{})
    {:ok, %#{unquote(schema)}{}}
    """
    @spec unquote(:"delete_#{name}!")(unquote(schema).t()) :: unquote(schema).t()
    def unquote(:"delete_#{name}!")(%unquote(schema){} = struct) do
    @__repo__.delete(struct)
    end

    defoverridable [{unquote(:"delete_#{name}!"), 1}]
    end
    end
    end