X-Git-Url: https://plomlompom.com/repos/berlin_corona.txt?a=blobdiff_plain;f=plomtask%2Ftodos.py;h=e8e00acbd8cd77d58d7d99ce2d0551288ffb96f4;hb=d77d0661697655a7c2d0e9e0b270cf21e286d7fb;hp=7150f0d702c44ec89e170e5381b20c8e61ea42ae;hpb=982d712cbf12acde21ce448e0d1ed28468f1c90e;p=plomtask diff --git a/plomtask/todos.py b/plomtask/todos.py index 7150f0d..e8e00ac 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,38 +17,79 @@ class Todo: self.process = process self.is_done = is_done self.day = day - - def __eq__(self, other: object) -> bool: - return isinstance(other, self.__class__) and self.id_ == other.id_ + self.children: list[Todo] = [] + self.parents: list[Todo] = [] @classmethod - def from_table_row(cls, row: Row, db_conn: DatabaseConnection) -> Todo: - """Make Todo from database row.""" - return cls(id_=row[0], + def from_table_row(cls, db_conn: DatabaseConnection, row: Row) -> Todo: + """Make Todo from database row, write to DB cache.""" + todo = cls(id_=row[0], process=Process.by_id(db_conn, row[1]), is_done=row[2], day=Day.by_date(db_conn, row[3])) + assert todo.id_ is not None + db_conn.cached_todos[todo.id_] = todo + return todo @classmethod - def by_id(cls, db_conn: DatabaseConnection, id_: int) -> Todo: - """Get Todo of .id_=id_.""" - for row in db_conn.exec('SELECT * FROM todos WHERE id = ?', (id_,)): - return cls.from_table_row(row, db_conn) - raise NotFoundException(f'Todo of ID not found: {id_}') + 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_] + 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])] + for row in db_conn.exec('SELECT parent FROM todo_children ' + 'WHERE child = ?', (id_,)): + todo.parents += [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]: """Collect all Todos for Day of date.""" todos = [] - for row in db_conn.exec('SELECT * FROM todos WHERE day = ?', (date,)): - todos += [cls.from_table_row(row, db_conn)] + for row in db_conn.exec('SELECT id FROM todos WHERE day = ?', (date,)): + 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] + child.parents += [self] + def save(self, db_conn: DatabaseConnection) -> None: - """Write self to DB.""" + """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 (?,?,?,?)', (self.id_, self.process.id_, self.is_done, self.day.date)) 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_))