# `DDD.Type`
[🔗](https://github.com/blackuprise/vicander/blob/v0.1.1/lib/ddd/model/type.ex#L1)

The field types of entities, aggregates and value objects, and everything the framework
does with them: checking a value, storing it in Postgres, and writing it as JSON.

## Scalars

| type                | Elixir value        | Postgres column            |
|---------------------|---------------------|----------------------------|
| `:string`           | binary              | `varchar`                  |
| `:text`             | binary              | `text`                     |
| `:integer`          | integer             | `bigint`                   |
| `:float`            | number              | `float`                    |
| `:boolean`          | boolean             | `boolean`                  |
| `:atom`             | atom                | `varchar` (as a string)    |
| `:uuid`             | UUID string         | `uuid`                     |
| `:decimal`          | `Decimal`           | `numeric`                  |
| `:date`             | `Date`              | `date`                     |
| `:time`             | `Time`              | `time(6)`                  |
| `:naive_datetime`   | `NaiveDateTime`     | `timestamp(6)`             |
| `:datetime`         | `DateTime`          | `timestamp(0)`             |
| `:datetime_usec`    | `DateTime`          | `timestamp(6)`             |
| `:binary`           | binary              | `bytea`                    |
| `:map`              | map                 | `jsonb`                    |
| `:json`             | map or list         | `jsonb`                    |

## Composite types

  * `{:array, type}`: a list of `type` (a scalar, enum, reference, value object or map),
    stored as a Postgres array, for example `{:array, :string}` for tags
  * `{:enum, [:open, :done]}`: one of the listed atoms, stored as a string
  * `{:map, type}`: a map with string keys and values of `type`, stored as `jsonb`
  * `{:ref, Aggregate}`: the identity of another aggregate. The aggregates refer to each other
    by id only. It has the type of that aggregate's identity
  * `{:one, Module}` / `{:list, Module}`: nested entities or value objects, stored as `jsonb`
  * `:money`: shorthand for `{:one, DDD.Money}`

A value that does not fit its type is a validation violation with the code `:invalid_type`.
`nil` is always accepted by the type (use `required: true` to forbid it).

# `t`

```elixir
@type t() ::
  atom()
  | {:array, t()}
  | {:enum, [atom()]}
  | {:map, t()}
  | {:ref, module()}
  | {:one, module()}
  | {:list, module()}
```

# `column_type`

```elixir
@spec column_type(t()) :: Ecto.Type.t()
```

The column type a migration uses for a field (what the snapshot records).

# `describe`

```elixir
@spec describe(t()) :: String.t()
```

A short description of a type, for error messages.

# `dump`

```elixir
@spec dump(t(), term()) :: term()
```

A field value as the value of its Ecto column.

# `ecto_type`

```elixir
@spec ecto_type(t()) :: Ecto.Type.t()
```

The Ecto type the adapter uses for a field.

# `identity_type`

```elixir
@spec identity_type(module()) :: t()
```

The type of an aggregate's identity (what `{:ref, Aggregate}` holds).

# `json_dump`

```elixir
@spec json_dump(t(), term()) :: term()
```

A value as JSON-ready data (strings, numbers, booleans, lists, maps).

# `json_load`

```elixir
@spec json_load(t(), term()) :: term()
```

The inverse of `json_dump/2`.

# `load`

```elixir
@spec load(t(), term()) :: term()
```

A field value read from its Ecto column.

# `normalize!`

```elixir
@spec normalize!(term()) :: t()
```

Check a declared type and expand its shorthands. Raises `ArgumentError` on an unknown type,
so a typo fails at compile time.

    iex> DDD.Type.normalize!(:money)
    {:one, DDD.Money}
    iex> DDD.Type.normalize!({:array, :string})
    {:array, :string}

# `valid?`

```elixir
@spec valid?(t(), term()) :: boolean()
```

True when `value` fits `type` (`nil` always does).

    iex> DDD.Type.valid?({:enum, [:open, :done]}, :open)
    true
    iex> DDD.Type.valid?({:enum, [:open, :done]}, :weird)
    false
    iex> DDD.Type.valid?({:array, :integer}, [1, 2])
    true
    iex> DDD.Type.valid?(:integer, nil)
    true

---

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