Some checks failed
Build and Deploy Log Center / build-and-deploy (push) Failing after 12m39s
88 lines
3.1 KiB
Python
88 lines
3.1 KiB
Python
from sqlmodel import SQLModel, create_engine
|
|
from sqlmodel.ext.asyncio.session import AsyncSession
|
|
from sqlalchemy.ext.asyncio import create_async_engine
|
|
from sqlalchemy.orm import sessionmaker
|
|
from sqlalchemy import text
|
|
import os
|
|
from dotenv import load_dotenv
|
|
|
|
load_dotenv()
|
|
|
|
DB_USER = os.getenv("DB_USER")
|
|
DB_PASSWORD = os.getenv("DB_PASSWORD")
|
|
DB_HOST = os.getenv("DB_HOST")
|
|
DB_PORT = os.getenv("DB_PORT", "3306")
|
|
DB_NAME = os.getenv("DB_NAME")
|
|
|
|
DATABASE_URL = f"mysql+aiomysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}?charset=utf8mb4"
|
|
|
|
_engine = None
|
|
|
|
|
|
def get_engine():
|
|
"""Lazy engine creation to ensure pool is bound to the current event loop."""
|
|
global _engine
|
|
if _engine is None:
|
|
_engine = create_async_engine(
|
|
DATABASE_URL,
|
|
echo=True,
|
|
future=True,
|
|
pool_pre_ping=True,
|
|
pool_recycle=300,
|
|
)
|
|
return _engine
|
|
|
|
|
|
async def dispose_engine():
|
|
"""Dispose engine and reset so next call creates a fresh one."""
|
|
global _engine
|
|
if _engine is not None:
|
|
await _engine.dispose()
|
|
_engine = None
|
|
|
|
|
|
# Module-level alias for backward compatibility
|
|
engine = None # Use get_engine() instead
|
|
|
|
|
|
async def init_db():
|
|
eng = get_engine()
|
|
async with eng.begin() as conn:
|
|
# await conn.run_sync(SQLModel.metadata.drop_all)
|
|
await conn.run_sync(SQLModel.metadata.create_all)
|
|
|
|
# Migrate: add new columns to existing repairtask table
|
|
migrations = [
|
|
"ALTER TABLE repairtask ADD COLUMN IF NOT EXISTS repair_round INTEGER DEFAULT 1",
|
|
"ALTER TABLE repairtask ADD COLUMN IF NOT EXISTS failure_reason TEXT",
|
|
# Log source support
|
|
"ALTER TABLE errorlog ADD COLUMN IF NOT EXISTS source VARCHAR(20) DEFAULT 'runtime'",
|
|
"ALTER TABLE errorlog MODIFY COLUMN file_path VARCHAR(255) NULL",
|
|
"ALTER TABLE errorlog MODIFY COLUMN line_number INTEGER NULL",
|
|
"CREATE INDEX ix_errorlog_source ON errorlog (source)",
|
|
# ErrorLog failure_reason
|
|
"ALTER TABLE errorlog ADD COLUMN IF NOT EXISTS failure_reason TEXT",
|
|
# Bug severity (1-10 AI评估等级)
|
|
"ALTER TABLE errorlog ADD COLUMN IF NOT EXISTS severity INTEGER",
|
|
"ALTER TABLE errorlog ADD COLUMN IF NOT EXISTS severity_reason TEXT",
|
|
# Project repair_enabled toggle
|
|
"ALTER TABLE project ADD COLUMN IF NOT EXISTS repair_enabled BOOLEAN DEFAULT TRUE",
|
|
# Seed Project table from existing ErrorLog data
|
|
"""INSERT INTO project (project_id, created_at, updated_at)
|
|
SELECT DISTINCT e.project_id, NOW(), NOW()
|
|
FROM errorlog e
|
|
WHERE NOT EXISTS (SELECT 1 FROM project p WHERE p.project_id = e.project_id)""",
|
|
]
|
|
for sql in migrations:
|
|
try:
|
|
await conn.execute(text(sql))
|
|
except Exception:
|
|
pass # Already applied
|
|
|
|
async def get_session() -> AsyncSession:
|
|
async_session = sessionmaker(
|
|
get_engine(), class_=AsyncSession, expire_on_commit=False
|
|
)
|
|
async with async_session() as session:
|
|
yield session
|