from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker from sqlalchemy.orm import DeclarativeBase from app.config import get_settings settings = get_settings() # Normalizar la URL de base de datos para asegurar el uso del driver asincrónico asyncpg db_url = settings.database_url or "sqlite+aiosqlite:///./crowdata.db" if db_url: if db_url.startswith("postgresql://"): db_url = db_url.replace("postgresql://", "postgresql+asyncpg://", 1) elif db_url.startswith("postgres://"): db_url = db_url.replace("postgres://", "postgresql+asyncpg://", 1) # asyncpg no soporta 'sslmode=require', requiere 'ssl=require' if "sslmode=" in db_url: db_url = db_url.replace("sslmode=require", "ssl=require") db_url = db_url.replace("sslmode=disable", "ssl=disable") engine_kwargs = { "echo": settings.debug, "pool_pre_ping": True, } if db_url.startswith("postgresql"): engine_kwargs["pool_size"] = settings.db_pool_size engine_kwargs["max_overflow"] = settings.db_max_overflow engine = create_async_engine( db_url, **engine_kwargs ) AsyncSessionLocal = async_sessionmaker( engine, class_=AsyncSession, expire_on_commit=False, ) class Base(DeclarativeBase): pass async def get_db(): async with AsyncSessionLocal() as session: try: yield session await session.commit() except Exception: await session.rollback() raise finally: await session.close() async def init_db(): from app.auth.models import User # noqa: F401 - ensure models are loaded from app.reports.models import ReportCache # noqa: F401 # Use Alembic for migrations instead of create_all from alembic.config import Config from alembic import command import os # Find alembic.ini (could be in backend dir) alembic_ini = os.path.join(os.path.dirname(__file__), '..', 'alembic.ini') try: alembic_cfg = Config(alembic_ini) # Use the existing database URL from settings from app.config import get_settings settings = get_settings() # Normalize for synchronous alembic db_url = settings.database_url if db_url.startswith("sqlite+aiosqlite://"): db_url = db_url.replace("sqlite+aiosqlite://", "sqlite://") elif db_url.startswith("postgresql+asyncpg://"): db_url = db_url.replace("postgresql+asyncpg://", "postgresql://") alembic_cfg.set_main_option("sqlalchemy.url", db_url) command.upgrade(alembic_cfg, "head") except Exception as e: import logging logging.getLogger("app.database").warning(f"Error running migrations: {e}") # Fallback to create_all for dev environments async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all)