93 lines
3.5 KiB
Python
93 lines
3.5 KiB
Python
"""
|
|
GUARDiA ITSM — 데이터베이스 엔진 설정.
|
|
|
|
환경변수 DATABASE_URL 로 DB를 자동 선택한다:
|
|
- 미설정(기본): SQLite + aiosqlite (개발/단독 실행)
|
|
- postgresql+asyncpg://user:pass@host:5432/db: PostgreSQL (운영)
|
|
|
|
PostgreSQL 사용 시 asyncpg, alembic 패키지가 필요하다:
|
|
pip install asyncpg alembic
|
|
|
|
마이그레이션:
|
|
alembic init migrations
|
|
alembic revision --autogenerate -m "initial_schema"
|
|
alembic upgrade head
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import os
|
|
|
|
from sqlalchemy.ext.asyncio import (
|
|
AsyncSession,
|
|
async_sessionmaker,
|
|
create_async_engine,
|
|
)
|
|
from sqlalchemy.orm import DeclarativeBase
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# ── 환경변수 기반 DB URL 자동 선택 ───────────────────────────────────────────
|
|
DATABASE_URL: str = os.getenv(
|
|
"DATABASE_URL",
|
|
"sqlite+aiosqlite:///./guardia_itsm.db", # 기본: SQLite (개발)
|
|
)
|
|
|
|
# URL 정규화: postgres:// → postgresql+asyncpg:// (Heroku/Gitpod 호환)
|
|
if DATABASE_URL.startswith("postgres://"):
|
|
DATABASE_URL = DATABASE_URL.replace("postgres://", "postgresql+asyncpg://", 1)
|
|
|
|
_is_postgres = DATABASE_URL.startswith("postgresql")
|
|
|
|
# ── 엔진 생성 ────────────────────────────────────────────────────────────────
|
|
_engine_kwargs: dict = {
|
|
"echo": os.getenv("DB_ECHO", "false").lower() == "true",
|
|
"pool_pre_ping": True,
|
|
}
|
|
|
|
if _is_postgres:
|
|
# PostgreSQL: MVCC 기반 연결 풀링
|
|
_engine_kwargs["pool_size"] = int(os.getenv("DB_POOL_SIZE", "10"))
|
|
_engine_kwargs["max_overflow"] = int(os.getenv("DB_MAX_OVERFLOW", "20"))
|
|
logger.info("GUARDiA DB: PostgreSQL 모드 (pool_size=%s)", _engine_kwargs["pool_size"])
|
|
else:
|
|
# SQLite: 파일 잠금 방식, 오버플로 불가
|
|
_engine_kwargs["connect_args"] = {"check_same_thread": False}
|
|
logger.info("GUARDiA DB: SQLite 모드")
|
|
|
|
engine = create_async_engine(DATABASE_URL, **_engine_kwargs)
|
|
|
|
SessionLocal = async_sessionmaker(
|
|
engine,
|
|
class_=AsyncSession,
|
|
expire_on_commit=False,
|
|
)
|
|
|
|
|
|
# ── Base ─────────────────────────────────────────────────────────────────────
|
|
|
|
class Base(DeclarativeBase):
|
|
pass
|
|
|
|
|
|
# ── 의존성 주입 ───────────────────────────────────────────────────────────────
|
|
|
|
async def get_db():
|
|
"""FastAPI Depends용 — DB 세션 제공 후 자동 정리."""
|
|
async with SessionLocal() as session:
|
|
yield session
|
|
|
|
|
|
# ── 테이블 초기화 ─────────────────────────────────────────────────────────────
|
|
|
|
async def init_db() -> None:
|
|
"""
|
|
개발 환경에서 테이블 자동 생성.
|
|
운영(PostgreSQL)에서는 Alembic migration을 사용하므로
|
|
create_all은 이미 존재하는 테이블을 건드리지 않는다.
|
|
"""
|
|
from models import Base as ModelBase # noqa: F401 — 모델 등록용 임포트
|
|
async with engine.begin() as conn:
|
|
await conn.run_sync(ModelBase.metadata.create_all)
|
|
logger.info("DB 테이블 초기화 완료")
|