AshCommanded.Commanded.CommandActionMapper (AshCommanded v0.1.0)

View Source

Provides utilities for mapping between Commanded commands and Ash actions.

This module enhances the integration between commands and actions, providing:

  1. Advanced parameter transformation between commands and actions
  2. Support for different action types (create, update, destroy, etc.)
  3. Helper functions for command handling
  4. Utilities for applying actions with proper context
  5. Standardized error handling and reporting
  6. 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

infer_action_type(action_name)

@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

map_to_action(command, resource, action_name, opts \\ [])

@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 execute
  • resource - The Ash resource module
  • action_name - The name of the Ash action to call
  • opts - 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]
)

transactional_map_to_action(commands, repo, opts \\ [])

@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 specifications
  • repo - Repository to use for the transaction
  • opts - 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)