# `Trogon.Commanded.ValueObject`
[🔗](https://github.com/straw-hat-team/beam-monorepo/blob/trogon_commanded@v1.0.1/apps/trogon_commanded/lib/trogon/commanded/value_object.ex#L1)

Defines "Value Object" modules.

# `__using__`
*macro* 

```elixir
@spec __using__(opts :: []) :: any()
```

Converts the module into an `Ecto.Schema` and add factory functions to create structs.

## Using

- `Ecto.Schema`
- `Ecto.Type`

## Derives

- `Jason.Encoder`

## Usage

```elixir
defmodule MyValueObject do
  use Trogon.Commanded.ValueObject

  embedded_schema do
    field :title, :string
    # ...
  end
end
```

## Overridable

- `validate/2` to add custom validation to the existing `changeset/2` without overriding the whole `changeset/2`
  function.

    ```elixir
    defmodule MyValueObject do
      use Trogon.Commanded.ValueObject

      embedded_schema do
        field :amount, :integer
      end

      def validate(changeset, attrs) do
        changeset
        |> Changeset.validate_number(:amount, greater_than: 0)
      end
    end
    ```

- `changeset/2` returns an `t:Ecto.Changeset.t/0` for a given value object struct.

    > #### Overriding Changeset {: .warning}
    >
    > Be careful when overriding `changeset/2` because the default
    > implementation takes care of `cast`, `validate_required` the
    > `@enforced_keys` and nested embeds. You may want to call
    > `Trogon.Commanded.ValueObject.changeset/2` to have such features.
    >
    > If you only need to extend the changeset, you can override the
    > `validate/2` function instead.

# `changeset`

Returns an `t:Ecto.Changeset.t/0` for a given value object struct.

It reads the `@enforced_keys` from the struct and validates the required
fields. Also, it casts the embeds. It is useful when you override the
`changeset/2` function in your value object.

## Examples

```elixir
defmodule MyValueObject do
  use Trogon.Commanded.ValueObject

  @enforce_keys [:title, :amount]
  embedded_schema do
    field :title, :string
    field :amount, :integer
  end

  def changeset(message, attrs) do
    message
    |> ValueObject.changeset(attrs)
    |> Changeset.validate_number(:amount, greater_than: 0)
  end
end
```

# `new`

```elixir
@spec new(struct_module :: atom(), attrs :: map()) ::
  {:ok, struct()} | {:error, Ecto.Changeset.t()}
```

Creates a value object struct for the given module and attributes.

This function applies the changeset validation logic defined in the value object
module and returns either `{:ok, struct}` on success or `{:error, changeset}`
when validation fails.

## Parameters

- `struct_module` - The value object module that uses `Trogon.Commanded.ValueObject`
- `attrs` - A map of attributes to create the value object with

## Examples

Creating a simple value object:

    iex> Trogon.Commanded.ValueObject.new(TestSupport.MessageOne, %{title: "Hello"})
    {:ok, %TestSupport.MessageOne{title: "Hello"}}

Creating a value object with validation:

    iex> Trogon.Commanded.ValueObject.new(TestSupport.TransferableMoney, %{amount: 100, currency: :USD})
    {:ok, %TestSupport.TransferableMoney{amount: 100, currency: :USD}}

Validation failure example:

    iex> {:error, changeset} = Trogon.Commanded.ValueObject.new(TestSupport.TransferableMoney, %{amount: -5, currency: :USD})
    iex> changeset.valid?
    false

Missing required field:

    iex> {:error, changeset} = Trogon.Commanded.ValueObject.new(TestSupport.MyValueOject, %{amount: 25})
    iex> changeset.valid?
    false

# `new!`

```elixir
@spec new!(struct_module :: atom(), attrs :: map()) :: struct()
```

Creates a value object struct for the given module and attributes, raising on validation errors.

This function is similar to `new/2` but raises an `Ecto.InvalidChangesetError`
instead of returning an error tuple when validation fails.

## Parameters

- `struct_module` - The value object module that uses `Trogon.Commanded.ValueObject`
- `attrs` - A map of attributes to create the value object with

## Examples

Creating a simple value object:

    iex> Trogon.Commanded.ValueObject.new!(TestSupport.MessageOne, %{title: "Hello"})
    %TestSupport.MessageOne{title: "Hello"}

Creating a value object with validation:

    iex> Trogon.Commanded.ValueObject.new!(TestSupport.TransferableMoney, %{amount: 100, currency: :USD})
    %TestSupport.TransferableMoney{amount: 100, currency: :USD}

Validation failure raises an exception:

    iex> try do
    ...>   Trogon.Commanded.ValueObject.new!(TestSupport.TransferableMoney, %{amount: -5, currency: :USD})
    ...> rescue
    ...>   Ecto.InvalidChangesetError -> :error_raised
    ...> end
    :error_raised

Missing required field raises an exception:

    iex> try do
    ...>   Trogon.Commanded.ValueObject.new!(TestSupport.MyValueOject, %{amount: 25})
    ...> rescue
    ...>   Ecto.InvalidChangesetError -> :error_raised
    ...> end
    :error_raised

---

*Consult [api-reference.md](api-reference.md) for complete listing*
