@solidxai/core 0.1.11-beta.0 → 0.1.11-beta.2

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 (66) hide show
  1. package/CLAUDE.md +26 -0
  2. package/dist/controllers/service.controller.d.ts +1 -0
  3. package/dist/controllers/service.controller.d.ts.map +1 -1
  4. package/dist/controllers/service.controller.js +2 -2
  5. package/dist/controllers/service.controller.js.map +1 -1
  6. package/dist/helpers/field-crud-managers/IntFieldCrudManager.d.ts.map +1 -1
  7. package/dist/helpers/field-crud-managers/IntFieldCrudManager.js +4 -1
  8. package/dist/helpers/field-crud-managers/IntFieldCrudManager.js.map +1 -1
  9. package/dist/helpers/solid-registry.d.ts +2 -1
  10. package/dist/helpers/solid-registry.d.ts.map +1 -1
  11. package/dist/helpers/solid-registry.js.map +1 -1
  12. package/dist/repository/scheduled-job.repository.d.ts +3 -0
  13. package/dist/repository/scheduled-job.repository.d.ts.map +1 -1
  14. package/dist/repository/scheduled-job.repository.js +60 -0
  15. package/dist/repository/scheduled-job.repository.js.map +1 -1
  16. package/dist/seeders/module-metadata-seeder.service.d.ts +37 -2
  17. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  18. package/dist/seeders/module-metadata-seeder.service.js +1071 -232
  19. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  20. package/dist/seeders/seed-data/solid-core-metadata.json +7 -0
  21. package/dist/services/action-metadata.service.d.ts +7 -0
  22. package/dist/services/action-metadata.service.d.ts.map +1 -1
  23. package/dist/services/action-metadata.service.js +76 -3
  24. package/dist/services/action-metadata.service.js.map +1 -1
  25. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.d.ts.map +1 -1
  26. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js +6 -5
  27. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js.map +1 -1
  28. package/dist/services/locale.service.d.ts +14 -0
  29. package/dist/services/locale.service.d.ts.map +1 -1
  30. package/dist/services/locale.service.js +83 -0
  31. package/dist/services/locale.service.js.map +1 -1
  32. package/dist/services/role-metadata.service.d.ts +5 -0
  33. package/dist/services/role-metadata.service.d.ts.map +1 -1
  34. package/dist/services/role-metadata.service.js +95 -33
  35. package/dist/services/role-metadata.service.js.map +1 -1
  36. package/dist/services/view-metadata.service.d.ts +6 -0
  37. package/dist/services/view-metadata.service.d.ts.map +1 -1
  38. package/dist/services/view-metadata.service.js +70 -8
  39. package/dist/services/view-metadata.service.js.map +1 -1
  40. package/dist/subscribers/audit.subscriber.d.ts +2 -0
  41. package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
  42. package/dist/subscribers/audit.subscriber.js +25 -6
  43. package/dist/subscribers/audit.subscriber.js.map +1 -1
  44. package/dist/subscribers/computed-entity-field.subscriber.d.ts.map +1 -1
  45. package/dist/subscribers/computed-entity-field.subscriber.js +1 -0
  46. package/dist/subscribers/computed-entity-field.subscriber.js.map +1 -1
  47. package/dist/subscribers/created-by-updated-by.subscriber.d.ts.map +1 -1
  48. package/dist/subscribers/created-by-updated-by.subscriber.js.map +1 -1
  49. package/dist/subscribers/field-metadata.subscriber.d.ts.map +1 -1
  50. package/dist/subscribers/field-metadata.subscriber.js.map +1 -1
  51. package/package.json +1 -1
  52. package/src/controllers/service.controller.ts +3 -2
  53. package/src/helpers/field-crud-managers/IntFieldCrudManager.ts +4 -1
  54. package/src/helpers/solid-registry.ts +7 -1
  55. package/src/repository/scheduled-job.repository.ts +73 -0
  56. package/src/seeders/module-metadata-seeder.service.ts +1295 -264
  57. package/src/seeders/seed-data/solid-core-metadata.json +7 -0
  58. package/src/services/action-metadata.service.ts +87 -2
  59. package/src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts +10 -5
  60. package/src/services/locale.service.ts +111 -3
  61. package/src/services/role-metadata.service.ts +112 -49
  62. package/src/services/view-metadata.service.ts +83 -9
  63. package/src/subscribers/audit.subscriber.ts +34 -14
  64. package/src/subscribers/computed-entity-field.subscriber.ts +1 -0
  65. package/src/subscribers/created-by-updated-by.subscriber.ts +3 -0
  66. package/src/subscribers/field-metadata.subscriber.ts +3 -0
@@ -5244,6 +5244,13 @@
5244
5244
  }
5245
5245
  ]
5246
5246
  },
