LiveFlow.Validation (LiveFlow v0.4.0)

Copy Markdown View Source

Connection validation functions for LiveFlow.

Provides composable validator functions that check whether a connection between two nodes/handles should be allowed. Each validator takes a flow state and connection params, returning :ok or {:error, reason}.

Usage

Validators can be composed in a list and run with validate/3:

validators = [
  &LiveFlow.Validation.no_duplicate_edges/2,
  &LiveFlow.Validation.nodes_exist/2,
  &LiveFlow.Validation.no_cycles/2
]

case LiveFlow.Validation.validate(flow, params, validators) do
  :ok -> # create the edge
  {:error, reason} -> # reject with reason
end

Or use presets for common combinations:

validators = LiveFlow.Validation.preset(:strict)

Presets

  • :default — no duplicate edges + nodes exist
  • :strict — default + handles valid + connectable check

Summary

Functions

Validates that the source and target handles exist on their respective nodes and that both handles have connectable: true.

Limits the maximum number of connections per handle.

Prevents cycles in the flow graph.

Rejects duplicate edges between the same source/target/handles.

Validates that both source and target nodes exist in the flow.

Returns a preset list of validators.

Validates that both handles share the same connect_type.

Runs a list of validators against the given flow and connection params.

Types

conn_params()

@type conn_params() :: %{
  source: String.t(),
  target: String.t(),
  source_handle: String.t() | nil,
  target_handle: String.t() | nil
}

validator()

@type validator() :: (LiveFlow.State.t(), conn_params() -> :ok | {:error, String.t()})

Functions

handles_valid(flow, params)

@spec handles_valid(LiveFlow.State.t(), conn_params()) :: :ok | {:error, String.t()}

Validates that the source and target handles exist on their respective nodes and that both handles have connectable: true.

max_connections(flow, params, opts)

@spec max_connections(LiveFlow.State.t(), conn_params(), keyword()) ::
  :ok | {:error, String.t()}

Limits the maximum number of connections per handle.

Checks both the source and target handles. If either already has max or more connections, the new connection is rejected.

Options

  • :max - Maximum connections per handle (required)

no_cycles(flow, params)

@spec no_cycles(LiveFlow.State.t(), conn_params()) :: :ok | {:error, String.t()}

Prevents cycles in the flow graph.

Rejects a connection if there is already a path from the target node back to the source node (which would create a cycle).

no_duplicate_edges(flow, params)

@spec no_duplicate_edges(LiveFlow.State.t(), conn_params()) ::
  :ok | {:error, String.t()}

Rejects duplicate edges between the same source/target/handles.

Uses State.edge_exists?/5 which was previously unused.

nodes_exist(flow, params)

@spec nodes_exist(LiveFlow.State.t(), conn_params()) :: :ok | {:error, String.t()}

Validates that both source and target nodes exist in the flow.

preset(atom)

@spec preset(:default | :strict) :: [validator()]

Returns a preset list of validators.

  • :default[no_duplicate_edges, nodes_exist]
  • :strict — default + [handles_valid]

types_compatible(flow, params)

@spec types_compatible(LiveFlow.State.t(), conn_params()) ::
  :ok | {:error, String.t()}

Validates that both handles share the same connect_type.

If either handle has no connect_type set (nil), the check passes. Only rejects when both handles have explicit types that don't match.

validate(flow, params, validators)

@spec validate(LiveFlow.State.t(), conn_params(), [validator()]) ::
  :ok | {:error, String.t()}

Runs a list of validators against the given flow and connection params.

Returns :ok if all validators pass, or {:error, reason} on the first failure (short-circuits).