schema-setup.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import Parse from './parse-client.js';
  2. import { checkParseDatabase } from './parse-health.service.js';
  3. function isSchemaExistsError(msg: string): boolean {
  4. return (
  5. msg.includes('already exists')
  6. || msg.includes('Class already exists')
  7. || msg.includes('exists, cannot update')
  8. || msg.includes('Field already exists')
  9. );
  10. }
  11. async function ensureClassFields(
  12. className: string,
  13. fields: Record<string, 'String' | 'Number' | 'Date' | 'Array' | 'Boolean'>,
  14. ): Promise<void> {
  15. let added = 0;
  16. for (const [name, type] of Object.entries(fields)) {
  17. try {
  18. const schema = new Parse.Schema(className);
  19. schema.addField(name, type);
  20. await schema.update({ useMasterKey: true });
  21. added++;
  22. } catch (err: unknown) {
  23. const msg = err instanceof Error ? err.message : String(err);
  24. if (!isSchemaExistsError(msg)) {
  25. try {
  26. const schema = new Parse.Schema(className);
  27. schema.addField(name, type);
  28. await schema.save({ useMasterKey: true });
  29. added++;
  30. } catch (saveErr: unknown) {
  31. const saveMsg = saveErr instanceof Error ? saveErr.message : String(saveErr);
  32. if (!isSchemaExistsError(saveMsg)) {
  33. console.warn(`[Schema] ${className}.${name}:`, saveMsg);
  34. }
  35. }
  36. }
  37. }
  38. }
  39. console.log(`[Schema] ${className} — fields ensured (${Object.keys(fields).length} total, ${added} applied)`);
  40. }
  41. export async function ensureSchemas(): Promise<void> {
  42. const parseStatus = await checkParseDatabase();
  43. if (!parseStatus.connected) {
  44. console.warn('[Schema] Parse 不可用,跳过 Schema 检查:', parseStatus.error);
  45. return;
  46. }
  47. await ensureClassFields('GroupChat', {
  48. roomId: 'String',
  49. roomName: 'String',
  50. ownerId: 'String',
  51. ownerName: 'String',
  52. ownerRole: 'String',
  53. memberCount: 'Number',
  54. avatarUrl: 'String',
  55. status: 'String',
  56. guid: 'String',
  57. storeId: 'String',
  58. storeName: 'String',
  59. communityId: 'String',
  60. communityName: 'String',
  61. activityLevel: 'String',
  62. healthScore: 'Number',
  63. healthStatus: 'String',
  64. hasDocument: 'Boolean',
  65. documentPinned: 'Boolean',
  66. documentInNotice: 'Boolean',
  67. messageCountToday: 'Number',
  68. messageCountTotal: 'Number',
  69. memberChange24h: 'Number',
  70. lifecyclePhase: 'String',
  71. healthGrade: 'String',
  72. opsActivityScore: 'Number',
  73. customerActivityScore: 'Number',
  74. });
  75. await ensureClassFields('Store', {
  76. code: 'String',
  77. name: 'String',
  78. region: 'String',
  79. status: 'String',
  80. });
  81. await ensureClassFields('Community', {
  82. name: 'String',
  83. storeId: 'String',
  84. storeName: 'String',
  85. address: 'String',
  86. status: 'String',
  87. deliveryDate: 'String',
  88. lifecyclePhase: 'String',
  89. totalHouseholds: 'Number',
  90. avgPrice: 'Number',
  91. groupCount: 'Number',
  92. });
  93. await ensureClassFields('GroupMember', {
  94. roomId: 'String',
  95. userId: 'String',
  96. nickname: 'String',
  97. status: 'String',
  98. joinedAt: 'Date',
  99. leftAt: 'Date',
  100. guid: 'String',
  101. });
  102. await ensureClassFields('Message', {
  103. msgUniqueIdentifier: 'String',
  104. roomId: 'String',
  105. senderId: 'String',
  106. senderName: 'String',
  107. receiverId: 'String',
  108. content: 'String',
  109. atList: 'Array',
  110. msgType: 'Number',
  111. isGroupChat: 'Number',
  112. timestamp: 'Date',
  113. guid: 'String',
  114. seq: 'Number',
  115. });
  116. await ensureClassFields('_User', {
  117. phone: 'String',
  118. appSource: 'String',
  119. name: 'String',
  120. email: 'String',
  121. role: 'String',
  122. storeId: 'String',
  123. storeName: 'String',
  124. wecomUserId: 'String',
  125. regionCode: 'String',
  126. department: 'String',
  127. position: 'String',
  128. });
  129. await ensureClassFields('OrgDepartment', {
  130. partyId: 'String',
  131. name: 'String',
  132. parentPartyId: 'String',
  133. regionCode: 'String',
  134. storeId: 'String',
  135. orderIndex: 'Number',
  136. syncedAt: 'Date',
  137. });
  138. await ensureClassFields('OrgMember', {
  139. userId: 'String',
  140. name: 'String',
  141. partyIds: 'Array',
  142. mobile: 'String',
  143. position: 'String',
  144. syncedAt: 'Date',
  145. });
  146. await ensureClassFields('SystemMigration', {
  147. key: 'String',
  148. completedAt: 'Date',
  149. valueNumber: 'Number',
  150. });
  151. }