- def get_descendants(self, db_conn: DatabaseConnection) ->\
- list[dict[str, object]]:
- """Return tree of descendant Processes"""
- descendants = []
- for id_ in self.child_ids:
- child = self.__class__.by_id(db_conn, id_)
- descendants += [{'process': child,
- 'children': child.get_descendants(db_conn)}]
- return descendants
-
- def save(self, db_conn: DatabaseConnection) -> None:
- """Add (or re-write) self and connected VersionedAttributes to DB.
-
- Also is the point at which descendancy recursion is checked.
+ def get_steps(self, db_conn: DatabaseConnection, external_owner:
+ Process | None = None) -> dict[int, dict[str, object]]:
+ """Return tree of depended-on explicit and implicit ProcessSteps."""
+
+ def make_node(step: ProcessStep) -> dict[str, object]:
+ step_process = self.__class__.by_id(db_conn, step.step_process_id)
+ is_explicit = False
+ if external_owner is not None:
+ is_explicit = step.owner_id == external_owner.id_
+ step_steps = step_process.get_steps(db_conn, external_owner)
+ return {'process': step_process, 'parent_id': step.parent_step_id,
+ 'is_explicit': is_explicit, 'steps': step_steps}
+
+ def walk_steps(node_id: int, node: dict[str, Any]) -> None:
+ explicit_children = [s for s in self.explicit_steps
+ if s.parent_step_id == node_id]
+ for child in explicit_children:
+ node['steps'][child.id_] = make_node(child)
+ for id_, step in node['steps'].items():
+ walk_steps(id_, step)
+
+ steps: dict[int, dict[str, object]] = {}
+ 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 step.id_ is not None # for mypy
+ 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.