Coverage for core/database.py: 72.00%
25 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-09-03 15:30 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-09-03 15:30 +0000
1import logging
3from sqlalchemy import create_engine
4from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
5from sqlalchemy.orm import declarative_base, sessionmaker
7from core.config import settings
9logger = logging.getLogger("database")
12def make_async_url(url: str) -> str:
13 if url.startswith("mysql://"):
14 return url.replace("mysql://", "mysql+aiomysql://", 1)
15 if url.startswith("mysql+pymysql://"):
16 return url.replace("mysql+pymysql://", "mysql+aiomysql://", 1)
17 return url
20# Async engine/session for API
21async_engine = create_async_engine(
22 make_async_url(settings.DATABASE_URL),
23 echo=settings.DEBUG_MODE,
24 future=True,
25 pool_pre_ping=True,
26 pool_recycle=settings.DB_POOL_RECYCLE,
27 pool_size=settings.DB_POOL_SIZE,
28 pool_timeout=settings.DB_POOL_TIMEOUT,
29 max_overflow=settings.DB_MAX_OVERFLOW,
30 connect_args={
31 "charset": "utf8mb4",
32 },
33)
34AsyncSessionLocal = async_sessionmaker(
35 bind=async_engine,
36 class_=AsyncSession,
37 expire_on_commit=False,
38 autoflush=False,
39 autocommit=False,
40)
42# Sync engine/session for migration and schedule
43engine = create_engine(
44 settings.DATABASE_URL,
45 echo=settings.DEBUG_MODE,
46 future=True,
47 pool_pre_ping=True,
48 pool_recycle=settings.DB_POOL_RECYCLE,
49 pool_size=settings.DB_POOL_SIZE,
50 pool_timeout=settings.DB_POOL_TIMEOUT,
51 max_overflow=settings.DB_MAX_OVERFLOW,
52 connect_args={
53 "charset": "utf8mb4",
54 "connect_timeout": settings.DB_CONNECT_TIMEOUT,
55 "read_timeout": settings.DB_READ_TIMEOUT,
56 "write_timeout": settings.DB_WRITE_TIMEOUT,
57 },
58)
59SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
61# Base class for declarative models
62Base = declarative_base()
65async def init_db():
66 """Initialize the database with default data"""
67 try:
68 # Import here to avoid circular import
69 from core.init_db import init_database
71 await init_database()
72 logger.info("Database initialization completed")
73 except Exception as e:
74 logger.error(f"Database initialization failed: {str(e)}")
75 raise