Packages
Event-driven notification system for Ash Framework with multiple transport types
Current section
Files
Jump to
Current section
Files
lib/resource/info.ex
defmodule AshDispatch.Resource.Info do
@moduledoc """
Introspection helpers for AshDispatch.Resource.
Provides functions to query event configurations from resources at runtime.
## Usage
# Get all events for a resource
events = AshDispatch.Resource.Info.events(MyApp.Orders.ProductOrder)
# Get a specific event by name
event = AshDispatch.Resource.Info.event(MyApp.Orders.ProductOrder, :created)
# Get event options
event_id = AshDispatch.Resource.Info.event_id(event)
trigger_on = AshDispatch.Resource.Info.trigger_on(event)
channels = AshDispatch.Resource.Info.channels(event)
## Generated Functions
This module uses `Spark.InfoGenerator` to automatically generate helper functions
for querying the `dispatch` section and its entities.
**Resource-level:**
- `events(resource)` - Returns all events defined in the resource
**Event entity getters:**
- `name(event)` - Get event name
- `trigger_on(event)` - Get action names that trigger this event
- `module(event)` - Get callback module (if any)
- `event_id(event)` - Get event ID
- `domain(event)` - Get event domain
- `load(event)` - Get relationships to preload
- `channels(event)` - Get channel configurations
- `content(event)` - Get content configuration
- `metadata(event)` - Get metadata configuration
## Examples
# Find events triggered by specific action
iex> events = AshDispatch.Resource.Info.events(ProductOrder)
iex> Enum.filter(events, fn event ->
...> :create in List.wrap(AshDispatch.Resource.Info.trigger_on(event))
...> end)
[%AshDispatch.Resource.Dsl.Event{name: :created, ...}]
# Get all event IDs for a resource
iex> events = AshDispatch.Resource.Info.events(ProductOrder)
iex> Enum.map(events, &AshDispatch.Resource.Info.event_id/1)
["product_order.created", "product_order.cancelled"]
# Check if event has callback module
iex> event = AshDispatch.Resource.Info.event(ProductOrder, :created)
iex> if AshDispatch.Resource.Info.module(event) do
...> "Uses callback module"
...> else
...> "Uses inline config"
...> end
"Uses inline config"
"""
use Spark.InfoGenerator,
sections: [:dispatch],
extension: AshDispatch.Resource
@doc """
Get all events defined in a resource.
## Parameters
- `resource` - The resource module
## Returns
List of `%AshDispatch.Resource.Dsl.Event{}` structs
## Examples
iex> AshDispatch.Resource.Info.events(ProductOrder)
[%AshDispatch.Resource.Dsl.Event{name: :created, ...}]
"""
def events(resource) do
Spark.Dsl.Extension.get_entities(resource, [:dispatch])
end
@doc """
Get a specific event by name.
## Parameters
- `resource` - The resource module
- `name` - The event name (atom)
## Returns
- `%AshDispatch.Resource.Dsl.Event{}` if found
- `nil` if not found
## Examples
iex> AshDispatch.Resource.Info.event(ProductOrder, :created)
%AshDispatch.Resource.Dsl.Event{name: :created, ...}
iex> AshDispatch.Resource.Info.event(ProductOrder, :nonexistent)
nil
"""
def event(resource, name) do
resource
|> events()
|> Enum.find(&(&1.name == name))
end
@doc """
Get all events that trigger on a specific action.
## Parameters
- `resource` - The resource module
- `action_name` - The action name (atom)
## Returns
List of `%AshDispatch.Resource.Dsl.Event{}` structs
## Examples
iex> AshDispatch.Resource.Info.events_for_action(ProductOrder, :create)
[%AshDispatch.Resource.Dsl.Event{name: :created, trigger_on: :create}]
iex> AshDispatch.Resource.Info.events_for_action(ProductOrder, :update)
[]
"""
def events_for_action(resource, action_name) do
resource
|> events()
|> Enum.filter(fn event ->
trigger_on = event.trigger_on
cond do
is_atom(trigger_on) -> trigger_on == action_name
is_list(trigger_on) -> action_name in trigger_on
true -> false
end
end)
end
@doc """
Check if a resource has the AshDispatch.Resource extension.
## Parameters
- `resource` - The resource module
## Returns
- `true` if resource uses AshDispatch.Resource
- `false` otherwise
## Examples
iex> AshDispatch.Resource.Info.dispatch_enabled?(ProductOrder)
true
iex> AshDispatch.Resource.Info.dispatch_enabled?(SomeOtherResource)
false
"""
def dispatch_enabled?(resource) do
AshDispatch.Resource in Spark.extensions(resource)
end
@doc """
Get all event IDs for a resource.
## Parameters
- `resource` - The resource module
## Returns
List of event ID strings
## Examples
iex> AshDispatch.Resource.Info.event_ids(ProductOrder)
["product_order.created", "product_order.cancelled", "product_order.shipped"]
"""
def event_ids(resource) do
resource
|> events()
|> Enum.map(& &1.event_id)
|> Enum.reject(&is_nil/1)
end
@doc """
Get all events that use callback modules.
## Parameters
- `resource` - The resource module
## Returns
List of `%AshDispatch.Resource.Dsl.Event{}` structs that have a module defined
## Examples
iex> AshDispatch.Resource.Info.events_with_modules(ProductOrder)
[%AshDispatch.Resource.Dsl.Event{name: :complex_event, module: MyApp.Events.Complex}]
"""
def events_with_modules(resource) do
resource
|> events()
|> Enum.filter(& &1.module)
end
@doc """
Get all events that use inline configuration.
## Parameters
- `resource` - The resource module
## Returns
List of `%AshDispatch.Resource.Dsl.Event{}` structs that use inline config
## Examples
iex> AshDispatch.Resource.Info.inline_events(ProductOrder)
[%AshDispatch.Resource.Dsl.Event{name: :created, module: nil, channels: [...]}]
"""
def inline_events(resource) do
resource
|> events()
|> Enum.reject(& &1.module)
end
@doc """
Count total events for a resource.
## Parameters
- `resource` - The resource module
## Returns
Integer count of events
## Examples
iex> AshDispatch.Resource.Info.event_count(ProductOrder)
3
"""
def event_count(resource) do
resource
|> events()
|> length()
end
@doc """
Get all counters defined in a resource.
## Parameters
- `resource` - The resource module
## Returns
List of `%AshDispatch.Resource.Dsl.Counter{}` structs
## Examples
iex> AshDispatch.Resource.Info.counters(ProductOrder)
[%AshDispatch.Resource.Dsl.Counter{name: :pending_orders_counter, ...}]
"""
def counters(resource) do
Spark.Dsl.Extension.get_entities(resource, [:counters])
end
@doc """
Get a specific counter by name.
## Parameters
- `resource` - The resource module
- `name` - The counter name (atom)
## Returns
- `%AshDispatch.Resource.Dsl.Counter{}` if found
- `nil` if not found
## Examples
iex> AshDispatch.Resource.Info.counter(ProductOrder, :pending_orders_counter)
%AshDispatch.Resource.Dsl.Counter{name: :pending_orders_counter, ...}
"""
def counter(resource, name) do
resource
|> counters()
|> Enum.find(&(&1.name == name))
end
@doc """
Get entity_changes configuration for a resource, if any.
Returns the `%AshDispatch.Resource.Dsl.EntityChanges{}` struct if
`entity_changes true` is defined in the dispatch section, or `nil`.
"""
def entity_changes(resource) do
resource
|> events()
|> Enum.find(fn
%AshDispatch.Resource.Dsl.EntityChanges{} -> true
_ -> false
end)
end
@doc """
Check if entity change broadcasting is enabled for a resource.
"""
def entity_changes_enabled?(resource) do
case entity_changes(resource) do
%AshDispatch.Resource.Dsl.EntityChanges{enabled: true} -> true
_ -> false
end
end
@doc """
Get resource_meta configuration for a resource, if any.
Returns the `%AshDispatch.Resource.Dsl.ResourceMeta{}` struct if
`resource_meta` is defined in the dispatch section, or `nil`.
"""
def resource_meta(resource) do
resource
|> events()
|> Enum.find(fn
%AshDispatch.Resource.Dsl.ResourceMeta{} -> true
_ -> false
end)
end
end