first commit

This commit is contained in:
2026-03-04 12:17:52 +08:00
commit ecb3e1d9b2
42 changed files with 4081 additions and 0 deletions

357
api/v1/routes/database.py Normal file
View File

@@ -0,0 +1,357 @@
from fastapi import APIRouter, HTTPException, status
from typing import List
import logging
from pydantic import BaseModel
from database_manager import db_manager
from schemas import (
DatabaseConnection, QueryRequest, ExecuteRequest, TableDataRequest,
InsertDataRequest, UpdateDataRequest, DeleteDataRequest,
CreateTableRequest, AlterTableRequest, CommentRequest,
ApiResponse, ConnectionResponse, DatabaseInfo, TableInfo, QueryResult
)
logger = logging.getLogger(__name__)
# 创建路由器
router = APIRouter()
# 数据库连接管理接口
@router.post("/connections", response_model=ApiResponse, summary="创建数据库连接")
async def create_connection(connection: DatabaseConnection):
"""创建数据库连接"""
try:
# 准备额外的连接参数
kwargs = {}
if connection.mode:
kwargs['mode'] = connection.mode
if connection.threaded is not None:
kwargs['threaded'] = connection.threaded
if connection.extra_params:
kwargs.update(connection.extra_params)
connection_id = db_manager.create_connection(
db_type=connection.db_type,
host=connection.host,
port=connection.port,
username=connection.username,
password=connection.password,
database=connection.database,
**kwargs
)
response_data = ConnectionResponse(
connection_id=connection_id,
db_type=connection.db_type,
host=connection.host,
port=connection.port,
database=connection.database
)
return ApiResponse(
success=True,
message="数据库连接创建成功",
data=response_data.dict()
)
except Exception as e:
logger.error(f"创建连接失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"创建连接失败: {str(e)}"
)
@router.post("/connections/test", response_model=ApiResponse, summary="测试是否能连通数据库")
async def test_connection(connection: DatabaseConnection):
"""测试是否能连通数据库"""
try:
kwargs = {}
if connection.mode:
kwargs['mode'] = connection.mode
if connection.threaded is not None:
kwargs['threaded'] = connection.threaded
if connection.extra_params:
kwargs.update(connection.extra_params)
result = db_manager.test_connection(
db_type=connection.db_type,
host=connection.host,
port=connection.port,
username=connection.username,
password=connection.password,
database=connection.database,
**kwargs
)
if not result.get("ok"):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"连接测试失败: {result.get('error')}"
)
return ApiResponse(
success=True,
message="数据库连通性测试成功",
data=result
)
except HTTPException:
raise
except Exception as e:
logger.error(f"连接测试失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"连接测试失败: {str(e)}"
)
@router.get("/connections", response_model=ApiResponse, summary="获取所有连接")
async def list_connections():
"""获取所有活动连接"""
try:
connections = db_manager.list_connections()
return ApiResponse(
success=True,
message="获取连接列表成功",
data=connections
)
except Exception as e:
logger.error(f"获取连接列表失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"获取连接列表失败: {str(e)}"
)
class CloseConnectionRequest(BaseModel):
"""关闭连接请求体模型
Attributes:
connection_id: 需要关闭的连接ID
"""
connection_id: str
@router.post("/connections/close", response_model=ApiResponse, summary="关闭数据库连接POSTJSON传参")
async def close_connection(request: CloseConnectionRequest):
"""关闭数据库连接POST使用JSON Body传参
请求示例:
{"connection_id": "mysql_localhost_3306_test_db"}
"""
try:
db_manager.close_connection(request.connection_id)
return ApiResponse(
success=True,
message="数据库连接已关闭"
)
except Exception as e:
logger.error(f"关闭连接失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"关闭连接失败: {str(e)}"
)
# 数据库信息接口
@router.get("/databases/info", response_model=ApiResponse, summary="获取数据库信息使用query参数")
async def get_database_info(connection_id: str):
"""获取数据库信息通过URL query参数
Params:
- connection_id: 通过URL query传入例如 `?connection_id=xxx`
"""
try:
db_info = db_manager.get_database_info(connection_id)
return ApiResponse(
success=True,
message="获取数据库信息成功",
data=db_info
)
except Exception as e:
logger.error(f"获取数据库信息失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"获取数据库信息失败: {str(e)}"
)
@router.get("/databases/tables/info", response_model=ApiResponse, summary="获取表信息使用query参数")
async def get_table_info(connection_id: str, table_name: str):
"""获取表信息通过URL query参数
Params:
- connection_id: 通过URL query传入例如 `?connection_id=xxx`
- table_name: 通过URL query传入例如 `?table_name=users`
"""
try:
table_info = db_manager.get_table_info(connection_id, table_name)
return ApiResponse(
success=True,
message="获取表信息成功",
data=table_info
)
except Exception as e:
logger.error(f"获取表信息失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"获取表信息失败: {str(e)}"
)
# SQL执行接口
@router.post("/query", response_model=ApiResponse, summary="执行查询SQL")
async def execute_query(request: QueryRequest):
"""执行查询SQL"""
try:
result = db_manager.execute_query(
connection_id=request.connection_id,
sql=request.sql,
params=request.params
)
return ApiResponse(
success=True,
message="查询执行成功",
data=result
)
except Exception as e:
logger.error(f"查询执行失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"查询执行失败: {str(e)}"
)
@router.post("/execute", response_model=ApiResponse, summary="执行非查询SQL")
async def execute_non_query(request: ExecuteRequest):
"""执行非查询SQLINSERT, UPDATE, DELETE"""
try:
affected_rows = db_manager.execute_non_query(
connection_id=request.connection_id,
sql=request.sql,
params=request.params
)
return ApiResponse(
success=True,
message="SQL执行成功",
data={"affected_rows": affected_rows}
)
except Exception as e:
logger.error(f"SQL执行失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"SQL执行失败: {str(e)}"
)
# 表数据CRUD接口
@router.post("/tables/data/select", response_model=ApiResponse, summary="查询表数据")
async def select_table_data(request: TableDataRequest):
"""查询表数据"""
try:
# 构建查询SQL
sql = f"SELECT * FROM {request.table_name}"
if request.where_clause:
sql += f" WHERE {request.where_clause}"
if request.order_by:
sql += f" ORDER BY {request.order_by}"
# 添加分页
offset = (request.page - 1) * request.page_size
sql += f" LIMIT {request.page_size} OFFSET {offset}"
# 执行查询
data = db_manager.execute_query(request.connection_id, sql)
# 获取总数
count_sql = f"SELECT COUNT(*) as total FROM {request.table_name}"
if request.where_clause:
count_sql += f" WHERE {request.where_clause}"
count_result = db_manager.execute_query(request.connection_id, count_sql)
total = count_result[0]['total'] if count_result else 0
result = QueryResult(
data=data,
total=total,
page=request.page,
page_size=request.page_size
)
return ApiResponse(
success=True,
message="查询表数据成功",
data=result.dict()
)
except Exception as e:
logger.error(f"查询表数据失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"查询表数据失败: {str(e)}"
)
@router.post("/tables/data/insert", response_model=ApiResponse, summary="插入表数据")
async def insert_table_data(request: InsertDataRequest):
"""插入表数据"""
try:
# 构建插入SQL
columns = list(request.data.keys())
placeholders = [f":{col}" for col in columns]
sql = f"INSERT INTO {request.table_name} ({', '.join(columns)}) VALUES ({', '.join(placeholders)})"
affected_rows = db_manager.execute_non_query(
connection_id=request.connection_id,
sql=sql,
params=request.data
)
return ApiResponse(
success=True,
message="数据插入成功",
data={"affected_rows": affected_rows}
)
except Exception as e:
logger.error(f"插入数据失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"插入数据失败: {str(e)}"
)
@router.post("/tables/data/update", response_model=ApiResponse, summary="更新表数据改为POST")
async def update_table_data(request: UpdateDataRequest):
"""更新表数据HTTP方法改为POST"""
try:
# 构建更新SQL
set_clauses = [f"{col} = :{col}" for col in request.data.keys()]
sql = f"UPDATE {request.table_name} SET {', '.join(set_clauses)} WHERE {request.where_clause}"
affected_rows = db_manager.execute_non_query(
connection_id=request.connection_id,
sql=sql,
params=request.data
)
return ApiResponse(
success=True,
message="数据更新成功",
data={"affected_rows": affected_rows}
)
except Exception as e:
logger.error(f"更新数据失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"更新数据失败: {str(e)}"
)
@router.post("/tables/data/delete", response_model=ApiResponse, summary="删除表数据改为POST")
async def delete_table_data(request: DeleteDataRequest):
"""删除表数据HTTP方法改为POST"""
try:
sql = f"DELETE FROM {request.table_name} WHERE {request.where_clause}"
affected_rows = db_manager.execute_non_query(
connection_id=request.connection_id,
sql=sql
)
return ApiResponse(
success=True,
message="数据删除成功",
data={"affected_rows": affected_rows}
)
except Exception as e:
logger.error(f"删除数据失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"删除数据失败: {str(e)}"
)