@solidxai/core 0.1.11-beta.8 → 0.1.11-beta.9

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 (60) hide show
  1. package/dist/helpers/environment.helper.d.ts +1 -0
  2. package/dist/helpers/environment.helper.d.ts.map +1 -1
  3. package/dist/helpers/environment.helper.js +4 -0
  4. package/dist/helpers/environment.helper.js.map +1 -1
  5. package/dist/helpers/model-metadata-helper.service.d.ts +2 -1
  6. package/dist/helpers/model-metadata-helper.service.d.ts.map +1 -1
  7. package/dist/helpers/model-metadata-helper.service.js +6 -2
  8. package/dist/helpers/model-metadata-helper.service.js.map +1 -1
  9. package/dist/helpers/typeorm-db-helper.d.ts +1 -0
  10. package/dist/helpers/typeorm-db-helper.d.ts.map +1 -1
  11. package/dist/helpers/typeorm-db-helper.js +12 -0
  12. package/dist/helpers/typeorm-db-helper.js.map +1 -1
  13. package/dist/repository/scheduled-job.repository.d.ts +2 -2
  14. package/dist/repository/scheduled-job.repository.d.ts.map +1 -1
  15. package/dist/repository/scheduled-job.repository.js +6 -3
  16. package/dist/repository/scheduled-job.repository.js.map +1 -1
  17. package/dist/repository/security-rule.repository.d.ts +2 -2
  18. package/dist/repository/security-rule.repository.d.ts.map +1 -1
  19. package/dist/repository/security-rule.repository.js +6 -3
  20. package/dist/repository/security-rule.repository.js.map +1 -1
  21. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.d.ts.map +1 -1
  22. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js +2 -1
  23. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js.map +1 -1
  24. package/dist/services/crud-helper.service.d.ts.map +1 -1
  25. package/dist/services/crud-helper.service.js +25 -12
  26. package/dist/services/crud-helper.service.js.map +1 -1
  27. package/dist/services/model-metadata.service.d.ts.map +1 -1
  28. package/dist/services/model-metadata.service.js +2 -1
  29. package/dist/services/model-metadata.service.js.map +1 -1
  30. package/dist/services/module-metadata.service.d.ts.map +1 -1
  31. package/dist/services/module-metadata.service.js +2 -1
  32. package/dist/services/module-metadata.service.js.map +1 -1
  33. package/dist/subscribers/audit.subscriber.d.ts +0 -1
  34. package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
  35. package/dist/subscribers/audit.subscriber.js +5 -8
  36. package/dist/subscribers/audit.subscriber.js.map +1 -1
  37. package/dist/subscribers/computed-entity-field.subscriber.d.ts +9 -1
  38. package/dist/subscribers/computed-entity-field.subscriber.d.ts.map +1 -1
  39. package/dist/subscribers/computed-entity-field.subscriber.js +43 -12
  40. package/dist/subscribers/computed-entity-field.subscriber.js.map +1 -1
  41. package/dist/subscribers/scheduled-job.subscriber.d.ts.map +1 -1
  42. package/dist/subscribers/scheduled-job.subscriber.js +3 -2
  43. package/dist/subscribers/scheduled-job.subscriber.js.map +1 -1
  44. package/dist/subscribers/security-rule.subscriber.d.ts.map +1 -1
  45. package/dist/subscribers/security-rule.subscriber.js +5 -3
  46. package/dist/subscribers/security-rule.subscriber.js.map +1 -1
  47. package/package.json +1 -1
  48. package/src/helpers/environment.helper.ts +11 -0
  49. package/src/helpers/model-metadata-helper.service.ts +7 -2
  50. package/src/helpers/typeorm-db-helper.ts +15 -0
  51. package/src/repository/scheduled-job.repository.ts +10 -4
  52. package/src/repository/security-rule.repository.ts +10 -4
  53. package/src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts +5 -4
  54. package/src/services/crud-helper.service.ts +25 -12
  55. package/src/services/model-metadata.service.ts +2 -1
  56. package/src/services/module-metadata.service.ts +2 -1
  57. package/src/subscribers/audit.subscriber.ts +7 -9
  58. package/src/subscribers/computed-entity-field.subscriber.ts +79 -28
  59. package/src/subscribers/scheduled-job.subscriber.ts +3 -2
  60. package/src/subscribers/security-rule.subscriber.ts +8 -3
@@ -1 +1 @@
1
- {"version":3,"file":"scheduled-job.subscriber.d.ts","sourceRoot":"","sources":["../../src/subscribers/scheduled-job.subscriber.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AACzF,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EACL,UAAU,EAEV,yBAAyB,EACzB,WAAW,EACX,WAAW,EACX,WAAW,EACZ,MAAM,SAAS,CAAC;AAEjB,qBACa,sBACX,YAAW,yBAAyB,CAAC,YAAY,CAAC;IAW5B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC/C,OAAO,CAAC,QAAQ,CAAC,2BAA2B;IAC5C,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IAZnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;IAGlE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAIlC;gBAGqC,UAAU,EAAE,UAAU,EAC1C,2BAA2B,EAAE,2BAA2B,EACxD,gBAAgB,EAAE,sBAAsB;IAK3D,QAAQ;IAIF,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;IAQ5C,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;IAqB5C,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;YAIpC,cAAc;YAkDd,cAAc;CA0D7B"}
1
+ {"version":3,"file":"scheduled-job.subscriber.d.ts","sourceRoot":"","sources":["../../src/subscribers/scheduled-job.subscriber.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAEjE,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AACzF,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EACL,UAAU,EAEV,yBAAyB,EACzB,WAAW,EACX,WAAW,EACX,WAAW,EACZ,MAAM,SAAS,CAAC;AAEjB,qBACa,sBACX,YAAW,yBAAyB,CAAC,YAAY,CAAC;IAW5B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC/C,OAAO,CAAC,QAAQ,CAAC,2BAA2B;IAC5C,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IAZnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;IAGlE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAIlC;gBAGqC,UAAU,EAAE,UAAU,EAC1C,2BAA2B,EAAE,2BAA2B,EACxD,gBAAgB,EAAE,sBAAsB;IAK3D,QAAQ;IAIF,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;IAQ5C,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;IAqB5C,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;YAIpC,cAAc;YAkDd,cAAc;CA0D7B"}
@@ -52,6 +52,7 @@ const typeorm_1 = require("@nestjs/typeorm");
52
52
  const fs = __importStar(require("fs/promises"));
53
53
  const module_metadata_entity_1 = require("../entities/module-metadata.entity");
54
54
  const scheduled_job_entity_1 = require("../entities/scheduled-job.entity");
55
+ const environment_helper_1 = require("../helpers/environment.helper");
55
56
  const module_metadata_helper_service_1 = require("../helpers/module-metadata-helper.service");
56
57
  const scheduled_job_repository_1 = require("../repository/scheduled-job.repository");
57
58
  const typeorm_2 = require("typeorm");
@@ -101,7 +102,7 @@ let ScheduledJobSubscriber = ScheduledJobSubscriber_1 = class ScheduledJobSubscr
101
102
  this.logger.error(`Module metadata not found for scheduled job with ID ${jobEntity?.id}`);
102
103
  return;
103
104
  }
104
- const moduleMetadataRepo = event.queryRunner.manager.getRepository(module_metadata_entity_1.ModuleMetadata);
105
+ const moduleMetadataRepo = ((0, environment_helper_1.isEmbeddedDb)() ? event.queryRunner.manager : this.dataSource).getRepository(module_metadata_entity_1.ModuleMetadata);
105
106
  const populatedModuleMetadata = await moduleMetadataRepo.findOne({
106
107
  where: { id: moduleMetadata.id },
107
108
  });
@@ -150,7 +151,7 @@ let ScheduledJobSubscriber = ScheduledJobSubscriber_1 = class ScheduledJobSubscr
150
151
  }
