home · contact · privacy
Overhaul as_dict generation to avoid endless nesting of objects.
[plomtask] / plomtask / days.py
index 0815b9bde6e515381f644fd33a120b880b533abb..68cf989643924a42b1ef8b48cc04a63434efe6b9 100644 (file)
@@ -1,5 +1,7 @@
 """Collecting Day and date-related items."""
 from __future__ import annotations
 """Collecting Day and date-related items."""
 from __future__ import annotations
+from typing import Any
+from sqlite3 import Row
 from datetime import datetime, timedelta
 from plomtask.db import DatabaseConnection, BaseModel
 from plomtask.todos import Todo
 from datetime import datetime, timedelta
 from plomtask.db import DatabaseConnection, BaseModel
 from plomtask.todos import Todo
@@ -10,17 +12,45 @@ class Day(BaseModel[str]):
     """Individual days defined by their dates."""
     table_name = 'days'
     to_save = ['comment']
     """Individual days defined by their dates."""
     table_name = 'days'
     to_save = ['comment']
+    can_create_by_id = True
 
     def __init__(self, date: str, comment: str = '') -> None:
         id_ = valid_date(date)
         super().__init__(id_)
         self.datetime = datetime.strptime(self.date, DATE_FORMAT)
         self.comment = comment
 
     def __init__(self, date: str, comment: str = '') -> None:
         id_ = valid_date(date)
         super().__init__(id_)
         self.datetime = datetime.strptime(self.date, DATE_FORMAT)
         self.comment = comment
-        self.calendarized_todos: list[Todo] = []
+        self.todos: list[Todo] = []
 
     def __lt__(self, other: Day) -> bool:
         return self.date < other.date
 
 
     def __lt__(self, other: Day) -> bool:
         return self.date < other.date
 
+    @property
+    def as_dict(self) -> dict[str, object]:
+        """Return self as (json.dumps-coompatible) dict."""
+        d = super().as_dict
+        assert isinstance(d['_library'], dict)
+        d['todos'] = [t.as_dict_into_reference(d['_library'])
+                      for t in self.todos]
+        return d
+
+    @classmethod
+    def from_table_row(cls, db_conn: DatabaseConnection, row: Row | list[Any]
+                       ) -> Day:
+        """Make from DB row, with linked Todos."""
+        day = super().from_table_row(db_conn, row)
+        assert isinstance(day.id_, str)
+        day.todos = Todo.by_date(db_conn, day.id_)
+        return day
+
+    @classmethod
+    def by_id(cls, db_conn: DatabaseConnection, id_: str) -> Day:
+        """Extend BaseModel.by_id checking for new/lost .todos."""
+        day = super().by_id(db_conn, id_)
+        if day.id_ in Todo.days_to_update:
+            Todo.days_to_update.remove(day.id_)
+            day.todos = Todo.by_date(db_conn, day.id_)
+        return day
+
     @classmethod
     def by_date_range_filled(cls, db_conn: DatabaseConnection,
                              start: str, end: str) -> list[Day]:
     @classmethod
     def by_date_range_filled(cls, db_conn: DatabaseConnection,
                              start: str, end: str) -> list[Day]:
@@ -85,7 +115,15 @@ class Day(BaseModel[str]):
         next_datetime = self.datetime + timedelta(days=1)
         return next_datetime.strftime(DATE_FORMAT)
 
         next_datetime = self.datetime + timedelta(days=1)
         return next_datetime.strftime(DATE_FORMAT)
 
-    def collect_calendarized_todos(self, db_conn: DatabaseConnection) -> None:
-        """Fill self.calendarized_todos."""
-        self.calendarized_todos = [t for t in Todo.by_date(db_conn, self.date)
-                                   if t.calendarize]
+    @property
+    def calendarized_todos(self) -> list[Todo]:
+        """Return only those of self.todos that have .calendarize set."""
+        return [t for t in self.todos if t.calendarize]
+
+    @property
+    def total_effort(self) -> float:
+        """"Sum all .performed_effort of self.todos."""
+        total_effort = 0.0
+        for todo in self.todos:
+            total_effort += todo.performed_effort
+        return total_effort