From d23602ac56736b4a960d107a0d117635205d4d0d Mon Sep 17 00:00:00 2001 From: HibiKier <45528451+HibiKier@users.noreply.github.com> Date: Mon, 18 Nov 2024 11:06:13 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20webui=E5=92=8C=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E9=A1=B5=E9=9D=A2=E5=92=8C=E6=9F=A5=E8=AF=A2=E6=89=80?= =?UTF-8?q?=E6=9C=89=E8=A1=A8=E6=94=AF=E6=8C=81mysql=E5=92=8Csqlite=20(#17?= =?UTF-8?q?32)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../platform/qq_api/ug_watch.py | 7 +- zhenxun/builtin_plugins/superuser/exec_sql.py | 40 ++++++--- .../web_ui/api/tabs/database/__init__.py | 81 ++++++++++++++++--- .../web_ui/api/tabs/database/models/model.py | 15 ++++ zhenxun/configs/config.py | 2 +- 5 files changed, 118 insertions(+), 27 deletions(-) diff --git a/zhenxun/builtin_plugins/platform/qq_api/ug_watch.py b/zhenxun/builtin_plugins/platform/qq_api/ug_watch.py index 7890ceff..438cb2bc 100644 --- a/zhenxun/builtin_plugins/platform/qq_api/ug_watch.py +++ b/zhenxun/builtin_plugins/platform/qq_api/ug_watch.py @@ -24,5 +24,8 @@ async def do_something(session: Uninfo): ) logger.info("添加当前用户群组ID信息", "", session=session) elif not await FriendUser.exists(user_id=session.user.id, platform=platform): - await FriendUser.create(user_id=session.user.id, platform=platform) - logger.info("添加当前好友用户信息", "", session=session) + try: + await FriendUser.create(user_id=session.user.id, platform=platform) + logger.info("添加当前好友用户信息", "", session=session) + except Exception as e: + logger.error("添加当前好友用户信息失败", session=session, e=e) diff --git a/zhenxun/builtin_plugins/superuser/exec_sql.py b/zhenxun/builtin_plugins/superuser/exec_sql.py index 83a11689..379e3445 100644 --- a/zhenxun/builtin_plugins/superuser/exec_sql.py +++ b/zhenxun/builtin_plugins/superuser/exec_sql.py @@ -1,17 +1,18 @@ +from tortoise import Tortoise from nonebot import on_command +from nonebot.rule import to_me from nonebot.permission import SUPERUSER from nonebot.plugin import PluginMetadata -from nonebot.rule import to_me from nonebot_plugin_alconna import UniMsg from nonebot_plugin_session import EventSession -from tortoise import Tortoise -from zhenxun.configs.utils import PluginExtraData -from zhenxun.models.ban_console import BanConsole from zhenxun.services.log import logger from zhenxun.utils.enum import PluginType -from zhenxun.utils.image_utils import ImageTemplate +from zhenxun.configs.config import BotConfig from zhenxun.utils.message import MessageUtils +from zhenxun.configs.utils import PluginExtraData +from zhenxun.models.ban_console import BanConsole +from zhenxun.utils.image_utils import ImageTemplate __plugin_meta__ = PluginMetadata( name="数据库操作", @@ -43,13 +44,30 @@ _table_matcher = on_command( block=True, ) -SELECT_TABLE_SQL = """ +SELECT_TABLE_MYSQL_SQL = """ +SELECT table_name AS name, table_comment AS `desc` +FROM information_schema.tables +WHERE table_schema = DATABASE(); +""" + +SELECT_TABLE_SQLITE_SQL = """ +SELECT name FROM sqlite_master WHERE type='table'; +""" + +SELECT_TABLE_PSQL_SQL = """ select a.tablename as name,d.description as desc from pg_tables a left join pg_class c on relname=tablename left join pg_description d on oid=objoid and objsubid=0 where a.schemaname = 'public' """ +type2sql = { + "mysql": SELECT_TABLE_MYSQL_SQL, + "sqlite": SELECT_TABLE_SQLITE_SQL, + "postgres": SELECT_TABLE_PSQL_SQL, +} + + @_matcher.handle() async def _(session: EventSession, message: UniMsg): sql_text = message.extract_plain_text().strip() @@ -70,9 +88,7 @@ async def _(session: EventSession, message: UniMsg): _column = r.keys() data_list = [] for r in res: - data = [] - for c in _column: - data.append(r.get(c)) + data = [r.get(c) for c in _column] data_list.append(data) if not data_list: return await MessageUtils.build_message("查询结果为空!").send() @@ -90,11 +106,13 @@ async def _(session: EventSession, message: UniMsg): async def _(session: EventSession): try: db = Tortoise.get_connection("default") - query = await db.execute_query_dict(SELECT_TABLE_SQL) + sql_type = BotConfig.get_sql_type() + select_sql = type2sql[sql_type] + query = await db.execute_query_dict(select_sql) column_name = ["表名", "简介"] data_list = [] for table in query: - data_list.append([table["name"], table["desc"]]) + data_list.append([table["name"], table.get("desc")]) logger.info("查看数据库所有表", "查看所有表", session=session) table = await ImageTemplate.table_page( "数据库表", f"总共有 {len(data_list)} 张表捏", column_name, data_list diff --git a/zhenxun/builtin_plugins/web_ui/api/tabs/database/__init__.py b/zhenxun/builtin_plugins/web_ui/api/tabs/database/__init__.py index 53b8df04..8ec609e5 100644 --- a/zhenxun/builtin_plugins/web_ui/api/tabs/database/__init__.py +++ b/zhenxun/builtin_plugins/web_ui/api/tabs/database/__init__.py @@ -5,12 +5,13 @@ from fastapi import Request, APIRouter from fastapi.responses import JSONResponse from tortoise.exceptions import OperationalError +from zhenxun.configs.config import BotConfig from zhenxun.models.task_info import TaskInfo from zhenxun.models.plugin_info import PluginInfo from .models.sql_log import SqlLog from ....utils import authentication -from .models.model import SqlText, SqlModel +from .models.model import Column, SqlText, SqlModel from ....base_model import Result, QueryModel, BaseResultModel router = APIRouter(prefix="/database") @@ -22,19 +23,48 @@ driver: Driver = nonebot.get_driver() SQL_DICT = {} -SELECT_TABLE_SQL = """ -select a.tablename as name,d.description as desc from pg_tables a - left join pg_class c on relname=tablename - left join pg_description d on oid=objoid - and objsubid=0 where a.schemaname = 'public' +SELECT_TABLE_MYSQL_SQL = """ +SELECT table_name AS name, table_comment AS `desc` +FROM information_schema.tables +WHERE table_schema = DATABASE(); """ -SELECT_TABLE_COLUMN_SQL = """ +SELECT_TABLE_SQLITE_SQL = """ +SELECT name FROM sqlite_master WHERE type='table'; +""" + +SELECT_TABLE_PSQL_SQL = """ +select a.tablename as name,d.description as desc from pg_tables a + left join pg_class c on relname=tablename + left join pg_description d on oid=objoid and objsubid=0 where a.schemaname='public' +""" + +SELECT_TABLE_COLUMN_PSQL_SQL = """ SELECT column_name, data_type, character_maximum_length as max_length, is_nullable FROM information_schema.columns WHERE table_name = '{}'; """ +SELECT_TABLE_COLUMN_MYSQL_SQL = """ +SHOW COLUMNS FROM {}; +""" + +SELECT_TABLE_COLUMN_SQLITE_SQL = """ +PRAGMA table_info({}); +""" + +type2sql = { + "mysql": SELECT_TABLE_MYSQL_SQL, + "sqlite": SELECT_TABLE_SQLITE_SQL, + "postgres": SELECT_TABLE_PSQL_SQL, +} + +type2sql_column = { + "mysql": SELECT_TABLE_COLUMN_MYSQL_SQL, + "sqlite": SELECT_TABLE_COLUMN_SQLITE_SQL, + "postgres": SELECT_TABLE_COLUMN_PSQL_SQL, +} + @driver.on_startup async def _(): @@ -71,22 +101,47 @@ async def _(): ) async def _() -> Result[list[dict]]: db = Tortoise.get_connection("default") - query = await db.execute_query_dict(SELECT_TABLE_SQL) + sql_type = BotConfig.get_sql_type() + query = await db.execute_query_dict(type2sql[sql_type]) return Result.ok(query) @router.get( "/get_table_column", dependencies=[authentication()], - response_model=Result[list[dict]], + response_model=Result[list[Column]], response_class=JSONResponse, description="获取表字段", ) -async def _(table_name: str) -> Result[list[dict]]: +async def _(table_name: str) -> Result[list[Column]]: db = Tortoise.get_connection("default") - # print(SELECT_TABLE_COLUMN_SQL.format(table_name)) - query = await db.execute_query_dict(SELECT_TABLE_COLUMN_SQL.format(table_name)) - return Result.ok(query) + sql_type = BotConfig.get_sql_type() + sql = type2sql_column[sql_type] + query = await db.execute_query_dict(sql.format(table_name)) + result_list = [] + if sql_type == "sqlite": + result_list.extend( + Column( + column_name=result["name"], + data_type=result["type"], + max_length=-1, + is_nullable="YES" if result["notnull"] == 1 else "NO", + ) + for result in query + ) + elif sql_type == "mysql": + result_list.extend( + Column( + column_name=result["Field"], + data_type=result["Type"], + max_length=-1, + is_nullable=result["Null"], + ) + for result in query + ) + else: + result_list.extend(Column(**result) for result in query) + return Result.ok(result_list) @router.post( diff --git a/zhenxun/builtin_plugins/web_ui/api/tabs/database/models/model.py b/zhenxun/builtin_plugins/web_ui/api/tabs/database/models/model.py index e18e4cfb..9a85f14f 100644 --- a/zhenxun/builtin_plugins/web_ui/api/tabs/database/models/model.py +++ b/zhenxun/builtin_plugins/web_ui/api/tabs/database/models/model.py @@ -22,3 +22,18 @@ class SqlModel(BaseModel): """插件名称""" sql_list: list[CommonSql] """插件列表""" + + +class Column(BaseModel): + """ + 列 + """ + + column_name: str + """列名""" + data_type: str + """数据类型""" + max_length: int | None + """最大长度""" + is_nullable: str + """是否可为空""" diff --git a/zhenxun/configs/config.py b/zhenxun/configs/config.py index ccb6bf36..d0bc6982 100644 --- a/zhenxun/configs/config.py +++ b/zhenxun/configs/config.py @@ -46,7 +46,7 @@ class BotSetting(BaseModel): """获取数据库类型 返回: - str: 数据库类型, postgres, aiomysql, sqlite + str: 数据库类型, postgres, mysql, sqlite """ return self.db_url.split(":", 1)[0] if self.db_url else ""