rez_core 4.0.242 → 4.0.243
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
|
@@ -12,7 +12,7 @@ export class EntityJSONService extends EntityServiceImpl {
|
|
|
12
12
|
constructor(
|
|
13
13
|
private readonly dataSource: DataSource,
|
|
14
14
|
private readonly filterService: FilterService,
|
|
15
|
-
private readonly loggerService: LoggingService,
|
|
15
|
+
private readonly loggerService: LoggingService,
|
|
16
16
|
) {
|
|
17
17
|
super();
|
|
18
18
|
}
|
|
@@ -23,27 +23,18 @@ export class EntityJSONService extends EntityServiceImpl {
|
|
|
23
23
|
flag?: 'flat_json' | 'dropdown' | 'all',
|
|
24
24
|
) {
|
|
25
25
|
const orgId = loggedInUser.organization_id;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
'EntityJSONService',
|
|
29
|
-
'getAttributeForFlatJSON',
|
|
30
|
-
`Loading attributes for entity: ${entityType}, org: ${orgId}`,
|
|
31
|
-
);
|
|
26
|
+
|
|
27
|
+
await this.loggerService.log('info', 'EntityJSONService', 'getAttributeForFlatJSON', `Loading attributes for entity: ${entityType}, org: ${orgId}`);
|
|
32
28
|
|
|
33
29
|
const mainAttributes = await this.dataSource
|
|
34
30
|
.getRepository(AttributeMaster)
|
|
35
31
|
.createQueryBuilder('attr')
|
|
36
|
-
.select(['attr.id', 'attr.name', 'attr.flat_json_key','attr.attribute_key'])
|
|
32
|
+
.select(['attr.id', 'attr.name', 'attr.flat_json_key', 'attr.attribute_key'])
|
|
37
33
|
.where('attr.mapped_entity_type = :entityType', { entityType })
|
|
38
34
|
.andWhere('attr.organization_id = :orgId', { orgId })
|
|
39
35
|
.getMany();
|
|
40
36
|
|
|
41
|
-
await this.loggerService.log(
|
|
42
|
-
'debug',
|
|
43
|
-
'EntityJSONService',
|
|
44
|
-
'getAttributeForFlatJSON',
|
|
45
|
-
`Loaded ${mainAttributes.length} main attributes`,
|
|
46
|
-
);
|
|
37
|
+
await this.loggerService.log('debug', 'EntityJSONService', 'getAttributeForFlatJSON', `Loaded ${mainAttributes.length} main attributes`);
|
|
47
38
|
|
|
48
39
|
const relatedEntityTypes = await this.dataSource
|
|
49
40
|
.getRepository(EntityRelation)
|
|
@@ -51,44 +42,24 @@ export class EntityJSONService extends EntityServiceImpl {
|
|
|
51
42
|
.select(['rel.target_entity_type'])
|
|
52
43
|
.where('rel.source_entity_type = :entityType', { entityType })
|
|
53
44
|
.andWhere('rel.organization_id = :orgId', { orgId })
|
|
54
|
-
.andWhere('rel.relation_type = :relationType', {
|
|
55
|
-
relationType: 'ONE_TO_ONE',
|
|
56
|
-
})
|
|
45
|
+
.andWhere('rel.relation_type = :relationType', { relationType: 'ONE_TO_ONE' })
|
|
57
46
|
.getRawMany();
|
|
58
47
|
|
|
59
|
-
const relatedTypesList = relatedEntityTypes.map(
|
|
60
|
-
|
|
61
|
-
);
|
|
62
|
-
await this.loggerService.log(
|
|
63
|
-
'debug',
|
|
64
|
-
'EntityJSONService',
|
|
65
|
-
'getAttributeForFlatJSON',
|
|
66
|
-
`Found ${relatedTypesList.length} ONE-TO-ONE related entity types`,
|
|
67
|
-
);
|
|
48
|
+
const relatedTypesList = relatedEntityTypes.map(x => x.rel_target_entity_type);
|
|
49
|
+
|
|
50
|
+
await this.loggerService.log('debug', 'EntityJSONService', 'getAttributeForFlatJSON', `Found ${relatedTypesList.length} ONE-TO-ONE related entity types`);
|
|
68
51
|
|
|
69
52
|
const relatedAttributes = relatedTypesList.length
|
|
70
53
|
? await this.dataSource
|
|
71
54
|
.getRepository(AttributeMaster)
|
|
72
55
|
.createQueryBuilder('attr')
|
|
73
|
-
.select([
|
|
74
|
-
|
|
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
|
-
})
|
|
56
|
+
.select(['attr.id', 'attr.name', 'attr.flat_json_key', 'attr.mapped_entity_type', 'attr.attribute_key'])
|
|
57
|
+
.where('attr.mapped_entity_type IN (:...types)', { types: relatedTypesList })
|
|
83
58
|
.andWhere('attr.organization_id = :orgId', { orgId })
|
|
84
59
|
.getMany()
|
|
85
60
|
: [];
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
'EntityJSONService',
|
|
89
|
-
'getAttributeForFlatJSON',
|
|
90
|
-
`Loaded ${relatedAttributes.length} related attributes`,
|
|
91
|
-
);
|
|
61
|
+
|
|
62
|
+
await this.loggerService.log('debug', 'EntityJSONService', 'getAttributeForFlatJSON', `Loaded ${relatedAttributes.length} related attributes`);
|
|
92
63
|
|
|
93
64
|
const linkedAttributes = await this.dataSource
|
|
94
65
|
.getRepository(LinkedAttributes)
|
|
@@ -100,110 +71,66 @@ export class EntityJSONService extends EntityServiceImpl {
|
|
|
100
71
|
)
|
|
101
72
|
.select([
|
|
102
73
|
'fla.applicable_entity_type AS applicable_entity_type',
|
|
103
|
-
'fla.applicable_attribute_key AS applicable_attribute_key',
|
|
104
|
-
'fla.attribute_key AS target_attribute_key',
|
|
74
|
+
'fla.applicable_attribute_key AS applicable_attribute_key',
|
|
75
|
+
'fla.attribute_key AS target_attribute_key',
|
|
105
76
|
'fla.saved_filter_code AS saved_filter_code',
|
|
106
77
|
'attr.name AS name',
|
|
107
|
-
'attr.id AS id'
|
|
108
|
-
])
|
|
78
|
+
'attr.id AS id',
|
|
79
|
+
])
|
|
109
80
|
.where('attr.organization_id = :orgId', { orgId })
|
|
110
81
|
.getRawMany();
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
'EntityJSONService',
|
|
114
|
-
'getAttributeForFlatJSON',
|
|
115
|
-
`Loaded ${linkedAttributes.length} linked attributes`,
|
|
116
|
-
);
|
|
82
|
+
|
|
83
|
+
await this.loggerService.log('debug', 'EntityJSONService', 'getAttributeForFlatJSON', `Loaded ${linkedAttributes.length} linked attributes`);
|
|
117
84
|
|
|
118
85
|
if (flag === 'flat_json' || flag === 'all') {
|
|
119
86
|
const result: Record<string, null> = {};
|
|
120
|
-
mainAttributes.forEach((attr)
|
|
121
|
-
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
linkedAttributes.forEach((link) => {
|
|
127
|
-
// Use target_attribute_key instead of applicable_attribute_key
|
|
128
|
-
if (link.target_attribute_key) result[link.target_attribute_key] = null;
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
if(flag === 'all') {
|
|
132
|
-
return {
|
|
133
|
-
flat_json: result,
|
|
134
|
-
attributes: { mainAttributes, relatedAttributes, linkedAttributes }
|
|
135
|
-
};
|
|
87
|
+
mainAttributes.forEach(attr => { if (attr.flat_json_key) result[attr.flat_json_key] = null; });
|
|
88
|
+
relatedAttributes.forEach(attr => { if (attr.flat_json_key) result[attr.flat_json_key] = null; });
|
|
89
|
+
linkedAttributes.forEach(link => { if (link.target_attribute_key) result[link.target_attribute_key] = null; });
|
|
90
|
+
|
|
91
|
+
if (flag === 'all') {
|
|
92
|
+
return { flat_json: result, attributes: { mainAttributes, relatedAttributes, linkedAttributes } };
|
|
136
93
|
}
|
|
137
|
-
|
|
94
|
+
|
|
138
95
|
return result;
|
|
139
96
|
}
|
|
140
|
-
|
|
141
97
|
|
|
142
98
|
const dropdown: any[] = [];
|
|
143
|
-
dropdown.push(
|
|
144
|
-
|
|
145
|
-
);
|
|
146
|
-
dropdown.push(
|
|
147
|
-
...relatedAttributes.map((a) => ({
|
|
148
|
-
label: a.name,
|
|
149
|
-
value: a.flat_json_key,
|
|
150
|
-
})),
|
|
151
|
-
);
|
|
99
|
+
dropdown.push(...mainAttributes.map(a => ({ label: a.name, value: a.flat_json_key })));
|
|
100
|
+
dropdown.push(...relatedAttributes.map(a => ({ label: a.name, value: a.flat_json_key })));
|
|
152
101
|
if (linkedAttributes.length > 0) {
|
|
153
|
-
dropdown.push({
|
|
154
|
-
...linkedAttributes.map((a) => ({
|
|
155
|
-
label: a.name,
|
|
156
|
-
value: a.attribute_key,
|
|
157
|
-
})),
|
|
158
|
-
});
|
|
102
|
+
dropdown.push(...linkedAttributes.map(a => ({ label: a.name, value: a.attribute_key })));
|
|
159
103
|
}
|
|
104
|
+
|
|
160
105
|
return dropdown;
|
|
161
106
|
}
|
|
162
107
|
|
|
163
108
|
async updateEntityJSON(entityType: string, entityId: number, loggedInUser) {
|
|
164
|
-
await this.loggerService.log(
|
|
165
|
-
|
|
166
|
-
'EntityJSONService',
|
|
167
|
-
'updateEntityJSON',
|
|
168
|
-
`Building flat JSON for entity: ${entityType}#${entityId}`,
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
// 1. Load flat JSON template + attributes
|
|
109
|
+
await this.loggerService.log('info', 'EntityJSONService', 'updateEntityJSON', `Building flat JSON for entity: ${entityType}#${entityId}`);
|
|
110
|
+
|
|
172
111
|
const response = await this.getAttributeForFlatJSON(entityType, loggedInUser, 'all');
|
|
173
|
-
|
|
174
|
-
// ---- Structural validation ----
|
|
112
|
+
|
|
175
113
|
if (!response || !('flat_json' in response) || !('attributes' in response) || !response.attributes) {
|
|
176
|
-
await this.loggerService.log(
|
|
177
|
-
'error',
|
|
178
|
-
'EntityJSONService',
|
|
179
|
-
'updateEntityJSON',
|
|
180
|
-
`getAttributeForFlatJSON() did not return expected structure`,
|
|
181
|
-
);
|
|
114
|
+
await this.loggerService.log('error', 'EntityJSONService', 'updateEntityJSON', `getAttributeForFlatJSON() did not return expected structure`);
|
|
182
115
|
return null;
|
|
183
116
|
}
|
|
184
|
-
|
|
117
|
+
|
|
185
118
|
const { flat_json: flatJson, attributes } = response;
|
|
186
119
|
if (!flatJson) return null;
|
|
187
|
-
|
|
188
|
-
// ---- Strong safety fix ----
|
|
120
|
+
|
|
189
121
|
const safeAttributes = {
|
|
190
122
|
mainAttributes: attributes.mainAttributes || [],
|
|
191
123
|
relatedAttributes: attributes.relatedAttributes || [],
|
|
192
124
|
linkedAttributes: attributes.linkedAttributes || [],
|
|
193
125
|
};
|
|
194
|
-
|
|
195
|
-
// 2. Build attribute_key → flat_json_key map
|
|
126
|
+
|
|
196
127
|
const attrMap: Record<string, string> = {};
|
|
197
128
|
const allAttrs = [...safeAttributes.mainAttributes, ...safeAttributes.relatedAttributes];
|
|
198
|
-
allAttrs.forEach(attr => {
|
|
199
|
-
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
// 3. Merge main entity data
|
|
129
|
+
allAttrs.forEach(attr => { if (attr.attribute_key) attrMap[attr.attribute_key] = attr.flat_json_key || attr.attribute_key; });
|
|
130
|
+
|
|
203
131
|
const mainData = await this.getResolvedEntityData(entityType, entityId, loggedInUser);
|
|
204
132
|
this.mergeEntityDataIntoFlatJson(flatJson, mainData, attrMap);
|
|
205
|
-
|
|
206
|
-
// 4. Merge ONE-TO-ONE related entities
|
|
133
|
+
|
|
207
134
|
const relations = await this.dataSource
|
|
208
135
|
.getRepository('frm_entity_relation_data')
|
|
209
136
|
.createQueryBuilder('erd')
|
|
@@ -212,77 +139,60 @@ export class EntityJSONService extends EntityServiceImpl {
|
|
|
212
139
|
.andWhere('erd.source_entity_id = :entityId', { entityId })
|
|
213
140
|
.andWhere('erd.relation_type = :rt', { rt: 'ONE_TO_ONE' })
|
|
214
141
|
.getRawMany();
|
|
215
|
-
|
|
142
|
+
|
|
216
143
|
for (const rel of relations) {
|
|
217
144
|
const relatedData = await this.getResolvedEntityData(rel.target_entity_type, rel.target_entity_id, loggedInUser);
|
|
218
145
|
this.mergeEntityDataIntoFlatJson(flatJson, relatedData, attrMap);
|
|
219
146
|
}
|
|
220
|
-
|
|
221
|
-
// 5. Merge linked attributes using saved filters
|
|
222
|
-
// 5. Merge linked attributes using saved filters
|
|
223
|
-
for (const linkAttr of safeAttributes.linkedAttributes) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const childEntityType = linkAttr.applicable_entity_type; // was undefined
|
|
227
|
-
const sourceKey = linkAttr.applicable_attribute_key; // already correct
|
|
228
|
-
const targetKey = linkAttr.target_attribute_key; // was undefined
|
|
229
|
-
// final JSON key = father_middle_name
|
|
230
|
-
|
|
231
|
-
if (!childEntityType || !sourceKey || !targetKey) continue;
|
|
232
|
-
|
|
233
|
-
// value must be taken from applicable_attribute_key
|
|
234
|
-
const mappingValue = mainData?.[sourceKey] ?? null;
|
|
235
|
-
|
|
236
|
-
const value = await this.applyLinkedFilterUsingSavedFilter(
|
|
237
|
-
childEntityType,
|
|
238
|
-
linkAttr.saved_filter_code,
|
|
239
|
-
sourceKey,
|
|
240
|
-
mappingValue,
|
|
241
|
-
targetKey, // IMPORTANT → write to father_middle_name
|
|
242
|
-
loggedInUser,
|
|
243
|
-
entityId
|
|
244
|
-
);
|
|
245
147
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
148
|
+
for (const linkAttr of safeAttributes.linkedAttributes) {
|
|
149
|
+
const childEntityType = linkAttr.applicable_entity_type;
|
|
150
|
+
const sourceKey = linkAttr.applicable_attribute_key;
|
|
151
|
+
const targetKey = linkAttr.target_attribute_key;
|
|
152
|
+
|
|
153
|
+
if (!childEntityType || !sourceKey || !targetKey) continue;
|
|
154
|
+
|
|
155
|
+
const mappingValue = mainData?.[sourceKey] ?? null;
|
|
251
156
|
|
|
157
|
+
const value = await this.applyLinkedFilterUsingSavedFilter(
|
|
158
|
+
childEntityType,
|
|
159
|
+
linkAttr.saved_filter_code,
|
|
160
|
+
sourceKey,
|
|
161
|
+
mappingValue,
|
|
162
|
+
targetKey,
|
|
163
|
+
loggedInUser,
|
|
164
|
+
entityId,
|
|
165
|
+
);
|
|
252
166
|
|
|
253
|
-
|
|
167
|
+
if (value !== null && value !== undefined) {
|
|
168
|
+
flatJson[targetKey] = value;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
await this.loggerService.log('info', 'EntityJSONService', 'updateEntityJSON', `Saving flat JSON for entity: ${entityType}#${entityId}`);
|
|
254
173
|
await this.dataSource.query(
|
|
255
174
|
`INSERT INTO frm_entity_json (entity_type, entity_id, json_data, created_by)
|
|
256
|
-
|
|
257
|
-
|
|
175
|
+
VALUES (?, ?, ?, ?)
|
|
176
|
+
ON DUPLICATE KEY UPDATE json_data = VALUES(json_data), updated_by = VALUES(created_by)`,
|
|
258
177
|
[entityType, entityId, JSON.stringify(flatJson), loggedInUser.id],
|
|
259
178
|
);
|
|
260
|
-
|
|
179
|
+
|
|
261
180
|
return flatJson;
|
|
262
181
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
// Helper: Merge entity data using attribute_key → flat_json_key mapping
|
|
266
|
-
private mergeEntityDataIntoFlatJson(
|
|
267
|
-
flatJson: Record<string, any>,
|
|
268
|
-
entityData: any | any[], // accept both object or array
|
|
269
|
-
attrMap: Record<string, string>,
|
|
270
|
-
) {
|
|
182
|
+
|
|
183
|
+
private mergeEntityDataIntoFlatJson(flatJson: Record<string, any>, entityData: any | any[], attrMap: Record<string, string>) {
|
|
271
184
|
const records = Array.isArray(entityData) ? entityData : [entityData];
|
|
272
|
-
|
|
185
|
+
|
|
273
186
|
for (const record of records) {
|
|
274
187
|
if (!record || typeof record !== 'object') continue;
|
|
275
|
-
|
|
276
188
|
for (const key of Object.keys(record)) {
|
|
277
|
-
const flatKey = attrMap[key] || key;
|
|
189
|
+
const flatKey = attrMap[key] || key;
|
|
278
190
|
if (flatJson.hasOwnProperty(flatKey)) {
|
|
279
191
|
flatJson[flatKey] = record[key];
|
|
280
192
|
}
|
|
281
193
|
}
|
|
282
194
|
}
|
|
283
195
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
196
|
|
|
287
197
|
private async applyLinkedFilterUsingSavedFilter(
|
|
288
198
|
childEntityType: string,
|
|
@@ -293,11 +203,7 @@ const targetKey = linkAttr.target_attribute_key; // was undefined
|
|
|
293
203
|
loggedInUser,
|
|
294
204
|
entity_id
|
|
295
205
|
) {
|
|
296
|
-
if (
|
|
297
|
-
!savedFilterCode &&
|
|
298
|
-
(mappingValue === null || mappingValue === undefined)
|
|
299
|
-
)
|
|
300
|
-
return null;
|
|
206
|
+
if (!savedFilterCode && (mappingValue === null || mappingValue === undefined)) return null;
|
|
301
207
|
|
|
302
208
|
const dto: any = {
|
|
303
209
|
entity_type: childEntityType,
|
|
@@ -307,31 +213,18 @@ const targetKey = linkAttr.target_attribute_key; // was undefined
|
|
|
307
213
|
size: 1,
|
|
308
214
|
};
|
|
309
215
|
|
|
310
|
-
if (
|
|
311
|
-
mappingValue !== null &&
|
|
312
|
-
mappingValue !== undefined &&
|
|
313
|
-
mappingValue !== ''
|
|
314
|
-
) {
|
|
216
|
+
if (mappingValue !== null && mappingValue !== undefined && mappingValue !== '') {
|
|
315
217
|
dto.quickFilter = [
|
|
316
|
-
{
|
|
317
|
-
filter_attribute: childFilterAttribute,
|
|
318
|
-
filter_operator: 'equal',
|
|
319
|
-
filter_value: mappingValue,
|
|
320
|
-
},
|
|
218
|
+
{ filter_attribute: childFilterAttribute, filter_operator: 'equal', filter_value: mappingValue },
|
|
321
219
|
];
|
|
322
220
|
}
|
|
323
221
|
|
|
324
222
|
dto.quickFilter = [
|
|
325
|
-
{
|
|
326
|
-
filter_attribute: 'parent_id',
|
|
327
|
-
filter_operator: 'equal',
|
|
328
|
-
filter_value: [entity_id],
|
|
329
|
-
},
|
|
223
|
+
{ filter_attribute: 'parent_id', filter_operator: 'equal', filter_value: [entity_id] },
|
|
330
224
|
];
|
|
331
225
|
|
|
332
226
|
const result = await this.filterService.applyFilter(dto);
|
|
333
227
|
const rows = result?.data?.entity_list || [];
|
|
334
228
|
return rows.length ? (rows[0][childFilterAttribute] ?? null) : null;
|
|
335
|
-
|
|
336
229
|
}
|
|
337
230
|
}
|