Packages

A comprehensive library for working with both static and dynamic enum structures in Elixir.

Current section

Files

Jump to
enumex lib enumex dynamic components context.ex
Raw

lib/enumex/dynamic/components/context.ex

# credo:disable-for-next-line Credo.Check.Refactor.ModuleDependencies
defmodule Enumex.Dynamic.Components.Context do
@moduledoc """
Provides a complete set of CRUD operations defining `Phoenix` context functions for dynamic enum.
## Dependencies
Requires `Ecto.Repo` module from `:ecto` dependency
as well as `EctoChangeset` and `EctoSchema` component.
## Required bindings
- `repo` - the ecto repository module.
## Usage
The component is used within an `Enumex.Dynamic` module:
defmodule MyApp.MyEnums do
use Enumex.Dynamic, components: [{Enumex.Dynamic.Components.Context, repo: MyApp.Repo}]
# enum definitions goes here
end
"""
use Enumex.Component
alias Ecto.Changeset
alias Ecto.Schema
@typedoc """
Type representing a result of the schema modification operations.
It provides type safety for handling both successful and failed modifications.
## Example
case result do
{:ok, schema} -> schema
{:error, changeset} -> handle_errors(changeset)
end
"""
@type schema_modification_result :: {:ok, Schema.schema()} | {:error, Changeset.t()}
@doc """
Changes an enum schema with the given attributes
and returns a changeset that can be used for validation and persistence.
## Parameters
* `schema`: The enum schema to modify
* `attrs`: A map of attributes to change
## Example
change(enum_schema, %{id: "first", index: 1})
"""
@callback change(Schema.schema(), map()) :: Changeset.t()
@doc """
Creates a new enum schema with the given attributes
and returns `{:ok, schema}` if successful, or `{:error, changeset}` if validation fails.
## Parameters
* `attrs`: A map of attributes to create the enum context with
## Example
case create(%{id: "first", index: 1}) do
{:ok, enum_schema} -> enum_schema
{:error, changeset} -> handle_errors(changeset)
end
"""
@callback create(map()) :: schema_modification_result()
@doc """
Deletes an enum schema from the database
and returns `{:ok, schema}` if successful, or `{:error, changeset}` if deletion fails.
## Parameters
* `schema`: The enum schema to delete
## Example
case delete(enum_schema) do
{:ok, enum_schema} -> enum_schema
{:error, changeset} -> handle_errors(changeset)
end
"""
@callback delete(Schema.schema()) :: schema_modification_result()
@doc """
Retrieves an enum schema by value id
and Returns the enum schema if found, or raises an error if not found.
## Parameters
* `id`: The id of the enum schema to retrieve
## Example
enum_schema = get!("first")
"""
@callback get!(any()) :: Schema.schema() | no_return()
@doc """
Retrieves all enum schemas
and returns a list of enum schemas, or raises an error if the operation fails.
## Example
list()
"""
@callback list :: [Schema.schema()] | no_return()
@doc """
Updates an existing enum schema with the given attributes
and returns `{:ok, schema}` if successful, or `{:error, changeset}` if validation fails.
## Parameters
* `schema`: The enum schema to update
* `attrs`: A map of attributes to change
## Example
case update(enum_schema, %{id: "second", index: 2}) do
{:ok, updated_enum_schema} -> updated_enum_schema
{:error, changeset} -> handle_errors(changeset)
end
"""
@callback update(Schema.schema(), map()) :: schema_modification_result()
comp %{component: component, enum_field_opts: enum_field_opts, plural: plural, repo: repo},
depends: [Enumex.Dynamic.Components.EctoChangeset, Enumex.Dynamic.Components.EctoSchema],
requires: [ecto: Ecto.Repo] do
@behaviour component
singular_var =
__MODULE__
|> Module.split()
|> List.last()
|> Macro.underscore()
# credo:disable-for-next-line Credo.Check.Warning.UnsafeToAtom
|> String.to_atom()
|> Macro.var(nil)
field_name_enum_name = enum_field_opts[:enum_name]
field_name_id = enum_field_opts[:id]
plural_string = Atom.to_string(plural)
@impl component
def change(%__MODULE__{} = unquote(singular_var), attrs \\ %{}) do
unquote(singular_var)
|> Map.put(unquote(field_name_enum_name), unquote(plural_string))
|> __MODULE__.enum_changeset(attrs)
end
@impl component
def create(attrs \\ %{}) do
%__MODULE__{}
|> change(attrs)
|> unquote(repo).insert()
end
@impl component
def delete(unquote(singular_var)) do
unquote(repo).delete(unquote(singular_var))
end
@impl component
def get!(id) do
unquote(repo).get_by!(__MODULE__, [
{unquote(field_name_enum_name), unquote(plural_string)},
{unquote(field_name_id), id}
])
end
@impl component
def list do
unquote(repo).all_by(__MODULE__, [{unquote(field_name_enum_name), unquote(plural_string)}])
end
@impl component
def update(%__MODULE__{} = unquote(singular_var), attrs) do
unquote(singular_var)
|> change(attrs)
|> unquote(repo).update()
end
end
end