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="关闭数据库连接(POST,JSON传参)") 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): """执行非查询SQL(INSERT, 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)}" )