lib/entity.ex

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

  @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