File size: 2,921 Bytes
83bdb4a
 
 
 
 
 
 
e374786
83bdb4a
e374786
83bdb4a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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)