lib/commanded/event/upcaster.ex

defprotocol Commanded.Event.Upcaster do
  @moduledoc """
  Protocol to allow an event to be transformed before being passed to a
  consumer.

  You can use an upcaster to change the shape of an event (e.g. add a new field
  with a default, rename a field) or rename an event.

  Because the upcaster changes any historical event to the latest version,
  consumers (aggregates, event handlers, and process managers) only need
  to support the latest version.

  ## Example

      defimpl Commanded.Event.Upcaster, for: AnEvent do
        def upcast(%AnEvent{} = event, _metadata) do
          %AnEvent{name: name} = event

          %AnEvent{event | first_name: name}
        end
      end

  ## Metadata

  The `upcast/2` function receives the domain event and a map of metadata
  associated with that event. The metadata is provided during command dispatch.

  In addition to the metadata key/values you provide, the following system
  values will be included in the metadata:

    - `application` - the `Commanded.Application` used to read the event.
    - `event_id` - a globally unique UUID to identify the event.
    - `event_number` - a globally unique, monotonically incrementing integer
      used to order the event amongst all events.
    - `stream_id` - the stream identity for the event.
    - `stream_version` - the version of the stream for the event.
    - `causation_id` - an optional UUID identifier used to identify which
      command caused the event.
    - `correlation_id` - an optional UUID identifier used to correlate related
      commands/events.
    - `created_at` - the datetime, in UTC, indicating when the event was
      created.

  These key/value metadata pairs will use atom keys to differentiate them from
  the user provided metadata which uses string keys.

  """

  @fallback_to_any true
  @spec upcast(event :: struct(), metadata :: map()) :: struct()
  def upcast(event, metadata)
end

defimpl Commanded.Event.Upcaster, for: Any do
  @moduledoc """
  The default implementation of the `Commanded.Event.Upcaster`.

  This will return an event unchanged.
  """

  def upcast(event, _metadata), do: event
end