HealthSync_Intelligence/app/utils/database_utils.py
hyerimmy 910bd902b1
Some checks failed
HealthSync Intelligence CI / build-and-push (push) Has been cancelled
feat : initial commit
2025-06-20 05:28:30 +00:00

194 lines
7.1 KiB
Python

# app/utils/database_utils.py (execute_insert_with_return 메소드 추가)
"""
PostgreSQL 데이터베이스 유틸리티 (databases + asyncpg) - RETURNING 지원 추가
"""
import databases
import logging
from typing import Dict, Any, List, Optional
from app.config.settings import settings
from app.repositories.queries import BaseQueries
logger = logging.getLogger(__name__)
class SimpleDatabase:
"""PostgreSQL 데이터베이스 연결 클래스"""
def __init__(self):
self.database = databases.Database(settings.database_url)
self._connected = False
async def connect(self):
"""데이터베이스 연결"""
if not self._connected:
try:
await self.database.connect()
self._connected = True
logger.info("데이터베이스 연결 성공")
except Exception as e:
logger.error(f"데이터베이스 연결 실패: {str(e)}")
raise
async def disconnect(self):
"""데이터베이스 연결 해제"""
if self._connected:
try:
await self.database.disconnect()
self._connected = False
logger.info("데이터베이스 연결 해제")
except Exception as e:
logger.error(f"데이터베이스 연결 해제 실패: {str(e)}")
async def test_connection(self) -> Dict[str, Any]:
"""데이터베이스 연결 테스트"""
try:
if not self._connected:
await self.connect()
# 기본 쿼리 실행
test_result = await self.database.fetch_val(BaseQueries.CONNECTION_TEST)
db_version = await self.database.fetch_val(BaseQueries.DATABASE_VERSION)
current_db = await self.database.fetch_val(BaseQueries.CURRENT_DATABASE)
current_user = await self.database.fetch_val(BaseQueries.CURRENT_USER)
return {
"status": "connected",
"test_query": test_result,
"database_name": current_db,
"username": current_user,
"host": settings.db_host,
"port": settings.db_port,
"db_version": db_version[:50] + "..." if len(db_version) > 50 else db_version
}
except Exception as e:
logger.error(f"데이터베이스 연결 실패: {str(e)}")
return {
"status": "failed",
"error": str(e),
"error_type": type(e).__name__
}
async def list_tables(self) -> List[Dict[str, Any]]:
"""테이블 목록 조회"""
try:
if not self._connected:
await self.connect()
rows = await self.database.fetch_all(BaseQueries.LIST_TABLES)
tables = []
for row in rows:
tables.append({
"table_name": row["table_name"],
"table_schema": row["table_schema"],
"table_type": row["table_type"]
})
return tables
except Exception as e:
logger.error(f"테이블 목록 조회 실패: {str(e)}")
raise Exception(f"테이블 목록 조회 실패: {str(e)}")
async def query_table(self, table_name: str, limit: int = 5) -> Dict[str, Any]:
"""테이블 데이터 조회"""
try:
if not self._connected:
await self.connect()
# 안전한 쿼리 실행
query = BaseQueries.get_table_data_query(table_name, limit)
rows = await self.database.fetch_all(query)
# 컬럼 정보 조회
columns_result = await self.database.fetch_all(
BaseQueries.GET_TABLE_COLUMNS,
{"table_name": table_name}
)
columns = [col["column_name"] for col in columns_result]
# 결과 변환
data = []
for row in rows:
data.append(dict(row))
return {
"table_name": table_name,
"column_count": len(columns),
"row_count": len(data),
"columns": columns,
"data": data
}
except Exception as e:
logger.error(f"테이블 조회 실패: {str(e)}")
raise Exception(f"테이블 '{table_name}' 조회 실패: {str(e)}")
async def execute_query(self, query: str, values: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
"""쿼리 실행 (SELECT 전용)"""
try:
if not self._connected:
await self.connect()
logger.info(f"쿼리 실행: {query[:100]}{'...' if len(query) > 100 else ''}")
# SELECT 쿼리 실행
rows = await self.database.fetch_all(query, values or {})
result = [dict(row) for row in rows]
logger.info(f"쿼리 결과: {len(result)}건 조회")
return result
except Exception as e:
logger.error(f"쿼리 실행 실패: {str(e)}")
logger.error(f"실행 쿼리: {query}")
logger.error(f"파라미터: {values}")
raise Exception(f"쿼리 실행 실패: {str(e)}")
async def execute_insert_update(self, query: str, values: Optional[Dict[str, Any]] = None) -> int:
"""INSERT, UPDATE, DELETE 쿼리 실행"""
try:
if not self._connected:
await self.connect()
logger.info(f"INSERT/UPDATE 실행: {query[:100]}{'...' if len(query) > 100 else ''}")
result = await self.database.execute(query, values or {})
logger.info(f"INSERT/UPDATE 결과: {result}건 영향")
return result
except Exception as e:
logger.error(f"INSERT/UPDATE 실행 실패: {str(e)}")
logger.error(f"실행 쿼리: {query}")
logger.error(f"파라미터: {values}")
raise Exception(f"INSERT/UPDATE 실행 실패: {str(e)}")
async def execute_insert_with_return(self, query: str, values: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
"""INSERT ... RETURNING 쿼리 실행"""
try:
if not self._connected:
await self.connect()
logger.info(f"INSERT RETURNING 실행: {query[:100]}{'...' if len(query) > 100 else ''}")
# RETURNING이 있는 INSERT는 fetch_one으로 실행
result = await self.database.fetch_one(query, values or {})
if result:
result_dict = dict(result)
logger.info(f"INSERT RETURNING 결과: {result_dict}")
return result_dict
else:
raise Exception("INSERT RETURNING 실행 결과가 없음")
except Exception as e:
logger.error(f"INSERT RETURNING 실행 실패: {str(e)}")
logger.error(f"실행 쿼리: {query}")
logger.error(f"파라미터: {values}")
raise Exception(f"INSERT RETURNING 실행 실패: {str(e)}")
# 전역 데이터베이스 인스턴스
simple_db = SimpleDatabase()