list-schemas.ts 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. /**
  2. * 列出 Parse Server 所有表及其字段
  3. *
  4. * 用法: cd backend && npx tsx scripts/list-schemas.ts
  5. */
  6. import 'dotenv/config';
  7. import Parse from '../src/db/parse-client.js';
  8. interface FieldDef {
  9. type: string;
  10. targetClass?: string;
  11. }
  12. async function main(): Promise<void> {
  13. console.log('=== Parse Server 数据库 Schema 一览 ===\n');
  14. console.log(`Server: ${Parse.serverURL}`);
  15. console.log(`App ID: ${Parse.applicationId}\n`);
  16. // 测试连接
  17. try {
  18. await new Parse.Query('_User').limit(1).find({ useMasterKey: true });
  19. console.log('✅ Parse 连接正常\n');
  20. } catch (err: any) {
  21. console.error('❌ Parse 连接失败:', err.message);
  22. process.exit(1);
  23. }
  24. // 获取所有 schema
  25. const schemas = await Parse.Schema.all({ useMasterKey: true });
  26. console.log(`共 ${schemas.length} 个表:\n`);
  27. console.log('-'.repeat(90));
  28. for (const schema of schemas) {
  29. const className = schema.className;
  30. const fields = schema.fields as Record<string, FieldDef>;
  31. // 跳过内部系统表
  32. if (className.startsWith('_') && className !== '_User') {
  33. continue;
  34. }
  35. console.log(`\n📦 ${className}`);
  36. console.log(` 字段数: ${Object.keys(fields).length}`);
  37. const entries = Object.entries(fields)
  38. .filter(([name]) => !name.startsWith('_'))
  39. .sort(([a], [b]) => a.localeCompare(b));
  40. const stringFields: string[] = [];
  41. const numberFields: string[] = [];
  42. const pointerFields: string[] = [];
  43. const arrayFields: string[] = [];
  44. const dateFields: string[] = [];
  45. const booleanFields: string[] = [];
  46. const otherFields: string[] = [];
  47. for (const [name, def] of entries) {
  48. const type = def.type;
  49. if (type === 'String') {
  50. stringFields.push(name);
  51. } else if (type === 'Number') {
  52. numberFields.push(name);
  53. } else if (type === 'Pointer') {
  54. const target = def.targetClass ? ` → ${def.targetClass}` : '';
  55. pointerFields.push(`${name}${target}`);
  56. } else if (type === 'Array') {
  57. arrayFields.push(name);
  58. } else if (type === 'Date') {
  59. dateFields.push(name);
  60. } else if (type === 'Boolean') {
  61. booleanFields.push(name);
  62. } else {
  63. otherFields.push(`${name}(${type})`);
  64. }
  65. }
  66. if (stringFields.length) console.log(` String: ${stringFields.join(', ')}`);
  67. if (numberFields.length) console.log(` Number: ${numberFields.join(', ')}`);
  68. if (pointerFields.length) console.log(` Pointer: ${pointerFields.join(', ')}`);
  69. if (arrayFields.length) console.log(` Array: ${arrayFields.join(', ')}`);
  70. if (dateFields.length) console.log(` Date: ${dateFields.join(', ')}`);
  71. if (booleanFields.length) console.log(` Boolean: ${booleanFields.join(', ')}`);
  72. if (otherFields.length) console.log(` Other: ${otherFields.join(', ')}`);
  73. }
  74. console.log('\n' + '-'.repeat(90));
  75. console.log('\n完成!');
  76. }
  77. main().catch((err) => {
  78. console.error('失败:', err.message);
  79. process.exit(1);
  80. });