From: Christian Heller <c.heller@plomlompom.de>
Date: Fri, 21 Jun 2024 22:16:33 +0000 (+0200)
Subject: Refactor BaseModel sorting from GET handlers into class definitions.
X-Git-Url: https://plomlompom.com/repos/%7B%7Bprefix%7D%7D/static/do_tasks?a=commitdiff_plain;h=692bfbac8d81ad5f1f0210e550dcabd15c58e8a5;p=plomtask

Refactor BaseModel sorting from GET handlers into class definitions.
---

diff --git a/plomtask/conditions.py b/plomtask/conditions.py
index b60d0af..15dcb9d 100644
--- a/plomtask/conditions.py
+++ b/plomtask/conditions.py
@@ -12,6 +12,8 @@ class Condition(BaseModel[int]):
     to_save_versioned = ['title', 'description']
     to_search = ['title.newest', 'description.newest']
     can_create_by_id = True
+    sorters = {'is_active': lambda c: c.is_active,
+               'title': lambda c: c.title.newest}
 
     def __init__(self, id_: int | None, is_active: bool = False) -> None:
         super().__init__(id_)
diff --git a/plomtask/db.py b/plomtask/db.py
index 71c59d5..13cdaef 100644
--- a/plomtask/db.py
+++ b/plomtask/db.py
@@ -4,7 +4,7 @@ from os import listdir
 from os.path import isfile
 from difflib import Differ
 from sqlite3 import connect as sql_connect, Cursor, Row
-from typing import Any, Self, TypeVar, Generic
+from typing import Any, Self, TypeVar, Generic, Callable
 from plomtask.exceptions import HandledException, NotFoundException
 from plomtask.dating import valid_date
 
@@ -241,6 +241,7 @@ class BaseModel(Generic[BaseModelId]):
     to_search: list[str] = []
     can_create_by_id = False
     _exists = True
+    sorters: dict[str, Callable[..., Any]] = {}
 
     def __init__(self, id_: BaseModelId | None) -> None:
         if isinstance(id_, int) and id_ < 1:
@@ -335,6 +336,22 @@ class BaseModel(Generic[BaseModelId]):
         """Convenience method to return cls' name in lowercase."""
         return cls.__name__.lower()
 
+    @classmethod
+    def sort_by(cls, seq: list[Any], sort_key: str, default: str = 'title'
+                ) -> str:
+        """Sort cls list by cls.sorters[sort_key] (reverse if '-'-prefixed)."""
+        reverse = False
+        if len(sort_key) > 1 and '-' == sort_key[0]:
+            sort_key = sort_key[1:]
+            reverse = True
+        if sort_key not in cls.sorters:
+            sort_key = default
+        sorter: Callable[..., Any] = cls.sorters[sort_key]
+        seq.sort(key=sorter, reverse=reverse)
+        if reverse:
+            sort_key = f'-{sort_key}'
+        return sort_key
+
     # cache management
     # (we primarily use the cache to ensure we work on the same object in
     # memory no matter where and how we retrieve it, e.g. we don't want
diff --git a/plomtask/http.py b/plomtask/http.py
index 0f5e88e..417c5a6 100644
--- a/plomtask/http.py
+++ b/plomtask/http.py
@@ -400,23 +400,7 @@ class TaskHandler(BaseHTTPRequestHandler):
         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':
-            todos.sort(key=lambda t: t.is_done, reverse=True)
-        elif sort_by == 'title':
-            todos.sort(key=lambda t: t.title_then)
-        elif sort_by == '-title':
-            todos.sort(key=lambda t: t.title_then, reverse=True)
-        elif sort_by == 'comment':
-            todos.sort(key=lambda t: t.comment)
-        elif sort_by == '-comment':
-            todos.sort(key=lambda t: t.comment, reverse=True)
-        elif sort_by == '-date':
-            todos.sort(key=lambda t: t.date, reverse=True)
-        else:
-            todos.sort(key=lambda t: t.date)
-            sort_by = 'title'
+        sort_by = Todo.sort_by(todos, sort_by)
         return {'start': start, 'end': end, 'process_id': process_id,
                 'comment_pattern': comment_pattern, 'todos': todos,
                 'all_processes': Process.all(self.conn), 'sort_by': sort_by}
