From b95acce800b17042d333688d786c3670bdb4168a Mon Sep 17 00:00:00 2001 From: Rumio <32546670+webjoin111@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:45:33 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(db):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=A4=9A=E6=95=B0=E6=8D=AE=E5=BA=93=E8=84=9A=E6=9C=AC=E5=85=BC?= =?UTF-8?q?=E5=AE=B9=E6=80=A7=E4=B8=8E=E5=88=9D=E5=A7=8B=E5=8C=96=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E5=A4=84=E7=90=86=20(#2095)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🐛 fix(db): 优化多数据库脚本兼容性与初始化错误处理 - 为 `BotConsole`、`GroupConsole` 和 `GroupInfo` 模型增加针对 PostgreSQL 和 MySQL 的字段类型转换脚本 - 统一将插件和任务相关的禁用/可用字段类型修改为 `TEXT` - 优化数据库初始化逻辑,增加对 `OperationalError` 的细粒度处理,忽略常见的重复执行错误 - 简化 `db_context` 内部配置解析逻辑 * :rotating_light: auto fix by pre-commit hooks --------- Co-authored-by: webjoin111 <455457521@qq.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: HibiKier <45528451+HibiKier@users.noreply.github.com> --- zhenxun/models/bot_console.py | 26 ++++++++++++- zhenxun/models/group_console.py | 50 +++++++++++++++++++++++-- zhenxun/models/group_info.py | 22 ++++++++++- zhenxun/services/db_context/__init__.py | 26 ++++++++++--- 4 files changed, 112 insertions(+), 12 deletions(-) diff --git a/zhenxun/models/bot_console.py b/zhenxun/models/bot_console.py index f16e39f5..8d21a763 100644 --- a/zhenxun/models/bot_console.py +++ b/zhenxun/models/bot_console.py @@ -2,6 +2,7 @@ from typing import Literal, overload from tortoise import fields +from zhenxun.configs.config import BotConfig from zhenxun.services.cache.runtime_cache import BotMemoryCache from zhenxun.services.db_context import Model from zhenxun.utils.enum import CacheType @@ -469,9 +470,32 @@ class BotConsole(Model): @classmethod async def _run_script(cls): - return [ + db_type = (BotConfig.get_sql_type() or "").lower() + + scripts = [ "ALTER TABLE bot_console RENAME COLUMN block_plugin TO block_plugins;", "ALTER TABLE bot_console RENAME COLUMN block_task TO block_tasks;", "ALTER TABLE bot_console ADD available_plugins text default '';", "ALTER TABLE bot_console ADD available_tasks text default '';", ] + + if "postgres" in db_type: + scripts.extend( + [ + "ALTER TABLE bot_console ALTER COLUMN block_plugins TYPE TEXT;", + "ALTER TABLE bot_console ALTER COLUMN block_tasks TYPE TEXT;", + "ALTER TABLE bot_console ALTER COLUMN available_plugins TYPE TEXT;", + "ALTER TABLE bot_console ALTER COLUMN available_tasks TYPE TEXT;", + ] + ) + elif "mysql" in db_type: + scripts.extend( + [ + "ALTER TABLE bot_console MODIFY COLUMN block_plugins TEXT;", + "ALTER TABLE bot_console MODIFY COLUMN block_tasks TEXT;", + "ALTER TABLE bot_console MODIFY COLUMN available_plugins TEXT;", + "ALTER TABLE bot_console MODIFY COLUMN available_tasks TEXT;", + ] + ) + + return scripts diff --git a/zhenxun/models/group_console.py b/zhenxun/models/group_console.py index 5d596e7d..f1f317db 100644 --- a/zhenxun/models/group_console.py +++ b/zhenxun/models/group_console.py @@ -4,6 +4,7 @@ from typing_extensions import Self from tortoise import fields from tortoise.backends.base.client import BaseDBAsyncClient +from zhenxun.configs.config import BotConfig from zhenxun.models.plugin_info import PluginInfo from zhenxun.models.task_info import TaskInfo from zhenxun.services.cache import CacheRoot @@ -514,11 +515,52 @@ class GroupConsole(Model): @classmethod def _run_script(cls): - return [ + db_type = (BotConfig.get_sql_type() or "").lower() + + scripts = [ "ALTER TABLE group_console ADD superuser_block_plugin" - " character varying(255) NOT NULL DEFAULT '';", + " Text NOT NULL DEFAULT '';", "ALTER TABLE group_console ADD superuser_block_task" - " character varying(255) NOT NULL DEFAULT '';", + " Text NOT NULL DEFAULT '';", "CREATE INDEX idx_group_console_group_id ON group_console(group_id);", - "CREATE INDEX idx_group_console_group_null_channel ON group_console(group_id) WHERE channel_id IS NULL;", # 单独创建channel为空的索引 # noqa: E501 + ( + "CREATE INDEX idx_group_console_group_null_channel ON " + "group_console(group_id) WHERE channel_id IS NULL;" + ), ] + + if "postgres" in db_type: + scripts.extend( + [ + ( + "ALTER TABLE group_console ALTER COLUMN " + "block_plugin TYPE TEXT;" + ), + ( + "ALTER TABLE group_console ALTER COLUMN " + "superuser_block_plugin TYPE TEXT;" + ), + ("ALTER TABLE group_console ALTER COLUMN " "block_task TYPE TEXT;"), + ( + "ALTER TABLE group_console ALTER COLUMN " + "superuser_block_task TYPE TEXT;" + ), + ] + ) + elif "mysql" in db_type: + scripts.extend( + [ + ("ALTER TABLE group_console MODIFY COLUMN " "block_plugin TEXT;"), + ( + "ALTER TABLE group_console MODIFY COLUMN " + "superuser_block_plugin TEXT;" + ), + ("ALTER TABLE group_console MODIFY COLUMN " "block_task TEXT;"), + ( + "ALTER TABLE group_console MODIFY COLUMN " + "superuser_block_task TEXT;" + ), + ] + ) + + return scripts diff --git a/zhenxun/models/group_info.py b/zhenxun/models/group_info.py index b60120a1..23d32711 100644 --- a/zhenxun/models/group_info.py +++ b/zhenxun/models/group_info.py @@ -1,5 +1,6 @@ from tortoise import fields +from zhenxun.configs.config import BotConfig from zhenxun.services.db_context import Model @@ -109,7 +110,9 @@ class GroupInfo(Model): @classmethod def _run_script(cls): - return [ + db_type = (BotConfig.get_sql_type() or "").lower() + + scripts = [ "ALTER TABLE group_info ADD group_flag Integer NOT NULL DEFAULT 0;", # group_info表添加一个group_flag "ALTER TABLE group_info ALTER COLUMN group_id TYPE character varying(255);", @@ -118,3 +121,20 @@ class GroupInfo(Model): "ALTER TABLE group_info ADD platform character varying(255) NOT NULL" " DEFAULT 'qq';", ] + + if "postgres" in db_type: + scripts.extend( + [ + "ALTER TABLE group_info ALTER COLUMN block_plugin TYPE TEXT;", + "ALTER TABLE group_info ALTER COLUMN block_task TYPE TEXT;", + ] + ) + elif "mysql" in db_type: + scripts.extend( + [ + "ALTER TABLE group_info MODIFY COLUMN block_plugin TEXT;", + "ALTER TABLE group_info MODIFY COLUMN block_task TEXT;", + ] + ) + + return scripts diff --git a/zhenxun/services/db_context/__init__.py b/zhenxun/services/db_context/__init__.py index b5ec0be6..f42e24e4 100644 --- a/zhenxun/services/db_context/__init__.py +++ b/zhenxun/services/db_context/__init__.py @@ -7,6 +7,7 @@ import nonebot from nonebot.utils import is_coroutine_callable from tortoise import Tortoise from tortoise.connection import connections +from tortoise.exceptions import OperationalError from zhenxun.configs.config import BotConfig from zhenxun.services.log import logger @@ -50,11 +51,8 @@ def get_config() -> dict: raise DbUrlIsNode("数据库Url连接字符串为空,请检查配置文件(.env.dev)") parsed = urlparse(BotConfig.db_url) - # 基础配置 config = { - "connections": { - "default": BotConfig.db_url # 默认直接使用连接字符串 - }, + "connections": {"default": BotConfig.db_url}, "apps": { "models": { "models": db_model.models, @@ -64,7 +62,6 @@ def get_config() -> dict: "timezone": "Asia/Shanghai", } - # 根据数据库类型应用高级配置 if parsed.scheme.startswith("postgres"): config["connections"]["default"] = { "engine": "tortoise.backends.asyncpg", @@ -143,7 +140,24 @@ async def init(): await asyncio.wait_for( db.execute_query_dict(sql), timeout=DB_TIMEOUT_SECONDS ) - # await TestSQL.raw(sql) + except OperationalError as e: + err_str = str(e).lower() + if any( + x in err_str + for x in [ + "already exists", + "duplicate column", + "已经存在", + "已存在", + ] + ): + pass + elif any( + x in err_str for x in ["does not exist", "check that", "不存在"] + ) and ("drop" in sql.lower() or "rename" in sql.lower()): + pass + else: + logger.warning(f"执行SQL警告: {sql} || {e}") except Exception as e: logger.debug(f"执行SQL: {sql} 错误...", e=e) if sql_list: