From 4aa24a14112007111c2c5bb7d815e58ac5376213 Mon Sep 17 00:00:00 2001 From: Automated Action Date: Thu, 19 Jun 2025 00:13:15 +0000 Subject: [PATCH] Integrate organization features and resolve migration conflicts - Add missing migration files for tags (005) and subtasks (006) - Update model imports to include Tag and todo_tags association - Integrate tags router into API endpoints - Fix migration sequence and dependencies - Format all code with Ruff - Complete integration of all organization features --- alembic/versions/005_add_tags.py | 51 ++++++++++++++++++++++++++++ alembic/versions/006_add_subtasks.py | 43 +++++++++++++++++++++++ app/api/v1/__init__.py | 2 ++ app/api/v1/projects.py | 2 +- app/models/__init__.py | 4 ++- 5 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 alembic/versions/005_add_tags.py create mode 100644 alembic/versions/006_add_subtasks.py diff --git a/alembic/versions/005_add_tags.py b/alembic/versions/005_add_tags.py new file mode 100644 index 0000000..8338b27 --- /dev/null +++ b/alembic/versions/005_add_tags.py @@ -0,0 +1,51 @@ +"""Add tags and todo_tags tables + +Revision ID: 005 +Revises: 004 +Create Date: 2025-06-18 16:00:00.000000 + +""" + +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = "005" +down_revision = "004" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # Create tags table + op.create_table( + "tags", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("name", sa.String(length=50), nullable=False), + sa.Column("color", sa.String(length=7), nullable=True), + sa.Column( + "created_at", + sa.DateTime(timezone=True), + server_default=sa.text("(CURRENT_TIMESTAMP)"), + nullable=True, + ), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("name"), + ) + op.create_index(op.f("ix_tags_id"), "tags", ["id"], unique=False) + + # Create todo_tags association table + op.create_table( + "todo_tags", + sa.Column("todo_id", sa.Integer(), nullable=False), + sa.Column("tag_id", sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(["tag_id"], ["tags.id"], ondelete="CASCADE"), + sa.ForeignKeyConstraint(["todo_id"], ["todos.id"], ondelete="CASCADE"), + sa.PrimaryKeyConstraint("todo_id", "tag_id"), + ) + + +def downgrade() -> None: + op.drop_table("todo_tags") + op.drop_index(op.f("ix_tags_id"), table_name="tags") + op.drop_table("tags") diff --git a/alembic/versions/006_add_subtasks.py b/alembic/versions/006_add_subtasks.py new file mode 100644 index 0000000..e718628 --- /dev/null +++ b/alembic/versions/006_add_subtasks.py @@ -0,0 +1,43 @@ +"""Add parent_id for subtasks functionality + +Revision ID: 006 +Revises: 005 +Create Date: 2025-06-18 17:00:00.000000 + +""" + +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = "006" +down_revision = "005" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # Add parent_id column to todos table + op.add_column( + "todos", + sa.Column("parent_id", sa.Integer(), nullable=True), + ) + + # Add foreign key constraint for self-referential relationship + op.create_foreign_key( + "fk_todos_parent_id", + "todos", + "todos", + ["parent_id"], + ["id"], + ondelete="CASCADE", + ) + + # Add index for better performance + op.create_index(op.f("ix_todos_parent_id"), "todos", ["parent_id"], unique=False) + + +def downgrade() -> None: + op.drop_index(op.f("ix_todos_parent_id"), table_name="todos") + op.drop_constraint("fk_todos_parent_id", "todos", type_="foreignkey") + op.drop_column("todos", "parent_id") diff --git a/app/api/v1/__init__.py b/app/api/v1/__init__.py index 47502ff..dbb8385 100644 --- a/app/api/v1/__init__.py +++ b/app/api/v1/__init__.py @@ -2,10 +2,12 @@ from fastapi import APIRouter from .todos import router as todos_router from .categories import router as categories_router from .projects import router as projects_router +from .tags import router as tags_router api_router = APIRouter() api_router.include_router(todos_router, prefix="/todos", tags=["todos"]) api_router.include_router(categories_router, prefix="/categories", tags=["categories"]) api_router.include_router(projects_router, prefix="/projects", tags=["projects"]) +api_router.include_router(tags_router, prefix="/tags", tags=["tags"]) __all__ = ["api_router"] diff --git a/app/api/v1/projects.py b/app/api/v1/projects.py index e2ac4f8..25ddd81 100644 --- a/app/api/v1/projects.py +++ b/app/api/v1/projects.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import Optional from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session diff --git a/app/models/__init__.py b/app/models/__init__.py index 79623a1..abd979d 100644 --- a/app/models/__init__.py +++ b/app/models/__init__.py @@ -1,5 +1,7 @@ from .todo import Todo from .category import Category from .project import Project +from .tag import Tag +from .todo_tag import todo_tags -__all__ = ["Todo", "Category", "Project"] +__all__ = ["Todo", "Category", "Project", "Tag", "todo_tags"]