@solidstarters/solid-core 1.2.163 → 1.2.166

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/dist/controllers/test-queue.controller.d.ts +1 -1
  2. package/dist/controllers/test-queue.controller.d.ts.map +1 -1
  3. package/dist/controllers/test-queue.controller.js +6 -4
  4. package/dist/controllers/test-queue.controller.js.map +1 -1
  5. package/dist/decorators/error-codes-provider.decorator.d.ts +4 -0
  6. package/dist/decorators/error-codes-provider.decorator.d.ts.map +1 -0
  7. package/dist/decorators/error-codes-provider.decorator.js +12 -0
  8. package/dist/decorators/error-codes-provider.decorator.js.map +1 -0
  9. package/dist/entities/security-rule.entity.js +0 -1
  10. package/dist/entities/security-rule.entity.js.map +1 -1
  11. package/dist/filters/http-exception.filter.d.ts +3 -2
  12. package/dist/filters/http-exception.filter.d.ts.map +1 -1
  13. package/dist/filters/http-exception.filter.js +23 -16
  14. package/dist/filters/http-exception.filter.js.map +1 -1
  15. package/dist/helpers/error-mapper.service.d.ts +12 -2
  16. package/dist/helpers/error-mapper.service.d.ts.map +1 -1
  17. package/dist/helpers/error-mapper.service.js +85 -72
  18. package/dist/helpers/error-mapper.service.js.map +1 -1
  19. package/dist/helpers/solid-core-error-codes-provider.service.d.ts +7 -0
  20. package/dist/helpers/solid-core-error-codes-provider.service.d.ts.map +1 -0
  21. package/dist/helpers/solid-core-error-codes-provider.service.js +67 -0
  22. package/dist/helpers/solid-core-error-codes-provider.service.js.map +1 -0
  23. package/dist/helpers/solid-registry.d.ts +5 -1
  24. package/dist/helpers/solid-registry.d.ts.map +1 -1
  25. package/dist/helpers/solid-registry.js +16 -0
  26. package/dist/helpers/solid-registry.js.map +1 -1
  27. package/dist/index.d.ts +1 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +1 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/interfaces.d.ts +16 -0
  32. package/dist/interfaces.d.ts.map +1 -1
  33. package/dist/interfaces.js.map +1 -1
  34. package/dist/jobs/chatter-queue-options.d.ts +8 -0
  35. package/dist/jobs/chatter-queue-options.d.ts.map +1 -0
  36. package/dist/jobs/chatter-queue-options.js +10 -0
  37. package/dist/jobs/chatter-queue-options.js.map +1 -0
  38. package/dist/jobs/chatter-queue-publisher.service.d.ts +22 -0
  39. package/dist/jobs/chatter-queue-publisher.service.d.ts.map +1 -0
  40. package/dist/jobs/chatter-queue-publisher.service.js +39 -0
  41. package/dist/jobs/chatter-queue-publisher.service.js.map +1 -0
  42. package/dist/jobs/chatter-queue-subscriber.service.d.ts +17 -0
  43. package/dist/jobs/chatter-queue-subscriber.service.d.ts.map +1 -0
  44. package/dist/jobs/chatter-queue-subscriber.service.js +59 -0
  45. package/dist/jobs/chatter-queue-subscriber.service.js.map +1 -0
  46. package/dist/jobs/{database/computed-field-evaluation-publisher.service.d.ts → computed-field-evaluation-publisher.service.d.ts} +2 -2
  47. package/dist/jobs/computed-field-evaluation-publisher.service.d.ts.map +1 -0
  48. package/dist/jobs/{database/computed-field-evaluation-publisher.service.js → computed-field-evaluation-publisher.service.js} +8 -8
  49. package/dist/jobs/computed-field-evaluation-publisher.service.js.map +1 -0
  50. package/dist/jobs/{database/computed-field-evaluation-queue-options.d.ts → computed-field-evaluation-queue-options.d.ts} +1 -1
  51. package/dist/jobs/computed-field-evaluation-queue-options.d.ts.map +1 -0
  52. package/dist/jobs/{database/computed-field-evaluation-queue-options.js → computed-field-evaluation-queue-options.js} +2 -2
  53. package/dist/jobs/computed-field-evaluation-queue-options.js.map +1 -0
  54. package/dist/jobs/{database/computed-field-evaluation-subscriber.service.d.ts → computed-field-evaluation-subscriber.service.d.ts} +3 -3
  55. package/dist/jobs/computed-field-evaluation-subscriber.service.d.ts.map +1 -0
  56. package/dist/jobs/computed-field-evaluation-subscriber.service.js +51 -0
  57. package/dist/jobs/computed-field-evaluation-subscriber.service.js.map +1 -0
  58. package/dist/jobs/database/computed-field-evaluation-publisher-database.service.d.ts +12 -0
  59. package/dist/jobs/database/computed-field-evaluation-publisher-database.service.d.ts.map +1 -0
  60. package/dist/jobs/database/computed-field-evaluation-publisher-database.service.js +39 -0
  61. package/dist/jobs/database/computed-field-evaluation-publisher-database.service.js.map +1 -0
  62. package/dist/jobs/database/computed-field-evaluation-queue-options-database.d.ts +8 -0
  63. package/dist/jobs/database/computed-field-evaluation-queue-options-database.d.ts.map +1 -0
  64. package/dist/jobs/database/computed-field-evaluation-queue-options-database.js +10 -0
  65. package/dist/jobs/database/computed-field-evaluation-queue-options-database.js.map +1 -0
  66. package/dist/jobs/database/computed-field-evaluation-subscriber-database.service.d.ts +18 -0
  67. package/dist/jobs/database/computed-field-evaluation-subscriber-database.service.d.ts.map +1 -0
  68. package/dist/jobs/database/{computed-field-evaluation-subscriber.service.js → computed-field-evaluation-subscriber-database.service.js} +8 -8
  69. package/dist/jobs/database/computed-field-evaluation-subscriber-database.service.js.map +1 -0
  70. package/dist/jobs/database/generate-code-queue-options-database.js +2 -2
  71. package/dist/jobs/database/generate-code-queue-options-database.js.map +1 -1
  72. package/dist/jobs/database/test-queue-subscriber-database.service.d.ts.map +1 -1
  73. package/dist/jobs/database/test-queue-subscriber-database.service.js +7 -1
  74. package/dist/jobs/database/test-queue-subscriber-database.service.js.map +1 -1
  75. package/dist/jobs/generate-code-publisher.service.d.ts +11 -0
  76. package/dist/jobs/generate-code-publisher.service.d.ts.map +1 -0
  77. package/dist/jobs/generate-code-publisher.service.js +39 -0
  78. package/dist/jobs/generate-code-publisher.service.js.map +1 -0
  79. package/dist/jobs/generate-code-queue-options.d.ts +8 -0
  80. package/dist/jobs/generate-code-queue-options.d.ts.map +1 -0
  81. package/dist/jobs/generate-code-queue-options.js +10 -0
  82. package/dist/jobs/generate-code-queue-options.js.map +1 -0
  83. package/dist/jobs/generate-code-subscriber.service.d.ts +18 -0
  84. package/dist/jobs/generate-code-subscriber.service.d.ts.map +1 -0
  85. package/dist/jobs/generate-code-subscriber.service.js +70 -0
  86. package/dist/jobs/generate-code-subscriber.service.js.map +1 -0
  87. package/dist/jobs/test-queue-subscriber.service.d.ts +1 -1
  88. package/dist/jobs/test-queue-subscriber.service.d.ts.map +1 -1
  89. package/dist/jobs/test-queue-subscriber.service.js +9 -6
  90. package/dist/jobs/test-queue-subscriber.service.js.map +1 -1
  91. package/dist/jobs/trigger-mcp-client-publisher.service.d.ts +11 -0
  92. package/dist/jobs/trigger-mcp-client-publisher.service.d.ts.map +1 -0
  93. package/dist/jobs/trigger-mcp-client-publisher.service.js +39 -0
  94. package/dist/jobs/trigger-mcp-client-publisher.service.js.map +1 -0
  95. package/dist/jobs/trigger-mcp-client-queue-options.d.ts +8 -0
  96. package/dist/jobs/trigger-mcp-client-queue-options.d.ts.map +1 -0
  97. package/dist/jobs/trigger-mcp-client-queue-options.js +10 -0
  98. package/dist/jobs/trigger-mcp-client-queue-options.js.map +1 -0
  99. package/dist/jobs/trigger-mcp-client-subscriber.service.d.ts +18 -0
  100. package/dist/jobs/trigger-mcp-client-subscriber.service.d.ts.map +1 -0
  101. package/dist/jobs/trigger-mcp-client-subscriber.service.js +103 -0
  102. package/dist/jobs/trigger-mcp-client-subscriber.service.js.map +1 -0
  103. package/dist/jobs/twilio-sms-publisher.service.d.ts +11 -0
  104. package/dist/jobs/twilio-sms-publisher.service.d.ts.map +1 -0
  105. package/dist/jobs/twilio-sms-publisher.service.js +39 -0
  106. package/dist/jobs/twilio-sms-publisher.service.js.map +1 -0
  107. package/dist/jobs/twilio-sms-queue-options.d.ts +8 -0
  108. package/dist/jobs/twilio-sms-queue-options.d.ts.map +1 -0
  109. package/dist/jobs/twilio-sms-queue-options.js +10 -0
  110. package/dist/jobs/twilio-sms-queue-options.js.map +1 -0
  111. package/dist/jobs/twilio-sms-subscriber.service.d.ts +17 -0
  112. package/dist/jobs/twilio-sms-subscriber.service.d.ts.map +1 -0
  113. package/dist/jobs/twilio-sms-subscriber.service.js +48 -0
  114. package/dist/jobs/twilio-sms-subscriber.service.js.map +1 -0
  115. package/dist/repository/security-rule.repository.js +2 -2
  116. package/dist/repository/security-rule.repository.js.map +1 -1
  117. package/dist/seeders/seed-data/solid-core-metadata.json +2 -2
  118. package/dist/services/authentication.service.js +3 -3
  119. package/dist/services/authentication.service.js.map +1 -1
  120. package/dist/services/queues/database-publisher.service.js +2 -2
  121. package/dist/services/queues/database-publisher.service.js.map +1 -1
  122. package/dist/services/queues/database-subscriber.service.d.ts.map +1 -1
  123. package/dist/services/queues/database-subscriber.service.js +2 -1
  124. package/dist/services/queues/database-subscriber.service.js.map +1 -1
  125. package/dist/services/queues/publisher-factory.service.js +1 -1
  126. package/dist/services/queues/publisher-factory.service.js.map +1 -1
  127. package/dist/services/solid-introspect.service.d.ts +1 -0
  128. package/dist/services/solid-introspect.service.d.ts.map +1 -1
  129. package/dist/services/solid-introspect.service.js +14 -0
  130. package/dist/services/solid-introspect.service.js.map +1 -1
  131. package/dist/solid-core.module.d.ts.map +1 -1
  132. package/dist/solid-core.module.js +23 -4
  133. package/dist/solid-core.module.js.map +1 -1
  134. package/dist/subscribers/audit.subscriber.d.ts +8 -0
  135. package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
  136. package/dist/subscribers/audit.subscriber.js +52 -3
  137. package/dist/subscribers/audit.subscriber.js.map +1 -1
  138. package/dist/subscribers/computed-entity-field.subscriber.d.ts +3 -3
  139. package/dist/subscribers/computed-entity-field.subscriber.d.ts.map +1 -1
  140. package/dist/subscribers/computed-entity-field.subscriber.js +5 -7
  141. package/dist/subscribers/computed-entity-field.subscriber.js.map +1 -1
  142. package/dist/tsconfig.tsbuildinfo +1 -1
  143. package/package.json +1 -1
  144. package/src/controllers/test-queue.controller.ts +4 -3
  145. package/src/decorators/error-codes-provider.decorator.ts +9 -0
  146. package/src/entities/security-rule.entity.ts +1 -1
  147. package/src/filters/http-exception.filter.ts +48 -23
  148. package/src/helpers/error-mapper.service.ts +117 -176
  149. package/src/helpers/solid-core-error-codes-provider.service.ts +63 -0
  150. package/src/helpers/solid-registry.ts +20 -1
  151. package/src/index.ts +1 -0
  152. package/src/interfaces.ts +36 -0
  153. package/src/jobs/chatter-queue-options.ts +9 -0
  154. package/src/jobs/chatter-queue-publisher.service.ts +37 -0
  155. package/src/jobs/chatter-queue-subscriber.service.ts +46 -0
  156. package/src/jobs/computed-field-evaluation-publisher.service.ts +23 -0
  157. package/src/jobs/{database/computed-field-evaluation-queue-options.ts → computed-field-evaluation-queue-options.ts} +2 -2
  158. package/src/jobs/computed-field-evaluation-subscriber.service.ts +38 -0
  159. package/src/jobs/database/{computed-field-evaluation-publisher.service.ts → computed-field-evaluation-publisher-database.service.ts} +2 -2
  160. package/src/jobs/database/computed-field-evaluation-queue-options-database.ts +9 -0
  161. package/src/jobs/database/{computed-field-evaluation-subscriber.service.ts → computed-field-evaluation-subscriber-database.service.ts} +2 -2
  162. package/src/jobs/database/generate-code-queue-options-database.ts +2 -2
  163. package/src/jobs/database/test-queue-subscriber-database.service.ts +10 -2
  164. package/src/jobs/generate-code-publisher.service.ts +23 -0
  165. package/src/jobs/generate-code-queue-options.ts +9 -0
  166. package/src/jobs/generate-code-subscriber.service.ts +59 -0
  167. package/src/jobs/test-queue-subscriber.service.ts +15 -7
  168. package/src/jobs/trigger-mcp-client-publisher.service.ts +22 -0
  169. package/src/jobs/trigger-mcp-client-queue-options.ts +9 -0
  170. package/src/jobs/trigger-mcp-client-subscriber.service.ts +104 -0
  171. package/src/jobs/twilio-sms-publisher.service.ts +23 -0
  172. package/src/jobs/twilio-sms-queue-options.ts +9 -0
  173. package/src/jobs/twilio-sms-subscriber.service.ts +32 -0
  174. package/src/repository/security-rule.repository.ts +2 -2
  175. package/src/seeders/seed-data/solid-core-metadata.json +2 -2
  176. package/src/services/authentication.service.ts +4 -4
  177. package/src/services/queues/database-publisher.service.ts +2 -2
  178. package/src/services/queues/database-subscriber.service.ts +2 -1
  179. package/src/services/queues/publisher-factory.service.ts +1 -1
  180. package/src/services/solid-introspect.service.ts +22 -0
  181. package/src/solid-core.module.ts +35 -8
  182. package/src/subscribers/audit.subscriber.ts +235 -5
  183. package/src/subscribers/computed-entity-field.subscriber.ts +7 -5
  184. package/dist/jobs/database/computed-field-evaluation-publisher.service.d.ts.map +0 -1
  185. package/dist/jobs/database/computed-field-evaluation-publisher.service.js.map +0 -1
  186. package/dist/jobs/database/computed-field-evaluation-queue-options.d.ts.map +0 -1
  187. package/dist/jobs/database/computed-field-evaluation-queue-options.js.map +0 -1
  188. package/dist/jobs/database/computed-field-evaluation-subscriber.service.d.ts.map +0 -1
  189. package/dist/jobs/database/computed-field-evaluation-subscriber.service.js.map +0 -1
