rez_core 4.0.291 → 4.0.292

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rez_core",
3
- "version": "4.0.291",
3
+ "version": "4.0.292",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "private": false,
@@ -6,11 +6,12 @@ import { EntityJSONController } from './controller/entity_json.controller';
6
6
  import { FilterModule } from '../filter/filter.module';
7
7
  import { UtilsModule } from 'src/utils/utils.module';
8
8
  import { EntityJson } from './entity/entityJson.entity';
9
+ import { EntityJSONRepository } from './service/entityJson.repository';
9
10
 
10
11
  @Module({
11
12
  imports: [EntityModule, TypeOrmModule.forFeature([EntityJson]),FilterModule,UtilsModule],
12
13
  controllers: [EntityJSONController],
13
- providers: [EntityJSONService],
14
+ providers: [EntityJSONService,EntityJSONRepository],
14
15
  exports: [],
15
16
  })
16
17
  export class EntityJSONModule {}
@@ -0,0 +1,37 @@
1
+ import { Injectable } from "@nestjs/common";
2
+ import { InjectRepository } from "@nestjs/typeorm";
3
+ import { Repository } from "typeorm";
4
+ import { EntityJson } from "../entity/entityJson.entity";
5
+ import { create } from "domain";
6
+
7
+
8
+ @Injectable()
9
+ export class EntityJSONRepository {
10
+ constructor(
11
+ @InjectRepository(EntityJson)
12
+ private readonly entityJSONRepository: Repository<EntityJson>,
13
+ ) {}
14
+
15
+ async create(flatJson: Partial<EntityJson>) {
16
+ const { entity_type, entity_id } = flatJson;
17
+
18
+ // Step 1 — check if exists by unique keys
19
+ const existing = await this.entityJSONRepository.findOne({
20
+ where: { entity_type, entity_id },
21
+ });
22
+
23
+ if (existing) {
24
+ // Step 2 — normal update (no merge)
25
+ await this.entityJSONRepository.update(existing.id, flatJson);
26
+
27
+ // Optionally return updated row (common practice)
28
+ return this.entityJSONRepository.findOne({
29
+ where: { id: existing.id },
30
+ });
31
+ }
32
+
33
+ // Step 3 — insert new
34
+ const created = this.entityJSONRepository.create(flatJson);
35
+ return this.entityJSONRepository.save(created);
36
+ }
37
+ }
@@ -6,13 +6,15 @@ import { EntityRelation } from 'src/module/meta/entity/entity-relation.entity';
6
6
  import { EntityServiceImpl } from 'src/module/meta/service/entity-service-impl.service';
7
7
  import { LoggingService } from 'src/utils/service/loggingUtil.service';
8
8
  import { DataSource } from 'typeorm';
9
+ import { EntityJSONRepository } from './entityJson.repository';
9
10
 
10
11
  @Injectable()
