Jido.Composer.Node.MapNode (Jido Composer v0.6.0)

Copy Markdown View Source

Applies the same node to each element of a runtime-determined list.

MapNode implements the traverse composition constructor — it takes a collection from context (resolved via the over path) and runs a single node against every element. Results are collected as an ordered list under %{results: [...]}.

Unlike FanOutNode (which runs N different branches known at definition time), MapNode runs one node N times over a collection discovered at runtime.

Options

  • :name — state name (required)
  • :over — context key or path to the list (atom() or [atom()])
  • :node — any Node struct, or a bare Jido.Action module (auto-wrapped)
  • :max_concurrency — limit parallel tasks (default: list length)
  • :timeout — per-element timeout in ms (default: 30_000)
  • :on_error:fail_fast (default) or :collect_partial

Example

{:ok, map_node} = MapNode.new(
  name: :process,
  over: [:extract, :items],
  node: DoubleValueAction
)

# Use in a workflow:
nodes: %{
  extract: ExtractAction,
  process: map_node,
  aggregate: AggregateAction
}

# After execution:
# ctx[:process][:results] => [%{value: 2}, %{value: 4}, %{value: 6}]

Input Preparation

Each element from the collection is prepared as action params:

  • Map elements are merged directly into the flattened context (Map.merge(flat_context, element)), so the action receives both the element's keys and the upstream context.
  • Non-map elements (integers, strings, etc.) are wrapped as %{item: element} and merged into the context.

Edge Cases

  • Empty list: produces %{results: []} and completes with :ok.
  • Missing key: if the over path doesn't resolve to a list (key is missing, value is nil, or value is not a list), it's treated as an empty list.
  • Nested path: over: [:step_a, :sub_key, :items] uses get_in/2 to traverse arbitrarily deep context structures.

Summary

Types

t()

@type t() :: %Jido.Composer.Node.MapNode{
  max_concurrency: pos_integer() | nil,
  merge: :ordered_list,
  name: atom(),
  node: struct(),
  on_error: :fail_fast | :collect_partial,
  over: atom() | [atom()],
  timeout: pos_integer()
}

Functions

new(opts)

@spec new(keyword()) :: {:ok, t()} | {:error, term()}