Current section

Files

Jump to
ash_dispatch lib resource.ex
Raw

lib/resource.ex

defmodule AshDispatch.Resource do
  @moduledoc """
  Ash.Resource extension for defining event dispatching and counter broadcasting.

  This extension adds `dispatch` and `counters` sections to Ash resources, allowing
  you to define events and counters that are triggered by resource actions.

  ## Event Dispatching

      defmodule MyApp.Orders.ProductOrder do
        use Ash.Resource,
          extensions: [AshDispatch.Resource]

        actions do
          create :create_from_cart do
            # ... action logic ...
          end
        end

        dispatch do
          event :created,
            trigger_on: :create_from_cart,
            channels: [
              [transport: :in_app, audience: :user],
              [transport: :email, audience: :user, delay: 300]
            ],
            content: [
              subject: "Order created",
              notification_title: "Order created"
            ]
        end

        counters do
          counter :pending_orders do
            trigger_on [:create_from_cart, :cancel]
            counter_name :pending_orders
            audience :user
            invalidates ["orders"]
          end
        end
      end

  ## Complex Events

  For events that need custom logic, reference a callback module:

      dispatch do
        event :created,
          trigger_on: :create_from_cart,
          module: MyApp.Events.OrderCreated
      end

  The callback module implements `AshDispatch.Event` behaviour.

  ## Auto-Injection

  The extension automatically injects changes into actions:
  - `DispatchEvent` for events specified in `dispatch` section
  - `BroadcastCounterUpdate` for counters specified in `counters` section

  You don't need to manually add these changes.

  ## Features

  - **Inline definitions** - Simple events/counters defined in the resource
  - **Auto-injection** - Changes automatically added to actions
  - **Type safety** - Compile-time validation of configurations
  - **Optional complexity** - Use callback modules when needed
  """

  use Spark.Dsl.Extension,
    sections: [
      AshDispatch.Resource.Dsl.dispatch_section(),
      AshDispatch.Resource.Dsl.counters_section()
    ],
    transformers: [
      AshDispatch.Resource.Transformers.ValidateEvents,
      AshDispatch.Resource.Transformers.InjectDispatchChanges,
      AshDispatch.Resource.Transformers.InjectCounterBroadcasts,
      AshDispatch.Resource.Transformers.InjectEntityNotifier
    ]

  @doc """
  Codegen callback for `mix ash.codegen` integration.

  Called automatically when running `mix ash.codegen`. Delegates to
  `mix ash_dispatch.gen` with the same arguments.
  """
  def codegen(args) do
    Mix.Task.reenable("ash_dispatch.gen")
    Mix.Task.run("ash_dispatch.gen", args)
  end
end