home · contact · privacy
Re-factor date ranging and default to range 'yesterday' to 'tomorrow'.
authorChristian Heller <c.heller@plomlompom.de>
Thu, 30 May 2024 06:57:46 +0000 (08:57 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Thu, 30 May 2024 06:57:46 +0000 (08:57 +0200)
plomtask/dating.py
plomtask/days.py
plomtask/db.py
plomtask/http.py
tests/days.py

index 711da95efabfc97153cca3c5d85eb63348244397..c55d847a1319a3687ac0ac06edc63b79e142ca09 100644 (file)
@@ -3,8 +3,6 @@ from datetime import datetime, timedelta
 from plomtask.exceptions import BadFormatException
 
 DATE_FORMAT = '%Y-%m-%d'
-MIN_RANGE_DATE = '2024-01-01'
-MAX_RANGE_DATE = '2030-12-31'
 
 
 def valid_date(date_str: str) -> str:
index d7083b4310bf76c168f6f33d29cf55c8ada7a29f..0815b9bde6e515381f644fd33a120b880b533abb 100644 (file)
@@ -22,31 +22,33 @@ class Day(BaseModel[str]):
         return self.date < other.date
 
     @classmethod
-    def all(cls, db_conn: DatabaseConnection,
-            date_range: tuple[str, str] = ('', ''),
-            fill_gaps: bool = False) -> list[Day]:
-        """Return list of Days in database within (open) date_range interval.
-
-        On fill_gaps=True, will instantiate (without saving) Days of all dates
-        within the date range that don't exist yet.
-        """
-        ret = cls.by_date_range_with_limits(db_conn, date_range, 'id')
+    def by_date_range_filled(cls, db_conn: DatabaseConnection,
+                             start: str, end: str) -> list[Day]:
+        """Return days existing and non-existing between dates start/end."""
+        ret = cls.by_date_range_with_limits(db_conn, (start, end), 'id')
         days, start_date, end_date = ret
+        return cls.with_filled_gaps(days, start_date, end_date)
+
+    @classmethod
+    def with_filled_gaps(cls, days: list[Day], start_date: str, end_date: str
+                         ) -> list[Day]:
+        """In days, fill with (un-saved) Days gaps between start/end_date."""
+        if start_date > end_date:
+            return days
         days.sort()
-        if fill_gaps:
-            if start_date not in [d.date for d in days]:
-                days = [Day(start_date)] + days
-            if end_date not in [d.date for d in days]:
-                days += [Day(end_date)]
-            if len(days) > 1:
-                gapless_days = []
-                for i, day in enumerate(days):
-                    gapless_days += [day]
-                    if i < len(days) - 1:
-                        while day.next_date != days[i+1].date:
-                            day = Day(day.next_date)
-                            gapless_days += [day]
-                days = gapless_days
+        if start_date not in [d.date for d in days]:
+            days[:] = [Day(start_date)] + days
+        if end_date not in [d.date for d in days]:
+            days += [Day(end_date)]
+        if len(days) > 1:
+            gapless_days = []
+            for i, day in enumerate(days):
+                gapless_days += [day]
+                if i < len(days) - 1:
+                    while day.next_date != days[i+1].date:
+                        day = Day(day.next_date)
+                        gapless_days += [day]
+            days[:] = gapless_days
         return days
 
     @property
index 4396b444a61f0c2f59e2046b554e79c56e541faa..b5461a507e9612e2593643e6d6e198779e2fc456 100644 (file)
@@ -6,7 +6,7 @@ from difflib import Differ
 from sqlite3 import connect as sql_connect, Cursor, Row
 from typing import Any, Self, TypeVar, Generic
 from plomtask.exceptions import HandledException, NotFoundException
-from plomtask.dating import (MIN_RANGE_DATE, MAX_RANGE_DATE, valid_date)
+from plomtask.dating import valid_date
 
 EXPECTED_DB_VERSION = 4
 MIGRATIONS_DIR = 'migrations'
@@ -358,19 +358,19 @@ class BaseModel(Generic[BaseModelId]):
     @classmethod
     def by_date_range_with_limits(cls: type[BaseModelInstance],
                                   db_conn: DatabaseConnection,
-                                  date_range: tuple[str, str] = ('', ''),
+                                  date_range: tuple[str, str],
                                   date_col: str = 'day'
                                   ) -> tuple[list[BaseModelInstance], str,
                                              str]:
         """Return list of Days in database within (open) date_range interval.
 
-        If no range values provided, defaults them to MIN_RANGE_DATE and
-        MAX_RANGE_DATE. Also knows to properly interpret 'today' as value.
+        If no range values provided, defaults them to 'yesterday' and
+        'tomorrow'. Knows to properly interpret these and 'today' as value.
         """
-        min_date = MIN_RANGE_DATE
-        max_date = MAX_RANGE_DATE
-        start_date = valid_date(date_range[0] if date_range[0] else min_date)
-        end_date = valid_date(date_range[1] if date_range[1] else max_date)
+        start_str = date_range[0] if date_range[0] else 'yesterday'
+        end_str = date_range[1] if date_range[1] else 'tomorrow'
+        start_date = valid_date(start_str)
+        end_date = valid_date(end_str)
         items = []
         sql = f'SELECT id FROM {cls.table_name} '
         sql += f'WHERE {date_col} >= ? AND {date_col} <= ?'
index a2e8fa69fd05d4423751a4fa3ad3623ed4dffe8c..cf7bb0810719674a943ba2f7f8eec45e72befdbf 100644 (file)
@@ -113,7 +113,9 @@ class TaskHandler(BaseHTTPRequestHandler):
         """Show Days from ?start= to ?end=."""
         start = self.params.get_str('start')
         end = self.params.get_str('end')
-        days = Day.all(self.conn, date_range=(start, end), fill_gaps=True)
+        ret = Day.by_date_range_with_limits(self.conn, (start, end), 'id')
+        days, start, end = ret
+        days = Day.with_filled_gaps(days, start, end)
         for day in days:
             day.collect_calendarized_todos(self.conn)
         return {'start': start, 'end': end, 'days': days}
@@ -161,11 +163,11 @@ class TaskHandler(BaseHTTPRequestHandler):
         process_id = self.params.get_int_or_none('process_id')
         comment_pattern = self.params.get_str('comment_pattern')
         todos = []
-        for t in Todo.by_date_range(self.conn, (start, end)):
-            if (process_id and t.process.id_ != process_id)\
-                    or (comment_pattern not in t.comment):
-                continue
-            todos += [t]
+        ret = Todo.by_date_range_with_limits(self.conn, (start, end))
+        todos_by_date_range, start, end = ret
+        todos = [t for t in todos_by_date_range
+                 if comment_pattern in t.comment
+                 and ((not process_id) or t.process.id_ == process_id)]
         if sort_by == 'doneness':
             todos.sort(key=lambda t: t.is_done)
         elif sort_by == '-doneness':
index c1e1343c63c7cb24e6e7133f09538a06f7104e11..4727fac743dad82bc5aee56635d253ac9b63c192 100644 (file)
@@ -60,25 +60,21 @@ class TestsWithDB(TestCaseWithDB):
         """Test .by_id()."""
         self.check_by_id()
 
-    def test_Day_all(self) -> None:
-        """Test Day.all(), especially in regards to date range filtering."""
+    def test_Day_by_date_range_filled(self) -> None:
+        """Test Day.by_date_range_filled."""
         date1, date2, date3 = self.default_ids
         day1, day2, day3 = self.check_all()
-        self.assertEqual(Day.all(self.db_conn, ('', '')),
-                         [day1, day2, day3])
         # check date range is a closed interval
-        self.assertEqual(Day.all(self.db_conn, (date1, date3)),
+        self.assertEqual(Day.by_date_range_filled(self.db_conn, date1, date3),
                          [day1, day2, day3])
         # check first date range value excludes what's earlier
-        self.assertEqual(Day.all(self.db_conn, (date2, date3)),
+        self.assertEqual(Day.by_date_range_filled(self.db_conn, date2, date3),
                          [day2, day3])
-        self.assertEqual(Day.all(self.db_conn, (date3, '')),
-                         [day3])
         # check second date range value excludes what's later
-        self.assertEqual(Day.all(self.db_conn, ('', date2)),
+        self.assertEqual(Day.by_date_range_filled(self.db_conn, date1, date2),
                          [day1, day2])
         # check swapped (impossible) date range returns emptiness
-        self.assertEqual(Day.all(self.db_conn, (date3, date1)),
+        self.assertEqual(Day.by_date_range_filled(self.db_conn, date3, date1),
                          [])
         # check fill_gaps= instantiates unsaved dates within date range
         # (but does not store them)
@@ -86,14 +82,16 @@ class TestsWithDB(TestCaseWithDB):
         day6 = Day('2024-01-06')
         day6.save(self.db_conn)
         day7 = Day('2024-01-07')
-        self.assertEqual(Day.all(self.db_conn, (day5.date, day7.date),
-                                 fill_gaps=True),
+        self.assertEqual(Day.by_date_range_filled(self.db_conn,
+                                                  day5.date, day7.date),
                          [day5, day6, day7])
         self.check_storage([day1, day2, day3, day6])
         # check 'today' is interpreted as today's date
         today = Day(todays_date())
         today.save(self.db_conn)
-        self.assertEqual(Day.all(self.db_conn, ('today', 'today')), [today])
+        self.assertEqual(Day.by_date_range_filled(self.db_conn,
+                                                  'today', 'today'),
+                         [today])
 
     def test_Day_remove(self) -> None:
         """Test .remove() effects on DB and cache."""