feat: sort tasks by due time
This commit is contained in:
+38
-9
@@ -15,11 +15,40 @@ from sqlalchemy import (
|
||||
UniqueConstraint,
|
||||
)
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from sqlalchemy.types import TypeDecorator
|
||||
from uuid_utils import uuid7
|
||||
|
||||
from .db import Base
|
||||
|
||||
|
||||
class UTCDateTime(TypeDecorator):
|
||||
"""Store absolute instants as UTC while preserving the existing SQL column types.
|
||||
|
||||
SQLite's native datetime processor preserves offsets present in historical text;
|
||||
those aware values are converted by instant. Legacy naive values are necessarily
|
||||
interpreted as the UTC convention previously used by this application.
|
||||
"""
|
||||
|
||||
impl = DateTime(timezone=True)
|
||||
cache_ok = True
|
||||
|
||||
def process_bind_param(self, value: datetime | None, dialect):
|
||||
if value is None:
|
||||
return None
|
||||
if value.tzinfo is None:
|
||||
normalized = value.replace(tzinfo=UTC)
|
||||
else:
|
||||
normalized = value.astimezone(UTC)
|
||||
return normalized.replace(tzinfo=None) if dialect.name == "sqlite" else normalized
|
||||
|
||||
def process_result_value(self, value: datetime | None, dialect):
|
||||
if value is None:
|
||||
return None
|
||||
if value.tzinfo is None:
|
||||
return value.replace(tzinfo=UTC)
|
||||
return value.astimezone(UTC)
|
||||
|
||||
|
||||
def new_id() -> UUID:
|
||||
return UUID(str(uuid7()))
|
||||
|
||||
@@ -104,13 +133,13 @@ class Task(Base):
|
||||
description: Mapped[str] = mapped_column(Text, default="")
|
||||
priority: Mapped[int] = mapped_column(Integer, default=0)
|
||||
completed: Mapped[bool] = mapped_column(Boolean, default=False, index=True)
|
||||
due_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
due_at: Mapped[datetime | None] = mapped_column(UTCDateTime(), nullable=True)
|
||||
due_has_time: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
version: Mapped[int] = mapped_column(Integer, default=1)
|
||||
position: Mapped[int] = mapped_column(Integer, default=0)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow, onupdate=utcnow)
|
||||
deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(UTCDateTime(), default=utcnow)
|
||||
updated_at: Mapped[datetime] = mapped_column(UTCDateTime(), default=utcnow, onupdate=utcnow)
|
||||
deleted_at: Mapped[datetime | None] = mapped_column(UTCDateTime(), nullable=True)
|
||||
external_id: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
||||
|
||||
|
||||
@@ -120,9 +149,9 @@ class RecurrenceTemplate(Base):
|
||||
user_id: Mapped[UUID] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
task_id: Mapped[UUID] = mapped_column(ForeignKey("tasks.id", ondelete="CASCADE"), unique=True)
|
||||
rrule: Mapped[str] = mapped_column(Text)
|
||||
starts_at: Mapped[datetime] = mapped_column(DateTime(timezone=True))
|
||||
ends_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
|
||||
starts_at: Mapped[datetime] = mapped_column(UTCDateTime())
|
||||
ends_at: Mapped[datetime | None] = mapped_column(UTCDateTime(), nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(UTCDateTime(), default=utcnow)
|
||||
|
||||
|
||||
class RecurrenceException(Base):
|
||||
@@ -130,9 +159,9 @@ class RecurrenceException(Base):
|
||||
__table_args__ = (UniqueConstraint("template_id", "occurrence_at", name="uq_recurrence_exception"),)
|
||||
id: Mapped[UUID] = mapped_column(primary_key=True, default=new_id)
|
||||
template_id: Mapped[UUID] = mapped_column(ForeignKey("recurrence_templates.id", ondelete="CASCADE"), index=True)
|
||||
occurrence_at: Mapped[datetime] = mapped_column(DateTime(timezone=True))
|
||||
occurrence_at: Mapped[datetime] = mapped_column(UTCDateTime())
|
||||
title: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
||||
due_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
due_at: Mapped[datetime | None] = mapped_column(UTCDateTime(), nullable=True)
|
||||
completed: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
deleted: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user