diff --git a/README.md b/README.md index a3d3cbb..b6b5b61 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ A simple Todo API application built with FastAPI and SQLite. - RESTful API for managing todo items - SQLite database with SQLAlchemy ORM - Alembic migrations for database versioning +- Priority levels for todo items (Low, Medium, High) +- Filter todos by priority - Health check endpoint - Swagger UI documentation @@ -65,9 +67,10 @@ API Documentation is available at: ### Todo Operations - `GET /todos` - List all todos -- `POST /todos` - Create a new todo + - Optional query parameter: `priority` (1=Low, 2=Medium, 3=High) to filter by priority +- `POST /todos` - Create a new todo (with optional priority field: 1=Low, 2=Medium, 3=High) - `GET /todos/{todo_id}` - Get a specific todo -- `PUT /todos/{todo_id}` - Update a todo +- `PUT /todos/{todo_id}` - Update a todo (including priority) - `DELETE /todos/{todo_id}` - Delete a todo ## Database diff --git a/app/api/routes/todos.py b/app/api/routes/todos.py index 20f4c8b..2670c8d 100644 --- a/app/api/routes/todos.py +++ b/app/api/routes/todos.py @@ -1,6 +1,6 @@ -from fastapi import APIRouter, Depends, HTTPException, status +from fastapi import APIRouter, Depends, HTTPException, status, Query from sqlalchemy.orm import Session -from typing import List +from typing import List, Optional from app.db.database import get_db from app.models.todo import Todo as TodoModel @@ -20,8 +20,18 @@ def create_todo(todo: TodoCreate, db: Session = Depends(get_db)): return db_todo @router.get("/", response_model=List[Todo]) -def read_todos(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): - todos = db.query(TodoModel).offset(skip).limit(limit).all() +def read_todos( + skip: int = 0, + limit: int = 100, + priority: Optional[int] = Query(None, ge=1, le=3, description="Filter by priority (1=Low, 2=Medium, 3=High)"), + db: Session = Depends(get_db) +): + query = db.query(TodoModel) + + if priority is not None: + query = query.filter(TodoModel.priority == priority) + + todos = query.offset(skip).limit(limit).all() return todos @router.get("/{todo_id}", response_model=Todo) diff --git a/app/models/todo.py b/app/models/todo.py index 9bfbd20..abb4ea7 100644 --- a/app/models/todo.py +++ b/app/models/todo.py @@ -9,5 +9,6 @@ class Todo(Base): title = Column(String, index=True) description = Column(String) completed = Column(Boolean, default=False) + priority = Column(Integer, default=1, index=True) # 1: Low, 2: Medium, 3: High created_at = Column(DateTime, default=func.now()) updated_at = Column(DateTime, default=func.now(), onupdate=func.now()) \ No newline at end of file diff --git a/app/schemas/todo.py b/app/schemas/todo.py index 7c784fe..6af54ee 100644 --- a/app/schemas/todo.py +++ b/app/schemas/todo.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel +from pydantic import BaseModel, Field from datetime import datetime from typing import Optional @@ -6,6 +6,7 @@ class TodoBase(BaseModel): title: str description: Optional[str] = None completed: Optional[bool] = False + priority: Optional[int] = Field(default=1, ge=1, le=3, description="Priority level: 1=Low, 2=Medium, 3=High") class TodoCreate(TodoBase): pass @@ -14,6 +15,7 @@ class TodoUpdate(BaseModel): title: Optional[str] = None description: Optional[str] = None completed: Optional[bool] = None + priority: Optional[int] = Field(default=None, ge=1, le=3, description="Priority level: 1=Low, 2=Medium, 3=High") class Todo(TodoBase): id: int diff --git a/migrations/versions/add_priority_field.py b/migrations/versions/add_priority_field.py new file mode 100644 index 0000000..ff66ee0 --- /dev/null +++ b/migrations/versions/add_priority_field.py @@ -0,0 +1,29 @@ +"""add_priority_field + +Revision ID: 002 +Revises: 001 +Create Date: 2025-05-13 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '002' +down_revision = '001' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + op.add_column('todos', sa.Column('priority', sa.Integer(), nullable=True, server_default='1')) + op.create_index(op.f('ix_todos_priority'), 'todos', ['priority'], unique=False) + + # Set default value for existing rows + op.execute("UPDATE todos SET priority = 1 WHERE priority IS NULL") + + +def downgrade() -> None: + op.drop_index(op.f('ix_todos_priority'), table_name='todos') + op.drop_column('todos', 'priority') \ No newline at end of file