AshWorkflow.TransitionLog (AshWorkflow v0.6.0)

Copy Markdown View Source

Runtime helpers shared by AshWorkflow.Changes.RecordEvent and the generated state_at/2 and history/1 code interface functions.

Kept out of the generated functions themselves so the injected code (via Spark.Dsl.Transformer.eval/3) stays a thin delegate, and so this logic is directly unit-testable.

Summary

Functions

Drops every row that a later undo reversed.

Returns the most recent row representing an actual state change, or nil if there is none.

Returns the transition log rows for record, ordered by occurred_at ascending.

Returns the state record was in at at, resolved by walking its transition log in Elixir. Portable across data layers because it does not rely on a "latest row per record" query.

Returns the undoes self-referencing foreign key on log_resource, or nil if the log does not declare one.

Functions

effective(rows)

@spec effective([Ash.Resource.record()]) :: [Ash.Resource.record()]

Drops every row that a later undo reversed.

An undo row carries undoes_id pointing at the row it reverses, so the superseded set is just the non-nil undoes_id values. Redo falls out of the same rule without a special case: undoing an undo marks the undo row itself superseded, which leaves the redo row — and the state it lands on — standing.

head_state_change(record)

@spec head_state_change(Ash.Resource.record()) :: Ash.Resource.record() | nil

Returns the most recent row representing an actual state change, or nil if there is none.

Rows where from_state == to_state are skipped: an action timeout writes one to record that it fired, and it did not move the workflow anywhere, so it is not what an undo should reverse.

history(record, opts \\ [])

Returns the transition log rows for record, ordered by occurred_at ascending.

Raises if the resource has no transition_log configured.

Options

  • :effective — when true, omits rows that a later undo reversed, leaving the corrected account of what stands rather than the full record of what happened. Defaults to false.

state_at(record, at, opts \\ [])

@spec state_at(Ash.Resource.record(), DateTime.t(), Keyword.t()) :: atom() | nil

Returns the state record was in at at, resolved by walking its transition log in Elixir. Portable across data layers because it does not rely on a "latest row per record" query.

Returns nil if at is before the earliest logged row.

Options

  • :effective — when true, answers from the corrected account rather than the literal one: rows reversed by a later undo are ignored, so a state the workflow briefly occupied and then rewound out of is not reported. Every known correction is applied regardless of when it happened, so this is "what we now say was true at at", not "what the log said at at". Defaults to false.

undoes_foreign_key(log_resource)

@spec undoes_foreign_key(Ash.Resource.t()) :: atom() | nil

Returns the undoes self-referencing foreign key on log_resource, or nil if the log does not declare one.