11
12
  export class EntityJSONService extends EntityServiceImpl {
12
13
  constructor(
13
14
  private readonly dataSource: DataSource,
14
15
  private readonly filterService: FilterService,
15
- private readonly loggerService: LoggingService, // <-- inject logging service
16
+ private readonly loggerService: LoggingService,
17
+ private readonly EntityJSONRepository:EntityJSONRepository
16
18
  ) {
17
19
  super();
18
20
  }
@@ -23,27 +25,18 @@ export class EntityJSONService extends EntityServiceImpl {
23
25
  flag?: 'flat_json' | 'dropdown' | 'all',
24
26
  ) {
25
27
  const orgId = loggedInUser.organization_id;
26
- await this.loggerService.log(
27
- 'info',
28
- 'EntityJSONService',
29
- 'getAttributeForFlatJSON',
30
- `Loading attributes for entity: ${entityType}, org: ${orgId}`,
31
- );
28
+
29
+ await this.loggerService.log('info', 'EntityJSONService', 'getAttributeForFlatJSON', `Loading attributes for entity: ${entityType}, org: ${orgId}`);
32
30
 
33
31
  const mainAttributes = await this.dataSource
34
32
  .getRepository(AttributeMaster)
35
33
  .createQueryBuilder('attr')
36
- .select(['attr.id', 'attr.name', 'attr.flat_json_key','attr.attribute_key'])
34
+ .select(['attr.id', 'attr.name', 'attr.flat_json_key', 'attr.attribute_key'])
37
35
  .where('attr.mapped_entity_type = :entityType', { entityType })
38
36
  .andWhere('attr.organization_id = :orgId', { orgId })
39
37
  .getMany();
40
38
 
41
- await this.loggerService.log(
42
- 'debug',
43
- 'EntityJSONService',
44
- 'getAttributeForFlatJSON',
45
- `Loaded ${mainAttributes.length} main attributes`,
46
- );
39
+ await this.loggerService.log('debug', 'EntityJSONService', 'getAttributeForFlatJSON', `Loaded ${mainAttributes.length} main attributes`);
47
40
 
48
41
  const relatedEntityTypes = await this.dataSource
49
42
  .getRepository(EntityRelation)
@@ -51,44 +44,24 @@ export class EntityJSONService extends EntityServiceImpl {
51
44
  .select(['rel.target_entity_type'])
52
45
  .where('rel.source_entity_type = :entityType', { entityType })
53
46
  .andWhere('rel.organization_id = :orgId', { orgId })
54
- .andWhere('rel.relation_type = :relationType', {
55
- relationType: 'ONE_TO_ONE',
56
- })
47
+ .andWhere('rel.relation_type = :relationType', { relationType: 'ONE_TO_ONE' })
57
48
  .getRawMany();
58
49
 
59
- const relatedTypesList = relatedEntityTypes.map(
60
- (x) => x.rel_target_entity_type,
61
- );
62
- await this.loggerService.log(
63
- 'debug',
64
- 'EntityJSONService',
65
- 'getAttributeForFlatJSON',
66
- `Found ${relatedTypesList.length} ONE-TO-ONE related entity types`,
67
- );
50
+ const relatedTypesList = relatedEntityTypes.map(x => x.rel_target_entity_type);
51
+
52
+ await this.loggerService.log('debug', 'EntityJSONService', 'getAttributeForFlatJSON', `Found ${relatedTypesList.length} ONE-TO-ONE related entity types`);
68
53
 
69
54
  const relatedAttributes = relatedTypesList.length
70
55
  ? await this.dataSource
71
56
  .getRepository(AttributeMaster)
72
57
  .createQueryBuilder('attr')
73
- .select([
74
- 'attr.id',
75
- 'attr.name',
76
- 'attr.flat_json_key',
77
- 'attr.mapped_entity_type',
78
- 'attr.attribute_key',
79
- ])
80
- .where('attr.mapped_entity_type IN (:...types)', {
81
- types: relatedTypesList,
82
- })
58
+ .select(['attr.id', 'attr.name', 'attr.flat_json_key', 'attr.mapped_entity_type', 'attr.attribute_key'])
59
+ .where('attr.mapped_entity_type IN (:...types)', { types: relatedTypesList })
83
60
  .andWhere('attr.organization_id = :orgId', { orgId })
84
61
  .getMany()
85
62
  : [];
86
- await this.loggerService.log(
87
- 'debug',
88
- 'EntityJSONService',
89
- 'getAttributeForFlatJSON',
90
- `Loaded ${relatedAttributes.length} related attributes`,
91
- );
63
+
64
+ await this.loggerService.log('debug', 'EntityJSONService', 'getAttributeForFlatJSON', `Loaded ${relatedAttributes.length} related attributes`);
92
65
 
93
66
  const linkedAttributes = await this.dataSource
94
67
  .getRepository(LinkedAttributes)
@@ -99,103 +72,67 @@ export class EntityJSONService extends EntityServiceImpl {
99
72
  'fla.applicable_entity_type = attr.mapped_entity_type AND fla.applicable_attribute_key = attr.attribute_key',
100
73
  )
101
74
  .select([
102
- 'fla.applicable_entity_type',
103
- 'attr.id',
104
- 'attr.name',
105
- 'attr.attribute_key',
75
+ 'fla.applicable_entity_type AS applicable_entity_type',
76
+ 'fla.applicable_attribute_key AS applicable_attribute_key',
77
+ 'fla.attribute_key AS target_attribute_key',
78
+ 'fla.saved_filter_code AS saved_filter_code',
79
+ 'attr.name AS name',
80
+ 'attr.id AS id',
106
81
  ])
107
82
  .where('attr.organization_id = :orgId', { orgId })
108
83
  .getRawMany();
109
- await this.loggerService.log(
110
- 'debug',
111
- 'EntityJSONService',
112
- 'getAttributeForFlatJSON',
113
- `Loaded ${linkedAttributes.length} linked attributes`,
114
- );
84
+
85
+ await this.loggerService.log('debug', 'EntityJSONService', 'getAttributeForFlatJSON', `Loaded ${linkedAttributes.length} linked attributes`);
115
86
 
116
87
  if (flag === 'flat_json' || flag === 'all') {
117
88
  const result: Record<string, null> = {};
118
- mainAttributes.forEach((attr) => {
119
- if (attr.flat_json_key) result[attr.flat_json_key] = null;
120
- });
121
- relatedAttributes.forEach((attr) => {
122
- if (attr.flat_json_key) result[attr.flat_json_key] = null;
123
- });
124
- linkedAttributes.forEach((link) => {
125
- if (link.applicable_attribute_key)
126
- result[link.applicable_attribute_key] = null;
127
- });
128
- if(flag === 'all')
129
- return {flat_json: result,attributes: {mainAttributes,relatedAttributes,linkedAttributes}};
130
-
131
- return result;
89
+ mainAttributes.forEach(attr => { if (attr.flat_json_key) result[attr.flat_json_key] = null; });
90
+ relatedAttributes.forEach(attr => { if (attr.flat_json_key) result[attr.flat_json_key] = null; });
91
+ linkedAttributes.forEach(link => { if (link.target_attribute_key) result[link.target_attribute_key] = null; });
92
+
93
+ if (flag === 'all') {
94
+ return { flat_json: result, attributes: { mainAttributes, relatedAttributes, linkedAttributes } };
95
+ }
96
+
97
+ return result;
132
98
  }
133
99
 
134
100
  const dropdown: any[] = [];
135
- dropdown.push(
136
- ...mainAttributes.map((a) => ({ label: a.name, value: a.flat_json_key })),
137
- );
138
- dropdown.push(
139
- ...relatedAttributes.map((a) => ({
140
- label: a.name,
141
- value: a.flat_json_key,
142
- })),
143
- );
101
+ dropdown.push(...mainAttributes.map(a => ({ label: a.name, value: a.flat_json_key })));
102
+ dropdown.push(...relatedAttributes.map(a => ({ label: a.name, value: a.flat_json_key })));
144
103
  if (linkedAttributes.length > 0) {
145
- dropdown.push({
146
- ...linkedAttributes.map((a) => ({
147
- label: a.name,
148
- value: a.attribute_key,
149
- })),
150
- });
104
+ dropdown.push(...linkedAttributes.map(a => ({ label: a.name, value: a.attribute_key })));
151
105
  }
106
+
152
107
  return dropdown;
153
108
  }
154
109
 
155
110
  async updateEntityJSON(entityType: string, entityId: number, loggedInUser) {
156
- await this.loggerService.log(
157
- 'info',
158
- 'EntityJSONService',
159
- 'updateEntityJSON',
160
- `Building flat JSON for entity: ${entityType}#${entityId}`,
161
- );
162
-
163
- // 1. Load flat JSON template + attributes
111
+ await this.loggerService.log('info', 'EntityJSONService', 'updateEntityJSON', `Building flat JSON for entity: ${entityType}#${entityId}`);
112
+
164
113
  const response = await this.getAttributeForFlatJSON(entityType, loggedInUser, 'all');
165
-
166
- // ---- Structural validation ----
114
+
167
115
  if (!response || !('flat_json' in response) || !('attributes' in response) || !response.attributes) {
168
- await this.loggerService.log(
169
- 'error',
170
- 'EntityJSONService',
171
- 'updateEntityJSON',
172
- `getAttributeForFlatJSON() did not return expected structure`,
173
- );
116
+ await this.loggerService.log('error', 'EntityJSONService', 'updateEntityJSON', `getAttributeForFlatJSON() did not return expected structure`);
174
117
  return null;
175
118
  }
176
-
119
+
177
120
  const { flat_json: flatJson, attributes } = response;
178
121
  if (!flatJson) return null;
179
-
180
- // ---- Strong safety fix ----
122
+
181
123
  const safeAttributes = {
182
124
  mainAttributes: attributes.mainAttributes || [],
183
125
  relatedAttributes: attributes.relatedAttributes || [],
184
126
  linkedAttributes: attributes.linkedAttributes || [],
185
127
  };
186
-
187
- // 2. Build attribute_key → flat_json_key map
128
+
188
129
  const attrMap: Record<string, string> = {};
189
130
  const allAttrs = [...safeAttributes.mainAttributes, ...safeAttributes.relatedAttributes];
190
- allAttrs.forEach(attr => {
191
- if (attr.attribute_key) attrMap[attr.attribute_key] = attr.flat_json_key || attr.attribute_key;
192
- });
193
-
194
- // 3. Merge main entity data
131
+ allAttrs.forEach(attr => { if (attr.attribute_key) attrMap[attr.attribute_key] = attr.flat_json_key || attr.attribute_key; });
132
+
195
133
  const mainData = await this.getResolvedEntityData(entityType, entityId, loggedInUser);
196
134
  this.mergeEntityDataIntoFlatJson(flatJson, mainData, attrMap);
197
-
198
- // 4. Merge ONE-TO-ONE related entities
135
+
199
136
  const relations = await this.dataSource
200
137
  .getRepository('frm_entity_relation_data')
201
138
  .createQueryBuilder('erd')
@@ -204,67 +141,62 @@ export class EntityJSONService extends EntityServiceImpl {
204
141
  .andWhere('erd.source_entity_id = :entityId', { entityId })
205
142
  .andWhere('erd.relation_type = :rt', { rt: 'ONE_TO_ONE' })
206
143
  .getRawMany();
207
-
144
+
208
145
  for (const rel of relations) {
209
146
  const relatedData = await this.getResolvedEntityData(rel.target_entity_type, rel.target_entity_id, loggedInUser);
210
147
  this.mergeEntityDataIntoFlatJson(flatJson, relatedData, attrMap);
211
148
  }
212
-
213
- // 5. Merge linked attributes using saved filters
149
+
214
150
  for (const linkAttr of safeAttributes.linkedAttributes) {
215
- if (!linkAttr.applicable_entity_type || !linkAttr.applicable_attribute_key) continue;
216
-
217
- const mappingValue = mainData?.[linkAttr.parent_attribute_key || ''] ?? null;
151
+ const childEntityType = linkAttr.applicable_entity_type;
152
+ const sourceKey = linkAttr.applicable_attribute_key;
153
+ const targetKey = linkAttr.target_attribute_key;
154
+
155
+ if (!childEntityType || !sourceKey || !targetKey) continue;
156
+
157
+ const mappingValue = mainData?.[sourceKey] ?? null;
158
+
218
159
  const value = await this.applyLinkedFilterUsingSavedFilter(
219
- linkAttr.applicable_entity_type,
160
+ childEntityType,
220
161
  linkAttr.saved_filter_code,
221
- linkAttr.applicable_attribute_key,
162
+ sourceKey,
222
163
  mappingValue,
223
- linkAttr.target_attribute_key || linkAttr.applicable_attribute_key,
164
+ targetKey,
224
165
  loggedInUser,
225
166
  entityId,
226
167
  );
227
-
168
+
228
169
  if (value !== null && value !== undefined) {
229
- const flatKey = attrMap[linkAttr.target_attribute_key || linkAttr.applicable_attribute_key]
230
- || (linkAttr.target_attribute_key || linkAttr.applicable_attribute_key);
231
- flatJson[flatKey] = value;
170
+ flatJson[targetKey] = value;
232
171
  }
233
172
  }
234
-
235
- // 6. Save JSON
236
- await this.dataSource.query(
237
- `INSERT INTO frm_entity_json (entity_type, entity_id, json_data, created_by)
238
- VALUES (?, ?, ?, ?)
239
- ON DUPLICATE KEY UPDATE json_data = VALUES(json_data), updated_by = VALUES(created_by)`,
240
- [entityType, entityId, JSON.stringify(flatJson), loggedInUser.id],
241
- );
242
-
173
+
174
+ await this.loggerService.log('info', 'EntityJSONService', 'updateEntityJSON', `Saving flat JSON for entity: ${entityType}#${entityId}`);
175
+ let JsonData = {
176
+ entity_type: entityType,
177
+ entity_id: entityId,
178
+ json_data: flatJson,
179
+ created_by: loggedInUser.id,
180
+ }
181
+
182
+ await this.EntityJSONRepository.create(JsonData);
183
+
243
184
  return flatJson;
244
185
  }
245
-
246
-
247
- // Helper: Merge entity data using attribute_key → flat_json_key mapping
248
- private mergeEntityDataIntoFlatJson(
249
- flatJson: Record<string, any>,
250
- entityData: any | any[], // accept both object or array
251
- attrMap: Record<string, string>,
252
- ) {
186
+
187
+ private mergeEntityDataIntoFlatJson(flatJson: Record<string, any>, entityData: any | any[], attrMap: Record<string, string>) {
253
188
  const records = Array.isArray(entityData) ? entityData : [entityData];
254
-
189
+
255
190
  for (const record of records) {
256
191
  if (!record || typeof record !== 'object') continue;
257
-
258
192
  for (const key of Object.keys(record)) {
259
- const flatKey = attrMap[key] || key; // map to flat_json_key if exists
193
+ const flatKey = attrMap[key] || key;
260
194
  if (flatJson.hasOwnProperty(flatKey)) {
261
195
  flatJson[flatKey] = record[key];
262
196
  }
263
197
  }
264
198
  }
265
199
  }
266
-
267
-
268
200
 
269
201
  private async applyLinkedFilterUsingSavedFilter(
270
202
  childEntityType: string,
@@ -275,11 +207,7 @@ export class EntityJSONService extends EntityServiceImpl {
275
207
  loggedInUser,
276
208
  entity_id
277
209
  ) {
278
- if (
279
- !savedFilterCode &&
280
- (mappingValue === null || mappingValue === undefined)
281
- )
282
- return null;
210
+ if (!savedFilterCode && (mappingValue === null || mappingValue === undefined)) return null;
283
211
 
284
212
  const dto: any = {
285
213
  entity_type: childEntityType,
@@ -289,30 +217,18 @@ export class EntityJSONService extends EntityServiceImpl {
289
217
  size: 1,
290
218
  };
291
219
 
292
- if (
293
- mappingValue !== null &&
294
- mappingValue !== undefined &&
295
- mappingValue !== ''
296
- ) {
220
+ if (mappingValue !== null && mappingValue !== undefined && mappingValue !== '') {
297
221
  dto.quickFilter = [
298
- {
299
- filter_attribute: childFilterAttribute,
300
- filter_operator: 'equal',
301
- filter_value: mappingValue,
302
- },
222
+ { filter_attribute: childFilterAttribute, filter_operator: 'equal', filter_value: mappingValue },
303
223
  ];
304
224
  }
305
225
 
306
226
  dto.quickFilter = [
307
- {
308
- filter_attribute: 'parent_id',
309
- filter_operator: 'equal',
310
- filter_value: entity_id,
311
- },
227
+ { filter_attribute: 'parent_id', filter_operator: 'equal', filter_value: [entity_id] },
312
228
  ];
313
229
 
314
230
  const result = await this.filterService.applyFilter(dto);
315
231
  const rows = result?.data?.entity_list || [];
316
- return rows.length ? (rows[0][targetAttribute] ?? null) : null;
232
+ return rows.length ? (rows[0][childFilterAttribute] ?? null) : null;
317
233
  }
318
234
  }
@@ -849,7 +849,7 @@ export class FilterService {
849
849
 
850
850
  private buildDateCondition(attr: string, op: string, val: any, key: string) {
851
851
  const dateColumn = `DATE(e.${attr})`;
852
- const monthColumn = `DATE_TRUNC('month', e.${attr})`;
852
+ const monthColumn = `DATE_FORMAT(e.${attr}, '%Y-%m-01')`; // MySQL equivalent
853
853
 
854
854
  const numVal = Number(val);
855
855
 
@@ -888,7 +888,7 @@ export class FilterService {
888
888
  params: { [key]: val },
889
889
  };
890
890
 
891
- // ===== MONTH COMPARISONS (NUMERIC OR DATE) =====
891
+ // ===== MONTH COMPARISONS =====
892
892
  case 'is_month_before':
893
893
  if (!isNaN(numVal)) {
894
894
  const target = moment()
@@ -896,12 +896,12 @@ export class FilterService {
896
896
  .startOf('month')
897
897
  .format('YYYY-MM-DD');
898
898
  return {
899
- query: `${monthColumn} < DATE_TRUNC('month', :${key})`,
899
+ query: `${monthColumn} < DATE_FORMAT(:${key}, '%Y-%m-01')`,
900
900
  params: { [key]: target },
901
901
  };
902
902
  }
903
903
  return {
904
- query: `${monthColumn} < DATE_TRUNC('month', :${key})`,
904
+ query: `${monthColumn} < DATE_FORMAT(:${key}, '%Y-%m-01')`,
905
905
  params: { [key]: val },
906
906
  };
907
907
 
@@ -912,27 +912,28 @@ export class FilterService {
912
912
  .startOf('month')
913
913
  .format('YYYY-MM-DD');
914
914
  return {
915
- query: `${monthColumn} > DATE_TRUNC('month', :${key})`,
915
+ query: `${monthColumn} > DATE_FORMAT(:${key}, '%Y-%m-01')`,
916
916
  params: { [key]: target },
917
917
  };
918
918
  }
919
919
  return {
920
- query: `${monthColumn} > DATE_TRUNC('month', :${key})`,
920
+ query: `${monthColumn} > DATE_FORMAT(:${key}, '%Y-%m-01')`,
921
921
  params: { [key]: val },
922
922
  };
923
923
 
924
- // ===== DAY BEFORE / AFTER WITH MOMENT =====
924
+ // ===== DAY BEFORE / AFTER =====
925
925
  case 'is_day_before':
926
926
  if (isNaN(numVal))
927
927
  throw new BadRequestException(
928
928
  'Value must be a number for is_day_before',
929
929
  );
930
930
 
931
+ const beforeDate = moment()
932
+ .subtract(numVal, 'days')
933
+ .format('YYYY-MM-DD');
931
934
  return {
932
935
  query: `${dateColumn} < :${key}`,
933
- params: {
934
- [key]: moment().subtract(numVal, 'days').format('YYYY-MM-DD'),
935
- },
936
+ params: { [key]: beforeDate },
936
937
  };
937
938
 
938
939
  case 'is_day_after':
@@ -941,11 +942,10 @@ export class FilterService {
941
942
  'Value must be a number for is_day_after',
942
943
  );
943
944
 
945
+ const afterDate = moment().add(numVal, 'days').format('YYYY-MM-DD');
944
946
  return {
945
947
  query: `${dateColumn} > :${key}`,
946
- params: {
947
- [key]: moment().add(numVal, 'days').format('YYYY-MM-DD'),
948
- },
948
+ params: { [key]: afterDate },
949
949
  };
950
950
 
951
951
  // ===== BETWEEN =====