2025-12-04 14:48:38 +08:00
|
|
|
|
"""数据库配置管理API"""
|
2025-12-16 13:55:16 +08:00
|
|
|
|
from loguru import logger
|
2025-12-04 14:48:38 +08:00
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
|
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
|
|
from typing import List, Dict, Any
|
|
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
from th_agenter.models.user import User
|
2025-12-16 13:55:16 +08:00
|
|
|
|
from th_agenter.db.database import get_session
|
2025-12-04 14:48:38 +08:00
|
|
|
|
from th_agenter.services.database_config_service import DatabaseConfigService
|
|
|
|
|
|
from th_agenter.services.auth import AuthService
|
2025-12-16 13:55:16 +08:00
|
|
|
|
from utils.util_schemas import FileListResponse,ExcelPreviewRequest,NormalResponse
|
2025-12-04 14:48:38 +08:00
|
|
|
|
|
|
|
|
|
|
# 在文件顶部添加
|
|
|
|
|
|
from functools import lru_cache
|
|
|
|
|
|
|
2025-12-16 13:55:16 +08:00
|
|
|
|
router = APIRouter(prefix="/api/database-config", tags=["database-config"])
|
2025-12-04 14:48:38 +08:00
|
|
|
|
# 创建服务单例
|
|
|
|
|
|
@lru_cache()
|
|
|
|
|
|
def get_database_config_service() -> DatabaseConfigService:
|
|
|
|
|
|
"""获取DatabaseConfigService单例"""
|
|
|
|
|
|
# 注意:这里需要处理db session的问题
|
|
|
|
|
|
return DatabaseConfigService(None) # 临时方案
|
|
|
|
|
|
|
|
|
|
|
|
# 或者使用全局变量
|
|
|
|
|
|
_database_service_instance = None
|
|
|
|
|
|
|
2025-12-16 13:55:16 +08:00
|
|
|
|
def get_database_service(session: Session = Depends(get_session)) -> DatabaseConfigService:
|
2025-12-04 14:48:38 +08:00
|
|
|
|
"""获取DatabaseConfigService实例"""
|
|
|
|
|
|
global _database_service_instance
|
|
|
|
|
|
if _database_service_instance is None:
|
2025-12-16 13:55:16 +08:00
|
|
|
|
_database_service_instance = DatabaseConfigService(session)
|
2025-12-04 14:48:38 +08:00
|
|
|
|
else:
|
|
|
|
|
|
# 更新db session
|
2025-12-16 13:55:16 +08:00
|
|
|
|
_database_service_instance.db = session
|
2025-12-04 14:48:38 +08:00
|
|
|
|
return _database_service_instance
|
2025-12-16 13:55:16 +08:00
|
|
|
|
|
2025-12-04 14:48:38 +08:00
|
|
|
|
class DatabaseConfigCreate(BaseModel):
|
|
|
|
|
|
name: str = Field(..., description="配置名称")
|
|
|
|
|
|
db_type: str = Field(default="postgresql", description="数据库类型")
|
|
|
|
|
|
host: str = Field(..., description="主机地址")
|
|
|
|
|
|
port: int = Field(..., description="端口号")
|
|
|
|
|
|
database: str = Field(..., description="数据库名")
|
|
|
|
|
|
username: str = Field(..., description="用户名")
|
|
|
|
|
|
password: str = Field(..., description="密码")
|
|
|
|
|
|
is_default: bool = Field(default=False, description="是否为默认配置")
|
|
|
|
|
|
connection_params: Dict[str, Any] = Field(default=None, description="额外连接参数")
|
|
|
|
|
|
|
|
|
|
|
|
class DatabaseConfigResponse(BaseModel):
|
|
|
|
|
|
id: int
|
|
|
|
|
|
name: str
|
|
|
|
|
|
db_type: str
|
2025-12-16 13:55:16 +08:00
|
|
|
|
host: str
|
2025-12-04 14:48:38 +08:00
|
|
|
|
port: int
|
|
|
|
|
|
database: str
|
|
|
|
|
|
username: str
|
2025-12-16 13:55:16 +08:00
|
|
|
|
password: str
|
2025-12-04 14:48:38 +08:00
|
|
|
|
is_active: bool
|
|
|
|
|
|
is_default: bool
|
|
|
|
|
|
created_at: str
|
2025-12-16 13:55:16 +08:00
|
|
|
|
updated_at: str
|
2025-12-04 14:48:38 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-12-16 13:55:16 +08:00
|
|
|
|
@router.post("/", response_model=NormalResponse, summary="创建或更新数据库配置")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def create_database_config(
|
|
|
|
|
|
config_data: DatabaseConfigCreate,
|
|
|
|
|
|
current_user: User = Depends(AuthService.get_current_user),
|
2025-12-16 13:55:16 +08:00
|
|
|
|
service: DatabaseConfigService = Depends(get_database_service)
|
2025-12-04 14:48:38 +08:00
|
|
|
|
):
|
|
|
|
|
|
"""创建或更新数据库配置"""
|
2025-12-16 13:55:16 +08:00
|
|
|
|
config = await service.create_or_update_config(current_user.id, config_data.model_dump())
|
|
|
|
|
|
return NormalResponse(
|
|
|
|
|
|
success=True,
|
|
|
|
|
|
message="保存数据库配置成功",
|
|
|
|
|
|
data=config
|
2025-12-04 14:48:38 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-12-16 13:55:16 +08:00
|
|
|
|
@router.get("/", response_model=List[DatabaseConfigResponse], summary="获取用户的数据库配置列表")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def get_database_configs(
|
|
|
|
|
|
current_user: User = Depends(AuthService.get_current_user),
|
2025-12-16 13:55:16 +08:00
|
|
|
|
service: DatabaseConfigService = Depends(get_database_service)
|
2025-12-04 14:48:38 +08:00
|
|
|
|
):
|
|
|
|
|
|
"""获取用户的数据库配置列表"""
|
2025-12-16 13:55:16 +08:00
|
|
|
|
configs = service.get_user_configs(current_user.id)
|
2025-12-04 14:48:38 +08:00
|
|
|
|
|
2025-12-16 13:55:16 +08:00
|
|
|
|
config_list = [config.to_dict(include_password=True, decrypt_service=service) for config in configs]
|
|
|
|
|
|
return config_list
|
2025-12-04 14:48:38 +08:00
|
|
|
|
|
2025-12-16 13:55:16 +08:00
|
|
|
|
@router.post("/{config_id}/test", response_model=NormalResponse, summary="测试数据库连接")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def test_database_connection(
|
|
|
|
|
|
config_id: int,
|
|
|
|
|
|
current_user: User = Depends(AuthService.get_current_user),
|
2025-12-16 13:55:16 +08:00
|
|
|
|
service: DatabaseConfigService = Depends(get_database_service)
|
2025-12-04 14:48:38 +08:00
|
|
|
|
):
|
|
|
|
|
|
"""测试数据库连接"""
|
2025-12-16 13:55:16 +08:00
|
|
|
|
result = await service.test_connection(config_id, current_user.id)
|
|
|
|
|
|
return result
|
2025-12-04 14:48:38 +08:00
|
|
|
|
|
2025-12-16 13:55:16 +08:00
|
|
|
|
@router.post("/{config_id}/connect", response_model=NormalResponse, summary="连接数据库并获取表列表")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def connect_database(
|
|
|
|
|
|
config_id: int,
|
|
|
|
|
|
current_user: User = Depends(AuthService.get_current_user),
|
|
|
|
|
|
service: DatabaseConfigService = Depends(get_database_service)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""连接数据库并获取表列表"""
|
2025-12-16 13:55:16 +08:00
|
|
|
|
result = await service.connect_and_get_tables(config_id, current_user.id)
|
|
|
|
|
|
return result
|
2025-12-04 14:48:38 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-12-16 13:55:16 +08:00
|
|
|
|
@router.get("/tables/{table_name}/data", summary="获取表数据预览")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def get_table_data(
|
|
|
|
|
|
table_name: str,
|
|
|
|
|
|
db_type: str,
|
|
|
|
|
|
limit: int = 100,
|
|
|
|
|
|
current_user: User = Depends(AuthService.get_current_user),
|
|
|
|
|
|
service: DatabaseConfigService = Depends(get_database_service)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""获取表数据预览"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
result = await service.get_table_data(table_name, current_user.id, db_type, limit)
|
|
|
|
|
|
return result
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"获取表数据失败: {str(e)}")
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
|
detail=str(e)
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2025-12-16 13:55:16 +08:00
|
|
|
|
@router.get("/tables/{table_name}/schema", summary="获取表结构信息")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def get_table_schema(
|
|
|
|
|
|
table_name: str,
|
|
|
|
|
|
current_user: User = Depends(AuthService.get_current_user),
|
2025-12-16 13:55:16 +08:00
|
|
|
|
service: DatabaseConfigService = Depends(get_database_service)
|
2025-12-04 14:48:38 +08:00
|
|
|
|
):
|
|
|
|
|
|
"""获取表结构信息"""
|
2025-12-16 13:55:16 +08:00
|
|
|
|
result = await service.describe_table(table_name, current_user.id) # 这在哪里实现的?
|
|
|
|
|
|
return result
|
2025-12-04 14:48:38 +08:00
|
|
|
|
|
2025-12-16 13:55:16 +08:00
|
|
|
|
@router.get("/by-type/{db_type}", response_model=DatabaseConfigResponse, summary="根据数据库类型获取配置")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def get_config_by_type(
|
|
|
|
|
|
db_type: str,
|
|
|
|
|
|
current_user: User = Depends(AuthService.get_current_user),
|
2025-12-16 13:55:16 +08:00
|
|
|
|
service: DatabaseConfigService = Depends(get_database_service)
|
2025-12-04 14:48:38 +08:00
|
|
|
|
):
|
|
|
|
|
|
"""根据数据库类型获取配置"""
|
2025-12-16 13:55:16 +08:00
|
|
|
|
config = service.get_config_by_type(current_user.id, db_type)
|
|
|
|
|
|
if not config:
|
2025-12-04 14:48:38 +08:00
|
|
|
|
raise HTTPException(
|
2025-12-16 13:55:16 +08:00
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
|
detail=f"未找到类型为 {db_type} 的配置"
|
2025-12-04 14:48:38 +08:00
|
|
|
|
)
|
2025-12-16 13:55:16 +08:00
|
|
|
|
# 返回包含解密密码的配置
|
|
|
|
|
|
return config.to_dict(include_password=True, decrypt_service=service)
|