Lightning.Collaboration.WorkflowResolver (Lightning v2.16.8-pre)
View SourceSingle authority for resolving "given a workflow_id and an action, what
%Workflow{} should a collaboration session edit, and in which Ecto state?".
Both the channel join and the session save delegate here so they cannot
disagree on whether an id maps to a :built or :loaded struct — the
structural root cause behind the workflows_pkey duplicate INSERT on collab
reconnect (#4830).
The resolver performs no authorization (Permissions.can stays at the
channel). It does enforce project-ownership, but only when a :project opt is
supplied, because ownership is a property of the resolved row, not of the
user.
Summary
Types
The discriminant the resolver returns alongside the workflow, so callers read newness from the tag rather than re-deriving it from struct shape
Functions
Resolves the %Workflow{} a collaboration session should edit.
Hydrates a read-only %Workflow{} from a specific snapshot version.
Types
@type action() :: :new | :edit
@type kind() :: :new | :existing | :version
The discriminant the resolver returns alongside the workflow, so callers read newness from the tag rather than re-deriving it from struct shape:
:new—:newaction with no existing DB row (a freshly built:builtstruct).:existing— a:newaction for an id that already has a row, or an:editaction (loaded row).:version— a snapshot version-view (resolve_version/3).
@type resolve_opts() :: [ version: non_neg_integer() | nil, project: Lightning.Projects.Project.t() | nil ]
Functions
@spec resolve( workflow_id :: Ecto.UUID.t(), action :: action(), opts :: resolve_opts() ) :: {:ok, Lightning.Workflows.Workflow.t(), kind()} | {:error, :workflow_not_found | :wrong_project | :snapshot_not_found | :invalid_action}
Resolves the %Workflow{} a collaboration session should edit.
Returns {:ok, workflow, kind} where workflow is already in the correct
Ecto state (with jobs, edges, and triggers populated and the
has_auth_method flag set on each trigger) and kind is the newness
discriminant (see kind/0).
Cases:
action: :new, no existing row — a freshly built%Workflow{}keyed onworkflow_id, withproject_idfrom the supplied project, empty jobs/edges/triggers, andlock_version: 0. Ecto state:built, kind:new. The first-INSERT case.action: :new, row already exists — the persisted workflow loaded with jobs/edges/triggers. Ecto state:loaded, kind:existing. Resolving an existing id to its loaded row routes the save to UPDATE rather than a duplicate INSERT (#4830).action: :edit, no version, row exists — the persisted workflow loaded with jobs/edges/triggers andhas_auth_methodset. Ecto state:loaded, kind:existing.action: :edit, no version, no row —{:error, :workflow_not_found}.- unknown action —
{:error, :invalid_action}.
@spec resolve_version( workflow_id :: Ecto.UUID.t(), version :: non_neg_integer(), opts :: resolve_opts() ) :: {:ok, Lightning.Workflows.Workflow.t(), kind()} | {:error, :snapshot_not_found}
Hydrates a read-only %Workflow{} from a specific snapshot version.
Dispatched from resolve/3 when a non-nil :version opt is present, and may
also be called directly. The version is a non_neg_integer() already parsed
by the caller — the resolver never parses version strings.
Returns a %Workflow{} in Ecto state :built carrying the snapshot's
lock_version and tagged with kind :version. A version-view is a read-only
point-in-time view that is never saved through this path; the :version kind
lets callers distinguish it from a genuinely-new workflow.
Sets project_id from the supplied project and performs no ownership
check, unlike the :edit latest path. Performs no authorization (auth
stays at the channel).
Returns {:error, :snapshot_not_found} when no snapshot exists for the
version.