@@ -26,8 +26,15 @@ let AuditSubscriber = class AuditSubscriber {
26
26
  this.chatterMessageService = chatterMessageService;
27
27
  this.modelMetadataRepo = modelMetadataRepo;
28
28
  this.modelMetadataHelperService = modelMetadataHelperService;
29
+ this.perTxn = new WeakMap();
29
30
  this.dataSource.subscribers.push(this);
30
31
  }
32
+ enqueue(event, call) {
33
+ const qr = event.queryRunner;
34
+ const arr = this.perTxn.get(qr) ?? [];
35
+ arr.push(call);
36
+ this.perTxn.set(qr, arr);
37
+ }
31
38
  async shouldTrackAudit(entity, metadata) {
32
39
  const model = await this.modelMetadataRepo.findOne({
33
40
  where: {
@@ -55,19 +62,61 @@ let AuditSubscriber = class AuditSubscriber {
55
62
  }
56
63
  async afterInsert(event) {
57
64
  if (await this.shouldTrackAudit(event.entity, event.metadata)) {
58
- await this.chatterMessageService.postAuditMessageOnInsert(event.entity, event.metadata);
65
+ this.enqueue(event, {
66
+ kind: 'insert',
67
+ args: [event.entity, event.metadata],
68
+ });
59
69
  }
60
70
  }
61
71
  async afterUpdate(event) {
62
72
  if (await this.shouldTrackAudit(event.entity, event.metadata)) {
63
- await this.chatterMessageService.postAuditMessageOnUpdate(event.entity, event.metadata, event.databaseEntity, event.updatedColumns || []);
73
+ this.enqueue(event, {
74
+ kind: 'update',
75
+ args: [
76
+ event.entity,
77
+ event.metadata,
78
+ event.databaseEntity,
79
+ event.updatedColumns ?? [],
80
+ ],
81
+ });
64
82
  }
65
83
  }
66
84
  async afterRemove(event) {
67
85
  if (await this.shouldTrackAudit(event.entity, event.metadata)) {
68
- await this.chatterMessageService.postAuditMessageOnDelete(event.entity, event.metadata, event.databaseEntity);
86
+ this.enqueue(event, {
87
+ kind: 'delete',
88
+ args: [
89
+ event.entity,
90
+ event.metadata,
91
+ event.databaseEntity,
92
+ ],
93
+ });
94
+ }
95
+ }
96
+ async afterTransactionCommit(event) {
97
+ const batch = this.perTxn.get(event.queryRunner) ?? [];
98
+ this.perTxn.delete(event.queryRunner);
99
+ for (const item of batch) {
100
+ try {
101
+ switch (item.kind) {
102
+ case 'insert':
103
+ await this.chatterMessageService.postAuditMessageOnInsert(...item.args);
104
+ break;
105
+ case 'update':
106
+ await this.chatterMessageService.postAuditMessageOnUpdate(...item.args);
107
+ break;
108
+ case 'delete':
109
+ await this.chatterMessageService.postAuditMessageOnDelete(...item.args);
110
+ break;
111
+ }
112
+ }
113
+ catch (e) {
114
+ }
69
115
  }
70
116
  }
117
+ afterTransactionRollback(event) {
118
+ this.perTxn.delete(event.queryRunner);
119
+ }
71
120
  };
72
121
  exports.AuditSubscriber = AuditSubscriber;
73
122
  exports.AuditSubscriber = AuditSubscriber = __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"audit.subscriber.js","sourceRoot":"","sources":["../../src/subscribers/audit.subscriber.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@nestjs/common';\nimport { InjectDataSource, InjectRepository } from '@nestjs/typeorm';\nimport { DataSource, EntityMetadata, EntitySubscriberInterface, EventSubscriber, InsertEvent, RemoveEvent, Repository, UpdateEvent } from 'typeorm';\nimport { ModelMetadata } from '../entities/model-metadata.entity';\nimport { ChatterMessageService } from '../services/chatter-message.service';\nimport { lowerFirst } from 'src/helpers/string.helper';\nimport { ModelMetadataHelperService } from 'src/helpers/model-metadata-helper.service';\n\n@Injectable()\n@EventSubscriber()\nexport class AuditSubscriber implements EntitySubscriberInterface {\n\n constructor(\n @InjectDataSource()\n private readonly dataSource: DataSource,\n private readonly chatterMessageService: ChatterMessageService,\n @InjectRepository(ModelMetadata)\n private readonly modelMetadataRepo: Repository<ModelMetadata>,\n private readonly modelMetadataHelperService : ModelMetadataHelperService,\n ) {\n this.dataSource.subscribers.push(this);\n }\n\n private async shouldTrackAudit(entity: any, metadata: EntityMetadata): Promise<boolean> {\n const model = await this.modelMetadataRepo.findOne({\n where: {\n singularName: lowerFirst(metadata.name)\n },\n relations: {\n fields: true,\n module: true\n }\n });\n\n if (!model || !model.enableAuditTracking) {\n return false;\n }\n\n const modelFields = await this.modelMetadataHelperService.loadFieldHierarchy(model.singularName)\n\n const auditFields = modelFields.filter(field =>\n field.enableAuditTracking &&\n !['mediaSingle', 'mediaMultiple', 'computed', 'richText', 'json'].includes(field.type) &&\n !(field.type === 'relation' && field.relationType === 'one-to-many')\n );\n\n if (auditFields.length === 0) {\n return false;\n }\n\n return auditFields.some(field => {\n const fieldValue = entity[field.name];\n return fieldValue !== undefined && fieldValue !== null;\n });\n }\n\n async afterInsert(event: InsertEvent<any>) {\n if (await this.shouldTrackAudit(event.entity, event.metadata)) {\n await this.chatterMessageService.postAuditMessageOnInsert(event.entity, event.metadata);\n }\n }\n\n async afterUpdate(event: UpdateEvent<any>) {\n if (await this.shouldTrackAudit(event.entity, event.metadata)) {\n await this.chatterMessageService.postAuditMessageOnUpdate(event.entity, event.metadata, event.databaseEntity, event.updatedColumns || []);\n }\n }\n\n async afterRemove(event: RemoveEvent<any>) {\n if (await this.shouldTrackAudit(event.entity, event.metadata)) {\n await this.chatterMessageService.postAuditMessageOnDelete(event.entity, event.metadata, event.databaseEntity);\n }\n }\n} "]}
1
+ {"version":3,"file":"audit.subscriber.js","sourceRoot":"","sources":["../../src/subscribers/audit.subscriber.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@nestjs/common';\nimport { InjectDataSource, InjectRepository } from '@nestjs/typeorm';\nimport { DataSource, EntityMetadata, EntitySubscriberInterface, EventSubscriber, InsertEvent, RemoveEvent, Repository, UpdateEvent } from 'typeorm';\nimport { ModelMetadata } from '../entities/model-metadata.entity';\nimport { ChatterMessageService } from '../services/chatter-message.service';\nimport { lowerFirst } from 'src/helpers/string.helper';\nimport { ModelMetadataHelperService } from 'src/helpers/model-metadata-helper.service';\n\n\ntype DeferredCall =\n | { kind: 'insert'; args: Parameters<ChatterMessageService['postAuditMessageOnInsert']> }\n | { kind: 'update'; args: Parameters<ChatterMessageService['postAuditMessageOnUpdate']> }\n | { kind: 'delete'; args: Parameters<ChatterMessageService['postAuditMessageOnDelete']> };\n\n@Injectable()\n@EventSubscriber()\nexport class AuditSubscriber implements EntitySubscriberInterface {\n\n constructor(\n @InjectDataSource()\n private readonly dataSource: DataSource,\n private readonly chatterMessageService: ChatterMessageService,\n @InjectRepository(ModelMetadata)\n private readonly modelMetadataRepo: Repository<ModelMetadata>,\n private readonly modelMetadataHelperService: ModelMetadataHelperService,\n ) {\n this.dataSource.subscribers.push(this);\n }\n\n // Per-transaction buffer (auto-GC when queryRunner is gone)\n private perTxn = new WeakMap<any, DeferredCall[]>();\n\n private enqueue(event: { queryRunner: any }, call: DeferredCall) {\n const qr = event.queryRunner;\n const arr = this.perTxn.get(qr) ?? [];\n arr.push(call);\n this.perTxn.set(qr, arr);\n }\n\n private async shouldTrackAudit(entity: any, metadata: EntityMetadata): Promise<boolean> {\n const model = await this.modelMetadataRepo.findOne({\n where: {\n singularName: lowerFirst(metadata.name)\n },\n relations: {\n fields: true,\n module: true\n }\n });\n\n if (!model || !model.enableAuditTracking) {\n return false;\n }\n\n const modelFields = await this.modelMetadataHelperService.loadFieldHierarchy(model.singularName)\n\n const auditFields = modelFields.filter(field =>\n field.enableAuditTracking &&\n !['mediaSingle', 'mediaMultiple', 'computed', 'richText', 'json'].includes(field.type) &&\n !(field.type === 'relation' && field.relationType === 'one-to-many')\n );\n\n if (auditFields.length === 0) {\n return false;\n }\n\n return auditFields.some(field => {\n const fieldValue = entity[field.name];\n return fieldValue !== undefined && fieldValue !== null;\n });\n }\n\n async afterInsert(event: InsertEvent<any>) {\n if (await this.shouldTrackAudit(event.entity, event.metadata)) {\n // await this.chatterMessageService.postAuditMessageOnInsert(event.entity, event.metadata);\n this.enqueue(event, {\n kind: 'insert',\n args: [event.entity, event.metadata] as Parameters<ChatterMessageService['postAuditMessageOnInsert']>,\n });\n }\n }\n\n async afterUpdate(event: UpdateEvent<any>) {\n if (await this.shouldTrackAudit(event.entity, event.metadata)) {\n // await this.chatterMessageService.postAuditMessageOnUpdate(event.entity, event.metadata, event.databaseEntity, event.updatedColumns || []);\n this.enqueue(event, {\n kind: 'update',\n args: [\n event.entity, // entity (after)\n event.metadata,\n event.databaseEntity, // entity (before)\n event.updatedColumns ?? [],\n ] as Parameters<ChatterMessageService['postAuditMessageOnUpdate']>,\n });\n }\n }\n\n async afterRemove(event: RemoveEvent<any>) {\n if (await this.shouldTrackAudit(event.entity, event.metadata)) {\n // await this.chatterMessageService.postAuditMessageOnDelete(event.entity, event.metadata, event.databaseEntity);\n this.enqueue(event, {\n kind: 'delete',\n args: [\n event.entity,\n event.metadata,\n event.databaseEntity,\n ] as Parameters<ChatterMessageService['postAuditMessageOnDelete']>,\n });\n }\n }\n\n // --------- transaction lifecycle ----------\n async afterTransactionCommit(event: { queryRunner: any }) {\n const batch = this.perTxn.get(event.queryRunner) ?? [];\n this.perTxn.delete(event.queryRunner);\n\n // Now we’re OUTSIDE the DB transaction — safe to do I/O/DB writes inside chatter service.\n for (const item of batch) {\n try {\n switch (item.kind) {\n case 'insert': await this.chatterMessageService.postAuditMessageOnInsert(...item.args); break;\n case 'update': await this.chatterMessageService.postAuditMessageOnUpdate(...item.args); break;\n case 'delete': await this.chatterMessageService.postAuditMessageOnDelete(...item.args); break;\n }\n } catch (e) {\n // Best effort: log and continue; your core txn was already committed\n // Optionally: send to a generic error logger/metric here\n }\n }\n }\n\n afterTransactionRollback(event: { queryRunner: any }) {\n // Drop buffered calls; the write never happened\n this.perTxn.delete(event.queryRunner);\n }\n}\n\n// import { DataSource, EntityMetadata, EntitySubscriberInterface, EventSubscriber, InsertEvent, RemoveEvent, UpdateEvent } from 'typeorm';\n// import { Injectable } from '@nestjs/common';\n// import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';\n// import { Repository } from 'typeorm';\n// import { ModelMetadata } from '../entities/model-metadata.entity';\n// import { lowerFirst } from 'src/helpers/string.helper';\n// import { ModelMetadataHelperService } from 'src/helpers/model-metadata-helper.service';\n// import { ChatterMessagePayload } from 'src/jobs/chatter-queue-publisher.service';\n// import { RequestContextService } from 'src/services/request-context.service';\n// import { PublisherFactory } from 'src/services/queues/publisher-factory.service';\n\n// @EventSubscriber()\n// @Injectable()\n// export class AuditSubscriber implements EntitySubscriberInterface {\n// private perTxn = new WeakMap<any, ChatterMessagePayload[]>();\n\n// constructor(\n// @InjectDataSource() private readonly dataSource: DataSource,\n// @InjectRepository(ModelMetadata) private readonly modelMetadataRepo: Repository<ModelMetadata>,\n// private readonly modelMetadataHelperService: ModelMetadataHelperService,\n// private readonly requestContext: RequestContextService,\n// private readonly publisherFactory: PublisherFactory<any>\n// ) {\n// this.dataSource.subscribers.push(this);\n// }\n\n// // --- small cache to avoid metadata queries on every row ---\n// private modelCache = new Map<string, { enable: boolean; fields: Array<{ name: string; enableAuditTracking: boolean; type: string; relationType?: string }>; ts: number }>();\n// private cacheTTLms = 60_000;\n\n// private async shouldTrackAudit(entity: any, metadata: EntityMetadata): Promise<{ enable: boolean; auditFields?: string[] }> {\n// const key = metadata.name;\n// const now = Date.now();\n// const cached = this.modelCache.get(key);\n// if (cached && (now - cached.ts) < this.cacheTTLms) {\n// if (!cached.enable) return { enable: false };\n// const fields = cached.fields.filter(f =>\n// f.enableAuditTracking &&\n// !['mediaSingle', 'mediaMultiple', 'computed', 'richText', 'json'].includes(f.type) &&\n// !(f.type === 'relation' && f.relationType === 'one-to-many')\n// );\n// const present = fields.map(f => f.name).filter(n => entity?.[n] !== undefined);\n// return { enable: present.length > 0, auditFields: present };\n// }\n\n// const model = await this.modelMetadataRepo.findOne({\n// where: { singularName: lowerFirst(metadata.name) },\n// relations: { fields: true, module: true },\n// });\n// const enable = !!model?.enableAuditTracking;\n// const fields = model?.fields ?? [];\n// this.modelCache.set(key, { enable, fields, ts: now });\n\n// if (!enable) return { enable: false };\n// const filtered = fields.filter(f =>\n// f.enableAuditTracking &&\n// !['mediaSingle', 'mediaMultiple', 'computed', 'richText', 'json'].includes(f.type) &&\n// !(f.type === 'relation' && f.relationType === 'one-to-many')\n// );\n// const present = filtered.map(f => f.name).filter(n => entity?.[n] !== undefined);\n// return { enable: present.length > 0, auditFields: present };\n// }\n\n// private push(event: { queryRunner: any }, msg: ChatterMessagePayload) {\n// const arr = this.perTxn.get(event.queryRunner) ?? [];\n// arr.push(msg);\n// this.perTxn.set(event.queryRunner, arr);\n// }\n\n// async afterInsert(event: InsertEvent<any>) {\n// if (!event.entity) return;\n// const enable = await this.shouldTrackAudit(event.entity, event.metadata);\n// if (!enable) return;\n\n// const payload: ChatterMessagePayload = {\n// eventType: 'insert',\n// model: event.metadata.name,\n// entityId: String(event.entity.id ?? event.entity.uuid ?? ''),\n// occurredAt: new Date().toISOString(),\n// after: this.safeCopy(event.entity),\n// userId: this.getUserId(),\n// };\n// this.push(event, payload);\n// }\n\n// async afterUpdate(event: UpdateEvent<any>) {\n// // Updated entity may be null if you used raw query; fall back to databaseEntity\n// const current = event.entity ?? {};\n// const before = event.databaseEntity ?? {};\n// const { enable, auditFields } = await this.shouldTrackAudit(current, event.metadata);\n// if (!enable) return;\n\n// const changedCols = (event.updatedColumns || []).map(c => c.propertyName);\n// const payload: ChatterMessagePayload = {\n// eventType: 'update',\n// model: event.metadata.name,\n// entityId: String((current as any).id ?? (before as any).id ?? ''),\n// occurredAt: new Date().toISOString(),\n// before: this.pick(before, auditFields || changedCols),\n// after: this.pick(current, auditFields || changedCols),\n// diff: changedCols,\n// userId: this.getUserId(),\n// };\n// this.push(event, payload);\n// }\n\n// async afterRemove(event: RemoveEvent<any>) {\n// const base = event.entity ?? event.databaseEntity;\n// if (!base) return;\n\n// const { enable } = await this.shouldTrackAudit(base, event.metadata);\n// if (!enable) return;\n\n// const payload: ChatterMessagePayload = {\n// eventType: 'delete',\n// model: event.metadata.name,\n// entityId: String((base as any).id ?? ''),\n// occurredAt: new Date().toISOString(),\n// before: this.safeCopy(base),\n// userId: this.getUserId(),\n// };\n// this.push(event, payload);\n// }\n\n// // Publish AFTER the transaction commits -> no idle-in-transaction\n// async afterTransactionCommit(event: { queryRunner: any }) {\n// const batch = this.perTxn.get(event.queryRunner) ?? [];\n// this.perTxn.delete(event.queryRunner);\n// for (const msg of batch) {\n// try {\n// await this.publisherFactory.publish({ payload: msg, parentEntity: msg.model, parentEntityId: msg.entityId }, 'ChatterQueuePublisher');\n// } catch (err) {\n// // log + optionally send to a DLQ or retry queue\n// // do NOT throw; commit already happened\n// // your RabbitMqPublisher likely tracks failures in MqMessage tables anyway\n// }\n// }\n// }\n\n// afterTransactionRollback(event: { queryRunner: any }) {\n// this.perTxn.delete(event.queryRunner);\n// }\n\n// // --- small helpers to keep payloads JSON-safe and small ---\n// private safeCopy(obj: any) {\n// try {\n// return JSON.parse(JSON.stringify(obj));\n// } catch {\n// return {}; // strip circular refs\n// }\n// }\n\n// private pick(obj: any, keys: string[]) {\n// const out: any = {};\n// for (const k of keys) out[k] = obj?.[k];\n// return this.safeCopy(out);\n// }\n\n// private getUserId(): string | null {\n\n// const activeUser = this.requestContext.getActiveUser();\n// if (activeUser?.sub)\n// return String(activeUser.sub);\n// }\n\n\n// }"]}
@@ -1,5 +1,5 @@
1
1
  import { ComputedFieldMetadata, SolidRegistry } from "src/helpers/solid-registry";
2
- import { ComputedFieldEvaluationPublisher } from "src/jobs/database/computed-field-evaluation-publisher.service";
2
+ import { PublisherFactory } from "src/services/queues/publisher-factory.service";
3
3
  import { DataSource, EntitySubscriberInterface, InsertEvent, UpdateEvent } from "typeorm";
4
4
  export interface ComputedFieldEvaluationPayload extends ComputedFieldMetadata {
5
5
  databaseEntity: any;
@@ -7,9 +7,9 @@ export interface ComputedFieldEvaluationPayload extends ComputedFieldMetadata {
7
7
  export declare class ComputedEntityFieldSubscriber implements EntitySubscriberInterface {
8
8
  private readonly dataSource;
9
9
  private readonly solidRegistry;
10
- private readonly computedFieldPublisher;
10
+ private readonly publisherFactory;
11
11
  private readonly logger;
12
- constructor(dataSource: DataSource, solidRegistry: SolidRegistry, computedFieldPublisher: ComputedFieldEvaluationPublisher);
12
+ constructor(dataSource: DataSource, solidRegistry: SolidRegistry, publisherFactory: PublisherFactory<ComputedFieldEvaluationPayload>);
13
13
  beforeInsert(event: InsertEvent<any>): Promise<any>;
14
14
  beforeUpdate(event: UpdateEvent<any>): Promise<any>;
15
15
  afterInsert(event: InsertEvent<any>): void;
@@ -1 +1 @@
1
- {"version":3,"file":"computed-entity-field.subscriber.d.ts","sourceRoot":"","sources":["../../src/subscribers/computed-entity-field.subscriber.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAElF,OAAO,EAAE,gCAAgC,EAAE,MAAM,+DAA+D,CAAC;AACjH,OAAO,EAAE,UAAU,EAAE,yBAAyB,EAAmB,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG3G,MAAM,WAAW,8BAA+B,SAAQ,qBAAqB;IACzE,cAAc,EAAE,GAAG,CAAC;CACvB;AAED,qBAEa,6BAA8B,YAAW,yBAAyB;IAIvE,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IAL3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqC;gBAGvC,UAAU,EAAE,UAAU,EACtB,aAAa,EAAE,aAAa,EAC5B,sBAAsB,EAAE,gCAAgC;IAKvE,YAAY,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAInD,YAAY,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAIzD,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC;IAInC,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC;IAInC,WAAW,CAAC,KAAK,EAAE,GAAG;YAMR,6BAA6B;IAe3C,OAAO,CAAC,gCAAgC;IAiBxC,OAAO,CAAC,8BAA8B;YASxB,qBAAqB;YAOrB,eAAe;IAY7B,OAAO,CAAC,iCAAiC;CAU5C"}
1
+ {"version":3,"file":"computed-entity-field.subscriber.d.ts","sourceRoot":"","sources":["../../src/subscribers/computed-entity-field.subscriber.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAElF,OAAO,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,yBAAyB,EAAmB,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG3G,MAAM,WAAW,8BAA+B,SAAQ,qBAAqB;IACzE,cAAc,EAAE,GAAG,CAAC;CACvB;AAED,qBAEa,6BAA8B,YAAW,yBAAyB;IAIvE,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IALrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqC;gBAGvC,UAAU,EAAE,UAAU,EACtB,aAAa,EAAE,aAAa,EAC5B,gBAAgB,EAAE,gBAAgB,CAAC,8BAA8B,CAAC;IAMjF,YAAY,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAInD,YAAY,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAIzD,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC;IAInC,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC;IAInC,WAAW,CAAC,KAAK,EAAE,GAAG;YAMR,6BAA6B;IAe3C,OAAO,CAAC,gCAAgC;IAiBxC,OAAO,CAAC,8BAA8B;YASxB,qBAAqB;YAOrB,eAAe;IAY7B,OAAO,CAAC,iCAAiC;CAW5C"}
@@ -18,13 +18,13 @@ const common_1 = require("@nestjs/common");
18
18
  const typeorm_1 = require("@nestjs/typeorm");
19
19
  const create_field_metadata_dto_1 = require("../dtos/create-field-metadata.dto");
20
20
  const solid_registry_1 = require("../helpers/solid-registry");
21
- const computed_field_evaluation_publisher_service_1 = require("../jobs/database/computed-field-evaluation-publisher.service");
21
+ const publisher_factory_service_1 = require("../services/queues/publisher-factory.service");
22
22
  const typeorm_2 = require("typeorm");
23
23
  let ComputedEntityFieldSubscriber = class ComputedEntityFieldSubscriber {
24
- constructor(dataSource, solidRegistry, computedFieldPublisher) {
24
+ constructor(dataSource, solidRegistry, publisherFactory) {
25
25
  this.dataSource = dataSource;
26
26
  this.solidRegistry = solidRegistry;
27
- this.computedFieldPublisher = computedFieldPublisher;
27
+ this.publisherFactory = publisherFactory;
28
28
  this.logger = new common_1.Logger(this.constructor.name);
29
29
  this.dataSource.subscribers.push(this);
30
30
  }
@@ -85,9 +85,7 @@ let ComputedEntityFieldSubscriber = class ComputedEntityFieldSubscriber {
85
85
  ...computedField,
86
86
  databaseEntity,
87
87
  };
88
- this.computedFieldPublisher.publish({
89
- payload
90
- });
88
+ this.publisherFactory.publish({ payload }, 'ComputedFieldEvaluationPublisher');
91
89
  }
92
90
  };
93
91
  exports.ComputedEntityFieldSubscriber = ComputedEntityFieldSubscriber;
@@ -97,6 +95,6 @@ exports.ComputedEntityFieldSubscriber = ComputedEntityFieldSubscriber = __decora
97
95
  __param(0, (0, typeorm_1.InjectDataSource)()),
98
96
  __metadata("design:paramtypes", [typeorm_2.DataSource,
99
97
  solid_registry_1.SolidRegistry,
100
- computed_field_evaluation_publisher_service_1.ComputedFieldEvaluationPublisher])
98
+ publisher_factory_service_1.PublisherFactory])
101
99
  ], ComputedEntityFieldSubscriber);
102
100
  //# sourceMappingURL=computed-entity-field.subscriber.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"computed-entity-field.subscriber.js","sourceRoot":"","sources":["../../src/subscribers/computed-entity-field.subscriber.ts"],"names":[],"mappings":"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","sourcesContent":["import { camelize } from \"@angular-devkit/core/src/utils/strings\";\nimport { Injectable, InternalServerErrorException, Logger } from \"@nestjs/common\";\nimport { InjectDataSource } from \"@nestjs/typeorm\";\nimport { ComputedFieldTriggerOperation } from \"src/dtos/create-field-metadata.dto\";\nimport { ComputedFieldMetadata, SolidRegistry } from \"src/helpers/solid-registry\";\nimport { IEntityPreComputeFieldProvider } from \"src/interfaces\";\nimport { ComputedFieldEvaluationPublisher } from \"src/jobs/database/computed-field-evaluation-publisher.service\";\nimport { DataSource, EntitySubscriberInterface, EventSubscriber, InsertEvent, UpdateEvent } from \"typeorm\";\n\n// Create an interface i.e ComputedFieldEvaluationPayload which has same fields as the ComputedFieldMetadata and an additional field for the database entity\nexport interface ComputedFieldEvaluationPayload extends ComputedFieldMetadata {\n databaseEntity: any;\n}\n\n@Injectable()\n@EventSubscriber()\nexport class ComputedEntityFieldSubscriber implements EntitySubscriberInterface {\n private readonly logger = new Logger(this.constructor.name);\n constructor(\n @InjectDataSource()\n private readonly dataSource: DataSource,\n private readonly solidRegistry: SolidRegistry,\n private readonly computedFieldPublisher: ComputedFieldEvaluationPublisher,\n ) {\n this.dataSource.subscribers.push(this);\n }\n\n async beforeInsert(event: InsertEvent<any>): Promise<any> {\n await this.handleComputedFieldEvaluation(event.entity, ComputedFieldTriggerOperation.beforeInsert);\n }\n\n async beforeUpdate(event: UpdateEvent<any>): Promise<any> {\n await this.handleComputedFieldEvaluation(event.databaseEntity, ComputedFieldTriggerOperation.beforeUpdate);\n }\n\n afterInsert(event: InsertEvent<any>) {\n this.handleComputedFieldEvaluationJob(event.entity, ComputedFieldTriggerOperation.afterInsert);\n }\n\n afterUpdate(event: UpdateEvent<any>) {\n this.handleComputedFieldEvaluationJob(event.databaseEntity, ComputedFieldTriggerOperation.afterUpdate);\n }\n\n afterRemove(event: any) {\n this.handleComputedFieldEvaluationJob(event.databaseEntity, ComputedFieldTriggerOperation.afterRemove);\n }\n\n //FIXME: Need to add support for beforeRemove, beforeSoftRemove, afterSoftRemove, beforeRecover, afterRecover\n\n private async handleComputedFieldEvaluation(entity: any, currentOperation: ComputedFieldTriggerOperation): Promise<void> {\n if (!entity) {\n return;\n }\n const computedFieldsTobeEvaluated = this.getComputedFieldsForEvaluation(\n this.solidRegistry.getComputedFieldMetadata(),\n currentOperation,\n camelize(entity.constructor.name)\n );\n //TODO: We can add a feature i.e dependsOn, where we can check if the computed field depends on other computed fields and evaluate them first\n await Promise.all(\n computedFieldsTobeEvaluated.map(c => this.evaluateComputedField(c, entity))\n )\n }\n\n private handleComputedFieldEvaluationJob(entity: any, currentOperation: ComputedFieldTriggerOperation) {\n if (!entity) {\n return;\n }\n const computedFieldsTobeEvaluated = this.getComputedFieldsForEvaluation(\n this.solidRegistry.getComputedFieldMetadata(),\n currentOperation,\n camelize(entity.constructor.name)\n );\n //TODO: We can add a feature i.e dependsOn, where we can check if the computed field depends on other computed fields and evaluate them first\n for (const computedField of computedFieldsTobeEvaluated) {\n this.enqueueComputedFieldEvaluationJob(computedField, entity);\n }\n }\n\n // Based on the current model name and current operation, identify all the computed providers that need to be evaluated\n // Pass the database entity and the context to the provider of type IEntityComputedFieldProvider\n private getComputedFieldsForEvaluation(computedFieldMetadata: ComputedFieldMetadata[] = [], currentOperation: ComputedFieldTriggerOperation, currentModelName: string) {\n return computedFieldMetadata.filter(\n (computedField) => computedField.computedFieldTriggerConfig.some(\n (trigger) => trigger.operations.includes(currentOperation) &&\n trigger.modelName === currentModelName\n )\n );\n }\n\n private async evaluateComputedField(computedFieldMetadata: ComputedFieldMetadata<any>, entity: any) {\n const computedValue = await this.preComputeValue(computedFieldMetadata, entity);\n if (computedValue) {\n entity[computedFieldMetadata.fieldName] = computedValue; //TODO: This line here is just for backward compatibility, once the pre compute interface is change to return void, we will get rid of it.\n }\n }\n\n private async preComputeValue(computedFieldMetadata: ComputedFieldMetadata<any>, entity: any) {\n try {\n const provider = this.solidRegistry.getComputedFieldProvider(computedFieldMetadata.computedFieldValueProviderName);\n // Get the instance of the provider and assert it is of type IEntityComputedFieldProvider\n const providerInstance = provider.instance as IEntityPreComputeFieldProvider<any, any, any>; // IEntityComputedFieldProvider\n const computedValue = await providerInstance.preComputeValue(entity, computedFieldMetadata); //FIXME There should some way to check/assert if the provider actually has a postComputeAndSaveValue\n return computedValue; //TODO: This line here is just for backward compatibility, once the pre compute interface is change to return void, we will get rid of it.\n } catch (error) {\n throw new InternalServerErrorException(`Error evaluating computed field ${computedFieldMetadata.fieldName} for model ${computedFieldMetadata.modelName} for triggered entity ${entity.constructor.name}: ${error.message}`);\n }\n }\n\n private enqueueComputedFieldEvaluationJob(computedField: ComputedFieldMetadata<any>, databaseEntity: any) {\n const payload = {\n ...computedField,\n databaseEntity,\n };\n this.computedFieldPublisher.publish({\n payload\n });\n }\n\n}"]}
1
+ {"version":3,"file":"computed-entity-field.subscriber.js","sourceRoot":"","sources":["../../src/subscribers/computed-entity-field.subscriber.ts"],"names":[],"mappings":"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","sourcesContent":["import { camelize } from \"@angular-devkit/core/src/utils/strings\";\nimport { Injectable, InternalServerErrorException, Logger } from \"@nestjs/common\";\nimport { InjectDataSource } from \"@nestjs/typeorm\";\nimport { ComputedFieldTriggerOperation } from \"src/dtos/create-field-metadata.dto\";\nimport { ComputedFieldMetadata, SolidRegistry } from \"src/helpers/solid-registry\";\nimport { IEntityPreComputeFieldProvider } from \"src/interfaces\";\nimport { PublisherFactory } from \"src/services/queues/publisher-factory.service\";\nimport { DataSource, EntitySubscriberInterface, EventSubscriber, InsertEvent, UpdateEvent } from \"typeorm\";\n\n// Create an interface i.e ComputedFieldEvaluationPayload which has same fields as the ComputedFieldMetadata and an additional field for the database entity\nexport interface ComputedFieldEvaluationPayload extends ComputedFieldMetadata {\n databaseEntity: any;\n}\n\n@Injectable()\n@EventSubscriber()\nexport class ComputedEntityFieldSubscriber implements EntitySubscriberInterface {\n private readonly logger = new Logger(this.constructor.name);\n constructor(\n @InjectDataSource()\n private readonly dataSource: DataSource,\n private readonly solidRegistry: SolidRegistry,\n private readonly publisherFactory: PublisherFactory<ComputedFieldEvaluationPayload>\n // private readonly computedFieldPublisher: ComputedFieldEvaluationPublisherDatabase,\n ) {\n this.dataSource.subscribers.push(this);\n }\n\n async beforeInsert(event: InsertEvent<any>): Promise<any> {\n await this.handleComputedFieldEvaluation(event.entity, ComputedFieldTriggerOperation.beforeInsert);\n }\n\n async beforeUpdate(event: UpdateEvent<any>): Promise<any> {\n await this.handleComputedFieldEvaluation(event.databaseEntity, ComputedFieldTriggerOperation.beforeUpdate);\n }\n\n afterInsert(event: InsertEvent<any>) {\n this.handleComputedFieldEvaluationJob(event.entity, ComputedFieldTriggerOperation.afterInsert);\n }\n\n afterUpdate(event: UpdateEvent<any>) {\n this.handleComputedFieldEvaluationJob(event.databaseEntity, ComputedFieldTriggerOperation.afterUpdate);\n }\n\n afterRemove(event: any) {\n this.handleComputedFieldEvaluationJob(event.databaseEntity, ComputedFieldTriggerOperation.afterRemove);\n }\n\n //FIXME: Need to add support for beforeRemove, beforeSoftRemove, afterSoftRemove, beforeRecover, afterRecover\n\n private async handleComputedFieldEvaluation(entity: any, currentOperation: ComputedFieldTriggerOperation): Promise<void> {\n if (!entity) {\n return;\n }\n const computedFieldsTobeEvaluated = this.getComputedFieldsForEvaluation(\n this.solidRegistry.getComputedFieldMetadata(),\n currentOperation,\n camelize(entity.constructor.name)\n );\n //TODO: We can add a feature i.e dependsOn, where we can check if the computed field depends on other computed fields and evaluate them first\n await Promise.all(\n computedFieldsTobeEvaluated.map(c => this.evaluateComputedField(c, entity))\n )\n }\n\n private handleComputedFieldEvaluationJob(entity: any, currentOperation: ComputedFieldTriggerOperation) {\n if (!entity) {\n return;\n }\n const computedFieldsTobeEvaluated = this.getComputedFieldsForEvaluation(\n this.solidRegistry.getComputedFieldMetadata(),\n currentOperation,\n camelize(entity.constructor.name)\n );\n //TODO: We can add a feature i.e dependsOn, where we can check if the computed field depends on other computed fields and evaluate them first\n for (const computedField of computedFieldsTobeEvaluated) {\n this.enqueueComputedFieldEvaluationJob(computedField, entity);\n }\n }\n\n // Based on the current model name and current operation, identify all the computed providers that need to be evaluated\n // Pass the database entity and the context to the provider of type IEntityComputedFieldProvider\n private getComputedFieldsForEvaluation(computedFieldMetadata: ComputedFieldMetadata[] = [], currentOperation: ComputedFieldTriggerOperation, currentModelName: string) {\n return computedFieldMetadata.filter(\n (computedField) => computedField.computedFieldTriggerConfig.some(\n (trigger) => trigger.operations.includes(currentOperation) &&\n trigger.modelName === currentModelName\n )\n );\n }\n\n private async evaluateComputedField(computedFieldMetadata: ComputedFieldMetadata<any>, entity: any) {\n const computedValue = await this.preComputeValue(computedFieldMetadata, entity);\n if (computedValue) {\n entity[computedFieldMetadata.fieldName] = computedValue; //TODO: This line here is just for backward compatibility, once the pre compute interface is change to return void, we will get rid of it.\n }\n }\n\n private async preComputeValue(computedFieldMetadata: ComputedFieldMetadata<any>, entity: any) {\n try {\n const provider = this.solidRegistry.getComputedFieldProvider(computedFieldMetadata.computedFieldValueProviderName);\n // Get the instance of the provider and assert it is of type IEntityComputedFieldProvider\n const providerInstance = provider.instance as IEntityPreComputeFieldProvider<any, any, any>; // IEntityComputedFieldProvider\n const computedValue = await providerInstance.preComputeValue(entity, computedFieldMetadata); //FIXME There should some way to check/assert if the provider actually has a postComputeAndSaveValue\n return computedValue; //TODO: This line here is just for backward compatibility, once the pre compute interface is change to return void, we will get rid of it.\n } catch (error) {\n throw new InternalServerErrorException(`Error evaluating computed field ${computedFieldMetadata.fieldName} for model ${computedFieldMetadata.modelName} for triggered entity ${entity.constructor.name}: ${error.message}`);\n }\n }\n\n private enqueueComputedFieldEvaluationJob(computedField: ComputedFieldMetadata<any>, databaseEntity: any) {\n const payload = {\n ...computedField,\n databaseEntity,\n };\n this.publisherFactory.publish({payload}, 'ComputedFieldEvaluationPublisher')\n // this.computedFieldPublisher.publish({\n // payload\n // });\n }\n\n}"]}