Add due date functionality to Todo model

- Add due_date field as nullable DateTime with timezone support
- Add is_overdue property to check if task is overdue
- Add days_until_due property for time calculations
- Create migration 007 to add due_date column with index
- Maintain backward compatibility with nullable due_date
This commit is contained in:
Automated Action 2025-06-19 13:18:24 +00:00
parent ab8e9a826d
commit 7251fea2ba
2 changed files with 57 additions and 0 deletions

View File

@ -0,0 +1,32 @@
"""Add due_date field to todos table
Revision ID: 007
Revises: 006
Create Date: 2025-06-19 12:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "007"
down_revision = "006"
branch_labels = None
depends_on = None
def upgrade() -> None:
# Add due_date column to todos table
op.add_column(
"todos",
sa.Column("due_date", sa.DateTime(timezone=True), nullable=True),
)
# Add index for better performance on due date queries
op.create_index(op.f("ix_todos_due_date"), "todos", ["due_date"], unique=False)
def downgrade() -> None:
op.drop_index(op.f("ix_todos_due_date"), table_name="todos")
op.drop_column("todos", "due_date")

View File

@ -2,6 +2,8 @@ from sqlalchemy import Column, Integer, String, Boolean, DateTime, Enum, Foreign
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
import enum
from datetime import datetime, timezone
from typing import Optional
from app.db.base import Base
@ -23,6 +25,7 @@ class Todo(Base):
project_id = Column(Integer, ForeignKey("projects.id"), nullable=True)
category_id = Column(Integer, ForeignKey("categories.id"), nullable=True)
parent_id = Column(Integer, ForeignKey("todos.id"), nullable=True)
due_date = Column(DateTime(timezone=True), nullable=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
@ -42,3 +45,25 @@ class Todo(Base):
def is_subtask(self) -> bool:
"""Check if this todo is a subtask of another todo."""
return self.parent_id is not None
@property
def is_overdue(self) -> bool:
"""Check if this todo is overdue."""
if self.due_date is None or self.completed:
return False
return datetime.now(timezone.utc) > self.due_date
@property
def days_until_due(self) -> Optional[int]:
"""Calculate the number of days until the due date.
Returns:
int: Number of days until due (negative if overdue)
None: If no due date is set
"""
if self.due_date is None:
return None
now = datetime.now(timezone.utc)
delta = (self.due_date - now).days
return delta