AshCommanded.Commanded.CommandActionMapper (AshCommanded v0.1.0)
View SourceProvides utilities for mapping between Commanded commands and Ash actions.
This module enhances the integration between commands and actions, providing:
- Advanced parameter transformation between commands and actions
- Support for different action types (create, update, destroy, etc.)
- Helper functions for command handling
- Utilities for applying actions with proper context
- Standardized error handling and reporting
- Transaction support for atomic command execution
These utilities are used by generated code (command handlers, aggregates, etc.) but can also be used directly in custom implementations.
Summary
Functions
Infers the action type based on the action name.
Maps a command to an Ash action and executes it.
Maps and executes multiple commands in a single transaction.
Functions
@spec infer_action_type(atom()) :: :create | :update | :destroy | :read | :custom
Infers the action type based on the action name.
Examples
iex> infer_action_type(:create)
:create
iex> infer_action_type(:update_email)
:update
iex> infer_action_type(:destroy_account)
:destroy
iex> infer_action_type(:custom_operation)
:custom
@spec map_to_action(struct(), module(), atom(), keyword()) :: {:ok, Ash.Resource.record()} | {:error, AshCommanded.Commanded.Error.t() | [AshCommanded.Commanded.Error.t()]}
Maps a command to an Ash action and executes it.
Parameters
command
- The command struct to executeresource
- The Ash resource moduleaction_name
- The name of the Ash action to callopts
- Additional options for the action mapping
Options
:action_type
- The type of action (:create, :update, :destroy, :read, or :custom):identity_field
- The field used to identify the record (default: :id):param_mapping
- A map or function for transforming command fields to action params:context
- Context to pass to the Ash action:before_action
- Function to call before executing the action:after_action
- Function to call after executing the action:transforms
- List of parameter transformations to apply:validations
- List of parameter validations to apply:in_transaction?
- Whether to execute the command in a transaction (default: false):repo
- Repository to use for transaction (required if in_transaction? is true):transaction_opts
- Options for the transaction (timeout, isolation_level)
Return Values
{:ok, record}
- The action was executed successfully, returning the record{:error, error}
- An error occurred. The error will be a standardized AshCommanded.Commanded.Error or list of errors
Examples
Basic usage with default mappings:
map_to_action(%MyApp.Commands.RegisterUser{}, MyApp.User, :create)
With custom parameter mapping:
map_to_action(
%MyApp.Commands.UpdateEmail{id: "123", email: "new@example.com"},
MyApp.User,
:update_email,
action_type: :update,
param_mapping: %{email: :new_email},
context: %{actor: current_user}
)
With transformation functions:
map_to_action(
%MyApp.Commands.CreateProduct{},
MyApp.Product,
:create,
param_mapping: fn cmd ->
Map.put(cmd, :created_at, DateTime.utc_now())
end
)
With transaction support:
map_to_action(
%MyApp.Commands.RegisterUser{},
MyApp.User,
:create,
in_transaction?: true,
repo: MyApp.Repo,
transaction_opts: [timeout: 30_000]
)
@spec transactional_map_to_action([map()], module(), keyword()) :: {:ok, map()} | {:error, atom(), any(), %{required(atom()) => any()}}
Maps and executes multiple commands in a single transaction.
Parameters
commands
- List of command specificationsrepo
- Repository to use for the transactionopts
- Transaction options
Command Specifications
Each command specification is a map with the following keys:
:command
- The command struct to execute:resource
- The Ash resource module:action
- The action name:opts
- (Optional) Command-specific options
Return Values
{:ok, results}
- All commands executed successfully, with a map of results{:error, failed_operation, error, results_so_far}
- Transaction failed
Examples
AshCommanded.Commanded.CommandActionMapper.transactional_map_to_action([
%{
command: %MyApp.Commands.RegisterUser{name: "John", email: "john@example.com"},
resource: MyApp.User,
action: :create
},
%{
command: %MyApp.Commands.CreateProfile{user_id: "123", bio: "Developer"},
resource: MyApp.Profile,
action: :create,
opts: [param_mapping: %{user_id: :owner_id}]
}
], MyApp.Repo)