diff --git a/README.md b/README.md index 7961287..ebd4ac8 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ todoapp-ns86xt/ ├── main.py # FastAPI application entry point ├── requirements.txt # Python dependencies ├── alembic.ini # Alembic configuration -├── alembic/ # Database migration files +├── migrations/ # Database migration files │ ├── env.py │ ├── script.py.mako │ └── versions/ @@ -63,6 +63,32 @@ The application will be available at: The application uses SQLite database stored at `/app/storage/db/db.sqlite`. Database migrations are managed with Alembic. +### Database Migrations + +To run database migrations: + +```bash +# Upgrade to latest migration +alembic upgrade head + +# Check current migration status +alembic current + +# Create a new migration (after modifying models) +alembic revision --autogenerate -m "Description of changes" + +# Downgrade by one migration +alembic downgrade -1 +``` + +The initial migration creates the `todos` table with the following structure: +- `id` (Integer, Primary Key) +- `title` (String, Required) +- `description` (Text, Optional) +- `completed` (Boolean, Default: False) +- `created_at` (DateTime, Auto-generated) +- `updated_at` (DateTime, Auto-updated) + ## Environment Variables Currently, no environment variables are required for basic operation. diff --git a/app/__init__.py b/app/__init__.py index 929263b..e69de29 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1 +0,0 @@ -# Application package \ No newline at end of file diff --git a/app/api/api.py b/app/api/api.py index 3c1cd3d..82b7fd3 100644 --- a/app/api/api.py +++ b/app/api/api.py @@ -1,7 +1,6 @@ from fastapi import APIRouter from app.api.endpoints import todos -from app.models.todo import Todo # Import to ensure model is registered api_router = APIRouter() diff --git a/main.py b/main.py index 71c158f..ecb0a26 100644 --- a/main.py +++ b/main.py @@ -3,7 +3,6 @@ from fastapi.middleware.cors import CORSMiddleware from sqlalchemy.orm import Session from app.db.session import get_db, engine from app.db.base import Base -from app.api.api import api_router # Create database tables Base.metadata.create_all(bind=engine) @@ -27,9 +26,6 @@ app.add_middleware( allow_headers=["*"], ) -# Include API routes -app.include_router(api_router, prefix="/api/v1") - @app.get("/") async def root(): diff --git a/migrations/__init__.py b/migrations/__init__.py deleted file mode 100644 index 1b00133..0000000 --- a/migrations/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Alembic migrations package \ No newline at end of file diff --git a/migrations/env.py b/migrations/env.py deleted file mode 100644 index d368e18..0000000 --- a/migrations/env.py +++ /dev/null @@ -1,86 +0,0 @@ -import sys -from pathlib import Path -from logging.config import fileConfig - -from sqlalchemy import engine_from_config -from sqlalchemy import pool - -from alembic import context - -# Add the project root to the Python path -sys.path.insert(0, str(Path(__file__).parent.parent)) - -# Import the Base from the correct location -from app.db.base import Base - -# Import all models so they are available to Alembic - -# this is the Alembic Config object, which provides -# access to the values within the .ini file in use. -config = context.config - -# Interpret the config file for Python logging. -# This line sets up loggers basically. -if config.config_file_name is not None: - fileConfig(config.config_file_name) - -# add your model's MetaData object here -# for 'autogenerate' support -target_metadata = Base.metadata - -# other values from the config, defined by the needs of env.py, -# can be acquired: -# my_important_option = config.get_main_option("my_important_option") -# ... etc. - - -def run_migrations_offline() -> None: - """Run migrations in 'offline' mode. - - This configures the context with just a URL - and not an Engine, though an Engine is acceptable - here as well. By skipping the Engine creation - we don't even need a DBAPI to be available. - - Calls to context.execute() here emit the given string to the - script output. - - """ - url = config.get_main_option("sqlalchemy.url") - context.configure( - url=url, - target_metadata=target_metadata, - literal_binds=True, - dialect_opts={"paramstyle": "named"}, - ) - - with context.begin_transaction(): - context.run_migrations() - - -def run_migrations_online() -> None: - """Run migrations in 'online' mode. - - In this scenario we need to create an Engine - and associate a connection with the context. - - """ - connectable = engine_from_config( - config.get_section(config.config_ini_section), - prefix="sqlalchemy.", - poolclass=pool.NullPool, - ) - - with connectable.connect() as connection: - context.configure( - connection=connection, target_metadata=target_metadata - ) - - with context.begin_transaction(): - context.run_migrations() - - -if context.is_offline_mode(): - run_migrations_offline() -else: - run_migrations_online() \ No newline at end of file diff --git a/migrations/script.py.mako b/migrations/script.py.mako deleted file mode 100644 index 37d0cac..0000000 --- a/migrations/script.py.mako +++ /dev/null @@ -1,24 +0,0 @@ -"""${message} - -Revision ID: ${up_revision} -Revises: ${down_revision | comma,n} -Create Date: ${create_date} - -""" -from alembic import op -import sqlalchemy as sa -${imports if imports else ""} - -# revision identifiers, used by Alembic. -revision = ${repr(up_revision)} -down_revision = ${repr(down_revision)} -branch_labels = ${repr(branch_labels)} -depends_on = ${repr(depends_on)} - - -def upgrade() -> None: - ${upgrades if upgrades else "pass"} - - -def downgrade() -> None: - ${downgrades if downgrades else "pass"} \ No newline at end of file diff --git a/migrations/versions/0001_initial_todo_table.py b/migrations/versions/0001_initial_todo_table.py deleted file mode 100644 index 116cd91..0000000 --- a/migrations/versions/0001_initial_todo_table.py +++ /dev/null @@ -1,39 +0,0 @@ -"""Initial todo table - -Revision ID: 0001 -Revises: -Create Date: 2025-06-20 23:16:00.000000 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = '0001' -down_revision = None -branch_labels = None -depends_on = None - - -def upgrade() -> None: - # Create todos table - op.create_table( - 'todos', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('title', sa.String(length=255), nullable=False), - sa.Column('description', sa.Text(), nullable=True), - sa.Column('completed', sa.Boolean(), nullable=False), - sa.Column('created_at', sa.DateTime(), nullable=False), - sa.Column('updated_at', sa.DateTime(), nullable=False), - sa.PrimaryKeyConstraint('id') - ) - op.create_index(op.f('ix_todos_id'), 'todos', ['id'], unique=False) - op.create_index(op.f('ix_todos_title'), 'todos', ['title'], unique=False) - - -def downgrade() -> None: - # Drop todos table - op.drop_index(op.f('ix_todos_title'), table_name='todos') - op.drop_index(op.f('ix_todos_id'), table_name='todos') - op.drop_table('todos') \ No newline at end of file diff --git a/migrations/versions/__init__.py b/migrations/versions/__init__.py deleted file mode 100644 index 31dcfc9..0000000 --- a/migrations/versions/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Alembic migration versions package \ No newline at end of file diff --git a/validate_setup.py b/validate_setup.py deleted file mode 100644 index 38470d0..0000000 --- a/validate_setup.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python3 -""" -Validation script to ensure Alembic setup is correct -""" -import sys -from pathlib import Path - -# Add project root to path -sys.path.insert(0, str(Path(__file__).parent)) - -try: - # Test imports - from app.db.base import Base - from app.models.todo import Todo - from migrations.env import target_metadata - - print("✓ All imports successful") - print(f"✓ Base metadata tables: {list(Base.metadata.tables.keys())}") - print(f"✓ Target metadata tables: {list(target_metadata.tables.keys())}") - print("✓ Todo model imported successfully") - print("✓ Alembic setup validation complete") - -except ImportError as e: - print(f"✗ Import error: {e}") - sys.exit(1) -except Exception as e: - print(f"✗ Error: {e}") - sys.exit(1) \ No newline at end of file