151
152
  const jobName = jobEntity.scheduleName;
152
153
  const existingIndex = metaData.scheduledJobs.findIndex((job) => job.scheduleName === jobName);
153
- const jobDto = await this.scheduledJobRepo.toDto(populatedScheduleJob);
154
+ const jobDto = await this.scheduledJobRepo.toDto(populatedScheduleJob, (0, environment_helper_1.isEmbeddedDb)() ? entityManager : undefined);
154
155
  const { moduleId, lastRunAt, nextRunAt, ...dtoToWrite } = jobDto;
155
156
  if (existingIndex !== -1) {
156
157
  metaData.scheduledJobs[existingIndex] = dtoToWrite;
@@ -1 +1 @@
1
- {"version":3,"file":"scheduled-job.subscriber.js","sourceRoot":"","sources":["../../src/subscribers/scheduled-job.subscriber.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAoD;AACpD,6CAAmD;AACnD,gDAAkC;AAElC,+EAAqE;AACrE,2EAAiE;AACjE,8FAAyF;AACzF,qFAAiF;AACjF,qCAOiB;AAGV,IAAM,sBAAsB,8BAA5B,MAAM,sBAAsB;IAWjC,YACsB,UAAuC,EAC1C,2BAAwD,EACxD,gBAAwC;QAFpB,eAAU,GAAV,UAAU,CAAY;QAC1C,gCAA2B,GAA3B,2BAA2B,CAA6B;QACxD,qBAAgB,GAAhB,gBAAgB,CAAwB;QAZ1C,WAAM,GAAG,IAAI,eAAM,CAAC,wBAAsB,CAAC,IAAI,CAAC,CAAC;QAGjD,wBAAmB,GAAuC;YACzE,WAAW;YACX,WAAW;YACX,WAAW;SACZ,CAAC;QAOA,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,QAAQ;QACN,OAAO,mCAAY,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAgC;QAChD,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YAClB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;YAC7E,OAAO;QACT,CAAC;QACD,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACrE,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAgC;QAChD,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;YAC7E,OAAO;QACT,CAAC;QAGD,MAAM,YAAY,GAAG,CAAC,KAAK,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;QAG7E,MAAM,kBAAkB,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QAE3F,IAAI,kBAAkB,EAAE,CAAC;YACvB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,6CAA8C,KAAK,CAAC,cAA+B,CAAC,EAAE,kCAAkC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAClK,CAAC;YACF,OAAO;QACT,CAAC;QAED,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7E,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAgC;QAChD,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,KAAgC;QAC3D,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC;QAC/B,MAAM,cAAc,GAAG,SAAS,EAAE,MAAM,CAAC;QAEzC,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,uDAAuD,SAAS,EAAE,EAAE,EAAE,CACvE,CAAC;YACF,OAAO;QACT,CAAC;QAED,MAAM,kBAAkB,GAAG,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,aAAa,CAAC,uCAAc,CAAC,CAAC;QACnF,MAAM,uBAAuB,GAAG,MAAM,kBAAkB,CAAC,OAAO,CAAC;YAC/D,KAAK,EAAE,EAAE,EAAE,EAAE,cAAc,CAAC,EAAE,EAAE;SACjC,CAAC,CAAC;QAEH,IAAI,CAAC,uBAAuB,EAAE,CAAC;YAC7B,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,yCAAyC,cAAc,CAAC,EAAE,EAAE,CAC7D,CAAC;YACF,OAAO;QACT,CAAC;QACD,MAAM,QAAQ,GACZ,MAAM,IAAI,CAAC,2BAA2B,CAAC,yBAAyB,CAC9D,uBAAuB,CAAC,IAAI,CAC7B,CAAC;QACJ,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,QAAQ,EAAE,CAAC,CAAC;YAC1D,OAAO;QACT,CAAC;QACD,MAAM,QAAQ,GACZ,MAAM,IAAI,CAAC,2BAA2B,CAAC,8BAA8B,CACnE,QAAQ,CACT,CAAC;QAEJ,MAAM,OAAO,GAAG,SAAS,CAAC,YAAY,CAAC;QACvC,MAAM,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC,SAAS,CACpD,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,KAAK,OAAO,CACtC,CAAC;QACF,IAAI,aAAa,KAAK,CAAC,CAAC,EAAE,CAAC;YACzB,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;YAChD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,yBAAyB,OAAO,gBAAgB,CAAC,CAAC;QACpE,CAAC;QACD,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACzD,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,4BAA4B,QAAQ,EAAE,CAAC,CAAC;IAC1D,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,SAAuB,EAAE,aAA4B;QAEhF,MAAM,oBAAoB,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,mCAAY,EAAE;YACrE,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,CAAC,EAAE,EAAE;YAC3B,SAAS,EAAE,CAAC,QAAQ,CAAC;SACtB,CAAC,CAAC;QAEH,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,gCAAgC,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC;QAClE,CAAC;QACD,MAAM,QAAQ,GACZ,MAAM,IAAI,CAAC,2BAA2B,CAAC,yBAAyB,CAC9D,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAClC,CAAC;QAEJ,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,QAAQ,EAAE,CAAC,CAAC;YAC1D,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GACZ,MAAM,IAAI,CAAC,2BAA2B,CAAC,8BAA8B,CACnE,QAAQ,CACT,CAAC;QAGJ,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;YAC5B,QAAQ,CAAC,aAAa,GAAG,EAAE,CAAC;QAC9B,CAAC;QAGD,MAAM,OAAO,GAAG,SAAS,CAAC,YAAY,CAAC;QACvC,MAAM,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC,SAAS,CACpD,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,KAAK,OAAO,CACtC,CAAC;QAEF,MAAM,MAAM,GAA0B,MAAM,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,oBAAoC,CAAC,CAAC;QAE9G,MAAM,EACJ,QAAQ,EACR,SAAS,EACT,SAAS,EACT,GAAG,UAAU,EACd,GAAG,MAAM,CAAC;QACX,IAAI,aAAa,KAAK,CAAC,CAAC,EAAE,CAAC;YACzB,QAAQ,CAAC,aAAa,CAAC,aAAa,CAAC,GAAG,UAAU,CAAC;YACnD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,yBAAyB,OAAO,cAAc,CAAC,CAAC;QAClE,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACxC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,uBAAuB,OAAO,cAAc,CAAC,CAAC;QAChE,CAAC;QAED,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACzD,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,4BAA4B,QAAQ,EAAE,CAAC,CAAC;IAC1D,CAAC;CACF,CAAA;AApKY,wDAAsB;iCAAtB,sBAAsB;IADlC,IAAA,mBAAU,GAAE;IAaR,WAAA,IAAA,0BAAgB,GAAE,CAAA;qCAA8B,oBAAU;QACb,4DAA2B;QACtC,iDAAsB;GAdhD,sBAAsB,CAoKlC","sourcesContent":["import { Injectable, Logger } from \"@nestjs/common\";\nimport { InjectDataSource } from \"@nestjs/typeorm\";\nimport * as fs from \"fs/promises\";\nimport { CreateScheduledJobDto } from \"src/dtos/create-scheduled-job.dto\";\nimport { ModuleMetadata } from \"src/entities/module-metadata.entity\";\nimport { ScheduledJob } from \"src/entities/scheduled-job.entity\";\nimport { ModuleMetadataHelperService } from \"src/helpers/module-metadata-helper.service\";\nimport { ScheduledJobRepository } from \"src/repository/scheduled-job.repository\";\nimport {\n DataSource,\n EntityManager,\n EntitySubscriberInterface,\n InsertEvent,\n RemoveEvent,\n UpdateEvent,\n} from \"typeorm\";\n\n@Injectable()\nexport class ScheduledJobSubscriber\n implements EntitySubscriberInterface<ScheduledJob> {\n private readonly logger = new Logger(ScheduledJobSubscriber.name);\n\n /** Fields that, when changed (and only these changed), should NOT trigger metadata update. */\n private readonly ignoredUpdateFields: Array<keyof ScheduledJob | string> = [\n \"lastRunAt\",\n \"nextRunAt\",\n \"updatedAt\",\n ];\n\n constructor(\n @InjectDataSource() private readonly dataSource: DataSource,\n private readonly moduleMetadataHelperService: ModuleMetadataHelperService,\n private readonly scheduledJobRepo: ScheduledJobRepository\n ) {\n this.dataSource.subscribers.push(this);\n }\n\n listenTo() {\n return ScheduledJob;\n }\n\n async afterInsert(event: InsertEvent<ScheduledJob>) {\n if (!event.entity) {\n this.logger.debug('No schedule Job entity found in the afterInsert method');\n return;\n }\n await this.updateMetadata(event.entity, event.queryRunner.manager);\n }\n\n async afterUpdate(event: UpdateEvent<ScheduledJob>) {\n if (!event.databaseEntity) {\n this.logger.debug('No schedule Job entity found in the afterUpdate method');\n return;\n }\n\n // get hold of the changed field names \n const changedProps = (event.updatedColumns ?? []).map((c) => c.propertyName);\n\n // Decide whether to skip: only skip when *all* changed fields are in the ignore list\n const onlyIgnoredChanged = changedProps.every((p) => this.ignoredUpdateFields.includes(p));\n\n if (onlyIgnoredChanged) {\n this.logger.debug(`Skipping metadata update for ScheduledJob#${(event.databaseEntity as ScheduledJob).id}; only ignored fields changed: ${changedProps.join(\", \")}`\n );\n return;\n }\n\n await this.updateMetadata(event.databaseEntity, event.queryRunner.manager);\n }\n\n async afterRemove(event: RemoveEvent<ScheduledJob>) {\n await this.removeMetadata(event);\n }\n\n private async removeMetadata(event: RemoveEvent<ScheduledJob>) {\n const jobEntity = event.entity;\n const moduleMetadata = jobEntity?.module;\n\n if (!moduleMetadata) {\n this.logger.error(\n `Module metadata not found for scheduled job with ID ${jobEntity?.id}`\n );\n return;\n }\n\n const moduleMetadataRepo = event.queryRunner.manager.getRepository(ModuleMetadata);\n const populatedModuleMetadata = await moduleMetadataRepo.findOne({\n where: { id: moduleMetadata.id },\n });\n\n if (!populatedModuleMetadata) {\n this.logger.error(\n `Could not find ModuleMetadata with ID ${moduleMetadata.id}`\n );\n return;\n }\n const filePath =\n await this.moduleMetadataHelperService.getModuleMetadataFilePath(\n populatedModuleMetadata.name\n );\n try {\n await fs.access(filePath);\n } catch {\n this.logger.error(`Metadata file not found: ${filePath}`);\n return;\n }\n const metaData =\n await this.moduleMetadataHelperService.getModuleMetadataConfiguration(\n filePath\n );\n // Remove, update or insert logic\n const jobName = jobEntity.scheduleName;\n const existingIndex = metaData.scheduledJobs.findIndex(\n (job) => job.scheduleName === jobName\n );\n if (existingIndex !== -1) {\n metaData.scheduledJobs.splice(existingIndex, 1);\n this.logger.log(`Removed scheduled job ${jobName} from metadata`);\n }\n const updatedContent = JSON.stringify(metaData, null, 2);\n await fs.writeFile(filePath, updatedContent);\n this.logger.log(`Updated scheduledJobs in ${filePath}`);\n }\n\n private async updateMetadata(jobEntity: ScheduledJob, entityManager: EntityManager) {\n // populate the job with its relation\n const populatedScheduleJob = await entityManager.findOne(ScheduledJob, {\n where: { id: jobEntity.id },\n relations: ['module'],\n });\n\n if (!populatedScheduleJob) {\n throw new Error(`ScheduleJob not found for id ${jobEntity.id}`);\n }\n const filePath =\n await this.moduleMetadataHelperService.getModuleMetadataFilePath(\n populatedScheduleJob.module?.name\n );\n\n try {\n await fs.access(filePath);\n } catch {\n this.logger.error(`Metadata file not found: ${filePath}`);\n return;\n }\n\n const metaData =\n await this.moduleMetadataHelperService.getModuleMetadataConfiguration(\n filePath\n );\n\n // Ensure scheduledJobs exists\n if (!metaData.scheduledJobs) {\n metaData.scheduledJobs = [];\n }\n\n // Remove, update or insert logic\n const jobName = jobEntity.scheduleName;\n const existingIndex = metaData.scheduledJobs.findIndex(\n (job) => job.scheduleName === jobName\n );\n // Insert or update job in metadata\n const jobDto: CreateScheduledJobDto = await this.scheduledJobRepo.toDto(populatedScheduleJob as ScheduledJob);\n // Strip out bookkeeping/runtime fields before persisting to metadata JSON.\n const {\n moduleId,\n lastRunAt,\n nextRunAt,\n ...dtoToWrite\n } = jobDto;\n if (existingIndex !== -1) {\n metaData.scheduledJobs[existingIndex] = dtoToWrite;\n this.logger.log(`Updated scheduled job ${jobName} in metadata`);\n } else {\n metaData.scheduledJobs.push(dtoToWrite);\n this.logger.log(`Added scheduled job ${jobName} to metadata`);\n }\n\n const updatedContent = JSON.stringify(metaData, null, 2);\n await fs.writeFile(filePath, updatedContent);\n this.logger.log(`Updated scheduledJobs in ${filePath}`);\n }\n}\n"]}
1
+ {"version":3,"file":"scheduled-job.subscriber.js","sourceRoot":"","sources":["../../src/subscribers/scheduled-job.subscriber.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, Logger } from \"@nestjs/common\";\nimport { InjectDataSource } from \"@nestjs/typeorm\";\nimport * as fs from \"fs/promises\";\nimport { CreateScheduledJobDto } from \"src/dtos/create-scheduled-job.dto\";\nimport { ModuleMetadata } from \"src/entities/module-metadata.entity\";\nimport { ScheduledJob } from \"src/entities/scheduled-job.entity\";\nimport { isEmbeddedDb } from \"src/helpers/environment.helper\";\nimport { ModuleMetadataHelperService } from \"src/helpers/module-metadata-helper.service\";\nimport { ScheduledJobRepository } from \"src/repository/scheduled-job.repository\";\nimport {\n DataSource,\n EntityManager,\n EntitySubscriberInterface,\n InsertEvent,\n RemoveEvent,\n UpdateEvent,\n} from \"typeorm\";\n\n@Injectable()\nexport class ScheduledJobSubscriber\n implements EntitySubscriberInterface<ScheduledJob> {\n private readonly logger = new Logger(ScheduledJobSubscriber.name);\n\n /** Fields that, when changed (and only these changed), should NOT trigger metadata update. */\n private readonly ignoredUpdateFields: Array<keyof ScheduledJob | string> = [\n \"lastRunAt\",\n \"nextRunAt\",\n \"updatedAt\",\n ];\n\n constructor(\n @InjectDataSource() private readonly dataSource: DataSource,\n private readonly moduleMetadataHelperService: ModuleMetadataHelperService,\n private readonly scheduledJobRepo: ScheduledJobRepository\n ) {\n this.dataSource.subscribers.push(this);\n }\n\n listenTo() {\n return ScheduledJob;\n }\n\n async afterInsert(event: InsertEvent<ScheduledJob>) {\n if (!event.entity) {\n this.logger.debug('No schedule Job entity found in the afterInsert method');\n return;\n }\n await this.updateMetadata(event.entity, event.queryRunner.manager);\n }\n\n async afterUpdate(event: UpdateEvent<ScheduledJob>) {\n if (!event.databaseEntity) {\n this.logger.debug('No schedule Job entity found in the afterUpdate method');\n return;\n }\n\n // get hold of the changed field names \n const changedProps = (event.updatedColumns ?? []).map((c) => c.propertyName);\n\n // Decide whether to skip: only skip when *all* changed fields are in the ignore list\n const onlyIgnoredChanged = changedProps.every((p) => this.ignoredUpdateFields.includes(p));\n\n if (onlyIgnoredChanged) {\n this.logger.debug(`Skipping metadata update for ScheduledJob#${(event.databaseEntity as ScheduledJob).id}; only ignored fields changed: ${changedProps.join(\", \")}`\n );\n return;\n }\n\n await this.updateMetadata(event.databaseEntity, event.queryRunner.manager);\n }\n\n async afterRemove(event: RemoveEvent<ScheduledJob>) {\n await this.removeMetadata(event);\n }\n\n private async removeMetadata(event: RemoveEvent<ScheduledJob>) {\n const jobEntity = event.entity;\n const moduleMetadata = jobEntity?.module;\n\n if (!moduleMetadata) {\n this.logger.error(\n `Module metadata not found for scheduled job with ID ${jobEntity?.id}`\n );\n return;\n }\n\n const moduleMetadataRepo = (isEmbeddedDb() ? event.queryRunner.manager : this.dataSource).getRepository(ModuleMetadata);\n const populatedModuleMetadata = await moduleMetadataRepo.findOne({\n where: { id: moduleMetadata.id },\n });\n\n if (!populatedModuleMetadata) {\n this.logger.error(\n `Could not find ModuleMetadata with ID ${moduleMetadata.id}`\n );\n return;\n }\n const filePath =\n await this.moduleMetadataHelperService.getModuleMetadataFilePath(\n populatedModuleMetadata.name\n );\n try {\n await fs.access(filePath);\n } catch {\n this.logger.error(`Metadata file not found: ${filePath}`);\n return;\n }\n const metaData =\n await this.moduleMetadataHelperService.getModuleMetadataConfiguration(\n filePath\n );\n // Remove, update or insert logic\n const jobName = jobEntity.scheduleName;\n const existingIndex = metaData.scheduledJobs.findIndex(\n (job) => job.scheduleName === jobName\n );\n if (existingIndex !== -1) {\n metaData.scheduledJobs.splice(existingIndex, 1);\n this.logger.log(`Removed scheduled job ${jobName} from metadata`);\n }\n const updatedContent = JSON.stringify(metaData, null, 2);\n await fs.writeFile(filePath, updatedContent);\n this.logger.log(`Updated scheduledJobs in ${filePath}`);\n }\n\n private async updateMetadata(jobEntity: ScheduledJob, entityManager: EntityManager) {\n // populate the job with its relation\n const populatedScheduleJob = await entityManager.findOne(ScheduledJob, {\n where: { id: jobEntity.id },\n relations: ['module'],\n });\n\n if (!populatedScheduleJob) {\n throw new Error(`ScheduleJob not found for id ${jobEntity.id}`);\n }\n const filePath =\n await this.moduleMetadataHelperService.getModuleMetadataFilePath(\n populatedScheduleJob.module?.name\n );\n\n try {\n await fs.access(filePath);\n } catch {\n this.logger.error(`Metadata file not found: ${filePath}`);\n return;\n }\n\n const metaData =\n await this.moduleMetadataHelperService.getModuleMetadataConfiguration(\n filePath\n );\n\n // Ensure scheduledJobs exists\n if (!metaData.scheduledJobs) {\n metaData.scheduledJobs = [];\n }\n\n // Remove, update or insert logic\n const jobName = jobEntity.scheduleName;\n const existingIndex = metaData.scheduledJobs.findIndex(\n (job) => job.scheduleName === jobName\n );\n // Insert or update job in metadata\n const jobDto: CreateScheduledJobDto = await this.scheduledJobRepo.toDto(populatedScheduleJob as ScheduledJob, isEmbeddedDb() ? entityManager : undefined);\n // Strip out bookkeeping/runtime fields before persisting to metadata JSON.\n const {\n moduleId,\n lastRunAt,\n nextRunAt,\n ...dtoToWrite\n } = jobDto;\n if (existingIndex !== -1) {\n metaData.scheduledJobs[existingIndex] = dtoToWrite;\n this.logger.log(`Updated scheduled job ${jobName} in metadata`);\n } else {\n metaData.scheduledJobs.push(dtoToWrite);\n this.logger.log(`Added scheduled job ${jobName} to metadata`);\n }\n\n const updatedContent = JSON.stringify(metaData, null, 2);\n await fs.writeFile(filePath, updatedContent);\n this.logger.log(`Updated scheduledJobs in ${filePath}`);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"security-rule.subscriber.d.ts","sourceRoot":"","sources":["../../src/subscribers/security-rule.subscriber.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AACzF,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,yBAAyB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE1F,qBACa,sBAAuB,YAAW,yBAAyB,CAAC,YAAY,CAAC;IAI9E,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,QAAQ,CAAC,2BAA2B,EAAE,2BAA2B;IACjE,QAAQ,CAAC,gBAAgB,EAAE,sBAAsB;IALrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;gBAG7C,UAAU,EAAE,UAAU,EAC9B,2BAA2B,EAAE,2BAA2B,EACxD,gBAAgB,EAAE,sBAAsB;IAKrD,QAAQ;IAIF,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;IAI5C,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;IAI5C,iBAAiB,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC,GAAG,WAAW,CAAC,YAAY,CAAC;CAiDvF"}
1
+ {"version":3,"file":"security-rule.subscriber.d.ts","sourceRoot":"","sources":["../../src/subscribers/security-rule.subscriber.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAEjE,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AACzF,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,yBAAyB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE1F,qBACa,sBAAuB,YAAW,yBAAyB,CAAC,YAAY,CAAC;IAI9E,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,QAAQ,CAAC,2BAA2B,EAAE,2BAA2B;IACjE,QAAQ,CAAC,gBAAgB,EAAE,sBAAsB;IALrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;gBAG7C,UAAU,EAAE,UAAU,EAC9B,2BAA2B,EAAE,2BAA2B,EACxD,gBAAgB,EAAE,sBAAsB;IAKrD,QAAQ;IAIF,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;IAI5C,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;IAI5C,iBAAiB,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC,GAAG,WAAW,CAAC,YAAY,CAAC;CAqDvF"}
@@ -53,6 +53,7 @@ const fs = __importStar(require("fs/promises"));
53
53
  const constants_1 = require("../constants");
54
54
  const model_metadata_entity_1 = require("../entities/model-metadata.entity");
55
55
  const security_rule_entity_1 = require("../entities/security-rule.entity");
56
+ const environment_helper_1 = require("../helpers/environment.helper");
56
57
  const module_metadata_helper_service_1 = require("../helpers/module-metadata-helper.service");
57
58
  const security_rule_repository_1 = require("../repository/security-rule.repository");
58
59
  const typeorm_2 = require("typeorm");
@@ -80,7 +81,8 @@ let SecurityRuleSubscriber = SecurityRuleSubscriber_1 = class SecurityRuleSubscr
80
81
  this.logger.error(`Model metadata not found for security rule with id ${event.entity.id}`);
81
82
  return;
82
83
  }
83
- const modelMetadataRepo = event.manager.getRepository(model_metadata_entity_1.ModelMetadata);
84
+ const mgr = (0, environment_helper_1.isEmbeddedDb)() ? event.manager : this.dataSource;
85
+ const modelMetadataRepo = mgr.getRepository(model_metadata_entity_1.ModelMetadata);
84
86
  const populatedModelMetadata = await modelMetadataRepo.findOne({
85
87
  where: {
86
88
  id: modelMetadata.id
@@ -103,12 +105,12 @@ let SecurityRuleSubscriber = SecurityRuleSubscriber_1 = class SecurityRuleSubscr
103
105
  const metaData = await this.moduleMetadataHelperService.getModuleMetadataConfiguration(filePath);
104
106
  if (metaData.securityRules) {
105
107
  const securityRuleIndex = metaData.securityRules?.findIndex((ruleFromFile) => ruleFromFile.name === securityRule.name);
106
- const { id, roleId, modelMetadataId, ...requiredDto } = await this.securityRuleRepo.toDto(securityRule);
108
+ const { id, roleId, modelMetadataId, ...requiredDto } = await this.securityRuleRepo.toDto(securityRule, (0, environment_helper_1.isEmbeddedDb)() ? event.manager : undefined);
107
109
  metaData.securityRules[securityRuleIndex] = { ...requiredDto, securityRuleConfig: JSON.parse(securityRule.securityRuleConfig) };
108
110
  }
109
111
  else {
110
112
  const securityRules = [];
111
- const { id, roleId, modelMetadataId, ...requiredDto } = await this.securityRuleRepo.toDto(securityRule);
113
+ const { id, roleId, modelMetadataId, ...requiredDto } = await this.securityRuleRepo.toDto(securityRule, (0, environment_helper_1.isEmbeddedDb)() ? event.manager : undefined);
112
114
  securityRules.push({ ...requiredDto, securityRuleConfig: JSON.parse(securityRule.securityRuleConfig) });
113
115
  metaData.securityRules = securityRules;
114
116
  }
@@ -1 +1 @@
1
- {"version":3,"file":"security-rule.subscriber.js","sourceRoot":"","sources":["../../src/subscribers/security-rule.subscriber.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, Logger } from '@nestjs/common';\nimport { InjectDataSource } from \"@nestjs/typeorm\";\nimport * as fs from 'fs/promises'; // Use the Promise-based version of fs for async/await\nimport { SOLID_CORE_MODULE_NAME } from 'src/constants';\nimport { ModelMetadata } from 'src/entities/model-metadata.entity';\nimport { SecurityRule } from 'src/entities/security-rule.entity';\nimport { ModuleMetadataHelperService } from \"src/helpers/module-metadata-helper.service\";\nimport { SecurityRuleRepository } from 'src/repository/security-rule.repository';\nimport { DataSource, EntitySubscriberInterface, InsertEvent, UpdateEvent } from \"typeorm\";\n\n@Injectable()\nexport class SecurityRuleSubscriber implements EntitySubscriberInterface<SecurityRule> {\n private readonly logger = new Logger(SecurityRuleSubscriber.name);\n constructor(\n @InjectDataSource()\n private readonly dataSource: DataSource,\n readonly moduleMetadataHelperService: ModuleMetadataHelperService,\n readonly securityRuleRepo: SecurityRuleRepository,\n ) {\n this.dataSource.subscribers.push(this);\n }\n\n listenTo() {\n return SecurityRule;\n }\n\n async afterInsert(event: InsertEvent<SecurityRule>) {\n await this.saveSecurityRules(event);\n }\n\n async afterUpdate(event: UpdateEvent<SecurityRule>) {\n await this.saveSecurityRules(event);\n }\n\n async saveSecurityRules(event: UpdateEvent<SecurityRule> | InsertEvent<SecurityRule>) {\n const securityRule = event.entity as SecurityRule;\n const modelMetadata = event.entity.modelMetadata;\n if (!modelMetadata) {\n this.logger.error(`Model metadata not found for security rule with id ${event.entity.id}`);\n return;\n }\n\n const modelMetadataRepo = event.manager.getRepository(ModelMetadata);\n const populatedModelMetadata = await modelMetadataRepo.findOne({\n where: {\n id: modelMetadata.id\n },\n relations: {\n module: true,\n }\n });\n\n // Ignore further processing if the module is solid core module, since solid core security rules cannot be seeded from the UI\n if (populatedModelMetadata.module.name === SOLID_CORE_MODULE_NAME) {\n return;\n }\n\n const filePath = await this.moduleMetadataHelperService.getModuleMetadataFilePath(populatedModelMetadata.module.name);\n try {\n await fs.access(filePath);\n } catch (error: any) {\n // FIXME - Should we actually delete the security rule here, if the file is not found?\n this.logger.error(`File not found at path: ${filePath}`);\n return;\n }\n const metaData = await this.moduleMetadataHelperService.getModuleMetadataConfiguration(filePath);\n\n if (metaData.securityRules) {\n const securityRuleIndex = metaData.securityRules?.findIndex((ruleFromFile: { name: string }) => ruleFromFile.name === securityRule.name);\n const { id, roleId, modelMetadataId, ...requiredDto } = await this.securityRuleRepo.toDto(securityRule)\n metaData.securityRules[securityRuleIndex] = { ...requiredDto, securityRuleConfig: JSON.parse(securityRule.securityRuleConfig) }\n }\n else {\n const securityRules = []\n const { id, roleId, modelMetadataId, ...requiredDto } = await this.securityRuleRepo.toDto(securityRule)\n securityRules.push({ ...requiredDto, securityRuleConfig: JSON.parse(securityRule.securityRuleConfig) })\n metaData.securityRules = securityRules\n }\n // Write the updated object back to the file\n const updatedContent = JSON.stringify(metaData, null, 2);\n await fs.writeFile(filePath, updatedContent);\n }\n\n}"]}
1
+ {"version":3,"file":"security-rule.subscriber.js","sourceRoot":"","sources":["../../src/subscribers/security-rule.subscriber.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, Logger } from '@nestjs/common';\nimport { InjectDataSource } from \"@nestjs/typeorm\";\nimport * as fs from 'fs/promises'; // Use the Promise-based version of fs for async/await\nimport { SOLID_CORE_MODULE_NAME } from 'src/constants';\nimport { ModelMetadata } from 'src/entities/model-metadata.entity';\nimport { SecurityRule } from 'src/entities/security-rule.entity';\nimport { isEmbeddedDb } from \"src/helpers/environment.helper\";\nimport { ModuleMetadataHelperService } from \"src/helpers/module-metadata-helper.service\";\nimport { SecurityRuleRepository } from 'src/repository/security-rule.repository';\nimport { DataSource, EntitySubscriberInterface, InsertEvent, UpdateEvent } from \"typeorm\";\n\n@Injectable()\nexport class SecurityRuleSubscriber implements EntitySubscriberInterface<SecurityRule> {\n private readonly logger = new Logger(SecurityRuleSubscriber.name);\n constructor(\n @InjectDataSource()\n private readonly dataSource: DataSource,\n readonly moduleMetadataHelperService: ModuleMetadataHelperService,\n readonly securityRuleRepo: SecurityRuleRepository,\n ) {\n this.dataSource.subscribers.push(this);\n }\n\n listenTo() {\n return SecurityRule;\n }\n\n async afterInsert(event: InsertEvent<SecurityRule>) {\n await this.saveSecurityRules(event);\n }\n\n async afterUpdate(event: UpdateEvent<SecurityRule>) {\n await this.saveSecurityRules(event);\n }\n\n async saveSecurityRules(event: UpdateEvent<SecurityRule> | InsertEvent<SecurityRule>) {\n const securityRule = event.entity as SecurityRule;\n const modelMetadata = event.entity.modelMetadata;\n if (!modelMetadata) {\n this.logger.error(`Model metadata not found for security rule with id ${event.entity.id}`);\n return;\n }\n\n // On embedded PGlite, use the transaction's connection to avoid a\n // second pooled connection mid-transaction. On regular Postgres, use\n // the default DataSource (original behaviour).\n const mgr = isEmbeddedDb() ? event.manager : this.dataSource;\n const modelMetadataRepo = mgr.getRepository(ModelMetadata);\n const populatedModelMetadata = await modelMetadataRepo.findOne({\n where: {\n id: modelMetadata.id\n },\n relations: {\n module: true,\n }\n });\n\n // Ignore further processing if the module is solid core module, since solid core security rules cannot be seeded from the UI\n if (populatedModelMetadata.module.name === SOLID_CORE_MODULE_NAME) {\n return;\n }\n\n const filePath = await this.moduleMetadataHelperService.getModuleMetadataFilePath(populatedModelMetadata.module.name);\n try {\n await fs.access(filePath);\n } catch (error: any) {\n // FIXME - Should we actually delete the security rule here, if the file is not found?\n this.logger.error(`File not found at path: ${filePath}`);\n return;\n }\n const metaData = await this.moduleMetadataHelperService.getModuleMetadataConfiguration(filePath);\n\n if (metaData.securityRules) {\n const securityRuleIndex = metaData.securityRules?.findIndex((ruleFromFile: { name: string }) => ruleFromFile.name === securityRule.name);\n const { id, roleId, modelMetadataId, ...requiredDto } = await this.securityRuleRepo.toDto(securityRule, isEmbeddedDb() ? event.manager : undefined)\n metaData.securityRules[securityRuleIndex] = { ...requiredDto, securityRuleConfig: JSON.parse(securityRule.securityRuleConfig) }\n }\n else {\n const securityRules = []\n const { id, roleId, modelMetadataId, ...requiredDto } = await this.securityRuleRepo.toDto(securityRule, isEmbeddedDb() ? event.manager : undefined)\n securityRules.push({ ...requiredDto, securityRuleConfig: JSON.parse(securityRule.securityRuleConfig) })\n metaData.securityRules = securityRules\n }\n // Write the updated object back to the file\n const updatedContent = JSON.stringify(metaData, null, 2);\n await fs.writeFile(filePath, updatedContent);\n }\n\n}"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidxai/core",
3
- "version": "0.1.11-beta.8",
3
+ "version": "0.1.11-beta.9",
4
4
  "description": "This module is a NestJS module containing all the required core providers required by a Solid application",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -13,4 +13,15 @@ export function isRedisConfigured(configService: ConfigService): boolean {
13
13
  const host = configService.get<string>('REDIS_HOST');
14
14
  const port = configService.get<string>('REDIS_PORT');
15
15
  return host && port && isNumber(parseInt(port));
16
+ }
17
+
18
+ /**
19
+ * Returns true when the project is configured to use an embedded PGlite
20
+ * database with a single-connection pool. Several TypeORM subscriber and
21
+ * code-generation workarounds are only necessary (and only applied) under
22
+ * this constraint; on a regular multi-connection Postgres pool the original
23
+ * behaviour is preserved.
24
+ */
25
+ export function isEmbeddedDb(): boolean {
26
+ return process.env.DEFAULT_DATABASE_DRIVER === 'pglite';
16
27
  }
@@ -4,8 +4,10 @@ import { forwardRef, Inject, Injectable, Logger } from "@nestjs/common";
4
4
  import { _ } from "lodash";
5
5
  import { LEGACY_TABLE_FIELDS_PREFIX } from "src/entities/legacy-common.entity-with-existing-id.entity";
6
6
  import { LegacyTableType } from "src/enums/legacy-table-type.enum";
7
+ import { ModelMetadata } from "src/entities/model-metadata.entity";
7
8
  import { ModelMetadataRepository } from "src/repository/model-metadata.repository";
8
9
  import { SolidRegistry } from "./solid-registry";
10
+ import { EntityManager } from "typeorm";
9
11
 
10
12
  @Injectable()
11
13
  export class ModelMetadataHelperService {
@@ -143,8 +145,11 @@ export class ModelMetadataHelperService {
143
145
  return systemFieldsMetadata;
144
146
  }
145
147
 
146
- async loadFieldHierarchy(modelName: any) {
147
- const model = await this.modelMetadataRepo.findOne({
148
+ async loadFieldHierarchy(modelName: any, manager?: EntityManager) {
149
+ const repo = manager
150
+ ? manager.getRepository(ModelMetadata)
151
+ : this.modelMetadataRepo;
152
+ const model = await repo.findOne({
148
153
  where: {
149
154
  singularName: modelName,
150
155
  },
@@ -45,6 +45,21 @@ const solidCoreDbType: DatasourceType =
45
45
  ? (process.env.SOLID_CORE_DB_TYPE as DatasourceType)
46
46
  : DatasourceType.postgres;
47
47
 
48
+ // Must use ANSI CAST() syntax — not Postgres-specific `::text` — because TypeORM's
49
+ // replacePropertyNamesForTheWholeQuery regex treats ':' as part of the property name,
50
+ // so `alias.col::text` is parsed as property `col::text` (no match → no column substitution).
51
+ export function buildCastToText(driver: string, colExpr: string): string {
52
+ switch (driver) {
53
+ case DatasourceType.mssql:
54
+ return `CAST(${colExpr} AS NVARCHAR(MAX))`;
55
+ case DatasourceType.mysql:
56
+ case DatasourceType.mariadb:
57
+ return `CAST(${colExpr} AS CHAR)`;
58
+ default:
59
+ return `CAST(${colExpr} AS TEXT)`;
60
+ }
61
+ }
62
+
48
63
  export function getColumnType(solidType: string): ColumnOptions {
49
64
  switch (solidType) {
50
65
  case "longText":
@@ -3,7 +3,7 @@ import { CreateScheduledJobDto } from "src/dtos/create-scheduled-job.dto";
3
3
  import { ModuleMetadata } from "src/entities/module-metadata.entity";
4
4
  import { ScheduledJob } from "src/entities/scheduled-job.entity";
5
5
  import { RequestContextService } from "src/services/request-context.service";
6
- import { DataSource } from "typeorm";
6
+ import { DataSource, EntityManager } from "typeorm";
7
7
  import { SecurityRuleRepository } from "./security-rule.repository";
8
8
  import { SolidBaseRepository } from "./solid-base.repository";
9
9
 
@@ -101,19 +101,25 @@ export class ScheduledJobRepository extends SolidBaseRepository<ScheduledJob> {
101
101
 
102
102
  /**
103
103
  * Converts an entity to a plain DTO object.
104
+ * When manager is provided (e.g. from a TypeORM subscriber event), the
105
+ * fallback relation load uses it so the query runs on the active
106
+ * transaction's connection instead of the default DataSource pool.
104
107
  */
105
- async toDto(scheduledJob: ScheduledJob): Promise<CreateScheduledJobDto> {
108
+ async toDto(scheduledJob: ScheduledJob, manager?: EntityManager): Promise<CreateScheduledJobDto> {
106
109
  let populatedScheduledJob: ScheduledJob = scheduledJob;
107
110
  // If the scheduled job does not have the module relation loaded, load it
108
111
  if (!scheduledJob.module) {
109
- populatedScheduledJob = await this.findOne({
112
+ const repo = manager
113
+ ? manager.getRepository(ScheduledJob)
114
+ : this;
115
+ populatedScheduledJob = await repo.findOne({
110
116
  where: {
111
117
  id: scheduledJob.id,
112
118
  },
113
119
  relations: {
114
120
  module: true,
115
121
  },
116
- });
122
+ }) ?? scheduledJob;
117
123
  }
118
124
 
119
125
  if (!populatedScheduledJob.module) {
@@ -9,7 +9,7 @@ import { SecurityRule } from 'src/entities/security-rule.entity';
9
9
  import { SolidRegistry } from 'src/helpers/solid-registry';
10
10
  import { ActiveUserData } from 'src/interfaces/active-user-data.interface';
11
11
  import { CrudHelperService } from 'src/services/crud-helper.service';
12
- import { Brackets, DataSource, SelectQueryBuilder } from 'typeorm';
12
+ import { Brackets, DataSource, EntityManager, SelectQueryBuilder } from 'typeorm';
13
13
  import { SolidBaseRepository } from './solid-base.repository';
14
14
 
15
15
  @Injectable()
@@ -84,12 +84,18 @@ export class SecurityRuleRepository extends SolidBaseRepository<SecurityRule> {
84
84
  return configString.replace('$activeUserId', activeUser.sub.toString());
85
85
  }
86
86
 
87
- async toDto(securityRule: SecurityRule): Promise<UpdateSecurityRuleDto> {
87
+ async toDto(securityRule: SecurityRule, manager?: EntityManager): Promise<UpdateSecurityRuleDto> {
88
88
  // load the role and model relations for the security rule
89
89
  let populatedSecurityRule: SecurityRule = securityRule;
90
90
  // If the security rule does not have the role and model relations loaded, load them
91
91
  if (!securityRule.role || !securityRule.modelMetadata) {
92
- populatedSecurityRule = await this.findOne({
92
+ // When a manager is provided (e.g. from a TypeORM subscriber event),
93
+ // use it so the query runs on the active transaction's connection
94
+ // instead of trying to acquire a second connection from the pool.
95
+ const repo = manager
96
+ ? manager.getRepository(SecurityRule)
97
+ : this;
98
+ populatedSecurityRule = await repo.findOne({
93
99
  where: {
94
100
  id: securityRule.id,
95
101
  },
@@ -97,7 +103,7 @@ export class SecurityRuleRepository extends SolidBaseRepository<SecurityRule> {
97
103
  role: true,
98
104
  modelMetadata: true,
99
105
  },
100
- });
106
+ }) ?? securityRule;
101
107
  }
102
108
 
103
109
  return {
@@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
2
2
  import { InjectEntityManager } from '@nestjs/typeorm';
3
3
  import { ComputedFieldProvider } from 'src/decorators/computed-field-provider.decorator';
4
4
  import { CommonEntity } from 'src/entities/common.entity';
5
+ import { isEmbeddedDb } from 'src/helpers/environment.helper';
5
6
  import { ComputedFieldMetadata } from 'src/helpers/solid-registry';
6
7
  import { IEntityPreComputeFieldProvider } from 'src/interfaces';
7
8
  import { EntityManager } from 'typeorm';
@@ -45,10 +46,10 @@ export class AlphaNumExternalIdComputationProvider<T extends CommonEntity> imple
45
46
  }
46
47
  }
47
48
 
48
- // Use the originating transaction's EntityManager so the uniqueness check runs on the
49
- // active connection. Falls back to the injected manager only when no event context is
50
- // available (e.g. direct invocation outside a TypeORM lifecycle event).
51
- const manager = eventContext?.manager ?? this.entityManager;
49
+ // On embedded PGlite (pool size 1), use the originating transaction's EntityManager
50
+ // so the uniqueness check runs on the active connection. On regular Postgres, use the
51
+ // injected EntityManager (original behaviour).
52
+ const manager = isEmbeddedDb() ? (eventContext?.manager ?? this.entityManager) : this.entityManager;
52
53
 
53
54
  const uniqueCode = await this.generateUniqueExternalId(manager, resolvedPrefix, codeLength, computedFieldMetadata.fieldName, entityName);
54
55
  const finalExternalId = resolvedPrefix ? `${resolvedPrefix}-${uniqueCode}` : uniqueCode;
@@ -5,6 +5,7 @@ import { ActiveUserData } from "src/interfaces/active-user-data.interface";
5
5
  import { SolidRegistry } from "src/helpers/solid-registry";
6
6
  import { BadRequestException, Logger } from "@nestjs/common";
7
7
  import { ERROR_MESSAGES } from "src/constants/error-messages";
8
+ import { buildCastToText } from "src/helpers/typeorm-db-helper";
8
9
 
9
10
  export enum FilterCombinator {
10
11
  AND = '$and',
@@ -101,15 +102,19 @@ export class CrudHelperService {
101
102
  case '$eq':
102
103
  qb.andWhere(`${colExpr} = :${uniqueFieldAlias}`, { [uniqueFieldAlias]: normalizedPrimaryOperatorObj.$eq });
103
104
  break;
104
- case '$eqi':
105
- qb.andWhere(`LOWER(${colExpr}) = :${uniqueFieldAlias}`, { [uniqueFieldAlias]: normalizedPrimaryOperatorObj.$eqi.toLowerCase() });
105
+ case '$eqi': {
106
+ const castExpr = buildCastToText(this.getDriver(qb), colExpr);
107
+ qb.andWhere(`LOWER(${castExpr}) = :${uniqueFieldAlias}`, { [uniqueFieldAlias]: String(normalizedPrimaryOperatorObj.$eqi).toLowerCase() });
106
108
  break;
109
+ }
107
110
  case '$ne':
108
111
  qb.andWhere(`${colExpr} != :${uniqueFieldAlias}`, { [uniqueFieldAlias]: normalizedPrimaryOperatorObj.$ne });
109
112
  break;
110
- case '$nei':
111
- qb.andWhere(`LOWER(${colExpr}) != :${uniqueFieldAlias}`, { [uniqueFieldAlias]: normalizedPrimaryOperatorObj.$nei.toLowerCase() });
113
+ case '$nei': {
114
+ const castExpr = buildCastToText(this.getDriver(qb), colExpr);
115
+ qb.andWhere(`LOWER(${castExpr}) != :${uniqueFieldAlias}`, { [uniqueFieldAlias]: String(normalizedPrimaryOperatorObj.$nei).toLowerCase() });
112
116
  break;
117
+ }
113
118
  case '$gt':
114
119
  qb.andWhere(`${colExpr} > :${uniqueFieldAlias}`, { [uniqueFieldAlias]: normalizedPrimaryOperatorObj.$gt });
115
120
  break;
@@ -134,12 +139,16 @@ export class CrudHelperService {
134
139
  case '$notContains':
135
140
  qb.andWhere(`${colExpr} NOT LIKE :${uniqueFieldAlias}`, { [uniqueFieldAlias]: `%${normalizedPrimaryOperatorObj.$notContains}%` });
136
141
  break;
137
- case '$containsi':
138
- qb.andWhere(`LOWER(${colExpr}) LIKE :${uniqueFieldAlias}`, { [uniqueFieldAlias]: `%${normalizedPrimaryOperatorObj.$containsi.toLowerCase()}%` });
142
+ case '$containsi': {
143
+ const castExpr = buildCastToText(this.getDriver(qb), colExpr);
144
+ qb.andWhere(`LOWER(${castExpr}) LIKE :${uniqueFieldAlias}`, { [uniqueFieldAlias]: `%${String(normalizedPrimaryOperatorObj.$containsi).toLowerCase()}%` });
139
145
  break;
140
- case '$notContainsi':
141
- qb.andWhere(`LOWER(${colExpr}) NOT LIKE :${uniqueFieldAlias}`, { [uniqueFieldAlias]: `%${normalizedPrimaryOperatorObj.$notContainsi.toLowerCase()}%` });
146
+ }
147
+ case '$notContainsi': {
148
+ const castExpr = buildCastToText(this.getDriver(qb), colExpr);
149
+ qb.andWhere(`LOWER(${castExpr}) NOT LIKE :${uniqueFieldAlias}`, { [uniqueFieldAlias]: `%${String(normalizedPrimaryOperatorObj.$notContainsi).toLowerCase()}%` });
142
150
  break;
151
+ }
143
152
  case '$null':
144
153
  qb.andWhere(`${colExpr} IS NULL`);
145
154
  break;
@@ -152,15 +161,19 @@ export class CrudHelperService {
152
161
  case '$startsWith':
153
162
  qb.andWhere(`${colExpr} LIKE :${uniqueFieldAlias}`, { [uniqueFieldAlias]: `${normalizedPrimaryOperatorObj.$startsWith}%` });
154
163
  break;
155
- case '$startsWithi':
156
- qb.andWhere(`LOWER(${colExpr}) LIKE :${uniqueFieldAlias}`, { [uniqueFieldAlias]: `${normalizedPrimaryOperatorObj.$startsWithi.toLowerCase()}%` });
164
+ case '$startsWithi': {
165
+ const castExpr = buildCastToText(this.getDriver(qb), colExpr);
166
+ qb.andWhere(`LOWER(${castExpr}) LIKE :${uniqueFieldAlias}`, { [uniqueFieldAlias]: `${String(normalizedPrimaryOperatorObj.$startsWithi).toLowerCase()}%` });
157
167
  break;
168
+ }
158
169
  case '$endsWith':
159
170
  qb.andWhere(`${colExpr} LIKE :${uniqueFieldAlias}`, { [uniqueFieldAlias]: `%${normalizedPrimaryOperatorObj.$endsWith}` });
160
171
  break;
161
- case '$endsWithi':
162
- qb.andWhere(`LOWER(${colExpr}) LIKE :${uniqueFieldAlias}`, { [uniqueFieldAlias]: `%${normalizedPrimaryOperatorObj.$endsWithi.toLowerCase()}` });
172
+ case '$endsWithi': {
173
+ const castExpr = buildCastToText(this.getDriver(qb), colExpr);
174
+ qb.andWhere(`LOWER(${castExpr}) LIKE :${uniqueFieldAlias}`, { [uniqueFieldAlias]: `%${String(normalizedPrimaryOperatorObj.$endsWithi).toLowerCase()}` });
163
175
  break;
176
+ }
164
177
  default:
165
178
  throw new Error(`Operator ${operator} is not supported`);
166
179
  }
@@ -27,6 +27,7 @@ import { PermissionMetadata } from '../entities/permission-metadata.entity';
27
27
  import { RoleMetadata } from '../entities/role-metadata.entity';
28
28
  import { ViewMetadata } from '../entities/view-metadata.entity';
29
29
  import { CommandService } from '../helpers/command.service';
30
+ import { isEmbeddedDb } from '../helpers/environment.helper';
30
31
  import { startNodemonHeartbeat } from '../helpers/nodemon-heartbeat';
31
32
  import {
32
33
  REFRESH_MODEL_COMMAND,
@@ -968,7 +969,7 @@ export class ModelMetadataService {
968
969
  @DisallowInProduction()
969
970
  async generateCodeViaCtl(modelId: number): Promise<string> {
970
971
  const model = await this.findOne(modelId);
971
- const isEmbedded = process.env.DEFAULT_DATABASE_DRIVER === 'pglite';
972
+ const isEmbedded = isEmbeddedDb();
972
973
 
973
974
  // When using an embedded PGlite database, the single-connection limit means
974
975
  // a spawned `solid refresh-model` subprocess cannot get its own DB connection
@@ -26,6 +26,7 @@ import {
26
26
  } from '../helpers/schematic.service';
27
27
  import { CommandService } from '../helpers/command.service';
28
28
  import { SolidRegistry } from '../helpers/solid-registry';
29
+ import { isEmbeddedDb } from '../helpers/environment.helper';
29
30
  import { startNodemonHeartbeat } from '../helpers/nodemon-heartbeat';
30
31
  import { CodeGenerationOptions, ModuleMetadataConfiguration } from '../interfaces';
31
32
  import { CrudHelperService } from './crud-helper.service';
@@ -535,7 +536,7 @@ export class ModuleMetadataService {
535
536
  @DisallowInProduction()
536
537
  async generateCodeViaCtl(moduleId: number): Promise<string> {
537
538
  const module = await this.findOne(moduleId);
538
- const isEmbedded = process.env.DEFAULT_DATABASE_DRIVER === 'pglite';
539
+ const isEmbedded = isEmbeddedDb();
539
540
 
540
541
  // When using an embedded PGlite database, the single-connection limit means
541
542
  // a spawned `solid refresh-module` subprocess cannot get its own DB connection
@@ -4,6 +4,7 @@ import { lowerFirst } from 'src/helpers/string.helper';
4
4
  import { SolidRegistry } from 'src/helpers/solid-registry';
5
5
  import { DataSource, EntityMetadata, EntitySubscriberInterface, InsertEvent, RemoveEvent, UpdateEvent } from 'typeorm';
6
6
  import { AuditQueuePayload } from 'src/interfaces';
7
+ import { isEmbeddedDb } from 'src/helpers/environment.helper';
7
8
  import { RequestContextService } from 'src/services/request-context.service';
8
9
  import { PublisherFactory } from 'src/services/queues/publisher-factory.service';
9
10
  const AUDIT_BEFORE_SNAPSHOT = '__auditBeforeSnapshot';
@@ -88,7 +89,10 @@ export class AuditSubscriber implements EntitySubscriberInterface {
88
89
  */
89
90
  private async prepareManyToManyAuditUpdateSnapshot(event: UpdateEvent<any>, entityId: number | null, updatedColumnNames: string[]): Promise<{ before: any; after: any } | null> {
90
91
 
91
- const auditRelationFields = (await this.modelMetadataHelperService.loadFieldHierarchy(lowerFirst(event.metadata.name))).filter(field =>
92
+ // On embedded PGlite, pass the transaction's manager so the query runs
93
+ // on the active connection. On regular Postgres, use the default DataSource.
94
+ const mgr = isEmbeddedDb() ? event.manager : this.dataSource;
95
+ const auditRelationFields = (await this.modelMetadataHelperService.loadFieldHierarchy(lowerFirst(event.metadata.name), isEmbeddedDb() ? event.manager : undefined)).filter(field =>
92
96
  field.enableAuditTracking &&
93
97
  field.type === 'relation' &&
94
98
  field.relationType !== 'one-to-many'
@@ -106,7 +110,7 @@ export class AuditSubscriber implements EntitySubscriberInterface {
106
110
 
107
111
  const relationBefore = event.entity?.[AUDIT_BEFORE_SNAPSHOT] ?? null;
108
112
 
109
- const relationAfter = await event.manager.getRepository(event.metadata.target as any).findOne({
113
+ const relationAfter = await mgr.getRepository(event.metadata.target as any).findOne({
110
114
  where: { id: entityId } as any,
111
115
  relations: relations as any,
112
116
  });
@@ -151,7 +155,7 @@ export class AuditSubscriber implements EntitySubscriberInterface {
151
155
 
152
156
  if (batch.length === 0) return;
153
157
 
154
- if (this.shouldDeferAuditPublish()) {
158
+ if (isEmbeddedDb()) {
155
159
  setImmediate(() => void this.publishAuditBatch(batch));
156
160
  return;
157
161
  }
@@ -164,12 +168,6 @@ export class AuditSubscriber implements EntitySubscriberInterface {
164
168
  this.perTxn.delete(event.queryRunner);
165
169
  }
166
170
 
167
- private shouldDeferAuditPublish(): boolean {
168
- const driver = (process.env.DEFAULT_DATABASE_DRIVER ?? '').toLowerCase();
169
- const poolMax = Number(process.env.DEFAULT_DATABASE_POOL_MAX ?? 20);
170
- return driver === 'pglite' && Number.isFinite(poolMax) && poolMax <= 1;
171
- }
172
-
173
171
  private async publishAuditBatch(batch: AuditQueuePayload[]) {
174
172
  try {
175
173
  // allSettled: publish in parallel; a single failure does not block the rest.