| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- /**
- * 探查数据库表结构 + 数据量 + 示例数据
- *
- * 用法: cd backend && npx tsx scripts/discover-db.ts
- */
- import 'dotenv/config';
- import Parse from '../src/db/parse-client.js';
- async function countRows(className: string): Promise<number> {
- try {
- const n = await new Parse.Query(className).count({ useMasterKey: true });
- return n;
- } catch {
- return -1;
- }
- }
- async function showSample(className: string, fields: string[], limit = 2): Promise<void> {
- try {
- const q = new Parse.Query(className);
- q.limit(limit);
- q.descending('updatedAt');
- const rows = await q.find({ useMasterKey: true }) as any[];
- if (rows.length === 0) {
- console.log(' (无数据)');
- return;
- }
- for (const row of rows) {
- const vals: string[] = [];
- for (const f of fields) {
- const v = row.get(f);
- if (v === undefined || v === null) {
- vals.push(`${f}=null`);
- } else if (typeof v === 'object' && v.className) {
- vals.push(`${f}=Pointer(${v.className}:${v.id})`);
- } else if (typeof v === 'object') {
- vals.push(`${f}=${JSON.stringify(v).substring(0, 80)}`);
- } else {
- const s = String(v);
- vals.push(`${f}=${s.length > 60 ? s.substring(0, 60) + '...' : s}`);
- }
- }
- console.log(` ${vals.join(' | ')}`);
- }
- } catch (err: any) {
- console.log(` 查询失败: ${err.message}`);
- }
- }
- async function main(): Promise<void> {
- console.log('=== 数据库探查 ===\n');
- console.log(`Server: ${Parse.serverURL}`);
- console.log(`App ID: ${Parse.applicationId}\n`);
- // 测试连接
- try {
- const n = await new Parse.Query('_User').count({ useMasterKey: true });
- console.log(`✅ Parse 连接正常 (_User: ${n} 条)\n`);
- } catch (err: any) {
- console.error(`❌ Parse 连接失败: ${err.message}`);
- process.exit(1);
- }
- // 目标表
- const targets = ['GroupChat', 'GroupMember', 'Message', 'Community', 'Store', 'ResponsibilityAssignment'];
- const schemas = await Parse.Schema.all({ useMasterKey: true });
- const schemaMap = new Map(schemas.map(s => [s.className, s]));
- for (const className of targets) {
- const schema = schemaMap.get(className);
- const count = await countRows(className);
- console.log(`\n${'═'.repeat(80)}`);
- console.log(`📦 ${className} — ${count} 行`);
- console.log(`${'─'.repeat(80)}`);
- if (schema) {
- const fields = schema.fields as Record<string, { type: string; targetClass?: string }>;
- const entries = Object.entries(fields)
- .filter(([name]) => !name.startsWith('_'))
- .sort(([a], [b]) => a.localeCompare(b));
- const fieldNames: string[] = [];
- for (const [name, def] of entries) {
- const typeStr = def.type === 'Pointer' ? `Pointer→${def.targetClass || '?'}` : def.type;
- console.log(` ${name}: ${typeStr}`);
- fieldNames.push(name);
- }
- // 示例数据
- console.log(`\n 示例数据:`);
- const keyFields = fieldNames.filter(f =>
- ['roomId', 'roomName', 'name', 'status', 'nickname', 'content', 'senderName',
- 'msgType', 'lifecyclePhase', 'ownerName', 'scopeType', 'userName',
- 'memberCount', 'messageCountToday', 'messageCountTotal', 'groupCount',
- 'community', 'store', 'deliveryDate'].includes(f)
- );
- await showSample(className, keyFields.length > 0 ? keyFields : fieldNames.slice(0, 8));
- } else {
- console.log(' (Schema 未找到,可能表不存在)');
- }
- }
- // 检查 GroupChat 是否还有 memberCount/messageCountToday/messageCountTotal 字段
- console.log(`\n${'═'.repeat(80)}`);
- console.log('🔍 GroupChat 旧预计算字段检查');
- console.log(`${'─'.repeat(80)}`);
- const gcSchema = schemaMap.get('GroupChat');
- if (gcSchema) {
- const fields = gcSchema.fields as Record<string, { type: string }>;
- for (const name of ['memberCount', 'messageCountToday', 'messageCountTotal', 'ownerName', 'lastActivityAt', 'avatarUrl']) {
- console.log(` ${name}: ${fields[name] ? '存在 (' + fields[name].type + ')' : '❌ 已删除'}`);
- }
- }
- // 今日消息量
- console.log(`\n${'═'.repeat(80)}`);
- console.log('🔍 今日消息量');
- console.log(`${'─'.repeat(80)}`);
- const todayStart = new Date();
- todayStart.setHours(0, 0, 0, 0);
- const todayMsgQ = new Parse.Query('Message');
- todayMsgQ.greaterThanOrEqualTo('timestamp', todayStart);
- todayMsgQ.containedIn('msgType', [0, 2]);
- todayMsgQ.notEqualTo('content', '');
- const todayMsgCount = await todayMsgQ.count({ useMasterKey: true });
- console.log(` 今日文本/富文本消息: ${todayMsgCount} 条`);
- console.log('\n完成!\n');
- }
- main().catch((err) => {
- console.error('失败:', err.message);
- process.exit(1);
- });
|