🐛 fix(db): 优化多数据库脚本兼容性与初始化错误处理 (#2095)

* 🐛 fix(db): 优化多数据库脚本兼容性与初始化错误处理

- 为 `BotConsole`、`GroupConsole` 和 `GroupInfo` 模型增加针对 PostgreSQL 和 MySQL 的字段类型转换脚本
- 统一将插件和任务相关的禁用/可用字段类型修改为 `TEXT`
- 优化数据库初始化逻辑,增加对 `OperationalError` 的细粒度处理,忽略常见的重复执行错误
- 简化 `db_context` 内部配置解析逻辑

* 🚨 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>
This commit is contained in:
Rumio
2026-02-06 16:45:33 +08:00
committed by GitHub
co-authored by webjoin111 pre-commit-ci[bot] HibiKier
parent 4f152638b0
commit b95acce800
4 changed files with 112 additions and 12 deletions
+25 -1
View File
@@ -2,6 +2,7 @@ from typing import Literal, overload
from tortoise import fields from tortoise import fields
from zhenxun.configs.config import BotConfig
from zhenxun.services.cache.runtime_cache import BotMemoryCache from zhenxun.services.cache.runtime_cache import BotMemoryCache
from zhenxun.services.db_context import Model from zhenxun.services.db_context import Model
from zhenxun.utils.enum import CacheType from zhenxun.utils.enum import CacheType
@@ -469,9 +470,32 @@ class BotConsole(Model):
@classmethod @classmethod
async def _run_script(cls): 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_plugin TO block_plugins;",
"ALTER TABLE bot_console RENAME COLUMN block_task TO block_tasks;", "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_plugins text default '';",
"ALTER TABLE bot_console ADD available_tasks 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
+46 -4
View File
@@ -4,6 +4,7 @@ from typing_extensions import Self
from tortoise import fields from tortoise import fields
from tortoise.backends.base.client import BaseDBAsyncClient from tortoise.backends.base.client import BaseDBAsyncClient
from zhenxun.configs.config import BotConfig
from zhenxun.models.plugin_info import PluginInfo from zhenxun.models.plugin_info import PluginInfo
from zhenxun.models.task_info import TaskInfo from zhenxun.models.task_info import TaskInfo
from zhenxun.services.cache import CacheRoot from zhenxun.services.cache import CacheRoot
@@ -514,11 +515,52 @@ class GroupConsole(Model):
@classmethod @classmethod
def _run_script(cls): def _run_script(cls):
return [ db_type = (BotConfig.get_sql_type() or "").lower()
scripts = [
"ALTER TABLE group_console ADD superuser_block_plugin" "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" "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_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
+21 -1
View File
@@ -1,5 +1,6 @@
from tortoise import fields from tortoise import fields
from zhenxun.configs.config import BotConfig
from zhenxun.services.db_context import Model from zhenxun.services.db_context import Model
@@ -109,7 +110,9 @@ class GroupInfo(Model):
@classmethod @classmethod
def _run_script(cls): 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;", "ALTER TABLE group_info ADD group_flag Integer NOT NULL DEFAULT 0;",
# group_info表添加一个group_flag # group_info表添加一个group_flag
"ALTER TABLE group_info ALTER COLUMN group_id TYPE character varying(255);", "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" "ALTER TABLE group_info ADD platform character varying(255) NOT NULL"
" DEFAULT 'qq';", " 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
+20 -6
View File
@@ -7,6 +7,7 @@ import nonebot
from nonebot.utils import is_coroutine_callable from nonebot.utils import is_coroutine_callable
from tortoise import Tortoise from tortoise import Tortoise
from tortoise.connection import connections from tortoise.connection import connections
from tortoise.exceptions import OperationalError
from zhenxun.configs.config import BotConfig from zhenxun.configs.config import BotConfig
from zhenxun.services.log import logger from zhenxun.services.log import logger
@@ -50,11 +51,8 @@ def get_config() -> dict:
raise DbUrlIsNode("数据库Url连接字符串为空,请检查配置文件(.env.dev)") raise DbUrlIsNode("数据库Url连接字符串为空,请检查配置文件(.env.dev)")
parsed = urlparse(BotConfig.db_url) parsed = urlparse(BotConfig.db_url)
# 基础配置
config = { config = {
"connections": { "connections": {"default": BotConfig.db_url},
"default": BotConfig.db_url # 默认直接使用连接字符串
},
"apps": { "apps": {
"models": { "models": {
"models": db_model.models, "models": db_model.models,
@@ -64,7 +62,6 @@ def get_config() -> dict:
"timezone": "Asia/Shanghai", "timezone": "Asia/Shanghai",
} }
# 根据数据库类型应用高级配置
if parsed.scheme.startswith("postgres"): if parsed.scheme.startswith("postgres"):
config["connections"]["default"] = { config["connections"]["default"] = {
"engine": "tortoise.backends.asyncpg", "engine": "tortoise.backends.asyncpg",
@@ -143,7 +140,24 @@ async def init():
await asyncio.wait_for( await asyncio.wait_for(
db.execute_query_dict(sql), timeout=DB_TIMEOUT_SECONDS 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: except Exception as e:
logger.debug(f"执行SQL: {sql} 错误...", e=e) logger.debug(f"执行SQL: {sql} 错误...", e=e)
if sql_list: if sql_list: