Files
ai-agent-admin/backend-fastapi/core/database_connection/api.py
T
2026-06-08 18:14:59 +08:00

190 lines
7.0 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""数据库连接管理 API"""
import logging
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.base_schema import PaginatedResponse, ResponseModel
from app.config import settings
from app.database import get_db
from core.application.model import Application
from core.database_connection.schema import (
DatabaseConnectionCreate,
DatabaseConnectionResponse,
DatabaseConnectionSimpleOut,
DatabaseConnectionTestRequest,
DatabaseConnectionTestResponse,
DatabaseConnectionUpdate,
)
from core.database_connection.service import DatabaseConnectionService
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/database-connection", tags=["数据库连接管理"])
@router.get("", response_model=PaginatedResponse[DatabaseConnectionResponse], summary="获取连接列表")
async def list_connections(
page: int = Query(default=1, ge=1),
page_size: int = Query(default=settings.PAGE_SIZE, ge=1, le=settings.PAGE_MAX_SIZE, alias="pageSize"),
application_id: Optional[str] = Query(default=None, alias="applicationId"),
name: Optional[str] = None,
code: Optional[str] = None,
status: Optional[bool] = None,
db: AsyncSession = Depends(get_db),
):
items, total = await DatabaseConnectionService.get_list(
db,
page=page,
page_size=page_size,
application_id=application_id,
name=name,
code=code,
status=status,
)
app_ids = list({item.application_id for item in items if item.application_id})
app_name_map = {}
if app_ids:
app_result = await db.execute(
select(Application.id, Application.name).where(Application.id.in_(app_ids))
)
app_name_map = {row.id: row.name for row in app_result}
result_items = []
for item in items:
item_dict = DatabaseConnectionService.to_response_dict(item)
item_dict["application_name"] = app_name_map.get(item.application_id, "")
result_items.append(item_dict)
return PaginatedResponse(items=result_items, total=total)
@router.post("", response_model=DatabaseConnectionResponse, summary="创建连接")
async def create_connection(
data: DatabaseConnectionCreate,
db: AsyncSession = Depends(get_db),
):
try:
DatabaseConnectionService.validate_code(data.code)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
if await DatabaseConnectionService.check_code_exists(db, data.code):
raise HTTPException(status_code=400, detail=f"编码已存在: {data.code}")
try:
row = await DatabaseConnectionService.create(db, data.model_dump())
await db.commit()
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
return DatabaseConnectionService.to_response_dict(row)
@router.get("/get/all", response_model=List[DatabaseConnectionSimpleOut], summary="获取全部启用连接")
async def get_all_connections(
application_id: Optional[str] = Query(default=None, alias="applicationId"),
db: AsyncSession = Depends(get_db),
):
configs = await DatabaseConnectionService.get_manager_configs(db, application_id)
return [
DatabaseConnectionSimpleOut(
code=item["db_name"],
name=item.get("display_name") or item["name"],
db_type=item["db_type"],
host=item["host"],
port=item["port"],
database=item["database"],
is_system=item.get("is_system", False),
)
for item in configs
]
@router.get("/check-code/{code}", summary="检查编码是否可用")
async def check_code_available(code: str, db: AsyncSession = Depends(get_db)):
if code == "default":
return {"available": False, "message": "default is reserved"}
exists = await DatabaseConnectionService.check_code_exists(db, code)
return {"available": not exists}
@router.post("/test", response_model=DatabaseConnectionTestResponse, summary="测试未保存连接")
async def test_unsaved_connection(data: DatabaseConnectionTestRequest):
try:
result = await DatabaseConnectionService.test_config(data.model_dump())
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
if not result.get("success"):
logger.error(
"Database connection test failed (unsaved): host=%s port=%s db_type=%s message=%s",
data.host,
data.port,
data.db_type,
result.get("message"),
)
return DatabaseConnectionTestResponse(**result)
@router.get("/{conn_id}", response_model=DatabaseConnectionResponse, summary="获取连接详情")
async def get_connection(conn_id: str, db: AsyncSession = Depends(get_db)):
row = await DatabaseConnectionService.get_by_id(db, conn_id)
if not row:
raise HTTPException(status_code=404, detail="连接不存在")
return DatabaseConnectionService.to_response_dict(row)
@router.put("/{conn_id}", response_model=DatabaseConnectionResponse, summary="更新连接")
async def update_connection(
conn_id: str,
data: DatabaseConnectionUpdate,
db: AsyncSession = Depends(get_db),
):
row = await DatabaseConnectionService.get_by_id(db, conn_id)
if not row:
raise HTTPException(status_code=404, detail="连接不存在")
update_data = data.model_dump(exclude_unset=True)
try:
row = await DatabaseConnectionService.update(db, row, update_data)
await db.commit()
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
return DatabaseConnectionService.to_response_dict(row)
@router.delete("/{conn_id}", response_model=ResponseModel, summary="删除连接")
async def delete_connection(conn_id: str, db: AsyncSession = Depends(get_db)):
row = await DatabaseConnectionService.get_by_id(db, conn_id)
if not row:
raise HTTPException(status_code=404, detail="连接不存在")
try:
await DatabaseConnectionService.delete(db, row)
await db.commit()
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
return ResponseModel(message="删除成功")
@router.post("/{conn_id}/test", response_model=DatabaseConnectionTestResponse, summary="测试已保存连接")
async def test_saved_connection(conn_id: str, db: AsyncSession = Depends(get_db)):
row = await DatabaseConnectionService.get_by_id(db, conn_id)
if not row:
raise HTTPException(status_code=404, detail="连接不存在")
result = await DatabaseConnectionService.test_saved(db, row)
if not result.get("success"):
logger.error(
"Database connection test failed (saved): id=%s code=%s name=%s message=%s",
conn_id,
row.code,
row.name,
result.get("message"),
)
return DatabaseConnectionTestResponse(**result)