- def get_descendants(self, db_conn: DatabaseConnection) ->\
- dict[int, dict[str, object]]:
- """Return tree of descendant Processes"""
- descendants = {}
- for id_ in self.child_ids:
- child = self.__class__.by_id(db_conn, id_)
- descendants[id_] = {'process': child,
- 'children': child.get_descendants(db_conn)}
- return descendants
+ def used_as_step_by(self, db_conn: DatabaseConnection) -> list[Process]:
+ """Return Processes using self for a ProcessStep."""
+ if not self.id_:
+ return []
+ owner_ids = set()
+ for id_ in db_conn.column_where('process_steps', 'owner',
+ 'step_process', self.id_):
+ owner_ids.add(id_)
+ return [self.__class__.by_id(db_conn, id_) for id_ in owner_ids]
+
+ def get_steps(self, db_conn: DatabaseConnection, external_owner:
+ Process | None = None) -> dict[int, ProcessStepsNode]:
+ """Return tree of depended-on explicit and implicit ProcessSteps."""
+
+ def make_node(step: ProcessStep) -> ProcessStepsNode:
+ is_explicit = False
+ if external_owner is not None:
+ is_explicit = step.owner_id == external_owner.id_
+ process = self.__class__.by_id(db_conn, step.step_process_id)
+ step_steps = process.get_steps(db_conn, external_owner)
+ return ProcessStepsNode(process, step.parent_step_id,
+ is_explicit, step_steps, False)
+
+ def walk_steps(node_id: int, node: ProcessStepsNode) -> None:
+ explicit_children = [s for s in self.explicit_steps
+ if s.parent_step_id == node_id]
+ for child in explicit_children:
+ assert isinstance(child.id_, int)
+ node.steps[child.id_] = make_node(child)
+ node.seen = node_id in seen_step_ids
+ seen_step_ids.add(node_id)
+ for id_, step in node.steps.items():
+ walk_steps(id_, step)
+
+ steps: dict[int, ProcessStepsNode] = {}
+ seen_step_ids: Set[int] = set()
+ if external_owner is None:
+ external_owner = self
+ for step in [s for s in self.explicit_steps
+ if s.parent_step_id is None]:
+ assert isinstance(step.id_, int)
+ steps[step.id_] = make_node(step)
+ for step_id, step_node in steps.items():
+ walk_steps(step_id, step_node)
+ return steps
+
+ def _add_step(self,
+ db_conn: DatabaseConnection,
+ id_: int | None,
+ step_process_id: int,
+ parent_step_id: int | None) -> ProcessStep:
+ """Create new ProcessStep, save and add it to self.explicit_steps.
+
+ Also checks against step recursion.
+
+ The new step's parent_step_id will fall back to None either if no
+ matching ProcessStep is found (which can be assumed in case it was
+ just deleted under its feet), or if the parent step would not be
+ owned by the current Process.
+ """