defmodule Altex.Entity do @moduledoc """ An `Entity` is a wrapper around any `data` that implements the `Persistable` protocol. It's aim is to handle and track changes. (Yes, think about Ecto.Changeset but different) An `Entity-implementatoin` must implement the `Persistable` protocol, thus `Entity` can call `init`, `get`, and `validate`. """ alias __MODULE__ alias Altex.Persistable require UUID defstruct data: nil, uuid: nil, errors: [] @type t() :: %Entity{} @spec init(any) :: Entity.t() @doc """ ### Examples: iex> entity = Entity.init(1) ...> %Entity{data: 1, uuid: _uuid} = entity iex> entity = Entity.init(1.4) ...> %Entity{data: 1.4, uuid: _uuid} = entity iex> entity = Entity.init(:something) ...> %Entity{data: :something, uuid: _uuid } = entity iex> entity = Entity.init(~w/hello world/) ...> %Entity{data: ["hello", "world"], uuid: _uuid } = entity iex> entity = Entity.init({:foo, :bar}) ...> %Entity{data: {:foo, :bar}, uuid: _uuid } = entity """ def init(data, uuid \\ nil) do %Entity{uuid: uuid || UUID.uuid4(), data: Persistable.init(data)} |> validate() end @doc """ As force_init but skipping validation """ def force_init(data, uuid \\ nil) do %Entity{uuid: uuid || UUID.uuid4(), data: Persistable.init(data)} end @spec validate(t) :: t @doc ~s""" Check entity and set `errors: []` if any. """ def validate(entity) do Persistable.validate(entity.data, entity) end @spec get(t, any) :: any @doc ~s""" Get the value of `key` from `data` of the entity when the entity implements the get-function of the `Persistable` protocol. ### Example iex> e = Entity.init(%{foo: :bar}) ...> Entity.get(e, :foo) :bar iex> e = Entity.init(%{ 1 => :foo, 2 => :bar}) ...> Entity.get(e, 2) :bar """ def get(entity, key) do Persistable.get(entity.data, key) end end