Files
AIclinicalresearch/backend/scripts/verify-pkb-rvw-schema.ts
HaHafeng 06028c6952 feat(pkb): implement complete batch processing workflow and frontend optimization
- Frontend V3 architecture migration to modules/pkb
- Implement three work modes: full-text reading, deep reading, batch processing
- Complete batch processing: template selection, progress display, result export (CSV)
- Integrate Ant Design X Chat component with streaming support
- Add document upload modal with drag-and-drop support
- Optimize UI: multi-line table display, citation formatting, auto-scroll
- Fix 10+ technical issues: API mapping, state sync, form clearing
- Update documentation: development records and module status

Performance: 3 docs batch processing ~17-28s
Status: PKB module now production-ready (90% complete)
2026-01-07 18:23:43 +08:00

295 lines
10 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 验证PKB和RVW的数据库Schema状态
*
* 目的:
* 1. 检查pkb_schema是否存在及其表结构
* 2. 检查rvw_schema是否存在
* 3. 检查ReviewTask在哪个Schema中
* 4. 检查是否有旧数据需要迁移
*
* 运行方式:
* npx tsx scripts/verify-pkb-rvw-schema.ts
*/
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
interface SchemaInfo {
schema_name: string;
}
interface TableInfo {
table_schema: string;
table_name: string;
}
interface ColumnInfo {
column_name: string;
data_type: string;
is_nullable: string;
column_default: string | null;
}
interface RowCount {
count: bigint;
}
async function verifySchemas() {
console.log('🔍 开始验证PKB和RVW的数据库Schema状态...\n');
console.log('='.repeat(80));
try {
// ========================================
// 1. 检查所有Schema
// ========================================
console.log('\n📦 1. 检查数据库中所有的Schema');
console.log('='.repeat(80));
const schemas = await prisma.$queryRaw<SchemaInfo[]>`
SELECT schema_name
FROM information_schema.schemata
WHERE schema_name IN ('pkb_schema', 'rvw_schema', 'public', 'platform_schema')
ORDER BY schema_name
`;
console.log('✅ 找到以下Schema');
schemas.forEach(s => console.log(` - ${s.schema_name}`));
const hasRvwSchema = schemas.some(s => s.schema_name === 'rvw_schema');
const hasPkbSchema = schemas.some(s => s.schema_name === 'pkb_schema');
console.log(`\n📊 Schema存在性检查`);
console.log(` pkb_schema: ${hasPkbSchema ? '✅ 存在' : '❌ 不存在'}`);
console.log(` rvw_schema: ${hasRvwSchema ? '✅ 存在' : '❌ 不存在'}`);
// ========================================
// 2. 检查PKB相关表
// ========================================
console.log('\n');
console.log('='.repeat(80));
console.log('📚 2. 检查PKB相关表在pkb_schema中');
console.log('='.repeat(80));
if (hasPkbSchema) {
const pkbTables = await prisma.$queryRaw<TableInfo[]>`
SELECT table_schema, table_name
FROM information_schema.tables
WHERE table_schema = 'pkb_schema'
ORDER BY table_name
`;
console.log(`✅ pkb_schema中共有 ${pkbTables.length} 个表:`);
pkbTables.forEach(t => console.log(` - ${t.table_name}`));
// 检查每个表的行数
console.log('\n📊 PKB表数据统计');
for (const table of pkbTables) {
try {
const result = await prisma.$queryRaw<RowCount[]>`
SELECT COUNT(*) as count FROM pkb_schema.${prisma.$queryRawUnsafe(table.table_name)}
`;
const count = Number(result[0]?.count || 0);
console.log(` - ${table.table_name}: ${count}`);
} catch (error) {
console.log(` - ${table.table_name}: 查询失败`);
}
}
} else {
console.log('❌ pkb_schema不存在需要创建');
}
// ========================================
// 3. 检查RVW相关表
// ========================================
console.log('\n');
console.log('='.repeat(80));
console.log('📝 3. 检查RVW相关表review_tasks');
console.log('='.repeat(80));
// 查找review_tasks表在哪个schema
const reviewTaskLocation = await prisma.$queryRaw<TableInfo[]>`
SELECT table_schema, table_name
FROM information_schema.tables
WHERE table_name = 'review_tasks'
`;
if (reviewTaskLocation.length > 0) {
console.log('✅ 找到review_tasks表');
reviewTaskLocation.forEach(t => {
console.log(` - 位置: ${t.table_schema}.${t.table_name}`);
});
// 查看review_tasks表结构
const reviewSchema = reviewTaskLocation[0].table_schema;
console.log(`\n📋 review_tasks表结构${reviewSchema}中):`);
const reviewColumns = await prisma.$queryRaw<ColumnInfo[]>`
SELECT column_name, data_type, is_nullable, column_default
FROM information_schema.columns
WHERE table_schema = ${reviewSchema}
AND table_name = 'review_tasks'
ORDER BY ordinal_position
`;
console.log('='.repeat(80));
console.log(
'Column Name'.padEnd(25) +
'Data Type'.padEnd(20) +
'Nullable'.padEnd(12) +
'Default'
);
console.log('='.repeat(80));
reviewColumns.forEach(col => {
const colName = col.column_name.padEnd(25);
const dataType = col.data_type.padEnd(20);
const nullable = (col.is_nullable === 'YES' ? 'YES' : 'NO').padEnd(12);
const defaultVal = col.column_default || '';
console.log(`${colName}${dataType}${nullable}${defaultVal}`);
});
console.log('='.repeat(80));
console.log(`总计: ${reviewColumns.length} 个字段`);
// 查询数据量
const reviewCount = await prisma.$queryRaw<RowCount[]>`
SELECT COUNT(*) as count FROM ${prisma.$queryRawUnsafe(reviewSchema)}.review_tasks
`;
const count = Number(reviewCount[0]?.count || 0);
console.log(`\n📊 review_tasks表数据量: ${count}`);
if (reviewSchema === 'public') {
console.log('\n⚠ WARNING: review_tasks当前在public schema中');
console.log(' 建议迁移到rvw_schema以保持架构一致性');
}
} else {
console.log('❌ 未找到review_tasks表');
}
// ========================================
// 4. 检查rvw_schema状态
// ========================================
console.log('\n');
console.log('='.repeat(80));
console.log('🔍 4. 检查rvw_schema状态');
console.log('='.repeat(80));
if (hasRvwSchema) {
const rvwTables = await prisma.$queryRaw<TableInfo[]>`
SELECT table_schema, table_name
FROM information_schema.tables
WHERE table_schema = 'rvw_schema'
ORDER BY table_name
`;
if (rvwTables.length > 0) {
console.log(`✅ rvw_schema中共有 ${rvwTables.length} 个表:`);
rvwTables.forEach(t => console.log(` - ${t.table_name}`));
} else {
console.log('⚠️ rvw_schema存在但为空未创建任何表');
}
} else {
console.log('❌ rvw_schema不存在需要创建');
}
// ========================================
// 5. 检查User表状态
// ========================================
console.log('\n');
console.log('='.repeat(80));
console.log('👤 5. 检查User表状态');
console.log('='.repeat(80));
const userTables = await prisma.$queryRaw<TableInfo[]>`
SELECT table_schema, table_name
FROM information_schema.tables
WHERE table_name = 'users'
AND table_schema IN ('public', 'platform_schema')
`;
console.log('✅ 找到以下users表');
for (const userTable of userTables) {
console.log(` - ${userTable.table_schema}.${userTable.table_name}`);
const userCount = await prisma.$queryRaw<RowCount[]>`
SELECT COUNT(*) as count FROM ${prisma.$queryRawUnsafe(userTable.table_schema)}.users
`;
const count = Number(userCount[0]?.count || 0);
console.log(` 数据量: ${count}`);
}
// ========================================
// 6. 总结和建议
// ========================================
console.log('\n');
console.log('='.repeat(80));
console.log('📋 6. 迁移建议总结');
console.log('='.repeat(80));
console.log('\n✅ PKB模块迁移建议');
if (hasPkbSchema && pkbTables.length > 0) {
console.log(' 1. ✅ pkb_schema已存在且有表');
console.log(' 2. ✅ 可以直接迁移代码到新架构');
console.log(' 3. ⚠️ 注意检查旧代码是否连接到正确的schema');
} else {
console.log(' 1. ❌ 需要先创建pkb_schema和相关表');
console.log(' 2. ❌ 需要运行Prisma迁移');
}
console.log('\n⚠ RVW模块迁移建议');
if (reviewTaskLocation.length > 0) {
const currentSchema = reviewTaskLocation[0].table_schema;
if (currentSchema === 'public') {
console.log(' 1. ⚠️ review_tasks当前在public schema');
console.log(' 2. 🔄 建议先完整迁移功能后续再迁移Schema');
console.log(' 3. 📋 迁移步骤:');
console.log(' a. 创建rvw_schema如果不存在');
console.log(' b. 在rvw_schema中创建新表');
console.log(' c. 迁移数据');
console.log(' d. 更新代码');
console.log(' e. 删除旧表');
} else if (currentSchema === 'rvw_schema') {
console.log(' 1. ✅ review_tasks已在rvw_schema中');
console.log(' 2. ✅ 可以直接迁移代码');
}
} else {
console.log(' 1. ❌ review_tasks表不存在');
console.log(' 2. ❌ 需要从头创建');
}
console.log('\n💡 推荐迁移策略:');
console.log(' 【方案A渐进式迁移推荐】');
console.log(' 1. PKB: 直接迁移代码到新架构Schema已就绪');
console.log(' 2. RVW: 先迁移代码保持在public schema');
console.log(' 3. 验证功能完整性');
console.log(' 4. 后续独立任务将RVW迁移到rvw_schema');
console.log('');
console.log(' 【方案B一步到位风险较高】');
console.log(' 1. 同时迁移代码+Schema');
console.log(' 2. 需要数据迁移脚本');
console.log(' 3. 需要更长的测试时间');
console.log('\n='.repeat(80));
console.log('✅ 验证完成!');
console.log('='.repeat(80));
} catch (error) {
console.error('❌ 验证过程中出错:', error);
throw error;
} finally {
await prisma.$disconnect();
}
}
// 运行验证
verifySchemas()
.catch((error) => {
console.error('Fatal error:', error);
process.exit(1);
});