X-Git-Url: https://plomlompom.com/repos/?a=blobdiff_plain;f=plomtask%2Ftodos.py;h=7faea73b74df9c4b5a8f68f6dceced09f27c9b67;hb=63249f5d7cefb97574610848ca3473cb1f9687e2;hp=f1d98ad3a0719c3027bc55620b5f6a97be2ab628;hpb=6b329a28bb4aec8d1846f5cc5402ed6fca5eb3da;p=plomtask diff --git a/plomtask/todos.py b/plomtask/todos.py index f1d98ad..7faea73 100644 --- a/plomtask/todos.py +++ b/plomtask/todos.py @@ -4,7 +4,8 @@ from sqlite3 import Row from plomtask.db import DatabaseConnection from plomtask.days import Day from plomtask.processes import Process -from plomtask.exceptions import NotFoundException +from plomtask.exceptions import (NotFoundException, BadFormatException, + HandledException) class Todo: @@ -16,6 +17,7 @@ class Todo: self.process = process self.is_done = is_done self.day = day + self.children: list[Todo] = [] @classmethod def from_table_row(cls, db_conn: DatabaseConnection, row: Row) -> Todo: @@ -29,15 +31,23 @@ class Todo: return todo @classmethod - def by_id(cls, db_conn: DatabaseConnection, id_: int) -> Todo: - """Get Todo of .id_=id_ – from DB cache if possible.""" + def by_id(cls, db_conn: DatabaseConnection, id_: int | None) -> Todo: + """Get Todo of .id_=id_ and children (from DB cache if possible).""" if id_ in db_conn.cached_todos.keys(): todo = db_conn.cached_todos[id_] - assert isinstance(todo, Todo) - return todo - for row in db_conn.exec('SELECT * FROM todos WHERE id = ?', (id_,)): - return cls.from_table_row(db_conn, row) - raise NotFoundException(f'Todo of ID not found: {id_}') + else: + todo = None + for row in db_conn.exec('SELECT * FROM todos WHERE id = ?', + (id_,)): + todo = cls.from_table_row(db_conn, row) + break + if todo is None: + raise NotFoundException(f'Todo of ID not found: {id_}') + for row in db_conn.exec('SELECT child FROM todo_children ' + 'WHERE parent = ?', (id_,)): + todo.children += [cls.by_id(db_conn, row[0])] + assert isinstance(todo, Todo) + return todo @classmethod def by_date(cls, db_conn: DatabaseConnection, date: str) -> list[Todo]: @@ -47,8 +57,24 @@ class Todo: todos += [cls.by_id(db_conn, row[0])] return todos + def add_child(self, child: Todo) -> None: + """Add child to self.children, guard against recursion""" + def walk_steps(node: Todo) -> None: + if node.id_ == self.id_: + raise BadFormatException('bad child choice causes recursion') + for child in node.children: + walk_steps(child) + if self.id_ is None: + raise HandledException('Can only add children to saved Todos.') + if child.id_ is None: + raise HandledException('Can only add saved children to Todos.') + if child in self.children: + raise BadFormatException('cannot adopt same child twice') + walk_steps(child) + self.children += [child] + def save(self, db_conn: DatabaseConnection) -> None: - """Write self to DB and its cache.""" + """Write self and children to DB and its cache.""" if self.process.id_ is None: raise NotFoundException('Process of Todo without ID (not saved?)') cursor = db_conn.exec('REPLACE INTO todos VALUES (?,?,?,?)', @@ -57,3 +83,8 @@ class Todo: self.id_ = cursor.lastrowid assert self.id_ is not None db_conn.cached_todos[self.id_] = self + db_conn.exec('DELETE FROM todo_children WHERE parent = ?', + (self.id_,)) + for child in self.children: + db_conn.exec('INSERT INTO todo_children VALUES (?, ?)', + (self.id_, child.id_))