home · contact · privacy
Refactor models' .by_id().
[plomtask] / plomtask / todos.py
index ce83faddff55278c0efe44f604f6a5fddfaa5851..840c2985b846de2241def493be68b58939f34657 100644 (file)
@@ -1,25 +1,28 @@
 """Actionables."""
 from __future__ import annotations
 """Actionables."""
 from __future__ import annotations
+from typing import Any
 from sqlite3 import Row
 from sqlite3 import Row
-from plomtask.db import DatabaseConnection
-from plomtask.days import Day
+from plomtask.db import DatabaseConnection, BaseModel
 from plomtask.processes import Process
 from plomtask.conditions import Condition
 from plomtask.exceptions import (NotFoundException, BadFormatException,
                                  HandledException)
 
 
 from plomtask.processes import Process
 from plomtask.conditions import Condition
 from plomtask.exceptions import (NotFoundException, BadFormatException,
                                  HandledException)
 
 
-class Todo:
+class Todo(BaseModel):
     """Individual actionable."""
 
     # pylint: disable=too-many-instance-attributes
 
     """Individual actionable."""
 
     # pylint: disable=too-many-instance-attributes
 
+    table_name = 'todos'
+    to_save = ['process_id', 'is_done', 'date']
+
     def __init__(self, id_: int | None, process: Process,
     def __init__(self, id_: int | None, process: Process,
-                 is_done: bool, day: Day) -> None:
-        self.id_ = id_
+                 is_done: bool, date: str) -> None:
+        self.set_int_id(id_)
         self.process = process
         self._is_done = is_done
         self.process = process
         self._is_done = is_done
-        self.day = day
+        self.date = date
         self.children: list[Todo] = []
         self.parents: list[Todo] = []
         self.conditions: list[Condition] = []
         self.children: list[Todo] = []
         self.parents: list[Todo] = []
         self.conditions: list[Condition] = []
@@ -31,29 +34,28 @@ class Todo:
             self.undoes = process.undoes[:]
 
     @classmethod
             self.undoes = process.undoes[:]
 
     @classmethod
-    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=bool(row[2]),
-                   day=Day.by_date(db_conn, row[3]))
-        assert todo.id_ is not None
-        db_conn.cached_todos[todo.id_] = todo
+    def from_table_row(cls, db_conn: DatabaseConnection,
+                       row: Row | list[Any]) -> Todo:
+        """Make from DB row, write to DB cache."""
+        if row[1] == 0:
+            raise NotFoundException('calling Todo of '
+                                    'unsaved Process')
+        row_as_list = list(row)
+        row_as_list[1] = Process.by_id(db_conn, row[1])
+        todo = super().from_table_row(db_conn, row_as_list)
+        assert isinstance(todo, Todo)
         return todo
 
     @classmethod
     def by_id(cls, db_conn: DatabaseConnection, id_: int | None) -> Todo:
         """Get Todo of .id_=id_ and children (from DB cache if possible)."""
         return todo
 
     @classmethod
     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_]
+        if id_:
+            todo, from_cache = super()._by_id(db_conn, id_)
         else:
         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_}')
+            todo, from_cache = None, False
+        if todo is None:
+            raise NotFoundException(f'Todo of ID not found: {id_}')
+        if not from_cache:
             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 child FROM todo_children '
                                     'WHERE parent = ?', (id_,)):
                 todo.children += [cls.by_id(db_conn, row[0])]
@@ -88,7 +90,7 @@ class Todo:
         for row in db_conn.exec('SELECT todo FROM todo_fulfills '
                                 'WHERE condition = ?', (condition.id_,)):
             todo = cls.by_id(db_conn, row[0])
         for row in db_conn.exec('SELECT todo FROM todo_fulfills '
                                 'WHERE condition = ?', (condition.id_,)):
             todo = cls.by_id(db_conn, row[0])
-            if todo.day.date == date:
+            if todo.date == date:
                 enablers += [todo]
         return enablers
 
                 enablers += [todo]
         return enablers
 
@@ -100,7 +102,7 @@ class Todo:
         for row in db_conn.exec('SELECT todo FROM todo_undoes '
                                 'WHERE condition = ?', (condition.id_,)):
             todo = cls.by_id(db_conn, row[0])
         for row in db_conn.exec('SELECT todo FROM todo_undoes '
                                 'WHERE condition = ?', (condition.id_,)):
             todo = cls.by_id(db_conn, row[0])
-            if todo.day.date == date:
+            if todo.date == date:
                 disablers += [todo]
         return disablers
 
                 disablers += [todo]
         return disablers
 
@@ -115,6 +117,11 @@ class Todo:
                 return False
         return True
 
                 return False
         return True
 
+    @property
+    def process_id(self) -> int | str | None:
+        """Return ID of tasked Process."""
+        return self.process.id_
+
     @property
     def is_done(self) -> bool:
         """Wrapper around self._is_done so we can control its setter."""
     @property
     def is_done(self) -> bool:
         """Wrapper around self._is_done so we can control its setter."""
@@ -171,11 +178,8 @@ class Todo:
         """Write self and children to DB and its cache."""
         if self.process.id_ is None:
             raise NotFoundException('Process of Todo without ID (not saved?)')
         """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
+        self.save_core(db_conn)
+        assert isinstance(self.id_, int)
         db_conn.cached_todos[self.id_] = self
         db_conn.exec('DELETE FROM todo_children WHERE parent = ?',
                      (self.id_,))
         db_conn.cached_todos[self.id_] = self
         db_conn.exec('DELETE FROM todo_children WHERE parent = ?',
                      (self.id_,))