dump-qiwe-schema.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /**
  2. * 导出 QiWe 项目相关的所有表 Schema(供文档编写用)
  3. *
  4. * 用法: cd backend && npx tsx scripts/dump-qiwe-schema.ts
  5. */
  6. import 'dotenv/config';
  7. import Parse from '../src/db/parse-client.js';
  8. async function showTable(className: string): Promise<void> {
  9. const q = new Parse.Query(className);
  10. q.limit(1);
  11. q.descending('updatedAt');
  12. let rows: Parse.Object[] = [];
  13. try { rows = await q.find({ useMasterKey: true }); } catch { /* skip */ }
  14. let schema: Parse.Schema;
  15. try {
  16. schema = await new Parse.Schema(className).get({ useMasterKey: true });
  17. } catch (err: any) {
  18. console.log(`\n📦 ${className} — 表不存在 (${err.message})`);
  19. return;
  20. }
  21. const fields = schema.fields as Record<string, { type: string; targetClass?: string }>;
  22. const entries = Object.entries(fields)
  23. .filter(([n]) => !n.startsWith('_') && n !== 'ACL')
  24. .sort(([a], [b]) => a.localeCompare(b));
  25. const hasData = rows.length > 0;
  26. console.log(`\n📦 ${className}${hasData ? ' (有数据)' : ' (空)'}`);
  27. console.log('-'.repeat(65));
  28. for (const [name, def] of entries) {
  29. const typeStr = def.type === 'Pointer' ? `Pointer → ${def.targetClass || '?'}` : def.type;
  30. console.log(` ${name.padEnd(30)} ${typeStr}`);
  31. }
  32. if (hasData) {
  33. console.log('\n 示例字段值:');
  34. const r = rows[0] as any;
  35. for (const [name] of entries.slice(0, 12)) {
  36. const v = r.get(name);
  37. if (v === undefined || v === null || v === '') continue;
  38. let s: string;
  39. if (typeof v === 'object') {
  40. if (v.className) {
  41. s = `Pointer(${v.className}:${v.id?.slice(0, 8)}...)`;
  42. } else {
  43. s = JSON.stringify(v).substring(0, 100);
  44. }
  45. } else {
  46. s = String(v).substring(0, 100);
  47. }
  48. console.log(` ${name.padEnd(28)} ${s}`);
  49. }
  50. }
  51. }
  52. async function main(): Promise<void> {
  53. console.log('=== QiWe 项目数据库 Schema 完整导出 ===');
  54. console.log(`Server: ${Parse.serverURL}`);
  55. console.log(`App ID: ${Parse.applicationId}\n`);
  56. // 测试连接
  57. try {
  58. const n = await new Parse.Query('_User').count({ useMasterKey: true });
  59. console.log(`✅ Parse 连接正常 (_User: ${n} 条)\n`);
  60. } catch (err: any) {
  61. console.error('❌ Parse 连接失败:', err.message);
  62. process.exit(1);
  63. }
  64. // QiWe 核心表
  65. const qiweTables = [
  66. 'GroupChat', 'GroupMember', 'Message', 'MessageSyncCursor',
  67. 'WebhookLog', 'Contact',
  68. ];
  69. // 风控相关表
  70. const riskTables = [
  71. 'RiskEvent', 'RiskKeyword', 'AppNotification', 'ResponsibilityAssignment',
  72. ];
  73. // 组织结构表
  74. const orgTables = [
  75. 'Store', 'District', 'Community',
  76. ];
  77. // 其他
  78. const otherTables = [
  79. '_User', 'QiWeAccount',
  80. ];
  81. console.log('══════ QiWe 核心表 ══════');
  82. for (const t of qiweTables) await showTable(t);
  83. console.log('\n══════ 风控系统表 ══════');
  84. for (const t of riskTables) await showTable(t);
  85. console.log('\n══════ 组织结构表 ══════');
  86. for (const t of orgTables) await showTable(t);
  87. console.log('\n══════ 其他 ══════');
  88. for (const t of otherTables) await showTable(t);
  89. console.log('\n\n✅ 导出完成!\n');
  90. }
  91. main().catch((err) => {
  92. console.error('失败:', err.message);
  93. process.exit(1);
  94. });