@@ -426,15 +410,7 @@ class TaskHandler(BaseHTTPRequestHandler):
         pattern = self._params.get_str('pattern')
         sort_by = self._params.get_str('sort_by')
         conditions = Condition.matching(self.conn, pattern)
-        if sort_by == 'is_active':
-            conditions.sort(key=lambda c: c.is_active)
-        elif sort_by == '-is_active':
-            conditions.sort(key=lambda c: c.is_active, reverse=True)
-        elif sort_by == '-title':
-            conditions.sort(key=lambda c: c.title.newest, reverse=True)
-        else:
-            conditions.sort(key=lambda c: c.title.newest)
-            sort_by = 'title'
+        sort_by = Condition.sort_by(conditions, sort_by)
         return {'conditions': conditions,
                 'sort_by': sort_by,
                 'pattern': pattern}
@@ -501,23 +477,7 @@ class TaskHandler(BaseHTTPRequestHandler):
         pattern = self._params.get_str('pattern')
         sort_by = self._params.get_str('sort_by')
         processes = Process.matching(self.conn, pattern)
-        if sort_by == 'steps':
-            processes.sort(key=lambda p: len(p.explicit_steps))
-        elif sort_by == '-steps':
-            processes.sort(key=lambda p: len(p.explicit_steps), reverse=True)
-        elif sort_by == 'owners':
-            processes.sort(key=lambda p: p.n_owners or 0)
-        elif sort_by == '-owners':
-            processes.sort(key=lambda p: p.n_owners or 0, reverse=True)
-        elif sort_by == 'effort':
-            processes.sort(key=lambda p: p.effort.newest)
-        elif sort_by == '-effort':
-            processes.sort(key=lambda p: p.effort.newest, reverse=True)
-        elif sort_by == '-title':
-            processes.sort(key=lambda p: p.title.newest, reverse=True)
-        else:
-            processes.sort(key=lambda p: p.title.newest)
-            sort_by = 'title'
+        sort_by = Process.sort_by(processes, sort_by)
         return {'processes': processes, 'sort_by': sort_by, 'pattern': pattern}
 
     # POST handlers
diff --git a/plomtask/processes.py b/plomtask/processes.py
index 3615899..bb1de3a 100644
--- a/plomtask/processes.py
+++ b/plomtask/processes.py
@@ -36,6 +36,10 @@ class Process(BaseModel[int], ConditionsRelations):
     add_to_dict = ['explicit_steps']
     to_search = ['title.newest', 'description.newest']
     can_create_by_id = True
+    sorters = {'steps': lambda p: len(p.explicit_steps),
+               'owners': lambda p: p.n_owners,
+               'effort': lambda p: p.effort.newest,
+               'title': lambda p: p.title.newest}
 
     def __init__(self, id_: int | None, calendarize: bool = False) -> None:
         BaseModel.__init__(self, id_)
diff --git a/plomtask/todos.py b/plomtask/todos.py
index 4d7e393..f5388b5 100644
--- a/plomtask/todos.py
+++ b/plomtask/todos.py
@@ -51,6 +51,10 @@ class Todo(BaseModel[int], ConditionsRelations):
     days_to_update: Set[str] = set()
     children: list[Todo]
     parents: list[Todo]
+    sorters = {'doneness': lambda t: t.is_done,
+               'title': lambda t: t.title_then,
+               'comment': lambda t: t.comment,
+               'date': lambda t: t.date}
 
     # pylint: disable=too-many-arguments
     def __init__(self, id_: int | None,