EctoMiddleware.Resolution (ecto_middleware v2.0.0)

View Source

Resolution struct that tracks middleware execution context and state.

The resolution is passed to every middleware callback and contains information about the current operation, remaining middleware, and provides storage for sharing data between middleware.

Core Fields

  • :repo - The Repo module executing the operation (e.g., MyApp.Repo)
  • :action - The action being performed (e.g., :insert, :update, :get)
  • :args - The full arguments list passed to the Repo function
  • :middleware - The list of remaining middleware to execute
  • :entity - The primary entity/resource being operated on (changeset, struct, query, etc.)
  • :private - Map for passing data between middleware (use put_private/3 and get_private/2)

Using Private Storage

The :private field is a map for storing arbitrary data that middleware need to share:

defmodule SetContext do
  use EctoMiddleware

  def process_before(changeset, resolution) do
    resolution = put_private(resolution, :user_id, 123)
    resolution = put_private(resolution, :timestamp, DateTime.utc_now())
    {:cont, changeset, resolution}
  end
end

defmodule UseContext do
  use EctoMiddleware

  def process_after(result, resolution) do
    user_id = get_private(resolution, :user_id)
    timestamp = get_private(resolution, :timestamp)
    Logger.info("User #{user_id} at #{timestamp}")
    {:cont, result}
  end
end

Updating Resolution

To update the resolution and pass it forward, return a 3-tuple:

def process_before(changeset, resolution) do
  resolution = put_private(resolution, :key, :value)
  {:cont, changeset, resolution}
end

V1 Compatibility Fields (Deprecated)

The following fields exist for V1 backwards compatibility and will be removed in v3.0:

  • :before_input - Original resource before middleware transformations
  • :before_output - Resource after before middleware, before database operation
  • :after_input - Raw database result before after middleware
  • :after_output - Final result after all middleware
  • :before_middleware - V1 before middleware list
  • :after_middleware - V1 after middleware list

Do not use these fields in new code. Use :private storage instead.

Summary

Functions

Retrieves a value from the resolution's private storage.

Stores a key-value pair in the resolution's private storage.

Types

t()

@type t() :: %EctoMiddleware.Resolution{
  action: term(),
  after_input: term(),
  after_middleware: term(),
  after_output: term(),
  args: term(),
  before_input: term(),
  before_middleware: term(),
  before_output: term(),
  entity: term(),
  middleware: term(),
  private: term(),
  repo: term()
}

Functions

get_private(resolution, key, default \\ nil)

@spec get_private(t(), key :: atom(), default :: term()) :: term()

Retrieves a value from the resolution's private storage.

Returns the value if found, otherwise returns the provided default (or nil).

Examples

user_id = get_private(resolution, :user_id)
#=> 123

context = get_private(resolution, :context, %{})
#=> %{tenant: "acme"}

missing = get_private(resolution, :missing)
#=> nil

put_private(resolution, key, value)

@spec put_private(t(), key :: atom(), value :: term()) :: t()

Stores a key-value pair in the resolution's private storage.

This is useful for passing data between middleware in the chain.

Example

resolution = put_private(resolution, :user_id, 123)
resolution = put_private(resolution, :context, %{tenant: "acme"})