# `Diffo.Type.Dynamic`
[🔗](https://github.com/diffo-dev/diffo/blob/v0.9.0/lib/diffo/type/dynamic.ex#L4)

`Diffo.Type.Dynamic` is an `Ash.Type.NewType` for values whose exact type is not known until
runtime. The `:type` field holds the `Ash.Type.NewType` module and `:value` holds the cast value.

Dynamic is limited to types that have `storage_type: :map` — that is, `Ash.TypedStruct` and
`Ash.Type.NewType` subtypes of `:struct`, `:map`, `:union`, `:keyword`, or `:tuple`.
Scalar Ash types such as `Ash.Type.Date` or `Ash.Type.Decimal` are not supported.

In practice, `Diffo.Type.Dynamic` is used as a member of `Diffo.Type.Value` and is not
typically used as a standalone attribute type.
Outstanding comparison is implemented inline via `defoutstanding`.

## Nil handling

    iex> Ash.Type.cast_input(Diffo.Type.Dynamic, nil, [])
    {:ok, nil}

    iex> Ash.Type.dump_to_native(Diffo.Type.Dynamic, nil, [])
    {:ok, nil}

    iex> Ash.Type.cast_stored(Diffo.Type.Dynamic, nil, [])
    {:ok, nil}

## Invalid types

Scalar Ash types and modules that are not `Ash.Type.NewType` with `storage_type: :map` are
rejected at cast time:

    iex> Ash.Type.cast_input(Diffo.Type.Dynamic, %Diffo.Type.Dynamic{type: Ash.Type.Date, value: ~D[2026-01-01]}, [])
    {:error, "Dynamic type Ash.Type.Date must be an Ash.Type.NewType with storage_type :map"}

    iex> Ash.Type.cast_input(Diffo.Type.Dynamic, %Diffo.Type.Dynamic{type: Diffo.Type.NonExistent, value: nil}, [])
    {:error, "Dynamic type Diffo.Type.NonExistent must be an Ash.Type.NewType with storage_type :map"}

## Checking type compatibility

Use `is_valid?/1` to check whether a module is usable as a Dynamic type before
constructing a `%Diffo.Type.Dynamic{}`:

    iex> Diffo.Type.Dynamic.is_valid?(Ash.Type.Date)
    false

    iex> Diffo.Type.Dynamic.is_valid?(Diffo.Type.NonExistent)
    false

## Constraints

    iex> Diffo.Type.Dynamic.dynamic_constraints(nil)
    []

# `dynamic_constraints`

Returns the dynamic constraints from dynamic struct or map

# `handle_change?`

# `is_valid?`

Returns true if the module is a valid Dynamic type — an `Ash.Type.NewType` with
`storage_type: :map`. Returns false for unloaded modules, non-NewTypes, and scalar
Ash types such as `Ash.Type.Date`.

# `prepare_change?`

---

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