Alembic configuration
This commit is contained in:
@@ -1,10 +1,11 @@
|
|||||||
# app/core/lifespan.py
|
# app/core/lifespan.py
|
||||||
"""Summary description ....
|
"""Application lifespan management - Clean Migration Approach.
|
||||||
|
|
||||||
This module provides classes and functions for:
|
This module provides classes and functions for:
|
||||||
- ....
|
- Application startup and shutdown events
|
||||||
- ....
|
- Logging setup
|
||||||
- ....
|
- Default user creation
|
||||||
|
- NO database table creation (handled by Alembic)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@@ -14,7 +15,7 @@ from fastapi import FastAPI
|
|||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
|
|
||||||
from middleware.auth import AuthManager
|
from middleware.auth import AuthManager
|
||||||
from models.database.base import Base
|
# Remove this import if not needed: from models.database.base import Base
|
||||||
|
|
||||||
from .database import SessionLocal, engine
|
from .database import SessionLocal, engine
|
||||||
from .logging import setup_logging
|
from .logging import setup_logging
|
||||||
@@ -25,62 +26,106 @@ auth_manager = AuthManager()
|
|||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(app: FastAPI):
|
async def lifespan(app: FastAPI):
|
||||||
"""Application lifespan events."""
|
"""Application lifespan events - Clean migration approach."""
|
||||||
# Startup
|
|
||||||
app_logger = setup_logging() # Configure logging first
|
# === STARTUP ===
|
||||||
|
app_logger = setup_logging()
|
||||||
app_logger.info("Starting up ecommerce API")
|
app_logger.info("Starting up ecommerce API")
|
||||||
|
|
||||||
# Create tables
|
# === REMOVED: Database table creation ===
|
||||||
Base.metadata.create_all(bind=engine)
|
# Base.metadata.create_all(bind=engine) # ❌ Removed - handled by Alembic
|
||||||
|
# create_indexes() # ❌ Removed - handled by Alembic
|
||||||
|
|
||||||
# Create indexes
|
# === KEPT: Application-level initialization ===
|
||||||
create_indexes()
|
|
||||||
|
|
||||||
# Create default admin user
|
# Create default admin user (after migrations have run)
|
||||||
db = SessionLocal()
|
db = SessionLocal()
|
||||||
try:
|
try:
|
||||||
auth_manager.create_default_admin_user(db)
|
auth_manager.create_default_admin_user(db)
|
||||||
|
logger.info("Default admin user initialization completed")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to create default admin user: {e}")
|
logger.error(f"Failed to create default admin user: {e}")
|
||||||
|
# In development, this might fail if tables don't exist yet
|
||||||
|
# That's OK - migrations should be run separately
|
||||||
finally:
|
finally:
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
|
# Add any other application-level initialization here
|
||||||
|
# Examples:
|
||||||
|
# - Load configuration
|
||||||
|
# - Initialize caches
|
||||||
|
# - Set up external service connections
|
||||||
|
# - Load initial data (AFTER migrations)
|
||||||
|
|
||||||
|
logger.info("✅ Application startup completed")
|
||||||
|
|
||||||
yield
|
yield
|
||||||
|
|
||||||
# Shutdown
|
# === SHUTDOWN ===
|
||||||
app_logger.info("Shutting down ecommerce API")
|
app_logger.info("Shutting down ecommerce API")
|
||||||
|
# Add cleanup tasks here if needed
|
||||||
|
|
||||||
|
|
||||||
def create_indexes():
|
# === REMOVED FUNCTION ===
|
||||||
"""Create database indexes."""
|
# def create_indexes():
|
||||||
with engine.connect() as conn:
|
# """Create database indexes."""
|
||||||
try:
|
# # This is now handled by Alembic migrations
|
||||||
# User indexes
|
# pass
|
||||||
conn.execute(
|
|
||||||
text("CREATE INDEX IF NOT EXISTS idx_user_email ON users(email)")
|
|
||||||
)
|
|
||||||
conn.execute(
|
|
||||||
text("CREATE INDEX IF NOT EXISTS idx_user_username ON users(username)")
|
|
||||||
)
|
|
||||||
|
|
||||||
# Product indexes
|
|
||||||
conn.execute(
|
|
||||||
text("CREATE INDEX IF NOT EXISTS idx_product_gtin ON products(gtin)")
|
|
||||||
)
|
|
||||||
conn.execute(
|
|
||||||
text(
|
|
||||||
"CREATE INDEX IF NOT EXISTS idx_product_marketplace ON products(marketplace)"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Stock indexes
|
# === NEW HELPER FUNCTION ===
|
||||||
conn.execute(
|
def check_database_ready():
|
||||||
text(
|
"""Check if database is ready (migrations have been run)."""
|
||||||
"CREATE INDEX IF NOT EXISTS idx_stock_gtin_location ON stock(gtin, location)"
|
try:
|
||||||
)
|
with engine.connect() as conn:
|
||||||
)
|
# Try to query a table that should exist
|
||||||
|
result = conn.execute(text("SELECT name FROM sqlite_master WHERE type='table' LIMIT 1"))
|
||||||
|
tables = result.fetchall()
|
||||||
|
return len(tables) > 0
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
logger.info("Database indexes created successfully")
|
def get_migration_status():
|
||||||
except Exception as e:
|
"""Get current Alembic migration status."""
|
||||||
logger.warning(f"Index creation warning: {e}")
|
try:
|
||||||
|
from alembic import command
|
||||||
|
from alembic.config import Config
|
||||||
|
|
||||||
|
alembic_cfg = Config("alembic.ini")
|
||||||
|
|
||||||
|
# This would need more implementation to actually check status
|
||||||
|
# For now, just return a placeholder
|
||||||
|
return "Migration status check not implemented"
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Could not check migration status: {e}")
|
||||||
|
return "Unknown"
|
||||||
|
|
||||||
|
|
||||||
|
# === STARTUP VERIFICATION (Optional) ===
|
||||||
|
def verify_startup_requirements():
|
||||||
|
"""Verify that all startup requirements are met."""
|
||||||
|
|
||||||
|
issues = []
|
||||||
|
|
||||||
|
# Check if database exists and has tables
|
||||||
|
if not check_database_ready():
|
||||||
|
issues.append("Database not ready - run 'make migrate-up' first")
|
||||||
|
|
||||||
|
# Add other checks as needed
|
||||||
|
# - Configuration validation
|
||||||
|
# - External service connectivity
|
||||||
|
# - Required environment variables
|
||||||
|
|
||||||
|
if issues:
|
||||||
|
logger.error("❌ Startup verification failed:")
|
||||||
|
for issue in issues:
|
||||||
|
logger.error(f" - {issue}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
logger.info("✅ Startup verification passed")
|
||||||
|
return True
|
||||||
|
|
||||||
|
# You can call this in your main.py if desired:
|
||||||
|
# if not verify_startup_requirements():
|
||||||
|
# raise RuntimeError("Application startup requirements not met")
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
# Database migrations
|
||||||
|
alembic>=1.13.0
|
||||||
# Linting and formatting tools
|
# Linting and formatting tools
|
||||||
|
# Development tools
|
||||||
black>=23.0.0
|
black>=23.0.0
|
||||||
isort>=5.12.0
|
isort>=5.12.0
|
||||||
flake8>=6.0.0
|
flake8>=6.0.0
|
||||||
mypy>=1.0.0
|
mypy>=1.5.0
|
||||||
|
|
||||||
# Optional: More advanced linting
|
# Optional: More advanced linting
|
||||||
flake8-docstrings>=1.7.0
|
flake8-docstrings>=1.7.0
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# Database migrations
|
||||||
|
alembic>=1.13.0
|
||||||
starlette==0.27.0
|
starlette==0.27.0
|
||||||
# requirements.txt
|
# requirements.txt
|
||||||
# Core FastAPI and web framework
|
# Core FastAPI and web framework
|
||||||
|
|||||||
Reference in New Issue
Block a user