From: Christian Heller 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%7Bdb.prefix%7D%7D/static/%7B%7B%20web_path%20%7D%7D/%7B%7Bprefix%7D%7D/todos?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,