# `Chronicle.Events.Constraint`
[🔗](https://github.com/Cratis/Chronicle.Elixir/blob/main/lib/chronicle/events/constraint.ex#L4)

Macro for defining a standalone constraint module.

Model-bound `unique/2`, `unique_event_type/1`, and `remove_constraint/1,2` attributes on an
event type (see `Chronicle.Events.EventType`) cover the common case: a constraint that
belongs to exactly one event type's own module. `use Chronicle.Events.Constraint` is for
everything else — a constraint spanning several event types under one name, or one you want
to define apart from any single event type's module. It mirrors the C# client's
`IConstraint`/`IConstraintBuilder`.

## Defining a standalone constraint

    defmodule MyApp.Constraints.UniqueEmail do
      use Chronicle.Events.Constraint

      unique name: "UniqueEmail" do
        on MyApp.Events.UserRegistered, [:email]
        on MyApp.Events.UserEmailChanged, [:new_email]
        removed_with MyApp.Events.UserRemoved
      end
    end

A unique event type constraint, with a releasing event declared afterward:

    defmodule MyApp.Constraints.OneOpenLoan do
      use Chronicle.Events.Constraint

      unique_event_type MyApp.Events.LoanCheckedOut, name: "OneOpenLoan"
      removed_with MyApp.Events.LoanReturned
    end

Two `unique_event_type/1,2` declarations sharing a name become one constraint — mutual
exclusion: at most one event drawn from the named set is ever appended for the same event
source:

    defmodule MyApp.Constraints.PersonTerminalOutcome do
      use Chronicle.Events.Constraint

      unique_event_type MyApp.Events.PersonAliasedTo, name: "PersonTerminal"
      unique_event_type MyApp.Events.PersonErased, name: "PersonTerminal"
    end

## Registering

Standalone constraint modules are discovered automatically (like event types and read
models, through `:otp_app` or loaded-module discovery) or registered explicitly:

    {Chronicle.Client,
      connection_string: "chronicle://localhost:35000",
      event_store: "my-store",
      constraints: [MyApp.Constraints.UniqueEmail]}

## `unique/2` options

  * `:name` — **(required)** the constraint name
  * `:mode` — `:per_event_source` (default) or `:per_value`; see
    `Chronicle.Events.EventType.unique/2`
  * `:ignore_casing` — compare values case-insensitively
  * `:message` — a string, or a `{Module, :function}` callback invoked with the violation to
    compute one; see `Chronicle.Events.ConstraintViolation.details/1`
  * `:scope` — see `Chronicle.Events.EventType.unique/2`
  * `:event_sequences` — restrict the declaration to specific event sequences (default: all)

## `on/2`

Declares one of the event types (and the properties on it) that participate in the enclosing
`unique/2` constraint. Call it more than once in the same block to constrain several event
types under one name — the same event type cannot be added twice to one `unique/2` block.

## `removed_with/1,2`

Inside a `unique/2 ... do ... end` block, declares a removal event. With `properties:`, the
removal carries the value to release in `:per_value` mode, in the same order as the
constrained properties; omitted or empty releases every value for the event source. After a
bare `unique_event_type/1,2`, releases that constraint — there is no `properties:`, since a
unique event type constraint has no constrained value. Calling it before any
`unique_event_type/1,2` has been declared in the module is a compile-time error.

## `unique_event_type/1,2` options

  * `:name` — **(required)** the constraint name
  * `:message` — see above
  * `:scope` — see above
  * `:event_sequences` — see above

# `__chronicle_constraint__`

```elixir
@callback __chronicle_constraint__(:definitions) :: [map()]
```

Returns metadata for a standalone constraint module. Accepts `:definitions`, the list of
constraint definition maps this module declared, in the same shape
`Chronicle.Events.Constraints.from_event_types/1` produces per constraint.

# `on`
*macro* 

Declares one of the event types (and properties) participating in the enclosing `unique/2`
constraint. Call it more than once to constrain several event types under one name.

# `removed_with`
*macro* 

Declares a removal event. Inside a `unique/2 ... do ... end` block, releases the value with
optional `properties:`. After a bare `unique_event_type/1,2`, releases that constraint.

# `unique`
*macro* 

Starts a unique constraint built from one or more `on/2` declarations inside the block.

See the moduledoc for the supported options.

# `unique_event_type`
*macro* 

Declares a unique constraint for the whole event type.

See the moduledoc for the supported options. Two declarations sharing a `:name` merge into
one mutually-exclusive constraint.

---

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