@izara_project/izara-core-generate-service-code 1.0.85 → 1.0.86
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 +1 -1
- package/src/compile/compileProject.js +1 -2
- package/src/compile/loadSchemas.js +29 -17
- package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +1 -0
- package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +15 -4
- package/src/emit/crud/emitCrudApplicationArtifacts.js +10 -4
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +10 -4
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +36 -4
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +35 -3
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +754 -353
- package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +5 -2
- package/src/emit/rbac/emitRbacApplicationArtifacts.js +102 -6
- package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +34 -4
- package/src/emit/rbac/templates/DeleteTargetRole_Main.ejs +96 -0
- package/src/emit/rbac/templates/GetMyPermissions_Main.ejs +106 -0
- package/src/emit/rbac/templates/GetTargetRole_Main.ejs +62 -0
- package/src/emit/rbac/templates/UpdateTargetRole_Main.ejs +107 -0
- package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +12 -12
- package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +12 -0
- package/src/emit/resource/emitResourceArtifacts.js +43 -2
- package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +4 -2
- package/src/emit/systemText/emitSystemTextSchemas.js +5 -2
- package/src/generate.js +18 -12
- package/src/generateResources/IntTest/generateResources/generateResources.js +1 -1
- package/src/generateResources/IntTest/generateTests/generateTemplate.js +1 -1
- package/src/generateResources/IntTest/upload/uploadIntTest.js +8 -2
- package/test/createTargetRoleHandler.test.js +42 -1
- package/test/crudApplicationArtifacts.test.js +53 -0
- package/test/dynamicRbacFlowSchemas.test.js +5 -2
- package/test/publicApi.test.js +18 -14
- package/test/resourceArtifacts.test.js +3 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright (C)
|
|
2
|
+
Copyright (C) 2021 Sven Mason <http://izara.io>
|
|
3
3
|
|
|
4
4
|
This program is free software: you can redistribute it and/or modify
|
|
5
5
|
it under the terms of the GNU Affero General Public License as
|
|
@@ -8,12 +8,11 @@ License, or (at your option) any later version.
|
|
|
8
8
|
|
|
9
9
|
This program is distributed in the hope that it will be useful,
|
|
10
10
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
12
|
GNU Affero General Public License for more details.
|
|
13
13
|
|
|
14
14
|
You should have received a copy of the GNU Affero General Public License
|
|
15
|
-
along with this program.
|
|
16
|
-
<http: //www.gnu.org/licenses />.
|
|
15
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
16
|
*/
|
|
18
17
|
|
|
19
18
|
// ==================== Shared Core Utilities ====================
|
|
@@ -35,10 +34,6 @@ import {
|
|
|
35
34
|
dataDetailsLib,
|
|
36
35
|
uploadUseCase
|
|
37
36
|
} from '@izara_project/izara-core-library-service-schemas';
|
|
38
|
-
const { createObjType } = utils;
|
|
39
|
-
const { dynamoDbIdentifiersByStorageResource } = identifiersObject;
|
|
40
|
-
const { createUpdateDataDetail } = dataDetailsLib;
|
|
41
|
-
const { PREFIX, TOPIC_NAME_GENERATE_CODE, TOPIC_NAME_GRAPH_HANDLER } = consts;
|
|
42
37
|
|
|
43
38
|
// ==================== Shared Libraries ====================
|
|
44
39
|
import dynamodbSharedLib from '@izara_project/izara-core-library-dynamodb';
|
|
@@ -56,13 +51,632 @@ import {
|
|
|
56
51
|
//(<optionalRequire>)
|
|
57
52
|
//(</optionalRequire>)
|
|
58
53
|
|
|
54
|
+
const { createObjType } = utils;
|
|
55
|
+
const { dynamoDbIdentifiersByStorageResource } = identifiersObject;
|
|
56
|
+
const { createUpdateDataDetail } = dataDetailsLib;
|
|
57
|
+
const { PREFIX: _constPrefix, TOPIC_NAME_GENERATE_CODE, TOPIC_NAME_GRAPH_HANDLER } = consts;
|
|
58
|
+
|
|
59
|
+
const PREFIX = {
|
|
60
|
+
ASYNC: _constPrefix.updateNode,
|
|
61
|
+
UPDATE_OBJECT_ASYNC_COMPLETE: 'UpdateAsyncEndpointComplete'
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// ── 1. Update_Main Helpers ───────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Loads ObjectSchema and resolves submittedByUserId and targetIdentifiers
|
|
68
|
+
* @param {Object} _izContext - Izara context object
|
|
69
|
+
* @param {Object} requestParams - Incoming request parameters
|
|
70
|
+
* @param {Array<string>} errorsFound - Array to collect validation errors
|
|
71
|
+
* @returns {Promise<{ objType: string, objectSchema: Object }>}
|
|
72
|
+
*/
|
|
73
|
+
export async function resolveSchemaAndIdentity(_izContext, requestParams, errorsFound) {
|
|
74
|
+
const objType = createObjType(requestParams.objectType);
|
|
75
|
+
const objectSchema = await getObjectSchema.getObjSchemaS3WithHierarchy(
|
|
76
|
+
_izContext,
|
|
77
|
+
objType
|
|
78
|
+
);
|
|
79
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] objectSchema:`, objectSchema);
|
|
80
|
+
|
|
81
|
+
let submittedByUserId;
|
|
82
|
+
let targetIdentifiers;
|
|
83
|
+
if (
|
|
84
|
+
objectSchema.generatedBy === 'user' ||
|
|
85
|
+
objectSchema.generatedBy === 'systemWithUser'
|
|
86
|
+
) {
|
|
87
|
+
if (requestParams.submittedByUserId) {
|
|
88
|
+
submittedByUserId = requestParams.submittedByUserId;
|
|
89
|
+
} else if (_izContext.correlationIds) {
|
|
90
|
+
submittedByUserId = _izContext.correlationIds.get(coreConsts.SUBMITTED_BY_USER_ID);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
targetIdentifiers = requestParams.targetIdentifiers;
|
|
94
|
+
|
|
95
|
+
if (!targetIdentifiers && objectSchema.belongTo?.objectType === 'user' && submittedByUserId) {
|
|
96
|
+
targetIdentifiers = { submittedByUserId };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!submittedByUserId) {
|
|
100
|
+
errorsFound.push('Not have submittedByUserId');
|
|
101
|
+
}
|
|
102
|
+
if (objectSchema.hasOwnProperty('belongTo') && !targetIdentifiers) {
|
|
103
|
+
errorsFound.push('not have targetIdentifiers');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
requestParams.submittedByUserId = submittedByUserId;
|
|
107
|
+
if (targetIdentifiers) {
|
|
108
|
+
if (!targetIdentifiers.submittedByUserId && submittedByUserId) {
|
|
109
|
+
targetIdentifiers.submittedByUserId = submittedByUserId;
|
|
110
|
+
}
|
|
111
|
+
requestParams.targetIdentifiers = targetIdentifiers;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Identity & Target Context Resolved:`, {
|
|
115
|
+
submittedByUserId: requestParams.submittedByUserId,
|
|
116
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
117
|
+
belongTo: objectSchema.belongTo,
|
|
118
|
+
generatedBy: objectSchema.generatedBy
|
|
119
|
+
});
|
|
120
|
+
} else if (objectSchema.generatedBy === 'searchResultGenerated') {
|
|
121
|
+
throw new NoRetryError(
|
|
122
|
+
'error searchResultGenerated should not happen here'
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
requestParams.submittedByUserId = submittedByUserId;
|
|
127
|
+
return { objType, objectSchema };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ── 2. UpdateRbacCallback_Main Helpers ────────────────────────────────────────
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Checks awaiting steps status and collects returned results from App and Target RBAC
|
|
134
|
+
* @param {Object} _izContext - Izara context object
|
|
135
|
+
* @param {Object} requestParams - Request parameters with parentFlowId
|
|
136
|
+
* @returns {Promise<{ isComplete: boolean, rbacResults?: Object, originalRequestParams?: Object, collectedErrors?: Array<string> }>}
|
|
137
|
+
*/
|
|
138
|
+
export async function collectRbacAwaitingResults(_izContext, requestParams) {
|
|
139
|
+
const parts = requestParams.parentFlowId.split('_');
|
|
140
|
+
const rbacType = parts.pop();
|
|
141
|
+
const rbacPendingStepId = '<%- flowTag %>RbacCallback_' + parts.join('_');
|
|
142
|
+
const currentAwaitingStepId = requestParams.parentFlowId;
|
|
143
|
+
|
|
144
|
+
_izContext.logger.debug(
|
|
145
|
+
'[<%- flowTag %>RbacCallbackMain] Parsed RBAC pending details:',
|
|
146
|
+
{
|
|
147
|
+
rbacType,
|
|
148
|
+
rbacPendingStepId,
|
|
149
|
+
currentAwaitingStepId,
|
|
150
|
+
parentFlowId: requestParams.parentFlowId
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
const rbacAwaitingStepsResult =
|
|
155
|
+
await asyncFlowSharedLib.checkAllAwaitingStepsFinishedWithReturnParams(
|
|
156
|
+
_izContext,
|
|
157
|
+
rbacPendingStepId,
|
|
158
|
+
currentAwaitingStepId,
|
|
159
|
+
requestParams.errorsFound,
|
|
160
|
+
{
|
|
161
|
+
returnValue: requestParams.returnValue,
|
|
162
|
+
rbacType
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
_izContext.logger.debug(
|
|
167
|
+
'[<%- flowTag %>RbacCallbackMain] checkAllAwaitingStepsFinishedWithReturnParams result:',
|
|
168
|
+
{
|
|
169
|
+
rbacAwaitingStepsResult
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const {
|
|
174
|
+
isComplete,
|
|
175
|
+
collectedReturnValueByAwaitingStepId,
|
|
176
|
+
collectedErrors: errorsFound = [],
|
|
177
|
+
additionalAttributes
|
|
178
|
+
} = rbacAwaitingStepsResult;
|
|
179
|
+
|
|
180
|
+
if (isComplete === false) {
|
|
181
|
+
_izContext.logger.debug(
|
|
182
|
+
'[<%- flowTag %>RbacCallbackMain] Awaiting steps still pending completion:',
|
|
183
|
+
{
|
|
184
|
+
rbacPendingStepId,
|
|
185
|
+
isComplete
|
|
186
|
+
}
|
|
187
|
+
);
|
|
188
|
+
return { isComplete: false };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
_izContext.logger.debug(
|
|
192
|
+
'[<%- flowTag %>RbacCallbackMain] All awaiting steps completed — clearing awaiting steps:',
|
|
193
|
+
{
|
|
194
|
+
rbacPendingStepId
|
|
195
|
+
}
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
await asyncFlowSharedLib.clearAllAwaitingSteps(
|
|
199
|
+
_izContext,
|
|
200
|
+
rbacPendingStepId
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
let originalRequestParams = {};
|
|
204
|
+
if (additionalAttributes?.requestParams) {
|
|
205
|
+
originalRequestParams = additionalAttributes.requestParams;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const rbacResults = {};
|
|
209
|
+
if (collectedReturnValueByAwaitingStepId) {
|
|
210
|
+
for (const [stepId, attrs] of Object.entries(collectedReturnValueByAwaitingStepId)) {
|
|
211
|
+
const type = stepId.split('_').pop();
|
|
212
|
+
rbacResults[type] = attrs;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
isComplete: true,
|
|
218
|
+
rbacResults,
|
|
219
|
+
originalRequestParams,
|
|
220
|
+
collectedErrors: errorsFound
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
59
224
|
/**
|
|
60
|
-
*
|
|
225
|
+
* Asserts RBAC permission and publishes rejected response if unauthorized
|
|
226
|
+
* @param {Object} _izContext - Izara context object
|
|
227
|
+
* @param {Object} options - Validation options
|
|
228
|
+
* @returns {Promise<{ hasError: boolean, errorResult?: Object, rbacCallbackResults: Object }>}
|
|
229
|
+
*/
|
|
230
|
+
export async function assertRbacPermission(_izContext, { rbacResults, originalRequestParams, errorsFound }) {
|
|
231
|
+
const rbacCallbackResults = {};
|
|
232
|
+
let hasError = false;
|
|
233
|
+
|
|
234
|
+
for (const [type, result] of Object.entries(rbacResults || {})) {
|
|
235
|
+
if (result && result.error) {
|
|
236
|
+
errorsFound.push(result.error);
|
|
237
|
+
hasError = true;
|
|
238
|
+
} else {
|
|
239
|
+
rbacCallbackResults[type] = result;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
let isAllowed = false;
|
|
244
|
+
for (const item of Object.values(rbacCallbackResults)) {
|
|
245
|
+
if (item?.returnValue?.permission === true) {
|
|
246
|
+
isAllowed = true;
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (!isAllowed) {
|
|
252
|
+
errorsFound.push('Permission denied');
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
_izContext.logger.debug(
|
|
256
|
+
'[<%- flowTag %>RbacCallbackMain] Final rbacCallbackResults before calling <%- flowTag %>MainLogical:',
|
|
257
|
+
{
|
|
258
|
+
rbacCallbackResults,
|
|
259
|
+
isAllowed,
|
|
260
|
+
errorsFound
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
if (hasError || errorsFound.length > 0) {
|
|
265
|
+
const errorResult = {
|
|
266
|
+
errorsFound,
|
|
267
|
+
status: 'rejected',
|
|
268
|
+
requestParams: originalRequestParams
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
_izContext.logger.debug(
|
|
272
|
+
'[<%- flowTag %>RbacCallbackMain] RBAC check failed, publishing rejected status:',
|
|
273
|
+
errorResult
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
await sns.publishAsync(_izContext, {
|
|
277
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
278
|
+
_izContext,
|
|
279
|
+
'<%- upperCaseFlowTag %>_Out',
|
|
280
|
+
process.env.iz_serviceTag
|
|
281
|
+
),
|
|
282
|
+
Message: JSON.stringify(errorResult)
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
return { hasError: true, errorResult, rbacCallbackResults };
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return { hasError: false, rbacCallbackResults };
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// ── 3. UpdateLogicalLib Internal Helpers ──────────────────────────────────────
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Resolves and combines object schemas and updateDataDetails
|
|
295
|
+
* @param {Object} _izContext - Izara context object
|
|
296
|
+
* @param {string} objectType - Object type identifier
|
|
297
|
+
* @returns {Promise<{ objType: string, objectSchema: Object, objectSchemas: Object, updateDataDetails: Object }>}
|
|
298
|
+
*/
|
|
299
|
+
export async function resolveObjectSchemas(_izContext, objectType) {
|
|
300
|
+
const objType = createObjType(objectType);
|
|
301
|
+
const objectSchema = await getObjectSchema.getObjSchemaS3WithHierarchy(
|
|
302
|
+
_izContext,
|
|
303
|
+
objType
|
|
304
|
+
);
|
|
305
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] objectSchema:`, objectSchema);
|
|
306
|
+
|
|
307
|
+
const objectSchemas =
|
|
308
|
+
await uploadUseCase.generateObjectSchemaForCombineFieldNames(
|
|
309
|
+
_izContext,
|
|
310
|
+
objectSchema
|
|
311
|
+
);
|
|
312
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] objectSchemas:`, objectSchemas);
|
|
313
|
+
|
|
314
|
+
const updateDataDetails = await createUpdateDataDetail(
|
|
315
|
+
_izContext,
|
|
316
|
+
objectSchemas
|
|
317
|
+
);
|
|
318
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] updateDataDetails:`, updateDataDetails);
|
|
319
|
+
|
|
320
|
+
return { objType, objectSchema, objectSchemas, updateDataDetails };
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Validates versionedDataIds against object schema and request fields
|
|
325
|
+
* @param {Object} requestParams - Request parameters
|
|
326
|
+
* @param {Object} objectSchema - Object schema
|
|
327
|
+
* @param {Object} versionedDataIds - Versioned data IDs map
|
|
328
|
+
* @param {Array<string>} errorsFound - Array to collect validation errors
|
|
329
|
+
*/
|
|
330
|
+
export function validateVersionedDataIds(
|
|
331
|
+
requestParams,
|
|
332
|
+
objectSchema,
|
|
333
|
+
versionedDataIds,
|
|
334
|
+
errorsFound
|
|
335
|
+
) {
|
|
336
|
+
const versionedDataIdsKeys = Object.keys(versionedDataIds || {});
|
|
337
|
+
if (versionedDataIdsKeys.length === 0) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const updateMainNodeData = {};
|
|
342
|
+
const updateVersionedData = {};
|
|
343
|
+
|
|
344
|
+
for (const [fieldProp, fieldVal] of Object.entries(
|
|
345
|
+
requestParams.objInstanceFull?.fields || {}
|
|
346
|
+
)) {
|
|
347
|
+
const fieldSetting = objectSchema.fieldNames[fieldProp];
|
|
348
|
+
if (fieldSetting?.hasOwnProperty('versionedDataLabel')) {
|
|
349
|
+
const label = fieldSetting.versionedDataLabel;
|
|
350
|
+
if (!updateVersionedData[label]) {
|
|
351
|
+
updateVersionedData[label] = {};
|
|
352
|
+
}
|
|
353
|
+
Object.assign(updateVersionedData[label], { [fieldProp]: fieldVal });
|
|
354
|
+
} else {
|
|
355
|
+
Object.assign(updateMainNodeData, { [fieldProp]: fieldVal });
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const versionedDataIdLabelKeys = Object.keys(versionedDataIds);
|
|
360
|
+
const updateVersionedDataLabelKeys = Object.keys(updateVersionedData);
|
|
361
|
+
|
|
362
|
+
const missingVersionedDataIdLabels = updateVersionedDataLabelKeys.filter(
|
|
363
|
+
(l) => !versionedDataIdLabelKeys.includes(l)
|
|
364
|
+
);
|
|
365
|
+
const missingDataVersionedDataLabels = versionedDataIdLabelKeys.filter(
|
|
366
|
+
(l) => !updateVersionedDataLabelKeys.includes(l)
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
if (missingVersionedDataIdLabels.length > 0) {
|
|
370
|
+
errorsFound.push(
|
|
371
|
+
`missing versionedDataIds of versionedDataLabel '${missingVersionedDataIdLabels.join(', ')}'`
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
if (missingDataVersionedDataLabels.length > 0) {
|
|
375
|
+
errorsFound.push(
|
|
376
|
+
`missing data of versionedDataLabels '${missingDataVersionedDataLabels.join(', ')}'`
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
if (Object.keys(updateMainNodeData).length > 0) {
|
|
380
|
+
errorsFound.push('cannot update mainNode if have versionedDataIds');
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Extracts fields matching storage resource specifications
|
|
386
|
+
* @param {Object} _izContext - Izara context object
|
|
387
|
+
* @param {string} storageTag - Storage resource tag
|
|
388
|
+
* @param {Object} updateDataDetails - Complete update data details map
|
|
389
|
+
* @param {Object} updateDataDetail - Current storage update data detail
|
|
390
|
+
* @param {Object} requestParams - Request parameters
|
|
391
|
+
* @param {Object} identifiers - Identifiers map
|
|
392
|
+
* @returns {Object} Extracted fields object
|
|
393
|
+
*/
|
|
394
|
+
export function extractFieldsByStorageTag(
|
|
395
|
+
_izContext,
|
|
396
|
+
storageTag,
|
|
397
|
+
updateDataDetails,
|
|
398
|
+
updateDataDetail,
|
|
399
|
+
requestParams,
|
|
400
|
+
identifiers
|
|
401
|
+
) {
|
|
402
|
+
const result = {};
|
|
403
|
+
for (const fieldName of Object.keys(
|
|
404
|
+
requestParams.objInstanceFull?.fields || {}
|
|
405
|
+
)) {
|
|
406
|
+
if (
|
|
407
|
+
updateDataDetails[storageTag].fieldNames.includes(fieldName) &&
|
|
408
|
+
updateDataDetail.fieldNames.includes(fieldName) &&
|
|
409
|
+
!identifiers.hasOwnProperty(fieldName) &&
|
|
410
|
+
!result.hasOwnProperty(fieldName)
|
|
411
|
+
) {
|
|
412
|
+
Object.assign(result, {
|
|
413
|
+
[fieldName]: requestParams.objInstanceFull.fields[fieldName]
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return result;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Builds objInstanceFull matching updated object fields
|
|
422
|
+
* @param {Object} object - Source data object
|
|
423
|
+
* @param {Object} requestParams - Request parameters
|
|
424
|
+
* @returns {Object} Full object instance with identifiers and fields
|
|
425
|
+
*/
|
|
426
|
+
export function createObjInstanceFullFromParams(object, requestParams) {
|
|
427
|
+
const objInstanceFull = { identifiers: {}, fields: {} };
|
|
428
|
+
for (const field of Object.keys(object || {})) {
|
|
429
|
+
if (requestParams.objInstanceFull?.identifiers?.hasOwnProperty(field)) {
|
|
430
|
+
Object.assign(objInstanceFull.identifiers, {
|
|
431
|
+
[field]: requestParams.objInstanceFull.identifiers[field]
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
if (requestParams.objInstanceFull?.fields?.hasOwnProperty(field)) {
|
|
435
|
+
Object.assign(objInstanceFull.fields, {
|
|
436
|
+
[field]: requestParams.objInstanceFull.fields[field]
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return objInstanceFull;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Dispatches node update request to Graph Service
|
|
445
|
+
* @param {Object} _izContext - Izara context object
|
|
446
|
+
* @param {Object} options - Graph dispatch configuration
|
|
447
|
+
* @returns {Promise<void>}
|
|
448
|
+
*/
|
|
449
|
+
export async function dispatchToGraphEngine(
|
|
450
|
+
_izContext,
|
|
451
|
+
{
|
|
452
|
+
objType,
|
|
453
|
+
identifiers,
|
|
454
|
+
graphFields,
|
|
455
|
+
versionedDataIds,
|
|
456
|
+
originTimestamp,
|
|
457
|
+
settings,
|
|
458
|
+
parentFlowId,
|
|
459
|
+
callingFlowConfig,
|
|
460
|
+
storageTag,
|
|
461
|
+
records = []
|
|
462
|
+
}
|
|
463
|
+
) {
|
|
464
|
+
const awaitingStepIds = [{
|
|
465
|
+
awaitingStepId: asyncFlowSharedLib.createAwaitingStepId(
|
|
466
|
+
parentFlowId,
|
|
467
|
+
PREFIX.ASYNC
|
|
468
|
+
),
|
|
469
|
+
additionalAttributes: {
|
|
470
|
+
listOfRecords: records,
|
|
471
|
+
additionalAttributes: {}
|
|
472
|
+
}
|
|
473
|
+
}];
|
|
474
|
+
|
|
475
|
+
await asyncFlowSharedLib.createAwaitingMultipleSteps(
|
|
476
|
+
_izContext,
|
|
477
|
+
asyncFlowSharedLib.createPendingStepId(_izContext.uniqueRequestId),
|
|
478
|
+
awaitingStepIds,
|
|
479
|
+
{
|
|
480
|
+
additionalAttributes: {
|
|
481
|
+
callingFlowConfig
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
);
|
|
485
|
+
|
|
486
|
+
let updateNodeParams = {
|
|
487
|
+
objType,
|
|
488
|
+
objInstanceFull: { identifiers, fields: graphFields },
|
|
489
|
+
versionedDataIds,
|
|
490
|
+
originTimestamp,
|
|
491
|
+
settings,
|
|
492
|
+
parentFlowId
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
updateNodeParams =
|
|
496
|
+
callingFlowSharedLib.addCallingFlowToSnsRequestMessageObject(
|
|
497
|
+
updateNodeParams,
|
|
498
|
+
callingFlowSharedLib.addParentCallingFlowConfig(
|
|
499
|
+
callingFlowConfig,
|
|
500
|
+
callingFlowSharedLib.createCallingFlowConfig(
|
|
501
|
+
//(<callingFlowProperties>)
|
|
502
|
+
await lambdaSharedLib.lambdaFunctionName(
|
|
503
|
+
_izContext,
|
|
504
|
+
TOPIC_NAME_GENERATE_CODE.updateNodeComplete
|
|
505
|
+
),
|
|
506
|
+
{}
|
|
507
|
+
//(</callingFlowProperties>)
|
|
508
|
+
)
|
|
509
|
+
)
|
|
510
|
+
);
|
|
511
|
+
|
|
512
|
+
_izContext.logger.debug(
|
|
513
|
+
'messageObject before send message:',
|
|
514
|
+
updateNodeParams
|
|
515
|
+
);
|
|
516
|
+
|
|
517
|
+
await sns.publishAsync(_izContext, {
|
|
518
|
+
Message: JSON.stringify(updateNodeParams),
|
|
519
|
+
MessageAttributes: sns.createStringMessageAttributes(
|
|
520
|
+
_izContext,
|
|
521
|
+
callingFlowSharedLib.addCallingFlowToSnsResponseMessageAttributes(
|
|
522
|
+
callingFlowConfig,
|
|
523
|
+
{}
|
|
524
|
+
)
|
|
525
|
+
),
|
|
526
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
527
|
+
_izContext,
|
|
528
|
+
TOPIC_NAME_GRAPH_HANDLER.inUpdateNode,
|
|
529
|
+
storageTag
|
|
530
|
+
)
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Handles DynamoDB-only complete notification when no Graph callback is required
|
|
536
|
+
* @param {Object} _izContext - Izara context object
|
|
537
|
+
* @param {Object} options - Completion parameters
|
|
538
|
+
* @returns {Promise<void>}
|
|
539
|
+
*/
|
|
540
|
+
export async function handleDynamoDbOnlyComplete(
|
|
541
|
+
_izContext,
|
|
542
|
+
{
|
|
543
|
+
objType,
|
|
544
|
+
updateItem,
|
|
545
|
+
requestParams,
|
|
546
|
+
callingFlowConfig
|
|
547
|
+
}
|
|
548
|
+
) {
|
|
549
|
+
let messageObject = {
|
|
550
|
+
objType,
|
|
551
|
+
objInstanceFull: createObjInstanceFullFromParams(
|
|
552
|
+
updateItem,
|
|
553
|
+
requestParams
|
|
554
|
+
)
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
//(<additionalProperties>)
|
|
558
|
+
//(</additionalProperties>)
|
|
559
|
+
|
|
560
|
+
if (
|
|
561
|
+
callingFlowConfig[
|
|
562
|
+
callingFlowSharedLib.consts.CALLINGFLOWPROPERTIES_PROPERTYNAME
|
|
563
|
+
]
|
|
564
|
+
) {
|
|
565
|
+
_izContext.logger.debug('HAVE CALLING FLOW');
|
|
566
|
+
messageObject =
|
|
567
|
+
callingFlowSharedLib.addPassBackPropertiesToSnsResponseMessageObject(
|
|
568
|
+
callingFlowConfig,
|
|
569
|
+
messageObject
|
|
570
|
+
);
|
|
571
|
+
|
|
572
|
+
_izContext.logger.debug('after create callingFlow', messageObject);
|
|
573
|
+
await sns.publishAsync(_izContext, {
|
|
574
|
+
Message: JSON.stringify(messageObject),
|
|
575
|
+
MessageAttributes: sns.createStringMessageAttributes(
|
|
576
|
+
_izContext,
|
|
577
|
+
callingFlowSharedLib.addCallingFlowToSnsResponseMessageAttributes(
|
|
578
|
+
callingFlowConfig,
|
|
579
|
+
{}
|
|
580
|
+
)
|
|
581
|
+
),
|
|
582
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
583
|
+
_izContext,
|
|
584
|
+
TOPIC_NAME_GENERATE_CODE.outUpdateNodeComplete
|
|
585
|
+
)
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Handles update errors and publishes error response
|
|
592
|
+
* @param {Object} _izContext - Izara context object
|
|
593
|
+
* @param {Object} options - Error context details
|
|
594
|
+
* @returns {Promise<Object>} Error status result
|
|
595
|
+
*/
|
|
596
|
+
export async function handleUpdateError(
|
|
597
|
+
_izContext,
|
|
598
|
+
{
|
|
599
|
+
objType,
|
|
600
|
+
identifiers,
|
|
601
|
+
fields,
|
|
602
|
+
versionedDataIds,
|
|
603
|
+
callingFlowConfig,
|
|
604
|
+
errorsFound
|
|
605
|
+
}
|
|
606
|
+
) {
|
|
607
|
+
const updateNodeCompleteMessage =
|
|
608
|
+
callingFlowSharedLib.addPassBackPropertiesToSnsResponseMessageObject(
|
|
609
|
+
callingFlowConfig,
|
|
610
|
+
{
|
|
611
|
+
objType,
|
|
612
|
+
objInstanceFull: { identifiers, fields },
|
|
613
|
+
versionedDataIds,
|
|
614
|
+
status: 'error',
|
|
615
|
+
errorsFound
|
|
616
|
+
}
|
|
617
|
+
);
|
|
618
|
+
|
|
619
|
+
_izContext.logger.debug(
|
|
620
|
+
'messageParams OutUpdateNodeComplete:::',
|
|
621
|
+
updateNodeCompleteMessage
|
|
622
|
+
);
|
|
623
|
+
|
|
624
|
+
await sns.publishAsync(_izContext, {
|
|
625
|
+
Message: JSON.stringify(updateNodeCompleteMessage),
|
|
626
|
+
MessageAttributes: sns.createStringMessageAttributes(
|
|
627
|
+
_izContext,
|
|
628
|
+
callingFlowSharedLib.addCallingFlowToSnsResponseMessageAttributes(
|
|
629
|
+
callingFlowConfig,
|
|
630
|
+
{}
|
|
631
|
+
)
|
|
632
|
+
),
|
|
633
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
634
|
+
_izContext,
|
|
635
|
+
TOPIC_NAME_GENERATE_CODE.outUpdateNodeComplete
|
|
636
|
+
)
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
return updateNodeCompleteMessage;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Publishes completion message to SNS
|
|
644
|
+
* @param {Object} _izContext - Izara context object
|
|
645
|
+
* @param {Object} message - Response message object
|
|
646
|
+
* @param {Object} messageAttributes - Message attributes
|
|
647
|
+
* @returns {Promise<void>}
|
|
648
|
+
*/
|
|
649
|
+
export async function publishCompletionMessage(_izContext, message, messageAttributes) {
|
|
650
|
+
const topicArn = snsSharedLib.snsTopicArnByFlowSchema(
|
|
651
|
+
_izContext,
|
|
652
|
+
TOPIC_NAME_GENERATE_CODE.outUpdateNodeComplete
|
|
653
|
+
);
|
|
654
|
+
|
|
655
|
+
_izContext.logger.debug('[UpdateComplete] publishing to SNS', {
|
|
656
|
+
TopicArn: topicArn,
|
|
657
|
+
message
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
await sns.publishAsync(_izContext, {
|
|
661
|
+
Message: JSON.stringify(message),
|
|
662
|
+
MessageAttributes: sns.createStringMessageAttributes(
|
|
663
|
+
_izContext,
|
|
664
|
+
messageAttributes
|
|
665
|
+
),
|
|
666
|
+
TopicArn: topicArn
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// ── 4. Main Logical Function ──────────────────────────────────────────────────
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* Core logical processing library for <%- flowTag %> flow
|
|
61
674
|
* @param {Object} _izContext - Context object with logger
|
|
62
675
|
* @param {Object} requestParams - { objectType, objInstanceFull, versionedDataIds, additionalParams }
|
|
63
676
|
* @param {Object} callingFlowConfig - Calling flow configuration
|
|
677
|
+
* @param {Array<string>} errorsFound - Array of preceding errors
|
|
64
678
|
* @param {Object} phaseResults - Results from preceding phases
|
|
65
|
-
* @returns {Promise<Object>}
|
|
679
|
+
* @returns {Promise<Object>} Result with objType, objInstanceFull, versionedDataIds, status, errorsFound
|
|
66
680
|
*/
|
|
67
681
|
export async function <%- flowTag %>LogicalLib(
|
|
68
682
|
_izContext,
|
|
@@ -72,7 +686,7 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
72
686
|
phaseResults = {}
|
|
73
687
|
) {
|
|
74
688
|
try {
|
|
75
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] started`,
|
|
689
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] started`, {
|
|
76
690
|
requestParams,
|
|
77
691
|
callingFlowConfig,
|
|
78
692
|
phaseResults
|
|
@@ -81,381 +695,169 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
81
695
|
//(<beforeUpdateMainLogical>)
|
|
82
696
|
//(</beforeUpdateMainLogical>)
|
|
83
697
|
|
|
84
|
-
|
|
85
|
-
|
|
698
|
+
const settings = {};
|
|
699
|
+
if (requestParams.additionalParams?.settings) {
|
|
700
|
+
Object.assign(settings, requestParams.additionalParams.settings);
|
|
701
|
+
}
|
|
86
702
|
const returnSystemFieldsName = settings.returnSystemFieldsName === true;
|
|
87
703
|
const returnOldData = settings.returnOldData === true;
|
|
88
704
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
objType
|
|
98
|
-
);
|
|
99
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] objectSchema:`, objectSchema);
|
|
100
|
-
|
|
101
|
-
const objectSchemas =
|
|
102
|
-
await uploadUseCase.generateObjectSchemaForCombineFieldNames(
|
|
103
|
-
_izContext,
|
|
104
|
-
objectSchema
|
|
105
|
-
);
|
|
106
|
-
_izContext.logger.debug('objectSchemas', objectSchemas);
|
|
705
|
+
let identifiers = {};
|
|
706
|
+
if (requestParams.objInstanceFull?.identifiers) {
|
|
707
|
+
identifiers = requestParams.objInstanceFull.identifiers;
|
|
708
|
+
}
|
|
709
|
+
let fields = {};
|
|
710
|
+
if (requestParams.objInstanceFull?.fields) {
|
|
711
|
+
fields = requestParams.objInstanceFull.fields;
|
|
712
|
+
}
|
|
107
713
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
);
|
|
113
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] updateDataDetails:`, updateDataDetails);
|
|
714
|
+
let versionedDataIds = {};
|
|
715
|
+
if (requestParams.versionedDataIds) {
|
|
716
|
+
versionedDataIds = requestParams.versionedDataIds;
|
|
717
|
+
}
|
|
114
718
|
|
|
719
|
+
const parentFlowId = identifierUuid();
|
|
115
720
|
const originTimestamp = Date.now();
|
|
116
721
|
|
|
117
|
-
//
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
if (haveVersionedDataIdsToUpdate) {
|
|
121
|
-
const updateMainNodeData = {};
|
|
122
|
-
const updateVersionedData = {};
|
|
123
|
-
|
|
124
|
-
for (const [fieldProp, fieldVal] of Object.entries(
|
|
125
|
-
requestParams.objInstanceFull.fields
|
|
126
|
-
)) {
|
|
127
|
-
const fieldSetting = objectSchema.fieldNames[fieldProp];
|
|
128
|
-
if (fieldSetting.hasOwnProperty('versionedDataLabel')) {
|
|
129
|
-
updateVersionedData[fieldSetting.versionedDataLabel] ??= {};
|
|
130
|
-
Object.assign(updateVersionedData[fieldSetting.versionedDataLabel], {
|
|
131
|
-
[fieldProp]: fieldVal
|
|
132
|
-
});
|
|
133
|
-
} else {
|
|
134
|
-
Object.assign(updateMainNodeData, { [fieldProp]: fieldVal });
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
_izContext.logger.debug('updateMainNodeData::', updateMainNodeData);
|
|
139
|
-
_izContext.logger.debug('updateVersionedData::', updateVersionedData);
|
|
140
|
-
|
|
141
|
-
const versionedDataIdLabelKeys = Object.keys(versionedDataIds);
|
|
142
|
-
const updateVersionedDataLabelKeys = Object.keys(updateVersionedData);
|
|
722
|
+
// 1. Resolve schemas & data details
|
|
723
|
+
const { objType, objectSchema, updateDataDetails } =
|
|
724
|
+
await resolveObjectSchemas(_izContext, requestParams.objectType);
|
|
143
725
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (missingVersionedDataIdLabels.length)
|
|
152
|
-
errorsFound.push(
|
|
153
|
-
`missing versionedDataIds of versionedDataLabel '${missingVersionedDataIdLabels.join(', ')}'`
|
|
154
|
-
);
|
|
155
|
-
if (missingDataVersionedDataLabels.length)
|
|
156
|
-
errorsFound.push(
|
|
157
|
-
`missing data of versionedDataLabels '${missingDataVersionedDataLabels.join(', ')}'`
|
|
158
|
-
);
|
|
159
|
-
if (Object.keys(updateMainNodeData).length)
|
|
160
|
-
errorsFound.push('cannot update mainNode if have versionedDataIds');
|
|
161
|
-
}
|
|
726
|
+
// 2. Validate versioned data IDs
|
|
727
|
+
validateVersionedDataIds(
|
|
728
|
+
requestParams,
|
|
729
|
+
objectSchema,
|
|
730
|
+
versionedDataIds,
|
|
731
|
+
errorsFound
|
|
732
|
+
);
|
|
162
733
|
|
|
163
734
|
//(<validateBeforeUpdate>)
|
|
164
735
|
//(</validateBeforeUpdate>)
|
|
165
736
|
|
|
166
|
-
//
|
|
167
|
-
if (errorsFound.length) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
status: 'error',
|
|
176
|
-
errorsFound
|
|
177
|
-
}
|
|
178
|
-
);
|
|
179
|
-
|
|
180
|
-
_izContext.logger.debug(
|
|
181
|
-
'messageParams OutUpdateNodeComplete:::',
|
|
182
|
-
updateNodeCompleteMessage
|
|
183
|
-
);
|
|
184
|
-
await sns.publishAsync(_izContext, {
|
|
185
|
-
Message: JSON.stringify(updateNodeCompleteMessage),
|
|
186
|
-
MessageAttributes: sns.createStringMessageAttributes(
|
|
187
|
-
_izContext,
|
|
188
|
-
callingFlowSharedLib.addCallingFlowToSnsResponseMessageAttributes(
|
|
189
|
-
callingFlowConfig,
|
|
190
|
-
{}
|
|
191
|
-
)
|
|
192
|
-
),
|
|
193
|
-
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
194
|
-
_izContext,
|
|
195
|
-
TOPIC_NAME_GENERATE_CODE.outUpdateNodeComplete
|
|
196
|
-
)
|
|
737
|
+
// 3. Early exit on errors
|
|
738
|
+
if (errorsFound.length > 0) {
|
|
739
|
+
return await handleUpdateError(_izContext, {
|
|
740
|
+
objType,
|
|
741
|
+
identifiers,
|
|
742
|
+
fields,
|
|
743
|
+
versionedDataIds,
|
|
744
|
+
callingFlowConfig,
|
|
745
|
+
errorsFound
|
|
197
746
|
});
|
|
198
|
-
|
|
199
|
-
return updateNodeCompleteMessage;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// ── Helper: extract fields per storageTag ─────────────────────────────────
|
|
203
|
-
function createObjInstanceFullFieldsByStorageTag(
|
|
204
|
-
_izContext,
|
|
205
|
-
storageTag,
|
|
206
|
-
updateDataDetail
|
|
207
|
-
) {
|
|
208
|
-
const result = {};
|
|
209
|
-
for (const fieldName of Object.keys(
|
|
210
|
-
requestParams.objInstanceFull.fields
|
|
211
|
-
)) {
|
|
212
|
-
if (
|
|
213
|
-
updateDataDetails[storageTag].fieldNames.includes(fieldName) &&
|
|
214
|
-
updateDataDetail.fieldNames.includes(fieldName) &&
|
|
215
|
-
!identifiers.hasOwnProperty(fieldName) &&
|
|
216
|
-
!result.hasOwnProperty(fieldName)
|
|
217
|
-
) {
|
|
218
|
-
Object.assign(result, {
|
|
219
|
-
[fieldName]: requestParams.objInstanceFull.fields[fieldName]
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
return result;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// ── Helper: build objInstanceFull from updateItem ─────────────────────────
|
|
227
|
-
function createObjInstanceFullFromParams(object, requestParams) {
|
|
228
|
-
const objInstanceFull = { identifiers: {}, fields: {} };
|
|
229
|
-
for (const field of Object.keys(object)) {
|
|
230
|
-
if (requestParams.objInstanceFull.identifiers.hasOwnProperty(field)) {
|
|
231
|
-
Object.assign(objInstanceFull.identifiers, {
|
|
232
|
-
[field]: requestParams.objInstanceFull.identifiers[field]
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
if (requestParams.objInstanceFull.fields.hasOwnProperty(field)) {
|
|
236
|
-
Object.assign(objInstanceFull.fields, {
|
|
237
|
-
[field]: requestParams.objInstanceFull.fields[field]
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
return objInstanceFull;
|
|
242
747
|
}
|
|
243
748
|
|
|
244
|
-
//
|
|
245
|
-
|
|
749
|
+
// 4. Process storage resources
|
|
750
|
+
let hasGraphStorage = false;
|
|
246
751
|
const listOfRecords = [];
|
|
247
752
|
let updateItem;
|
|
248
753
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
754
|
+
for (const [storageTag, updateDataDetail] of Object.entries(updateDataDetails)) {
|
|
755
|
+
if (updateDataDetail.storageType === consts.STORAGE_TYPES.graph) {
|
|
756
|
+
const graphFields = extractFieldsByStorageTag(
|
|
757
|
+
_izContext,
|
|
758
|
+
storageTag,
|
|
759
|
+
updateDataDetails,
|
|
760
|
+
updateDataDetail,
|
|
761
|
+
requestParams,
|
|
762
|
+
identifiers
|
|
763
|
+
);
|
|
764
|
+
if (Object.keys(graphFields).length > 0) {
|
|
765
|
+
hasGraphStorage = true;
|
|
766
|
+
//(<beforeUpdateGraph>)
|
|
767
|
+
//(</beforeUpdateGraph>)
|
|
256
768
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
storageTag,
|
|
260
|
-
updateDataDetail
|
|
261
|
-
);
|
|
262
|
-
if (!Object.keys(graphFields).length) return;
|
|
769
|
+
//(<beforeUpdateNode>)
|
|
770
|
+
//(</beforeUpdateNode>)
|
|
263
771
|
|
|
264
|
-
|
|
265
|
-
|
|
772
|
+
//(<additionalAttributes>)
|
|
773
|
+
//(</additionalAttributes>)
|
|
266
774
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
775
|
+
await dispatchToGraphEngine(_izContext, {
|
|
776
|
+
objType,
|
|
777
|
+
identifiers,
|
|
778
|
+
graphFields,
|
|
779
|
+
versionedDataIds,
|
|
780
|
+
originTimestamp,
|
|
781
|
+
settings: { returnSystemFieldsName, returnOldData },
|
|
782
|
+
parentFlowId,
|
|
783
|
+
callingFlowConfig,
|
|
784
|
+
storageTag,
|
|
785
|
+
records: listOfRecords
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
} else if (updateDataDetail.storageType === consts.STORAGE_TYPES.dynamoDB) {
|
|
789
|
+
const dynamoFields = extractFieldsByStorageTag(
|
|
790
|
+
_izContext,
|
|
791
|
+
storageTag,
|
|
792
|
+
updateDataDetails,
|
|
793
|
+
updateDataDetail,
|
|
794
|
+
requestParams,
|
|
795
|
+
identifiers
|
|
796
|
+
);
|
|
797
|
+
if (Object.keys(dynamoFields).length > 0) {
|
|
798
|
+
//(<beforeUpdateDynamoDb>)
|
|
799
|
+
//(</beforeUpdateDynamoDb>)
|
|
270
800
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
801
|
+
const identifiersForUpdateData =
|
|
802
|
+
await dynamoDbIdentifiersByStorageResource(
|
|
803
|
+
_izContext,
|
|
804
|
+
objectSchema,
|
|
805
|
+
updateDataDetail,
|
|
806
|
+
identifiers
|
|
807
|
+
);
|
|
808
|
+
_izContext.logger.debug(
|
|
809
|
+
'identifiersForUpdateData',
|
|
810
|
+
identifiersForUpdateData
|
|
811
|
+
);
|
|
282
812
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
_izContext.uniqueRequestId
|
|
289
|
-
),
|
|
290
|
-
awaitingStepIds,
|
|
291
|
-
{
|
|
292
|
-
additionalAttributes: {
|
|
293
|
-
callingFlowConfig
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
);
|
|
297
|
-
_izContext.logger.debug(
|
|
298
|
-
'awaitingMultipleStep',
|
|
299
|
-
awaitingMultipleStep
|
|
300
|
-
);
|
|
813
|
+
let hasGraphInSchema = false;
|
|
814
|
+
for (const d of Object.values(updateDataDetails)) {
|
|
815
|
+
if (d.storageType === consts.STORAGE_TYPES.graph) {
|
|
816
|
+
hasGraphInSchema = true;
|
|
817
|
+
break;
|
|
301
818
|
}
|
|
819
|
+
}
|
|
302
820
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
updateNodeParams,
|
|
315
|
-
callingFlowSharedLib.addParentCallingFlowConfig(
|
|
316
|
-
callingFlowConfig,
|
|
317
|
-
callingFlowSharedLib.createCallingFlowConfig(
|
|
318
|
-
//(<callingFlowProperties>)
|
|
319
|
-
await lambdaSharedLib.lambdaFunctionName(
|
|
320
|
-
_izContext,
|
|
321
|
-
TOPIC_NAME_GENERATE_CODE.updateNodeComplete
|
|
322
|
-
),
|
|
323
|
-
{}
|
|
324
|
-
//(</callingFlowProperties>)
|
|
325
|
-
)
|
|
326
|
-
)
|
|
327
|
-
);
|
|
328
|
-
|
|
329
|
-
_izContext.logger.debug(
|
|
330
|
-
'messageObject before send message:',
|
|
331
|
-
updateNodeParams
|
|
332
|
-
);
|
|
333
|
-
|
|
334
|
-
const resSNS = await sns.publishAsync(_izContext, {
|
|
335
|
-
Message: JSON.stringify(updateNodeParams),
|
|
336
|
-
MessageAttributes: sns.createStringMessageAttributes(
|
|
337
|
-
_izContext,
|
|
338
|
-
callingFlowSharedLib.addCallingFlowToSnsResponseMessageAttributes(
|
|
339
|
-
callingFlowConfig,
|
|
340
|
-
{}
|
|
341
|
-
)
|
|
342
|
-
),
|
|
343
|
-
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
344
|
-
_izContext,
|
|
345
|
-
TOPIC_NAME_GRAPH_HANDLER.inUpdateNode,
|
|
346
|
-
storageTag
|
|
347
|
-
)
|
|
821
|
+
if (hasGraphInSchema) {
|
|
822
|
+
_izContext.logger.debug('must process graph first');
|
|
823
|
+
listOfRecords.push({
|
|
824
|
+
[storageTag]: {
|
|
825
|
+
serviceTag: updateDataDetail.serviceTag,
|
|
826
|
+
tableName: updateDataDetail.tableName,
|
|
827
|
+
objInstanceFull: {
|
|
828
|
+
identifiers: identifiersForUpdateData,
|
|
829
|
+
fields: dynamoFields
|
|
830
|
+
}
|
|
831
|
+
}
|
|
348
832
|
});
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
);
|
|
353
|
-
|
|
354
|
-
// ── DynamoDB ──────────────────────────────────────────────────────────
|
|
355
|
-
} else if (
|
|
356
|
-
updateDataDetail.storageType === consts.STORAGE_TYPES.dynamoDB
|
|
357
|
-
) {
|
|
358
|
-
const dynamoFields = createObjInstanceFullFieldsByStorageTag(
|
|
833
|
+
} else {
|
|
834
|
+
_izContext.logger.debug('can process record dynamo');
|
|
835
|
+
updateItem = await dynamodbSharedLib.updateItem(
|
|
359
836
|
_izContext,
|
|
360
|
-
|
|
361
|
-
updateDataDetail
|
|
362
|
-
);
|
|
363
|
-
if (!Object.keys(dynamoFields).length) return;
|
|
364
|
-
|
|
365
|
-
//(<beforeUpdateDynamoDb>)
|
|
366
|
-
//(</beforeUpdateDynamoDb>)
|
|
367
|
-
|
|
368
|
-
const identifiersForUpdateData =
|
|
369
|
-
await dynamoDbIdentifiersByStorageResource(
|
|
837
|
+
await dynamodbSharedLib.tableName(
|
|
370
838
|
_izContext,
|
|
371
|
-
|
|
372
|
-
updateDataDetail
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
'
|
|
377
|
-
identifiersForUpdateData
|
|
839
|
+
updateDataDetail.tableName,
|
|
840
|
+
updateDataDetail.serviceTag
|
|
841
|
+
),
|
|
842
|
+
identifiersForUpdateData,
|
|
843
|
+
dynamoFields,
|
|
844
|
+
{ returnValues: 'ALL_NEW' }
|
|
378
845
|
);
|
|
379
846
|
|
|
380
|
-
|
|
381
|
-
Object.values(updateDataDetails).some(
|
|
382
|
-
(updateDataDetail) =>
|
|
383
|
-
updateDataDetail.storageType === consts.STORAGE_TYPES.graph
|
|
384
|
-
)
|
|
385
|
-
) {
|
|
386
|
-
_izContext.logger.debug('must process graph first');
|
|
387
|
-
listOfRecords.push({
|
|
388
|
-
[storageTag]: {
|
|
389
|
-
serviceTag: updateDataDetail.serviceTag,
|
|
390
|
-
tableName: updateDataDetail.tableName,
|
|
391
|
-
objInstanceFull: {
|
|
392
|
-
identifiers: identifiersForUpdateData,
|
|
393
|
-
fields: dynamoFields
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
});
|
|
397
|
-
} else {
|
|
398
|
-
_izContext.logger.debug('can process record dynamo');
|
|
399
|
-
updateItem = await dynamodbSharedLib.updateItem(
|
|
400
|
-
_izContext,
|
|
401
|
-
await dynamodbSharedLib.tableName(
|
|
402
|
-
_izContext,
|
|
403
|
-
updateDataDetail.tableName,
|
|
404
|
-
updateDataDetail.serviceTag
|
|
405
|
-
),
|
|
406
|
-
identifiersForUpdateData,
|
|
407
|
-
dynamoFields,
|
|
408
|
-
{ returnValues: 'ALL_NEW' }
|
|
409
|
-
);
|
|
410
|
-
|
|
411
|
-
_izContext.logger.debug('updateItem:', updateItem);
|
|
412
|
-
}
|
|
847
|
+
_izContext.logger.debug('updateItem:', updateItem);
|
|
413
848
|
}
|
|
414
849
|
}
|
|
415
|
-
|
|
416
|
-
|
|
850
|
+
}
|
|
851
|
+
}
|
|
417
852
|
|
|
418
|
-
//
|
|
419
|
-
if (
|
|
420
|
-
|
|
853
|
+
// 5. If no graph storage, complete immediately
|
|
854
|
+
if (!hasGraphStorage) {
|
|
855
|
+
await handleDynamoDbOnlyComplete(_izContext, {
|
|
421
856
|
objType,
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
};
|
|
427
|
-
|
|
428
|
-
//(<additionalProperties>)
|
|
429
|
-
//(</additionalProperties>)
|
|
430
|
-
|
|
431
|
-
if (
|
|
432
|
-
callingFlowConfig[
|
|
433
|
-
callingFlowSharedLib.consts.CALLINGFLOWPROPERTIES_PROPERTYNAME
|
|
434
|
-
]
|
|
435
|
-
) {
|
|
436
|
-
_izContext.logger.debug('HAVE CALLING FLOW');
|
|
437
|
-
messageObject =
|
|
438
|
-
callingFlowSharedLib.addPassBackPropertiesToSnsResponseMessageObject(
|
|
439
|
-
callingFlowConfig,
|
|
440
|
-
messageObject
|
|
441
|
-
);
|
|
442
|
-
|
|
443
|
-
_izContext.logger.debug('after create callingFlow', messageObject);
|
|
444
|
-
await sns.publishAsync(_izContext, {
|
|
445
|
-
Message: JSON.stringify(messageObject),
|
|
446
|
-
MessageAttributes: sns.createStringMessageAttributes(
|
|
447
|
-
_izContext,
|
|
448
|
-
callingFlowSharedLib.addCallingFlowToSnsResponseMessageAttributes(
|
|
449
|
-
callingFlowConfig,
|
|
450
|
-
{}
|
|
451
|
-
)
|
|
452
|
-
),
|
|
453
|
-
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
454
|
-
_izContext,
|
|
455
|
-
TOPIC_NAME_GENERATE_CODE.outUpdateNodeComplete
|
|
456
|
-
)
|
|
457
|
-
});
|
|
458
|
-
}
|
|
857
|
+
updateItem,
|
|
858
|
+
requestParams,
|
|
859
|
+
callingFlowConfig
|
|
860
|
+
});
|
|
459
861
|
}
|
|
460
862
|
|
|
461
863
|
return {
|
|
@@ -469,7 +871,6 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
469
871
|
};
|
|
470
872
|
} catch (err) {
|
|
471
873
|
_izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] error:`, err);
|
|
472
|
-
_izContext.logger.error('[<%- flowTag %>LogicalLib] error:', err);
|
|
473
874
|
throw err;
|
|
474
875
|
}
|
|
475
876
|
}
|