fix(db): 知识库 V2 菜单迁移 — PL/pgSQL 安全检查 sys_menu 存在性

迁移 168 引用 sys_menu 表但在无基础 ERP 数据的数据库中不存在。
改用 DO $$ block + information_schema 检查,表不存在时安全跳过。
This commit is contained in:
iven
2026-05-27 11:04:45 +08:00
parent a4d09269a4
commit 803a27fb84

View File

@@ -6,56 +6,65 @@ pub struct Migration;
#[async_trait::async_trait] #[async_trait::async_trait]
impl MigrationTrait for Migration { impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
// 在"AI 知识库"同级位置添加"知识库 V2"菜单 // 安全插入:仅在 sys_menu 表存在且有 ai-knowledge 菜单时添加 V2 菜单
// parent_id 取旧 ai-knowledge 菜单的 parent_id
let sql = r#" let sql = r#"
INSERT INTO sys_menu (id, parent_id, name, path, icon, sort, permission, component, is_external, is_cached, status, visible, created_at, updated_at, deleted_at) DO $$
SELECT BEGIN
gen_random_uuid(), IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'sys_menu') THEN
parent_id, INSERT INTO sys_menu (id, parent_id, name, path, icon, sort, permission, component, is_external, is_cached, status, visible, created_at, updated_at, deleted_at)
'知识库 V2', SELECT
'/health/ai-knowledge-v2', gen_random_uuid(),
'DatabaseOutlined', parent_id,
54, '知识库 V2',
'ai.knowledge.list', '/health/ai-knowledge-v2',
'ai/KnowledgeV2Page', 'DatabaseOutlined',
false, 54,
false, 'ai.knowledge.list',
'active', 'ai/KnowledgeV2Page',
true, false,
now(), false,
now(), 'active',
NULL true,
FROM sys_menu now(),
WHERE path = '/health/ai-knowledge' AND deleted_at IS NULL now(),
LIMIT 1 NULL
ON CONFLICT DO NOTHING FROM sys_menu
WHERE path = '/health/ai-knowledge' AND deleted_at IS NULL
LIMIT 1
ON CONFLICT DO NOTHING;
IF FOUND THEN
INSERT INTO sys_role_menu (role_id, menu_id)
SELECT r.id, m.id
FROM sys_role r, sys_menu m
WHERE r.code = 'admin' AND r.deleted_at IS NULL
AND m.path = '/health/ai-knowledge-v2' AND m.deleted_at IS NULL
ON CONFLICT DO NOTHING;
END IF;
END IF;
END;
$$ LANGUAGE plpgsql
"#; "#;
manager.get_connection().execute_unprepared(sql).await?; manager.get_connection().execute_unprepared(sql).await?;
// 绑定到 admin 角色
let role_sql = r#"
INSERT INTO sys_role_menu (role_id, menu_id)
SELECT r.id, m.id
FROM sys_role r, sys_menu m
WHERE r.code = 'admin' AND r.deleted_at IS NULL
AND m.path = '/health/ai-knowledge-v2' AND m.deleted_at IS NULL
ON CONFLICT DO NOTHING
"#;
manager
.get_connection()
.execute_unprepared(role_sql)
.await?;
Ok(()) Ok(())
} }
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager manager
.get_connection() .get_connection()
.execute_unprepared("DELETE FROM sys_menu WHERE path = '/health/ai-knowledge-v2'") .execute_unprepared(
r#"
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'sys_menu') THEN
DELETE FROM sys_menu WHERE path = '/health/ai-knowledge-v2';
END IF;
END;
$$ LANGUAGE plpgsql
"#,
)
.await?; .await?;
Ok(()) Ok(())
} }