Source code for greatday.todo

"""Contains greatday's custom Todo types."""

from __future__ import annotations

from typing import Any, cast

from eris import ErisResult, Err, Ok
import magodo
from magodo import MagicTodoMixin
from magodo.types import Priority
from sqlmodel import Session, select

from . import models, spells
from .common import NULL_ID, drop_word_if_startswith


# cache used to optimize the `GreatTodo.from_line()` constructor method
_LINE_TO_TODO_CACHE: dict[str, "GreatTodo"] = {}


[docs]class GreatTodo(MagicTodoMixin): """Custom MagicTodo type used when working with Todos in the daily file.""" pre_todo_spells = spells.GREAT_PRE_TODO_SPELLS todo_spells = spells.GREAT_TODO_SPELLS post_todo_spells = spells.GREAT_POST_TODO_SPELLS to_line_spells = spells.GREAT_TO_LINE_SPELLS from_line_spells = spells.GREAT_FROM_LINE_SPELLS @property def ident(self) -> str: """Returns this Todo's unique identifier.""" result = self.metadata.get("id", NULL_ID) return result
[docs] @classmethod def from_line(cls, line: str) -> ErisResult[GreatTodo]: """Override's default implementation in order to add caching.""" todo = _LINE_TO_TODO_CACHE.get(line) if todo is None: result = super().from_line(line) if isinstance(result, Err): return result todo = result.ok() _LINE_TO_TODO_CACHE[line] = todo return Ok(todo)
[docs] @classmethod def from_model(cls, mtodo: models.Todo) -> GreatTodo: """Construct a GreatTodo from a Todo model class.""" contexts = tuple(ctx.name for ctx in mtodo.contexts) epics = tuple(epic.name for epic in mtodo.epics) projects = tuple(project.name for project in mtodo.projects) metadata = {"id": str(mtodo.id)} for mlink in mtodo.metatag_links: key = mlink.metatag.name value = mlink.value metadata[key] = value priority = cast(Priority, mtodo.priority) todo = magodo.Todo( contexts=contexts, create_date=mtodo.create_date, desc=mtodo.desc, done=mtodo.done, done_date=mtodo.done_date, epics=epics, priority=priority, projects=projects, metadata=metadata, ) return cls(todo)
[docs] def to_model(self, session: Session, key: str = None) -> models.Todo: """Converts a GreatTodo into something that the DB can work with.""" metadata = dict(self.metadata.items()) id_metatag = metadata.get("id") if id_metatag is not None: # we don't want to duplicate this in our DB (the primary key will # have the same value) del metadata["id"] if key is None and id_metatag is not None: key = id_metatag desc = drop_word_if_startswith(self.desc, "id:") mtodo_kwargs: dict[str, Any] = { "create_date": self.create_date, "desc": desc, "done": self.done, "done_date": self.done_date, "priority": self.priority, } stmt: Any if key is None: mtodo = models.Todo(**mtodo_kwargs) else: stmt = select(models.Todo).where(models.Todo.id == int(key)) results = session.exec(stmt) maybe_mtodo = results.first() if maybe_mtodo is None: mtodo = models.Todo(**mtodo_kwargs) mtodo.id = int(key) else: mtodo = maybe_mtodo for k, v in mtodo_kwargs.items(): setattr(mtodo, k, v) for attr, tag_model in [ ("contexts", models.Context), ("epics", models.Epic), ("projects", models.Project), ]: self_tag_list = getattr(self, attr) model_tag_list = [] for tag_name in self_tag_list: stmt = select(tag_model).where(tag_model.name == tag_name) results = session.exec(stmt) tag = results.first() if tag is None: tag = tag_model(name=tag_name) model_tag_list.append(tag) setattr(mtodo, attr, model_tag_list) metatag_links = [] for k, v in metadata.items(): stmt = select(models.Metatag).where(models.Metatag.name == k) results = session.exec(stmt) metatag = results.first() if metatag is None: metatag = models.Metatag(name=k) stmt = ( select(models.MetatagLink) .where(models.MetatagLink.todo_id == mtodo.id) .where(models.MetatagLink.metatag_id == metatag.id) ) results = session.exec(stmt) mlink = results.first() if mlink is None: mlink = models.MetatagLink( metatag=metatag, todo=mtodo, value=v ) metatag_links.append(mlink) mtodo.metatag_links = metatag_links return mtodo