home · contact · privacy
Fix Process.get_descendants eliminating sibling references to same Process.id_.
[plomtask] / plomtask / processes.py
index bebd39456a804de397b6357919a0ceb0f245be3d..4f97f62f8a8d55527d77b0f66c8719f5e0d2e66b 100644 (file)
@@ -41,7 +41,7 @@ class Process:
     @classmethod
     def by_id(cls, db_conn: DatabaseConnection, id_: int | None,
               create: bool = False) -> Process:
-        """Collect all Processes and their connected VersionedAttributes."""
+        """Collect Process, its VersionedAttributes, and its child IDs."""
         process = None
         for row in db_conn.exec('SELECT * FROM processes '
                                 'WHERE id = ?', (id_,)):
@@ -66,12 +66,27 @@ class Process:
                 process.child_ids += [row[1]]
         return process
 
-    def children(self, db_conn: DatabaseConnection) -> list[Process]:
-        """Return child Processes as determined by self.child_ids."""
-        return [self.__class__.by_id(db_conn, id_) for id_ in self.child_ids]
+    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."""
+        """Add (or re-write) self and connected VersionedAttributes to DB.
+
+        Also is the point at which descendancy recursion is checked.
+        """
+        def walk_descendants(node_id: int) -> None:
+            if node_id == self.id_:
+                raise BadFormatException('bad child selection: recursion')
+            descendant = self.by_id(db_conn, node_id)
+            for descendant_id in descendant.child_ids:
+                walk_descendants(descendant_id)
         cursor = db_conn.exec('REPLACE INTO processes VALUES (?)', (self.id_,))
         self.id_ = cursor.lastrowid
         self.title.save(db_conn)
@@ -80,6 +95,7 @@ class Process:
         db_conn.exec('DELETE FROM process_children WHERE parent_id = ?',
                      (self.id_,))
         for child_id in self.child_ids:
+            walk_descendants(child_id)
             db_conn.exec('INSERT INTO process_children VALUES (?, ?)',
                          (self.id_, child_id))