5247
+ "locales": [
5248
+ {
5249
+ "locale": "en",
5250
+ "displayName": "English",
5251
+ "isDefault": true
5252
+ }
5253
+ ],
5247
5254
  "permissions": [
5248
5255
  "mcp:invoke",
5249
5256
  "agent:invoke",
@@ -7,6 +7,13 @@ export declare class ActionMetadataService extends CRUDService<ActionMetadata> {
7
7
  readonly entityManager: EntityManager;
8
8
  readonly repo: ActionMetadataRepository;
9
9
  readonly moduleRef: ModuleRef;
10
+ private readonly logger;
11
+ private readonly comparableFields;
12
+ private readonly relationCompareFields;
13
+ private readonly jsonCompareFields;
14
+ private normalizeJsonFieldValue;
15
+ private getCanonicalJsonFieldString;
16
+ private hasChanges;
10
17
  constructor(entityManager: EntityManager, repo: ActionMetadataRepository, moduleRef: ModuleRef);
11
18
  findOneByUserKey(name: string, relations?: {}): Promise<ActionMetadata>;
12
19
  upsert(updateSolidActionDto: any): Promise<any>;
@@ -1 +1 @@
1
- {"version":3,"file":"action-metadata.service.d.ts","sourceRoot":"","sources":["../../src/services/action-metadata.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAGxC,OAAO,EAAE,wBAAwB,EAAE,MAAM,2CAA2C,CAAC;AACrF,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEpE,qBACa,qBAAsB,SAAQ,WAAW,CAAC,cAAc,CAAC;IAGlE,QAAQ,CAAC,aAAa,EAAE,aAAa;IAGrC,QAAQ,CAAC,IAAI,EAAE,wBAAwB;IACvC,QAAQ,CAAC,SAAS,EAAE,SAAS;gBAJpB,aAAa,EAAE,aAAa,EAG5B,IAAI,EAAE,wBAAwB,EAC9B,SAAS,EAAE,SAAS;IAMzB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,KAAK;IAU7C,MAAM,CAAC,oBAAoB,EAAE,GAAG;CAoBvC"}
1
+ {"version":3,"file":"action-metadata.service.d.ts","sourceRoot":"","sources":["../../src/services/action-metadata.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAGxC,OAAO,EAAE,wBAAwB,EAAE,MAAM,2CAA2C,CAAC;AACrF,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEpE,qBACa,qBAAsB,SAAQ,WAAW,CAAC,cAAc,CAAC;IA4ElE,QAAQ,CAAC,aAAa,EAAE,aAAa;IAGrC,QAAQ,CAAC,IAAI,EAAE,wBAAwB;IACvC,QAAQ,CAAC,SAAS,EAAE,SAAS;IA/E/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAYtB;IACX,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAwC;IAC9E,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAkC;IAEpE,OAAO,CAAC,uBAAuB;IAgC/B,OAAO,CAAC,2BAA2B;IAInC,OAAO,CAAC,UAAU;gBAsBP,aAAa,EAAE,aAAa,EAG5B,IAAI,EAAE,wBAAwB,EAC9B,SAAS,EAAE,SAAS;IAMzB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,KAAK;IAU7C,MAAM,CAAC,oBAAoB,EAAE,GAAG;CAgCvC"}
@@ -11,6 +11,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  var __param = (this && this.__param) || function (paramIndex, decorator) {
12
12
  return function (target, key) { decorator(target, key, paramIndex); }
13
13
  };
14
+ var ActionMetadataService_1;
14
15
  Object.defineProperty(exports, "__esModule", { value: true });
15
16
  exports.ActionMetadataService = void 0;
16
17
  const common_1 = require("@nestjs/common");
@@ -19,12 +20,74 @@ const typeorm_1 = require("@nestjs/typeorm");
19
20
  const crud_service_1 = require("./crud.service");
20
21
  const typeorm_2 = require("typeorm");
21
22
  const action_metadata_repository_1 = require("../repository/action-metadata.repository");
22
- let ActionMetadataService = class ActionMetadataService extends crud_service_1.CRUDService {
23
+ let ActionMetadataService = ActionMetadataService_1 = class ActionMetadataService extends crud_service_1.CRUDService {
24
+ normalizeJsonFieldValue(value) {
25
+ if (typeof value === 'string') {
26
+ const trimmedValue = value.trim();
27
+ if ((trimmedValue.startsWith('{') && trimmedValue.endsWith('}')) ||
28
+ (trimmedValue.startsWith('[') && trimmedValue.endsWith(']'))) {
29
+ try {
30
+ return this.normalizeJsonFieldValue(JSON.parse(trimmedValue));
31
+ }
32
+ catch {
33
+ return value;
34
+ }
35
+ }
36
+ return value;
37
+ }
38
+ if (Array.isArray(value)) {
39
+ return value.map((item) => this.normalizeJsonFieldValue(item));
40
+ }
41
+ if (value && typeof value === 'object') {
42
+ return Object.keys(value)
43
+ .sort()
44
+ .reduce((result, key) => {
45
+ result[key] = this.normalizeJsonFieldValue(value[key]);
46
+ return result;
47
+ }, {});
48
+ }
49
+ return value;
50
+ }
51
+ getCanonicalJsonFieldString(value) {
52
+ return JSON.stringify(this.normalizeJsonFieldValue(value) ?? null);
53
+ }
54
+ hasChanges(existingSolidAction, updateSolidActionDto) {
55
+ return this.comparableFields.some((key) => {
56
+ const value = updateSolidActionDto[key];
57
+ if (typeof value === 'undefined') {
58
+ return false;
59
+ }
60
+ if (this.relationCompareFields.has(key)) {
61
+ const relationValue = value;
62
+ return existingSolidAction[key]?.id !== relationValue?.id;
63
+ }
64
+ if (this.jsonCompareFields.has(key)) {
65
+ return this.getCanonicalJsonFieldString(existingSolidAction[key]) !== this.getCanonicalJsonFieldString(value);
66
+ }
67
+ return existingSolidAction[key] !== value;
68
+ });
69
+ }
23
70
  constructor(entityManager, repo, moduleRef) {
24
71
  super(entityManager, repo, 'actionMetadata', 'solid-core', moduleRef);
25
72
  this.entityManager = entityManager;
26
73
  this.repo = repo;
27
74
  this.moduleRef = moduleRef;
75
+ this.logger = new common_1.Logger(ActionMetadataService_1.name);
76
+ this.comparableFields = [
77
+ 'name',
78
+ 'displayName',
79
+ 'type',
80
+ 'domain',
81
+ 'context',
82
+ 'customComponent',
83
+ 'customIsModal',
84
+ 'serverEndpoint',
85
+ 'module',
86
+ 'model',
87
+ 'view',
88
+ ];
89
+ this.relationCompareFields = new Set(['module', 'model', 'view']);
90
+ this.jsonCompareFields = new Set(['domain', 'context']);
28
91
  }
29
92
  async findOneByUserKey(name, relations = {}) {
30
93
  const entity = await this.repo.findOne({
@@ -39,9 +102,19 @@ let ActionMetadataService = class ActionMetadataService extends crud_service_1.C
39
102
  const existingSolidAction = await this.repo.findOne({
40
103
  where: {
41
104
  name: updateSolidActionDto.name
42
- }
105
+ },
106
+ relations: {
107
+ module: true,
108
+ model: true,
109
+ view: true,
110
+ },
43
111
  });
44
112
  if (existingSolidAction) {
113
+ const hasChanges = this.hasChanges(existingSolidAction, updateSolidActionDto);
114
+ if (!hasChanges) {
115
+ this.logger.debug(`Skipping action upsert for ${updateSolidActionDto.name}; no changes detected.`);
116
+ return existingSolidAction;
117
+ }
45
118
  const updatedSolidActionDto = { ...existingSolidAction, ...updateSolidActionDto };
46
119
  return this.repo.save(updatedSolidActionDto);
47
120
  }
@@ -52,7 +125,7 @@ let ActionMetadataService = class ActionMetadataService extends crud_service_1.C
52
125
  }
53
126
  };
54
127
  exports.ActionMetadataService = ActionMetadataService;
55
- exports.ActionMetadataService = ActionMetadataService = __decorate([
128
+ exports.ActionMetadataService = ActionMetadataService = ActionMetadataService_1 = __decorate([
56
129
  (0, common_1.Injectable)(),
57
130
  __param(0, (0, typeorm_1.InjectEntityManager)()),
58
131
  __metadata("design:paramtypes", [typeorm_2.EntityManager,
@@ -1 +1 @@
1
- {"version":3,"file":"action-metadata.service.js","sourceRoot":"","sources":["../../src/services/action-metadata.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAA4C;AAC5C,uCAAyC;AACzC,6CAAsD;AACtD,iDAAwD;AACxD,qCAAwC;AAGxC,yFAAqF;AAI9E,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,0BAA2B;IACpE,YAEW,aAA4B,EAG5B,IAA8B,EAC9B,SAAoB;QAG7B,KAAK,CAAC,aAAa,EAAE,IAAI,EAAE,gBAAgB,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;QAP7D,kBAAa,GAAb,aAAa,CAAe;QAG5B,SAAI,GAAJ,IAAI,CAA0B;QAC9B,cAAS,GAAT,SAAS,CAAW;IAI/B,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,IAAY,EAAE,SAAS,GAAG,EAAE;QACjD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;YACrC,KAAK,EAAE;gBACL,IAAI,EAAE,IAAI;aACX;YACD,SAAS,EAAE,SAAS;SACrB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,oBAAyB;QAEpC,MAAM,mBAAmB,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;YAClD,KAAK,EAAE;gBACL,IAAI,EAAE,oBAAoB,CAAC,IAAI;aAChC;SACF,CAAC,CAAA;QAGF,IAAI,mBAAmB,EAAE,CAAC;YACxB,MAAM,qBAAqB,GAAG,EAAE,GAAG,mBAAmB,EAAE,GAAG,oBAAoB,EAAE,CAAC;YAClF,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAC/C,CAAC;aAEI,CAAC;YACJ,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;YAC9D,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;CAEF,CAAA;AA3CY,sDAAqB;gCAArB,qBAAqB;IADjC,IAAA,mBAAU,GAAE;IAGR,WAAA,IAAA,6BAAmB,GAAE,CAAA;qCACE,uBAAa;QAGtB,qDAAwB;QACnB,gBAAS;GAPpB,qBAAqB,CA2CjC","sourcesContent":["import { Injectable } from '@nestjs/common';\nimport { ModuleRef } from \"@nestjs/core\";\nimport { InjectEntityManager } from '@nestjs/typeorm';\nimport { CRUDService } from 'src/services/crud.service';\nimport { EntityManager } from 'typeorm';\n\n\nimport { ActionMetadataRepository } from 'src/repository/action-metadata.repository';\nimport { ActionMetadata } from '../entities/action-metadata.entity';\n\n@Injectable()\nexport class ActionMetadataService extends CRUDService<ActionMetadata> {\n constructor(\n @InjectEntityManager()\n readonly entityManager: EntityManager,\n // @InjectRepository(ActionMetadata, 'default')\n // readonly repo: Repository<ActionMetadata>,\n readonly repo: ActionMetadataRepository,\n readonly moduleRef: ModuleRef\n\n ) {\n super(entityManager, repo, 'actionMetadata', 'solid-core', moduleRef);\n }\n\n async findOneByUserKey(name: string, relations = {}) {\n const entity = await this.repo.findOne({\n where: {\n name: name,\n },\n relations: relations,\n });\n return entity;\n }\n\n async upsert(updateSolidActionDto: any) {\n // First check if module already exists using name\n const existingSolidAction = await this.repo.findOne({\n where: {\n name: updateSolidActionDto.name\n }\n })\n\n // if found\n if (existingSolidAction) {\n const updatedSolidActionDto = { ...existingSolidAction, ...updateSolidActionDto };\n return this.repo.save(updatedSolidActionDto);\n }\n // if not found - create new \n else {\n const moduleMetadata = this.repo.create(updateSolidActionDto);\n return this.repo.save(moduleMetadata);\n }\n }\n\n}\n"]}
1
+ {"version":3,"file":"action-metadata.service.js","sourceRoot":"","sources":["../../src/services/action-metadata.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, Logger } from '@nestjs/common';\nimport { ModuleRef } from \"@nestjs/core\";\nimport { InjectEntityManager } from '@nestjs/typeorm';\nimport { CRUDService } from 'src/services/crud.service';\nimport { EntityManager } from 'typeorm';\n\n\nimport { ActionMetadataRepository } from 'src/repository/action-metadata.repository';\nimport { ActionMetadata } from '../entities/action-metadata.entity';\n\n@Injectable()\nexport class ActionMetadataService extends CRUDService<ActionMetadata> {\n private readonly logger = new Logger(ActionMetadataService.name);\n private readonly comparableFields = [\n 'name',\n 'displayName',\n 'type',\n 'domain',\n 'context',\n 'customComponent',\n 'customIsModal',\n 'serverEndpoint',\n 'module',\n 'model',\n 'view',\n ] as const;\n private readonly relationCompareFields = new Set(['module', 'model', 'view']);\n private readonly jsonCompareFields = new Set(['domain', 'context']);\n\n private normalizeJsonFieldValue(value: any): any {\n if (typeof value === 'string') {\n const trimmedValue = value.trim();\n if (\n (trimmedValue.startsWith('{') && trimmedValue.endsWith('}')) ||\n (trimmedValue.startsWith('[') && trimmedValue.endsWith(']'))\n ) {\n try {\n return this.normalizeJsonFieldValue(JSON.parse(trimmedValue));\n } catch {\n return value;\n }\n }\n return value;\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => this.normalizeJsonFieldValue(item));\n }\n\n if (value && typeof value === 'object') {\n return Object.keys(value)\n .sort()\n .reduce((result, key) => {\n result[key] = this.normalizeJsonFieldValue(value[key]);\n return result;\n }, {} as Record<string, any>);\n }\n\n return value;\n }\n\n private getCanonicalJsonFieldString(value: any): string {\n return JSON.stringify(this.normalizeJsonFieldValue(value) ?? null);\n }\n\n private hasChanges(existingSolidAction: ActionMetadata, updateSolidActionDto: any): boolean {\n return this.comparableFields.some((key) => {\n const value = updateSolidActionDto[key];\n if (typeof value === 'undefined') {\n return false;\n }\n\n if (this.relationCompareFields.has(key)) {\n const relationValue = value as any;\n return (existingSolidAction as any)[key]?.id !== relationValue?.id;\n }\n\n if (this.jsonCompareFields.has(key)) {\n return this.getCanonicalJsonFieldString((existingSolidAction as any)[key]) !== this.getCanonicalJsonFieldString(value);\n }\n\n return (existingSolidAction as any)[key] !== value;\n });\n }\n\n constructor(\n @InjectEntityManager()\n readonly entityManager: EntityManager,\n // @InjectRepository(ActionMetadata, 'default')\n // readonly repo: Repository<ActionMetadata>,\n readonly repo: ActionMetadataRepository,\n readonly moduleRef: ModuleRef\n\n ) {\n super(entityManager, repo, 'actionMetadata', 'solid-core', moduleRef);\n }\n\n async findOneByUserKey(name: string, relations = {}) {\n const entity = await this.repo.findOne({\n where: {\n name: name,\n },\n relations: relations,\n });\n return entity;\n }\n\n async upsert(updateSolidActionDto: any) {\n // First check if module already exists using name\n const existingSolidAction = await this.repo.findOne({\n where: {\n name: updateSolidActionDto.name\n },\n relations: {\n module: true,\n model: true,\n view: true,\n },\n })\n\n // if found\n if (existingSolidAction) {\n const hasChanges = this.hasChanges(existingSolidAction, updateSolidActionDto);\n\n if (!hasChanges) {\n this.logger.debug(`Skipping action upsert for ${updateSolidActionDto.name}; no changes detected.`);\n return existingSolidAction;\n }\n\n const updatedSolidActionDto = { ...existingSolidAction, ...updateSolidActionDto };\n return this.repo.save(updatedSolidActionDto);\n }\n // if not found - create new \n else {\n const moduleMetadata = this.repo.create(updateSolidActionDto);\n return this.repo.save(moduleMetadata);\n }\n }\n\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"alpha-num-external-id-computed-field-provider.d.ts","sourceRoot":"","sources":["../../../../src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,8BAA8B,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,WAAW,yBAAyB;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,qBAEa,qCAAqC,CAAC,CAAC,SAAS,YAAY,CAAE,YAAW,8BAA8B,CAAC,CAAC,EAAE,yBAAyB,CAAC;IAG9I,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAAb,aAAa,EAAE,aAAa;IAG/C,IAAI,IAAI,MAAM;IAId,IAAI,IAAI,MAAM;IAIR,eAAe,CAAC,aAAa,EAAE,CAAC,EAAE,qBAAqB,EAAE,qBAAqB,CAAC,yBAAyB,CAAC;IAuB/G,OAAO,CAAC,kBAAkB;YASZ,kBAAkB;YASlB,wBAAwB;CAkBvC"}
1
+ {"version":3,"file":"alpha-num-external-id-computed-field-provider.d.ts","sourceRoot":"","sources":["../../../../src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,8BAA8B,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,WAAW,yBAAyB;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,qBAEa,qCAAqC,CAAC,CAAC,SAAS,YAAY,CAAE,YAAW,8BAA8B,CAAC,CAAC,EAAE,yBAAyB,CAAC;IAG9I,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAAb,aAAa,EAAE,aAAa;IAG/C,IAAI,IAAI,MAAM;IAId,IAAI,IAAI,MAAM;IAIR,eAAe,CAAC,aAAa,EAAE,CAAC,EAAE,qBAAqB,EAAE,qBAAqB,CAAC,yBAAyB,CAAC;IA4B/G,OAAO,CAAC,kBAAkB;YASZ,kBAAkB;YASlB,wBAAwB;CAkBvC"}
@@ -40,7 +40,8 @@ let AlphaNumExternalIdComputationProvider = class AlphaNumExternalIdComputationP
40
40
  resolvedPrefix = String(dynamicValue).trim().toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9\-]/g, '');
41
41
  }
42
42
  }
43
- const uniqueCode = await this.generateUniqueExternalId(resolvedPrefix, codeLength, computedFieldMetadata.fieldName, entityName);
43
+ const manager = eventContext?.manager ?? this.entityManager;
44
+ const uniqueCode = await this.generateUniqueExternalId(manager, resolvedPrefix, codeLength, computedFieldMetadata.fieldName, entityName);
44
45
  const finalExternalId = resolvedPrefix ? `${resolvedPrefix}-${uniqueCode}` : uniqueCode;
45
46
  triggerEntity[computedFieldMetadata.fieldName] = finalExternalId;
46
47
  }
@@ -52,18 +53,18 @@ let AlphaNumExternalIdComputationProvider = class AlphaNumExternalIdComputationP
52
53
  }
53
54
  return result;
54
55
  }
55
- async isExternalIdUnique(externalId, fieldName, entityName) {
56
- const count = await this.entityManager.count(entityName, {
56
+ async isExternalIdUnique(manager, externalId, fieldName, entityName) {
57
+ const count = await manager.count(entityName, {
57
58
  where: { [fieldName]: externalId },
58
59
  });
59
60
  return count === 0;
60
61
  }
61
- async generateUniqueExternalId(resolvedPrefix, codeLength, fieldName, entityName) {
62
+ async generateUniqueExternalId(manager, resolvedPrefix, codeLength, fieldName, entityName) {
62
63
  const maxAttempts = 10;
63
64
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
64
65
  const newId = this.generateRandomCode(codeLength);
65
66
  const fullId = resolvedPrefix ? `${resolvedPrefix}-${newId}` : newId;
66
- const isUnique = await this.isExternalIdUnique(fullId, fieldName, entityName);
67
+ const isUnique = await this.isExternalIdUnique(manager, fullId, fieldName, entityName);
67
68
  if (isUnique) {
68
69
  return newId;
69
70
  }
@@ -1 +1 @@
1
- {"version":3,"file":"alpha-num-external-id-computed-field-provider.js","sourceRoot":"","sources":["../../../../src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@nestjs/common';\nimport { InjectEntityManager } from '@nestjs/typeorm';\nimport { ComputedFieldProvider } from 'src/decorators/computed-field-provider.decorator';\nimport { CommonEntity } from 'src/entities/common.entity';\nimport { ComputedFieldMetadata } from 'src/helpers/solid-registry';\nimport { IEntityPreComputeFieldProvider } from 'src/interfaces';\nimport { EntityManager } from 'typeorm';\nimport { get } from \"lodash\";\nexport interface AlphaNumExternalIdContext {\n prefix?: string; // alias -> staticPrefix\n length?: number; // Optional: length of the unique code to generate, default is 5\n dynamicFieldPrefix?: string; // NEW: field name on the entity\n}\n\n@ComputedFieldProvider()\n@Injectable()\nexport class AlphaNumExternalIdComputationProvider<T extends CommonEntity> implements IEntityPreComputeFieldProvider<T, AlphaNumExternalIdContext> {\n constructor(\n @InjectEntityManager()\n private readonly entityManager: EntityManager\n ) { }\n\n name(): string {\n return this.constructor.name;\n }\n\n help(): string {\n return 'Provider used to compute external ID for a CommonEntity with support for static or dynamic prefix.';\n }\n\n async preComputeValue(triggerEntity: T, computedFieldMetadata: ComputedFieldMetadata<AlphaNumExternalIdContext>) {\n const { prefix, length, dynamicFieldPrefix } = computedFieldMetadata.computedFieldValueProviderCtxt;\n const eventContext = computedFieldMetadata.eventContext;\n const entityName = eventContext?.metadataName ?? eventContext.databaseEntity?.constructor?.name ?? '';\n\n const codeLength = length || 5;\n\n // Determine prefix\n let resolvedPrefix = prefix || '';\n\n if (dynamicFieldPrefix) {\n const dynamicValue = get(triggerEntity as any, dynamicFieldPrefix);\n if (dynamicValue) {\n resolvedPrefix = String(dynamicValue).trim().toLowerCase().replace(/\\s+/g, '-').replace(/[^a-z0-9\\-]/g, '');\n }\n }\n\n const uniqueCode = await this.generateUniqueExternalId(resolvedPrefix, codeLength, computedFieldMetadata.fieldName, entityName);\n const finalExternalId = resolvedPrefix ? `${resolvedPrefix}-${uniqueCode}` : uniqueCode;\n\n triggerEntity[computedFieldMetadata.fieldName] = finalExternalId;\n }\n\n private generateRandomCode(length = 5): string {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n let result = '';\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return result;\n }\n\n private async isExternalIdUnique(externalId: string, fieldName: string, entityName: string): Promise<boolean> {\n const count = await this.entityManager.count(entityName as any,\n {\n where: { [fieldName]: externalId },\n }\n );\n return count === 0;\n }\n\n private async generateUniqueExternalId(resolvedPrefix: string, codeLength: number, fieldName: string, entityName: string): Promise<string> {\n const maxAttempts = 10;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n\n const newId = this.generateRandomCode(codeLength);\n\n const fullId = resolvedPrefix ? `${resolvedPrefix}-${newId}` : newId;\n\n const isUnique = await this.isExternalIdUnique(fullId, fieldName, entityName);\n\n if (isUnique) {\n return newId;\n }\n }\n\n throw new Error('Failed to generate a unique external ID after multiple attempts');\n }\n}\n"]}
1
+ {"version":3,"file":"alpha-num-external-id-computed-field-provider.js","sourceRoot":"","sources":["../../../../src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@nestjs/common';\nimport { InjectEntityManager } from '@nestjs/typeorm';\nimport { ComputedFieldProvider } from 'src/decorators/computed-field-provider.decorator';\nimport { CommonEntity } from 'src/entities/common.entity';\nimport { ComputedFieldMetadata } from 'src/helpers/solid-registry';\nimport { IEntityPreComputeFieldProvider } from 'src/interfaces';\nimport { EntityManager } from 'typeorm';\nimport { get } from \"lodash\";\nexport interface AlphaNumExternalIdContext {\n prefix?: string; // alias -> staticPrefix\n length?: number; // Optional: length of the unique code to generate, default is 5\n dynamicFieldPrefix?: string; // NEW: field name on the entity\n}\n\n@ComputedFieldProvider()\n@Injectable()\nexport class AlphaNumExternalIdComputationProvider<T extends CommonEntity> implements IEntityPreComputeFieldProvider<T, AlphaNumExternalIdContext> {\n constructor(\n @InjectEntityManager()\n private readonly entityManager: EntityManager\n ) { }\n\n name(): string {\n return this.constructor.name;\n }\n\n help(): string {\n return 'Provider used to compute external ID for a CommonEntity with support for static or dynamic prefix.';\n }\n\n async preComputeValue(triggerEntity: T, computedFieldMetadata: ComputedFieldMetadata<AlphaNumExternalIdContext>) {\n const { prefix, length, dynamicFieldPrefix } = computedFieldMetadata.computedFieldValueProviderCtxt;\n const eventContext = computedFieldMetadata.eventContext;\n const entityName = eventContext?.metadataName ?? eventContext.databaseEntity?.constructor?.name ?? '';\n\n const codeLength = length || 5;\n\n // Determine prefix\n let resolvedPrefix = prefix || '';\n\n if (dynamicFieldPrefix) {\n const dynamicValue = get(triggerEntity as any, dynamicFieldPrefix);\n if (dynamicValue) {\n resolvedPrefix = String(dynamicValue).trim().toLowerCase().replace(/\\s+/g, '-').replace(/[^a-z0-9\\-]/g, '');\n }\n }\n\n // Use the originating transaction's EntityManager so the uniqueness check runs on the\n // active connection. Falls back to the injected manager only when no event context is\n // available (e.g. direct invocation outside a TypeORM lifecycle event).\n const manager = eventContext?.manager ?? this.entityManager;\n\n const uniqueCode = await this.generateUniqueExternalId(manager, resolvedPrefix, codeLength, computedFieldMetadata.fieldName, entityName);\n const finalExternalId = resolvedPrefix ? `${resolvedPrefix}-${uniqueCode}` : uniqueCode;\n\n triggerEntity[computedFieldMetadata.fieldName] = finalExternalId;\n }\n\n private generateRandomCode(length = 5): string {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n let result = '';\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return result;\n }\n\n private async isExternalIdUnique(manager: EntityManager, externalId: string, fieldName: string, entityName: string): Promise<boolean> {\n const count = await manager.count(entityName as any,\n {\n where: { [fieldName]: externalId },\n }\n );\n return count === 0;\n }\n\n private async generateUniqueExternalId(manager: EntityManager, resolvedPrefix: string, codeLength: number, fieldName: string, entityName: string): Promise<string> {\n const maxAttempts = 10;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n\n const newId = this.generateRandomCode(codeLength);\n\n const fullId = resolvedPrefix ? `${resolvedPrefix}-${newId}` : newId;\n\n const isUnique = await this.isExternalIdUnique(manager, fullId, fieldName, entityName);\n\n if (isUnique) {\n return newId;\n }\n }\n\n throw new Error('Failed to generate a unique external ID after multiple attempts');\n }\n}\n"]}
@@ -15,6 +15,20 @@ export declare class LocaleService extends CRUDService<Locale> implements OnAppl
15
15
  constructor(entityManager: EntityManager, repo: LocaleRepository, moduleRef: ModuleRef, requestContextService: RequestContextService, solidRegistry: SolidRegistry);
16
16
  private readonly logger;
17
17
  onApplicationBootstrap(): void;
18
+ private assertCanSetAsDefault;
19
+ create(createDto: any, files?: Express.Multer.File[], solidRequestContext?: any): Promise<Locale>;
20
+ insertMany(createDtos: any[], filesArray?: Express.Multer.File[][], solidRequestContext?: any): Promise<Locale[]>;
21
+ update(id: number, updateDto: any, files?: Express.Multer.File[], isPartialUpdate?: boolean, solidRequestContext?: any, isUpdate?: boolean): Promise<Locale>;
22
+ recover(id: number, solidRequestContext?: any): Promise<{
23
+ message: string;
24
+ data: Locale;
25
+ }>;
26
+ recoverMany(ids: number[], solidRequestContext?: any): Promise<{
27
+ message: string;
28
+ recoveredIds: number[];
29
+ }>;
30
+ delete(id: number, solidRequestContext?: any): Promise<Locale>;
31
+ deleteMany(ids: number[], solidRequestContext?: any): Promise<any>;
18
32
  loadLocales(): Promise<void>;
19
33
  }
20
34
  //# sourceMappingURL=locale.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"locale.service.d.ts","sourceRoot":"","sources":["../../src/services/locale.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,qBACa,aAAc,SAAQ,WAAW,CAAC,MAAM,CAAE,YAAW,sBAAsB;IAGpF,QAAQ,CAAC,aAAa,EAAE,aAAa;IAGrC,QAAQ,CAAC,IAAI,EAAE,gBAAgB;IAE/B,QAAQ,CAAC,SAAS,EAAE,SAAS;IAI7B,QAAQ,CAAC,qBAAqB,EAAE,qBAAqB;IACrD,QAAQ,CAAC,aAAa,EAAE,aAAa;gBAV5B,aAAa,EAAE,aAAa,EAG5B,IAAI,EAAE,gBAAgB,EAEtB,SAAS,EAAE,SAAS,EAIpB,qBAAqB,EAAE,qBAAqB,EAC5C,aAAa,EAAE,aAAa;IAIvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiC;IACxD,sBAAsB;IAIf,WAAW;CAKnB"}
1
+ {"version":3,"file":"locale.service.d.ts","sourceRoot":"","sources":["../../src/services/locale.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2C,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACjG,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAmB,MAAM,SAAS,CAAC;AAEzD,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,qBACa,aAAc,SAAQ,WAAW,CAAC,MAAM,CAAE,YAAW,sBAAsB;IAGpF,QAAQ,CAAC,aAAa,EAAE,aAAa;IAGrC,QAAQ,CAAC,IAAI,EAAE,gBAAgB;IAE/B,QAAQ,CAAC,SAAS,EAAE,SAAS;IAI7B,QAAQ,CAAC,qBAAqB,EAAE,qBAAqB;IACrD,QAAQ,CAAC,aAAa,EAAE,aAAa;gBAV5B,aAAa,EAAE,aAAa,EAG5B,IAAI,EAAE,gBAAgB,EAEtB,SAAS,EAAE,SAAS,EAIpB,qBAAqB,EAAE,qBAAqB,EAC5C,aAAa,EAAE,aAAa;IAIvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiC;IACxD,sBAAsB;YAKR,qBAAqB;IAkBpB,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,GAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAO,EAAE,mBAAmB,GAAE,GAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAUzG,UAAU,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE,UAAU,GAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAO,EAAE,mBAAmB,GAAE,GAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAgBzH,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,GAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAO,EAAE,eAAe,GAAE,OAAe,EAAE,mBAAmB,GAAE,GAAQ,EAAE,QAAQ,GAAE,OAAe,GAAG,OAAO,CAAC,MAAM,CAAC;IAUlL,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,mBAAmB,GAAE,GAAQ;;;;IAkBjD,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,mBAAmB,GAAE,GAAQ;;;;IAuBxD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,mBAAmB,GAAE,GAAQ;IAMhD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,mBAAmB,GAAE,GAAQ;IAMhE,WAAW;CAKlB"}
@@ -35,6 +35,89 @@ let LocaleService = LocaleService_1 = class LocaleService extends crud_service_1
35
35
  onApplicationBootstrap() {
36
36
  this.loadLocales();
37
37
  }
38
+ async assertCanSetAsDefault(currentLocaleId) {
39
+ const defaultLocales = await this.repo.find({
40
+ where: {
41
+ isDefault: true,
42
+ },
43
+ });
44
+ const conflictingDefaultLocale = defaultLocales.find((locale) => locale.id !== currentLocaleId);
45
+ if (conflictingDefaultLocale) {
46
+ throw new common_1.BadRequestException(`Locale "${conflictingDefaultLocale.displayName}" is already marked as default. Mark it as non-default first.`);
47
+ }
48
+ }
49
+ async create(createDto, files = [], solidRequestContext = {}) {
50
+ if (createDto?.isDefault === true) {
51
+ await this.assertCanSetAsDefault();
52
+ }
53
+ const savedLocale = await super.create(createDto, files, solidRequestContext);
54
+ await this.loadLocales();
55
+ return savedLocale;
56
+ }
57
+ async insertMany(createDtos, filesArray = [], solidRequestContext = {}) {
58
+ const defaultLocalesInPayload = (createDtos || []).filter((dto) => dto?.isDefault === true);
59
+ if (defaultLocalesInPayload.length > 1) {
60
+ throw new common_1.BadRequestException(`Only one locale can be marked as default.`);
61
+ }
62
+ if (defaultLocalesInPayload.length === 1) {
63
+ await this.assertCanSetAsDefault();
64
+ }
65
+ const savedLocales = await super.insertMany(createDtos, filesArray, solidRequestContext);
66
+ await this.loadLocales();
67
+ return savedLocales;
68
+ }
69
+ async update(id, updateDto, files = [], isPartialUpdate = false, solidRequestContext = {}, isUpdate = false) {
70
+ if (updateDto?.isDefault === true) {
71
+ await this.assertCanSetAsDefault(id);
72
+ }
73
+ const savedLocale = await super.update(id, updateDto, files, isPartialUpdate, solidRequestContext, isUpdate);
74
+ await this.loadLocales();
75
+ return savedLocale;
76
+ }
77
+ async recover(id, solidRequestContext = {}) {
78
+ const localeToRecover = await this.repo.findOne({
79
+ where: {
80
+ id,
81
+ deletedAt: (0, typeorm_2.Not)((0, typeorm_2.IsNull)()),
82
+ },
83
+ withDeleted: true,
84
+ });
85
+ if (localeToRecover?.isDefault) {
86
+ await this.assertCanSetAsDefault(id);
87
+ }
88
+ const recoveredLocale = await super.recover(id, solidRequestContext);
89
+ await this.loadLocales();
90
+ return recoveredLocale;
91
+ }
92
+ async recoverMany(ids, solidRequestContext = {}) {
93
+ const localesToRecover = await this.repo.find({
94
+ where: {
95
+ id: (0, typeorm_2.In)(ids),
96
+ deletedAt: (0, typeorm_2.Not)((0, typeorm_2.IsNull)()),
97
+ },
98
+ withDeleted: true,
99
+ });
100
+ const defaultLocalesToRecover = localesToRecover.filter((locale) => locale.isDefault);
101
+ if (defaultLocalesToRecover.length > 1) {
102
+ throw new common_1.BadRequestException(`Only one locale can be marked as default.`);
103
+ }
104
+ if (defaultLocalesToRecover.length === 1) {
105
+ await this.assertCanSetAsDefault(defaultLocalesToRecover[0].id);
106
+ }
107
+ const recoveredLocales = await super.recoverMany(ids, solidRequestContext);
108
+ await this.loadLocales();
109
+ return recoveredLocales;
110
+ }
111
+ async delete(id, solidRequestContext = {}) {
112
+ const deletedLocale = await super.delete(id, solidRequestContext);
113
+ await this.loadLocales();
114
+ return deletedLocale;
115
+ }
116
+ async deleteMany(ids, solidRequestContext = {}) {
117
+ const deletedLocales = await super.deleteMany(ids, solidRequestContext);
118
+ await this.loadLocales();
119
+ return deletedLocales;
120
+ }
38
121
  async loadLocales() {
39
122
  const locales = await this.repo.find();
40
123
  this.logger.debug(`Loaded ${locales.length} locales into registry`);
@@ -1 +1 @@
1
- {"version":3,"file":"locale.service.js","sourceRoot":"","sources":["../../src/services/locale.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAA4E;AAC5E,uCAAyC;AACzC,6CAAsD;AACtD,qCAAwC;AAGxC,8DAA2D;AAC3D,uEAAoE;AACpE,iDAAwD;AACxD,uEAAkE;AAE3D,IAAM,aAAa,qBAAnB,MAAM,aAAc,SAAQ,0BAAmB;IACpD,YAEE,aAAqC,EAG5B,IAAsB,EAEtB,SAAoB,EAIpB,qBAA4C,EAC5C,aAA4B;QAEtC,KAAK,CAAC,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;QAZpD,kBAAa,GAAb,aAAa,CAAe;QAG5B,SAAI,GAAJ,IAAI,CAAkB;QAEtB,cAAS,GAAT,SAAS,CAAW;QAIpB,0BAAqB,GAArB,qBAAqB,CAAuB;QAC5C,kBAAa,GAAb,aAAa,CAAe;QAItB,WAAM,GAAG,IAAI,eAAM,CAAC,eAAa,CAAC,IAAI,CAAC,CAAA;IADzD,CAAC;IAEA,sBAAsB;QAEpB,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IACA,KAAK,CAAC,WAAW;QAChB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACvC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,OAAO,CAAC,MAAM,wBAAwB,CAAC,CAAC;QACpE,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;CACF,CAAA;AA3BY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;IAGR,WAAA,IAAA,6BAAmB,GAAE,CAAA;qCACE,uBAAa;QAGtB,oCAAgB;QAEX,gBAAS;QAIG,+CAAqB;QAC7B,8BAAa;GAb5B,aAAa,CA2BzB","sourcesContent":["import { Injectable, Logger, OnApplicationBootstrap } from '@nestjs/common';\nimport { ModuleRef } from \"@nestjs/core\";\nimport { InjectEntityManager } from '@nestjs/typeorm';\nimport { EntityManager } from 'typeorm';\n\nimport { Locale } from 'src/entities/locale.entity';\nimport { SolidRegistry } from 'src/helpers/solid-registry';\nimport { LocaleRepository } from 'src/repository/locale.repository';\nimport { CRUDService } from 'src/services/crud.service';\nimport { RequestContextService } from './request-context.service';\n@Injectable()\nexport class LocaleService extends CRUDService<Locale> implements OnApplicationBootstrap{\n constructor(\n @InjectEntityManager()\n readonly entityManager: EntityManager,\n // @InjectRepository(Locale, 'default')\n // readonly repo: Repository<Locale>,\n readonly repo: LocaleRepository,\n // @InjectRepository(Locale, 'default')\n readonly moduleRef: ModuleRef,\n // @InjectRepository(ModelMetadata)\n // private readonly modelMetadataRepo: Repository<ModelMetadata>,\n // private readonly modelMetadataRepo: ModelMetadataRepository,\n readonly requestContextService: RequestContextService,\n readonly solidRegistry: SolidRegistry,\n ) {\n super(entityManager, repo, 'locale', 'solid-core', moduleRef);\n }\n private readonly logger = new Logger(LocaleService.name)\n onApplicationBootstrap() {\n // Load the security rules from the database\n this.loadLocales();\n }\n async loadLocales() {\n const locales = await this.repo.find();\n this.logger.debug(`Loaded ${locales.length} locales into registry`);\n this.solidRegistry.registerlocales(locales);\n }\n}\n"]}
1
+ {"version":3,"file":"locale.service.js","sourceRoot":"","sources":["../../src/services/locale.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { BadRequestException, Injectable, Logger, OnApplicationBootstrap } from '@nestjs/common';\nimport { ModuleRef } from \"@nestjs/core\";\nimport { InjectEntityManager } from '@nestjs/typeorm';\nimport { EntityManager, In, IsNull, Not } from 'typeorm';\n\nimport { Locale } from 'src/entities/locale.entity';\nimport { SolidRegistry } from 'src/helpers/solid-registry';\nimport { LocaleRepository } from 'src/repository/locale.repository';\nimport { CRUDService } from 'src/services/crud.service';\nimport { RequestContextService } from './request-context.service';\n@Injectable()\nexport class LocaleService extends CRUDService<Locale> implements OnApplicationBootstrap{\n constructor(\n @InjectEntityManager()\n readonly entityManager: EntityManager,\n // @InjectRepository(Locale, 'default')\n // readonly repo: Repository<Locale>,\n readonly repo: LocaleRepository,\n // @InjectRepository(Locale, 'default')\n readonly moduleRef: ModuleRef,\n // @InjectRepository(ModelMetadata)\n // private readonly modelMetadataRepo: Repository<ModelMetadata>,\n // private readonly modelMetadataRepo: ModelMetadataRepository,\n readonly requestContextService: RequestContextService,\n readonly solidRegistry: SolidRegistry,\n ) {\n super(entityManager, repo, 'locale', 'solid-core', moduleRef);\n }\n private readonly logger = new Logger(LocaleService.name)\n onApplicationBootstrap() {\n // Load the security rules from the database\n this.loadLocales();\n }\n\n private async assertCanSetAsDefault(currentLocaleId?: number) {\n const defaultLocales = await this.repo.find({\n where: {\n isDefault: true,\n } as any,\n });\n\n const conflictingDefaultLocale = defaultLocales.find(\n (locale) => locale.id !== currentLocaleId\n );\n\n if (conflictingDefaultLocale) {\n throw new BadRequestException(\n `Locale \"${conflictingDefaultLocale.displayName}\" is already marked as default. Mark it as non-default first.`\n );\n }\n }\n\n override async create(createDto: any, files: Express.Multer.File[] = [], solidRequestContext: any = {}): Promise<Locale> {\n if (createDto?.isDefault === true) {\n await this.assertCanSetAsDefault();\n }\n\n const savedLocale = await super.create(createDto, files, solidRequestContext);\n await this.loadLocales();\n return savedLocale;\n }\n\n override async insertMany(createDtos: any[], filesArray: Express.Multer.File[][] = [], solidRequestContext: any = {}): Promise<Locale[]> {\n const defaultLocalesInPayload = (createDtos || []).filter((dto) => dto?.isDefault === true);\n\n if (defaultLocalesInPayload.length > 1) {\n throw new BadRequestException(`Only one locale can be marked as default.`);\n }\n\n if (defaultLocalesInPayload.length === 1) {\n await this.assertCanSetAsDefault();\n }\n\n const savedLocales = await super.insertMany(createDtos, filesArray, solidRequestContext);\n await this.loadLocales();\n return savedLocales;\n }\n\n override async update(id: number, updateDto: any, files: Express.Multer.File[] = [], isPartialUpdate: boolean = false, solidRequestContext: any = {}, isUpdate: boolean = false): Promise<Locale> {\n if (updateDto?.isDefault === true) {\n await this.assertCanSetAsDefault(id);\n }\n\n const savedLocale = await super.update(id, updateDto, files, isPartialUpdate, solidRequestContext, isUpdate);\n await this.loadLocales();\n return savedLocale;\n }\n\n override async recover(id: number, solidRequestContext: any = {}) {\n const localeToRecover = await this.repo.findOne({\n where: {\n id,\n deletedAt: Not(IsNull()),\n } as any,\n withDeleted: true,\n });\n\n if (localeToRecover?.isDefault) {\n await this.assertCanSetAsDefault(id);\n }\n\n const recoveredLocale = await super.recover(id, solidRequestContext);\n await this.loadLocales();\n return recoveredLocale;\n }\n\n override async recoverMany(ids: number[], solidRequestContext: any = {}) {\n const localesToRecover = await this.repo.find({\n where: {\n id: In(ids),\n deletedAt: Not(IsNull()),\n } as any,\n withDeleted: true,\n });\n\n const defaultLocalesToRecover = localesToRecover.filter((locale) => locale.isDefault);\n if (defaultLocalesToRecover.length > 1) {\n throw new BadRequestException(`Only one locale can be marked as default.`);\n }\n\n if (defaultLocalesToRecover.length === 1) {\n await this.assertCanSetAsDefault(defaultLocalesToRecover[0].id);\n }\n\n const recoveredLocales = await super.recoverMany(ids, solidRequestContext);\n await this.loadLocales();\n return recoveredLocales;\n }\n\n override async delete(id: number, solidRequestContext: any = {}) {\n const deletedLocale = await super.delete(id, solidRequestContext);\n await this.loadLocales();\n return deletedLocale;\n }\n\n override async deleteMany(ids: number[], solidRequestContext: any = {}) {\n const deletedLocales = await super.deleteMany(ids, solidRequestContext);\n await this.loadLocales();\n return deletedLocales;\n }\n\n async loadLocales() {\n const locales = await this.repo.find();\n this.logger.debug(`Loaded ${locales.length} locales into registry`);\n this.solidRegistry.registerlocales(locales);\n }\n}\n"]}
@@ -11,15 +11,20 @@ export declare class RoleMetadataService extends CRUDService<RoleMetadata> {
11
11
  readonly permissionRepository: PermissionMetadataRepository;
12
12
  readonly moduleRef: ModuleRef;
13
13
  private readonly logger;
14
+ private readonly permissionAssignmentBatchSize;
14
15
  constructor(entityManager: EntityManager, repo: RoleMetadataRepository, permissionRepository: PermissionMetadataRepository, moduleRef: ModuleRef);
15
16
  findRoleByName(roleName: string): Promise<RoleMetadata>;
16
17
  assertRoleExistsByName(roleName: string): Promise<void>;
17
18
  createRolesIfNotExists(roles: CreateRoleMetadataDto[]): Promise<void>;
19
+ private resolveRoleModule;
18
20
  addAllPermissionsToRole(roleName: string): Promise<RoleMetadata>;
19
21
  addPermissionsToRole(roleName: string, permissionNames: string[]): Promise<RoleMetadata>;
20
22
  addPermissionToRole(roleName: string, permissionName: string[]): Promise<RoleMetadata>;
21
23
  private _addPermissionsToRole;
22
24
  removePermissionsFromRole(roleName: string, permissionNames: string[]): Promise<RoleMetadata>;
23
25
  private preloadPermissionByName;
26
+ private loadTargetPermissions;
27
+ private getRolePermissionJoinInfo;
28
+ private insertRolePermissionMappings;
24
29
  }
25
30
  //# sourceMappingURL=role-metadata.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"role-metadata.service.d.ts","sourceRoot":"","sources":["../../src/services/role-metadata.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAM,MAAM,SAAS,CAAC;AAG5C,OAAO,EAAE,4BAA4B,EAAE,MAAM,+CAA+C,CAAC;AAC7F,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAEzE,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAEhE,qBACa,mBAAoB,SAAQ,WAAW,CAAC,YAAY,CAAC;IAK9D,QAAQ,CAAC,aAAa,EAAE,aAAa;IAGrC,QAAQ,CAAC,IAAI,EAAE,sBAAsB;IAGrC,QAAQ,CAAC,oBAAoB,EAAE,4BAA4B;IAC3D,QAAQ,CAAC,SAAS,EAAE,SAAS;IAX/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwC;gBAIpD,aAAa,EAAE,aAAa,EAG5B,IAAI,EAAE,sBAAsB,EAG5B,oBAAoB,EAAE,4BAA4B,EAClD,SAAS,EAAE,SAAS;IAMzB,cAAc,CAAC,QAAQ,EAAE,MAAM;IAe/B,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAevD,sBAAsB,CAAC,KAAK,EAAE,qBAAqB,EAAE;IAmDrD,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAIhE,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC;IAIxF,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE;YAItD,qBAAqB;IAiE7B,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC;YAsBrF,uBAAuB;CAWtC"}
1
+ {"version":3,"file":"role-metadata.service.d.ts","sourceRoot":"","sources":["../../src/services/role-metadata.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAM,MAAM,SAAS,CAAC;AAG5C,OAAO,EAAE,4BAA4B,EAAE,MAAM,+CAA+C,CAAC;AAC7F,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAGzE,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAEhE,qBACa,mBAAoB,SAAQ,WAAW,CAAC,YAAY,CAAC;IAM9D,QAAQ,CAAC,aAAa,EAAE,aAAa;IAGrC,QAAQ,CAAC,IAAI,EAAE,sBAAsB;IAGrC,QAAQ,CAAC,oBAAoB,EAAE,4BAA4B;IAC3D,QAAQ,CAAC,SAAS,EAAE,SAAS;IAZ/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwC;IAC/D,OAAO,CAAC,QAAQ,CAAC,6BAA6B,CAAO;gBAI1C,aAAa,EAAE,aAAa,EAG5B,IAAI,EAAE,sBAAsB,EAG5B,oBAAoB,EAAE,4BAA4B,EAClD,SAAS,EAAE,SAAS;IAMzB,cAAc,CAAC,QAAQ,EAAE,MAAM;IAe/B,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAevD,sBAAsB,CAAC,KAAK,EAAE,qBAAqB,EAAE;YA0D7C,iBAAiB;IAgBzB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAIhE,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC;IAIxF,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE;YAItD,qBAAqB;IA8C7B,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC;YAsBrF,uBAAuB;YAUvB,qBAAqB;IAiBnC,OAAO,CAAC,yBAAyB;YAmBnB,4BAA4B;CAsB3C"}
@@ -22,6 +22,7 @@ const typeorm_2 = require("typeorm");
22
22
  const error_messages_1 = require("../constants/error-messages");
23
23
  const permission_metadata_repository_1 = require("../repository/permission-metadata.repository");
24
24
  const role_metadata_repository_1 = require("../repository/role-metadata.repository");
25
+ const module_metadata_entity_1 = require("../entities/module-metadata.entity");
25
26
  let RoleMetadataService = RoleMetadataService_1 = class RoleMetadataService extends crud_service_1.CRUDService {
26
27
  constructor(entityManager, repo, permissionRepository, moduleRef) {
27
28
  super(entityManager, repo, 'roleMetadata', 'solid-core', moduleRef);
@@ -30,6 +31,7 @@ let RoleMetadataService = RoleMetadataService_1 = class RoleMetadataService exte
30
31
  this.permissionRepository = permissionRepository;
31
32
  this.moduleRef = moduleRef;
32
33
  this.logger = new common_1.Logger(RoleMetadataService_1.name);
34
+ this.permissionAssignmentBatchSize = 500;
33
35
  }
34
36
  async findRoleByName(roleName) {
35
37
  const entity = await this.repo.findOne({
@@ -62,11 +64,14 @@ let RoleMetadataService = RoleMetadataService_1 = class RoleMetadataService exte
62
64
  for (let id = 0; id < roles.length; id++) {
63
65
  try {
64
66
  const roleObj = roles[id];
67
+ const module = await this.resolveRoleModule(roleObj);
65
68
  const existingRole = await this.repo.findOne({
66
69
  where: {
67
70
  name: roleObj.name,
68
71
  },
69
- relations: {},
72
+ relations: {
73
+ module: true,
74
+ },
70
75
  });
71
76
  if (!existingRole) {
72
77
  this.logger.debug(`Role ${roleObj.name} does not exist, hence creating`);
@@ -74,10 +79,14 @@ let RoleMetadataService = RoleMetadataService_1 = class RoleMetadataService exte
74
79
  if (roleObj.permissions && roleObj.permissions.length > 0) {
75
80
  await Promise.all(roleObj.permissions.map(permission => this.preloadPermissionByName(permission.name)));
76
81
  }
77
- const role = this.repo.create({ ...roleObj });
82
+ const role = this.repo.create({ ...roleObj, ...(module ? { module } : {}) });
78
83
  await this.repo.save(role);
79
84
  }
80
85
  else {
86
+ if (module && existingRole.module?.id !== module.id) {
87
+ existingRole.module = module;
88
+ await this.repo.save(existingRole);
89
+ }
81
90
  }
82
91
  }
83
92
  catch (error) {
@@ -85,6 +94,19 @@ let RoleMetadataService = RoleMetadataService_1 = class RoleMetadataService exte
85
94
  }
86
95
  }
87
96
  }
97
+ async resolveRoleModule(roleObj) {
98
+ if (roleObj.moduleId) {
99
+ return await this.entityManager.getRepository(module_metadata_entity_1.ModuleMetadata).findOne({
100
+ where: { id: roleObj.moduleId },
101
+ });
102
+ }
103
+ if (roleObj.moduleUserKey) {
104
+ return await this.entityManager.getRepository(module_metadata_entity_1.ModuleMetadata).findOne({
105
+ where: { name: roleObj.moduleUserKey },
106
+ });
107
+ }
108
+ return null;
109
+ }
88
110
  async addAllPermissionsToRole(roleName) {
89
111
  return await this._addPermissionsToRole(roleName, null);
90
112
  }
@@ -97,46 +119,41 @@ let RoleMetadataService = RoleMetadataService_1 = class RoleMetadataService exte
97
119
  async _addPermissionsToRole(roleName, permissionNames) {
98
120
  const role = await this.repo.findOne({
99
121
  where: { name: roleName },
100
- relations: {
101
- permissions: true
122
+ select: {
123
+ id: true,
124
+ name: true,
102
125
  }
103
126
  });
104
127
  if (!role) {
105
128
  throw new Error(`Role '${roleName}' not found.`);
106
129
  }
107
- let newPermissions;
108
- if (permissionNames && permissionNames.length != 0) {
109
- newPermissions = await this.permissionRepository.find({ where: { name: (0, typeorm_2.In)(permissionNames) } });
110
- if (newPermissions.length !== permissionNames.length) {
111
- throw new Error(`One or more permissions not found.`);
112
- }
130
+ const joinInfo = this.getRolePermissionJoinInfo();
131
+ const targetPermissions = await this.loadTargetPermissions(permissionNames);
132
+ if (!permissionNames || permissionNames.length === 0) {
133
+ await this.entityManager
134
+ .createQueryBuilder()
135
+ .delete()
136
+ .from(joinInfo.tableName)
137
+ .where(`${joinInfo.roleIdColumn} = :roleId`, { roleId: role.id })
138
+ .execute();
139
+ await this.insertRolePermissionMappings(role.id, targetPermissions.map((permission) => permission.id), joinInfo);
113
140
  }
114
141
  else {
115
- newPermissions = await this.permissionRepository.find();
116
- if (newPermissions.length == 0) {
117
- throw new Error(`No permissions configured in the system. Did you forget to run the PermissionSeederService?`);
118
- }
119
- }
120
- if (role.permissions && role.permissions.length > 0) {
121
- for (let i = 0; i < newPermissions.length; i++) {
122
- const newPermission = newPermissions[i];
123
- let newPermissionFound = true;
124
- for (let j = 0; j < role.permissions.length; j++) {
125
- const existingPermission = role.permissions[j];
126
- if (existingPermission.name === newPermission.name) {
127
- newPermissionFound = false;
128
- break;
129
- }
130
- }
131
- if (newPermissionFound) {
132
- role.permissions.push(newPermission);
133
- }
142
+ const existingRows = await this.entityManager
143
+ .createQueryBuilder()
144
+ .select(joinInfo.permissionIdColumn, 'permissionId')
145
+ .from(joinInfo.tableName, 'role_permission')
146
+ .where(`${joinInfo.roleIdColumn} = :roleId`, { roleId: role.id })
147
+ .getRawMany();
148
+ const existingPermissionIds = new Set(existingRows.map((row) => Number(row.permissionId)));
149
+ const missingPermissionIds = targetPermissions
150
+ .map((permission) => permission.id)
151
+ .filter((permissionId) => !existingPermissionIds.has(permissionId));
152
+ if (missingPermissionIds.length > 0) {
153
+ await this.insertRolePermissionMappings(role.id, missingPermissionIds, joinInfo);
134
154
  }
135
155
  }
136
- else {
137
- role.permissions = newPermissions;
138
- }
139
- return await this.repo.save(role);
156
+ return await this.findRoleByName(roleName);
140
157
  }
141
158
  async removePermissionsFromRole(roleName, permissionNames) {
142
159
  const role = await this.repo.findOne({
@@ -162,6 +179,51 @@ let RoleMetadataService = RoleMetadataService_1 = class RoleMetadataService exte
162
179
  }
163
180
  return existingPermission;
164
181
  }
182
+ async loadTargetPermissions(permissionNames) {
183
+ if (permissionNames && permissionNames.length !== 0) {
184
+ const uniquePermissionNames = [...new Set(permissionNames)];
185
+ const permissions = await this.permissionRepository.find({ where: { name: (0, typeorm_2.In)(uniquePermissionNames) } });
186
+ if (permissions.length !== uniquePermissionNames.length) {
187
+ throw new Error(`One or more permissions not found.`);
188
+ }
189
+ return permissions;
190
+ }
191
+ const permissions = await this.permissionRepository.find();
192
+ if (permissions.length === 0) {
193
+ throw new Error(`No permissions configured in the system. Did you forget to run the PermissionSeederService?`);
194
+ }
195
+ return permissions;
196
+ }
197
+ getRolePermissionJoinInfo() {
198
+ const relation = this.repo.metadata.relations.find((candidate) => candidate.propertyName === 'permissions');
199
+ if (!relation?.junctionEntityMetadata) {
200
+ throw new Error('Role-permission join table metadata not found.');
201
+ }
202
+ const roleIdColumn = relation.joinColumns[0]?.databaseName;
203
+ const permissionIdColumn = relation.inverseJoinColumns[0]?.databaseName;
204
+ if (!roleIdColumn || !permissionIdColumn) {
205
+ throw new Error('Role-permission join table column metadata not found.');
206
+ }
207
+ return {
208
+ tableName: relation.junctionEntityMetadata.tableName,
209
+ roleIdColumn,
210
+ permissionIdColumn,
211
+ };
212
+ }
213
+ async insertRolePermissionMappings(roleId, permissionIds, joinInfo) {
214
+ for (let index = 0; index < permissionIds.length; index += this.permissionAssignmentBatchSize) {
215
+ const batch = permissionIds.slice(index, index + this.permissionAssignmentBatchSize);
216
+ await this.entityManager
217
+ .createQueryBuilder()
218
+ .insert()
219
+ .into(joinInfo.tableName)
220
+ .values(batch.map((permissionId) => ({
221
+ [joinInfo.roleIdColumn]: roleId,
222
+ [joinInfo.permissionIdColumn]: permissionId,
223
+ })))
224
+ .execute();
225
+ }
226
+ }
165
227
  };
166
228
  exports.RoleMetadataService = RoleMetadataService;
167
229
  exports.RoleMetadataService = RoleMetadataService = RoleMetadataService_1 = __decorate([