@izara_project/izara-market-library-service-schemas 1.0.1 → 1.0.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 (31) hide show
  1. package/index.js +25 -0
  2. package/package.json +6 -2
  3. package/src/GenerateCodeLibs/index.js +24 -0
  4. package/src/GenerateCodeLibs/src/GenerateCodeLibs.js +1373 -0
  5. package/src/MainLibs/index.js +24 -0
  6. package/src/MainLibs/src/Consts.js +0 -0
  7. package/src/MainLibs/src/Utils.js +27 -0
  8. package/src/SourceManager/index.js +23 -0
  9. package/src/SourceManager/src/CreateSource.js +182 -0
  10. package/src/SourceManager/src/Utils.js +50 -0
  11. package/src/TemplateManager/index.js +23 -0
  12. package/src/TemplateManager/src/GenerateCode.js +135 -0
  13. package/src/TemplateManager/src/MainResourcesYaml/CreateSourceData.js +76 -0
  14. package/src/TemplateManager/src/MainResourcesYaml/TemplateAndData/DynamoDbMain/Data/MainDynamoDbYamlData.js +153 -0
  15. package/src/TemplateManager/src/MainResourcesYaml/TemplateAndData/DynamoDbMain/Template/DynamoDb.ejs +31 -0
  16. package/src/TemplateManager/src/MainResourcesYaml/TemplateAndData/DynamoDbMain/Template/DynamoDb.exampleData.js +12 -0
  17. package/src/TemplateManager/src/PerActionEndpoint/CreateSourceData.js +131 -0
  18. package/src/TemplateManager/src/PerActionEndpoint/DataPerActionEndpoint.js +0 -0
  19. package/src/TemplateManager/src/PerActionEndpoint/TemplateAndData/Handler/Handler.js +0 -0
  20. package/src/TemplateManager/src/PerActionEndpoint/TemplateAndData/MainFunction/MainFunctionTemplate/Create.js +18 -0
  21. package/src/TemplateManager/src/PerActionEndpoint/TemplateAndData/MainFunction/MainFunctionTemplate/Delete.js +18 -0
  22. package/src/TemplateManager/src/PerActionEndpoint/TemplateAndData/MainFunction/MainFunctionTemplate/Get.js +18 -0
  23. package/src/TemplateManager/src/PerActionEndpoint/TemplateAndData/MainFunction/MainFunctionTemplate/Update.js +18 -0
  24. package/src/TemplateManager/src/PerActionEndpoint/TemplateAndData/MainFunction/MainFunctionTemplateData.js +0 -0
  25. package/src/TemplateManager/src/PerActionEndpoint/TemplateAndData/ResourceYaml/Lambda/Data/LambdaYamlData.js +166 -0
  26. package/src/TemplateManager/src/PerActionEndpoint/TemplateAndData/ResourceYaml/Lambda/Template/HdrApi.ejs +0 -0
  27. package/src/TemplateManager/src/PerActionEndpoint/TemplateAndData/ResourceYaml/Lambda/Template/HdrDsq.ejs +0 -0
  28. package/src/TemplateManager/src/PerActionEndpoint/TemplateAndData/ResourceYaml/Lambda/Template/HdrInv.ejs +26 -0
  29. package/src/TemplateManager/src/PerActionEndpoint/TemplateAndData/ResourceYaml/Lambda/Template/HdrInv.exampleData.js +15 -0
  30. package/src/TemplateManager/src/PerActionEndpoint/TemplateAndData/ResourceYaml/Lambda/Template/HdrSqs.ejs +0 -0
  31. package/src/TemplateManager/src/libs/Consts.js +108 -0
@@ -0,0 +1,1373 @@
1
+ /*
2
+ Copyright(C) 2021 Sven Mason < http://izara.io>
3
+
4
+ This program is free software: you can redistribute it and / or modify
5
+ it under the terms of the GNU Affero General Public License as
6
+ published by the Free Software Foundation, either version 3 of the
7
+ License, or(at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12
+ GNU Affero General Public License for more details.
13
+
14
+ You should have received a copy of the GNU Affero General Public License
15
+ along with this program.If not, see < http://www.gnu.org/licenses/>.
16
+ */
17
+
18
+ 'use strict';
19
+
20
+ const lodash = require('lodash');
21
+ const hash = require("object-hash")
22
+
23
+
24
+ const sqsSharedLib = require('@izara_project/izara-shared/src/SqsSharedLib');
25
+ const snsSharedLib = require('@izara_project/izara-shared/src/SnsSharedLib');
26
+ const inMemoryCacheLib = require('@izara_project/izara-shared/src/InMemoryCacheLib');
27
+ const callingFlowSharedLib = require('@izara_project/izara-shared/src/CallingFlowSharedLib');
28
+
29
+ const sns = require('@izara_project/izara-core-library-external-request/src/resources/Sns');
30
+ const sqs = require('@izara_project/izara-core-library-external-request/src/resources/Sqs');
31
+
32
+ const NoRetryError = require('@izara_project/izara-core-library-core/src/NoRetryError');
33
+ const { validateObject } = require('@izara_project/izara-core-library-core/src/Validator');
34
+
35
+
36
+ const getObjectSchema = require('@izara_project/izara-core-library-service-schemas/src/GetObjectSchema')
37
+ // const serviceSchemas = require('./ServiceSchemas');
38
+ const validatorSchema = require('@izara_project/izara-core-library-service-schemas/src/ValidatorSchema');
39
+ const serviceConfig = require('@izara_project/izara-core-library-service-schemas/src/ServiceConfig');
40
+ const utils = require('@izara_project/izara-core-library-service-schemas/src/Utils');
41
+ const consts = require('@izara_project/izara-core-library-service-schemas/src/Consts');
42
+ const explodedReqParams = require('@izara_project/izara-core-library-service-schemas/src/libs/ExplodedReqParams');
43
+ const {
44
+ generateDeliminatorTreeIdentifier,
45
+ generateDeliminatorTreePerFieldName
46
+ } = require('@izara_project/izara-core-library-service-schemas/src/libs/DeliminatorTree');
47
+
48
+ const nodeLabelRegexPattern = "^[a-zA-Z0-9_-]+(?:\:[a-zA-Z0-9_-]+)?$"
49
+
50
+
51
+
52
+ const schemaFunctionPerAction = {
53
+ [consts.ACTIONS.create]: validatorSchema.generateValidatorSchemaForCreate,
54
+ [consts.ACTIONS.update]: validatorSchema.generateValidatorSchemaForUpdate,
55
+ [consts.ACTIONS.get]: validatorSchema.generateValidatorSchemaForIdentifier,
56
+ [consts.ACTIONS.delete]: validatorSchema.generateValidatorSchemaForIdentifier,
57
+ }
58
+
59
+ const explodeDataPerAction = {
60
+ [consts.ACTIONS.create]: explodedReqParams.explodedDataForCreate,
61
+ [consts.ACTIONS.get]: explodedReqParams.explodedDataForIdentifiers,
62
+ }
63
+
64
+
65
+ /*
66
+ ---------- Contain function use for generated code ----------
67
+ */
68
+
69
+ /**
70
+ *
71
+ * @param {middleware} middleware
72
+ * @param {string} objectType - name of ObjectType
73
+ * @param {string} action - action type of Lambda create | update | get | delete
74
+ * @param {object} [setting]
75
+ * @param {string[]} [setting.specificFieldNames] - optional - specific fieldNames use as param in generateValidatorFunction
76
+ */
77
+ function validateSchemaMiddleware(
78
+ middleware,
79
+ objectType,
80
+ action,
81
+ setting = {}
82
+ ) {
83
+
84
+ if (!schemaFunctionPerAction[action] || !explodeDataPerAction[action]) {
85
+ throw new NoRetryError(`Not found function for generateValidatorSchema or explodeDataPerAction of action:${action}`);
86
+ }
87
+
88
+ middleware.setServiceSchema(
89
+ schemaFunctionPerAction[action],
90
+ explodeDataPerAction[action],
91
+ {
92
+ objectType: objectType,
93
+ specificFieldNames: setting.specificFieldNames ? setting.specificFieldNames : []
94
+ },
95
+ );
96
+ }
97
+
98
+ /**
99
+ * use to validate record for Lambda handler hdrSqs/hdrDsq
100
+ * Note!: cannot throw error when use this function outside recordHandler
101
+ *
102
+ * @param {object} record - one record from sqs
103
+ * @param {string} lambdaFunctionName - name of Lambda used to build SQS/DLQ // QueueName
104
+ * @param {string} objectType - name of ObjectType
105
+ * @param {string} action - action type of Lambda create | update | get | delete
106
+ * @param {object} [setting]
107
+ * @param {string[]} [setting.specificFieldNames] - optional - specific fieldNames use as param in generateValidatorFunction
108
+ */
109
+ async function validateSchemaPerRecord(
110
+ record,
111
+ lambdaFunctionName,
112
+ objType,
113
+ action, // action
114
+ setting = {}
115
+ ) {
116
+ try {
117
+ record._izContext.logger.debug("validateSchemaPerRecord: ", record,
118
+ lambdaFunctionName,
119
+ objType,
120
+ action, // action
121
+ setting
122
+ )
123
+
124
+ if (!schemaFunctionPerAction[action] || !explodeDataPerAction[action]) {
125
+ throw new Error(`Not found function for generateValidatorSchema or function for explodeData of action:${action}`);
126
+ }
127
+
128
+ const objectSchema = await getObjectSchema.getObjSchemaFromS3WithHierarchy(record._izContext, objType);
129
+
130
+ const generateValidatorFunction = schemaFunctionPerAction[action];
131
+ const explodeDataFunction = explodeDataPerAction[action]
132
+
133
+ const generatedSchema = await generateValidatorFunction(record._izContext, objType, setting.specificFieldNames);
134
+ record._izContext.logger.debug(`generatedSchema in validateSchemaPerRecord : `, generatedSchema);
135
+
136
+
137
+ const explodedDataRequestParams = await explodeDataFunction(
138
+ record._izContext,
139
+ record.body.Message,
140
+ objectSchema
141
+ );
142
+
143
+
144
+ record._izContext.logger.debug('explodedDataRequestParams in validateSchemaPerRecord : ', JSON.stringify(explodedDataRequestParams));
145
+
146
+
147
+ let validateStatus = validateObject(record._izContext, generatedSchema, explodedDataRequestParams);
148
+ record._izContext.logger.debug('validateStatus : ', validateStatus);
149
+
150
+ // if not pass validate will sent messsage to dlq and throw NoRetryError
151
+ if (!validateStatus.pass) {
152
+ await messageToDlq(record, `Invalid: ${validateStatus.error}`, sqsSharedLib.sqsQueueUrlDLQ(lambdaFunctionName));
153
+ record._izError = new Error(validateStatus.error)
154
+ }
155
+ } catch (error) {
156
+ await messageToDlq(record, error.message, sqsSharedLib.sqsQueueUrlDLQ(lambdaFunctionName));
157
+ record._izError = new Error(error)
158
+ }
159
+
160
+ }
161
+
162
+
163
+
164
+ async function sendMsgOutComplete(_izContext, topicName, messageObj, callingFlowConfig) {
165
+
166
+ try {
167
+ // add callingFlow to message
168
+ messageObj = callingFlowSharedLib.addPassBackPropertiesToSnsResponseMessageObject(callingFlowConfig, messageObj);
169
+ let messageAttributes = callingFlowSharedLib.addCallingFlowToSnsResponseMessageAttributes(callingFlowConfig, {});
170
+
171
+ let sendMessageOutComplete = {
172
+ Message: JSON.stringify(messageObj),
173
+ MessageAttributes: sns.createStringMessageAttributes(_izContext, messageAttributes),
174
+ TopicArn: snsSharedLib.snsTopicArn(topicName),
175
+ };
176
+
177
+ _izContext.logger.debug(`Send message to ${topicName} :`, sendMessageOutComplete);
178
+ await sns.publishAsync(_izContext, sendMessageOutComplete);
179
+ return;
180
+ } catch (error) {
181
+ throw error;
182
+ }
183
+
184
+ }
185
+
186
+
187
+
188
+
189
+ /**
190
+ * @param {object} record - One record from sqs.
191
+ * @param {string} messageFailError - The message error.
192
+ * @param {object} lambdaFunctionName - Queue anme what to send to dlq./name of Lambda being invoked, used to build SQS/DLQ
193
+ *
194
+ */
195
+ async function messageToDlq(record, messageFailError, queueUrl) {
196
+
197
+ let messageBody = record.body
198
+
199
+ let params = {
200
+ QueueUrl: queueUrl,
201
+ MessageAttributes: {
202
+ messageFailError: {
203
+ DataType: "String",
204
+ StringValue: messageFailError
205
+ }
206
+ },
207
+ MessageBody: JSON.stringify(messageBody),
208
+ };
209
+
210
+ record._izContext.logger.debug('messageToDlq, params before sending DLQ', params);
211
+
212
+ await sqs.sendMessage(record._izContext, params).promise();
213
+ record._izContext.logger.debug("----- messageToDlq sendMessage success -----");
214
+ };
215
+
216
+
217
+ /**
218
+ * helper function for get endpoint
219
+ * create get data detail for each storageTag
220
+ *
221
+ * @param {Object} _izContext
222
+ * @param {Object} objectSchema
223
+ */
224
+ async function createGetDataDetails(_izContext, objectSchema) {
225
+
226
+ // group versionedData per storageTag
227
+ // or should group versionedData per graph serviceTag
228
+ let versionedDataPerStorageTag = {}
229
+ if (objectSchema?.addOnDataStructure?.length) {
230
+ for (let addOn of objectSchema.addOnDataStructure) {
231
+ if (addOn.type !== "versionedData") {
232
+ continue;
233
+ }
234
+
235
+ if (!versionedDataPerStorageTag.hasOwnProperty(addOn.storageResourceTag)) {
236
+ versionedDataPerStorageTag[addOn.storageResourceTag] = [];
237
+ }
238
+
239
+ versionedDataPerStorageTag[addOn.storageResourceTag].push(addOn);
240
+ }
241
+ }
242
+
243
+ _izContext.logger.debug("versionedDataPerStorageTag: ", versionedDataPerStorageTag);
244
+
245
+
246
+ let getGraphDataDetails = {};
247
+ let getDynamoDbDataDetails = {};
248
+
249
+
250
+ // reference to graph serviceTag that already used
251
+ let graphStorageTagPerGraphServiceTag = {} // {serviceTag:storageTag,... }
252
+
253
+
254
+ for (let [storageTag, storageData] of Object.entries(objectSchema.storageResources)) {
255
+
256
+ // collect fieldNames per storageTag
257
+ let storageTagFieldNames = [];
258
+ for (let [fieldName, fieldNameData] of Object.entries(objectSchema.fieldNames)) {
259
+ if (fieldNameData.storageResourceTags.includes(storageTag)) {
260
+ storageTagFieldNames.push(fieldName);
261
+ }
262
+ }
263
+
264
+ if (storageData.storageType === consts.STORAGE_TYPES.graph) {
265
+
266
+ let useStorageTag = storageTag;
267
+ let graphServiceTag = await serviceConfig.getGraphServiceTagWithCache(_izContext, storageData.graphServerTag);
268
+
269
+ // check duplicate graph serviceTag
270
+ if (!graphStorageTagPerGraphServiceTag.hasOwnProperty(graphServiceTag)) {
271
+ graphStorageTagPerGraphServiceTag[graphServiceTag] = storageTag;
272
+ } else {
273
+ // overwrite useStorageTag if graphServiceTag already used
274
+ _izContext.logger.debug("current storageTag: ", storageTag);
275
+ _izContext.logger.debug("use storageTag: ", useStorageTag);
276
+
277
+ useStorageTag = graphStorageTagPerGraphServiceTag[graphServiceTag];
278
+ }
279
+
280
+
281
+ if (!getGraphDataDetails.hasOwnProperty(useStorageTag)) {
282
+ getGraphDataDetails[useStorageTag] = {
283
+ storageType: storageData.storageType,
284
+ graphServiceTag: graphServiceTag,
285
+ fieldNames: storageTagFieldNames
286
+ }
287
+ } else {
288
+ getGraphDataDetails[useStorageTag].fieldNames =
289
+ [...new Set(getGraphDataDetails[useStorageTag].fieldNames.concat(storageTagFieldNames))];
290
+ }
291
+
292
+
293
+ // add versionedData fieldNames
294
+ if (versionedDataPerStorageTag.hasOwnProperty(storageTag)) {
295
+ if (!getGraphDataDetails[useStorageTag].hasOwnProperty("versionedDatas")) {
296
+ getGraphDataDetails[useStorageTag].versionedDatas = {};
297
+ }
298
+
299
+ for (let versionedData of versionedDataPerStorageTag[storageTag]) {
300
+ let versionedDataFieldNames = versionedData.fieldNames.map(data => data.fieldName);
301
+ Object.assign(
302
+ getGraphDataDetails[useStorageTag].versionedDatas,
303
+ { [versionedData.versionedDataLabel]: versionedDataFieldNames }
304
+ )
305
+ }
306
+ }
307
+
308
+ } else if (storageData.storageType === consts.STORAGE_TYPES.dynamoDB) {
309
+
310
+ Object.assign(getDynamoDbDataDetails, {
311
+ [storageTag]: {
312
+ storageType: storageData.storageType,
313
+ tableName: storageData.tableName,
314
+ fieldNames: storageTagFieldNames
315
+ }
316
+ })
317
+
318
+ if (storageData.groupByPartitionKeyField) {
319
+ Object.assign(
320
+ getDynamoDbDataDetails[storageTag],
321
+ {
322
+ groupByPartitionKeyField: storageData.groupByPartitionKeyField
323
+ }
324
+ )
325
+ }
326
+
327
+
328
+ } else {
329
+ throw new NoRetryError("Unhanled storageType");
330
+ }
331
+ }
332
+
333
+ _izContext.logger.debug("getGraphDataDetail: ", getGraphDataDetails);
334
+ _izContext.logger.debug("getDynamoDbData: ", getDynamoDbDataDetails);
335
+
336
+
337
+ //-------- sort descending order of fieldNames.length --------
338
+ let sortedGetGraphWithVersionedData = Object.entries(getGraphDataDetails)
339
+ .filter((getGraphDetail) => getGraphDetail[1].hasOwnProperty("versionedDatas"))
340
+ .sort((storageDataA, storageDataB) =>
341
+ storageDataB[1].fieldNames.length - storageDataA[1].fieldNames.length
342
+ );
343
+
344
+ _izContext.logger.debug("sortedGetGraphWithVersionedData: ", sortedGetGraphWithVersionedData);
345
+
346
+
347
+ let sortedGetGraphWithoutVersionedData = Object.entries(getGraphDataDetails)
348
+ .filter((getGraphDetail) => !getGraphDetail[1].hasOwnProperty("versionedDatas"))
349
+ .sort((storageDataA, storageDataB) =>
350
+ storageDataB[1].fieldNames.length - storageDataA[1].fieldNames.length
351
+ );
352
+
353
+ _izContext.logger.debug("sortedGetGraphWithoutVersionedData: ", sortedGetGraphWithoutVersionedData);
354
+
355
+
356
+ let sortedGetDynamoDbData = Object.entries(getDynamoDbDataDetails).sort((storageDataA, storageDataB) =>
357
+ storageDataB[1].fieldNames.length - storageDataA[1].fieldNames.length
358
+ );
359
+
360
+ _izContext.logger.debug("sortedGetDynamoDbData: ", sortedGetDynamoDbData);
361
+
362
+
363
+ // after sort data then filter duplicate fieldName
364
+ let allSortedGetDataDetails = [...sortedGetGraphWithVersionedData, ...sortedGetDynamoDbData, ...sortedGetGraphWithoutVersionedData];
365
+ _izContext.logger.debug("allSortedGetDataDetails: ", allSortedGetDataDetails);
366
+
367
+
368
+ let usedFieldName = [];
369
+ for (let [storageTag, getDataDetail] of allSortedGetDataDetails) {
370
+ let remainsFieldNames = [];
371
+ while (getDataDetail.fieldNames.length) {
372
+ let checkedFiedName = getDataDetail.fieldNames.pop();
373
+ if (!usedFieldName.includes(checkedFiedName)) {
374
+ usedFieldName.push(checkedFiedName);
375
+ remainsFieldNames.push(checkedFiedName);
376
+ }
377
+ }
378
+
379
+ getDataDetail.fieldNames = remainsFieldNames;
380
+ }
381
+
382
+ _izContext.logger.debug("newSortedArray after: ", allSortedGetDataDetails);
383
+
384
+
385
+ let getDataDetailResults = Object.fromEntries(
386
+ allSortedGetDataDetails.filter(([storageTag, getDataDetail]) => {
387
+ return (getDataDetail.fieldNames.length || getDataDetail.hasOwnProperty("versionedDatas"));
388
+ })
389
+ );
390
+
391
+ _izContext.logger.debug("getDataDetailResults: ", getDataDetailResults);
392
+
393
+ return getDataDetailResults;
394
+ }
395
+
396
+
397
+
398
+ /**
399
+ * create dynamoDb identifiers using request param and objectSchema
400
+ *
401
+ * @param {Object} _izContext
402
+ * @param {Object} objectSchema
403
+ * @param {Object} reqIdentifiers - input identifier from calling function
404
+ */
405
+ async function generateDynamoDbIdentifiers(_izContext, objectSchema, reqIdentifiers) {
406
+
407
+ // start create identifiers for dynamo
408
+ let dynamoIdentifiers = {};
409
+
410
+ for (let identifier of objectSchema.identifiers) {
411
+ if (identifier.name) {
412
+ let deliminator = identifier.deliminator || consts.DEFAULT_IDENTIFIER_DELIMINATOR;
413
+ let currentDeliminatorAmount = 0;
414
+
415
+ let concatenateValue = [];
416
+ for (let fieldName of identifier.fieldNames) {
417
+ concatenateValue.push(reqIdentifiers[fieldName]);
418
+
419
+ let deliminatorTreeFieldName = await generateDeliminatorTreePerFieldName(_izContext, fieldName, objectSchema.fieldNames[fieldName]);
420
+ _izContext.logger.debug("deliminatorTreeFieldName: ", deliminatorTreeFieldName);
421
+
422
+ if (deliminatorTreeFieldName[fieldName]?.deliminatorList?.[deliminator]) {
423
+ currentDeliminatorAmount = Math.max(
424
+ currentDeliminatorAmount,
425
+ deliminatorTreeFieldName[fieldName].deliminatorList[deliminator]
426
+ );
427
+ }
428
+ }
429
+
430
+ Object.assign(
431
+ dynamoIdentifiers,
432
+ {
433
+ [identifier.name]: concatenateValue.join(deliminator.repeat(currentDeliminatorAmount + 1))
434
+ }
435
+ );
436
+ } else {
437
+ Object.assign(
438
+ dynamoIdentifiers,
439
+ {
440
+ [identifier.fieldName]: reqIdentifiers[identifier.fieldName]
441
+ }
442
+ )
443
+ }
444
+ }
445
+
446
+ _izContext.logger.debug("dynamoIdentifiers: ", dynamoIdentifiers);
447
+
448
+ return dynamoIdentifiers;
449
+ }
450
+
451
+
452
+ /**
453
+ * create dynamoDb identifiers using request param and objectSchema
454
+ *
455
+ * @param {Object} _izContext
456
+ * @param {Object} objectSchema
457
+ * @param {Object} reqIdentifiers - input identifier from calling function
458
+ */
459
+ const generateDynamoDbIdentifiersWithCache = inMemoryCacheLib.inMemoryCacheLib(
460
+ generateDynamoDbIdentifiers, // fn
461
+ { // setting
462
+ max: 20, maxAge: 86400000, promise: true, profileName: 'generateDynamoDbIdentifiers',
463
+ normalizer: function (args) {
464
+ return hash([args[1], args[2]])
465
+ }
466
+ }
467
+ )
468
+
469
+ /**
470
+ *
471
+ * @param {Object} _izContext
472
+ * @param {Object} objectSchema
473
+ * @param {Object} getDataDetail
474
+ * @param {Object} reqIdentifiers
475
+ */
476
+ async function dynamoDbIdentifiersByStorageResource(_izContext, objectSchema, getDataDetail, reqIdentifiers) {
477
+
478
+ let dynamoIdentifiers = await generateDynamoDbIdentifiersWithCache(_izContext, objectSchema, reqIdentifiers)
479
+
480
+ let identifiersByStorageResource = {};
481
+
482
+ if (getDataDetail.groupByPartitionKeyField) {
483
+
484
+ let deliminatorTreeIdentifiers = await generateDeliminatorTreeIdentifier(_izContext, objectSchema);
485
+ _izContext.logger.debug("deliminatorTree: ", deliminatorTreeIdentifiers);
486
+
487
+ let compositeKeyDeliminator = objectSchema.compositeKeyDeliminator || consts.DEFAULT_IDENTIFIER_DELIMINATOR;
488
+
489
+ let currentDeliminatorAmount = 0;
490
+
491
+ for (let currentDeliminator of Object.values(deliminatorTreeIdentifiers)) {
492
+ if (currentDeliminator.deliminator === compositeKeyDeliminator) {
493
+ if (currentDeliminatorAmount < currentDeliminator.deliminatorList[compositeKeyDeliminator]) {
494
+ currentDeliminatorAmount = currentDeliminator.deliminatorList[compositeKeyDeliminator];
495
+ }
496
+ }
497
+ }
498
+
499
+ // sort dynamoDbIdentifiers data by objectSchema
500
+ let sortedIdentifiersValue = [];
501
+ for (let identifier of objectSchema.identifiers) {
502
+ let identifierName = identifier.fieldName || identifier.name;
503
+ sortedIdentifiersValue.push(dynamoIdentifiers[identifierName]);
504
+ }
505
+
506
+ let newIdentifierValue = sortedIdentifiersValue.join(compositeKeyDeliminator.repeat(currentDeliminatorAmount + 1));
507
+
508
+ identifiersByStorageResource = {
509
+ [getDataDetail.groupByPartitionKeyField]: newIdentifierValue
510
+ };
511
+
512
+ } else {
513
+ identifiersByStorageResource = dynamoIdentifiers;
514
+ }
515
+
516
+ return identifiersByStorageResource;
517
+ }
518
+
519
+
520
+
521
+ function collectGetData(_izContext, getDataResult, getDataDetail) {
522
+
523
+ if (!getDataResult) {
524
+ return {};
525
+ }
526
+
527
+ let collectedData = {};
528
+
529
+ if (getDataDetail.storageType === consts.STORAGE_TYPES.graph) {
530
+ // collect return data form main node
531
+ if (getDataResult.nodeProperties) {
532
+ for (let [mainFieldName, mainFieldNameValue] of Object.entries(getDataResult.nodeProperties)) {
533
+ if (getDataDetail.fieldNames.includes(mainFieldName)) {
534
+ Object.assign(collectedData, { [mainFieldName]: mainFieldNameValue });
535
+ }
536
+ }
537
+ }
538
+
539
+ // collect data from versionedData
540
+ if (getDataDetail.hasOwnProperty("versionedDatas") && Object.keys(getDataDetail.versionedDatas).length) {
541
+ let versionedDataLabels = Object.keys(getDataDetail.versionedDatas);
542
+
543
+ for (let versionedDataLabel of versionedDataLabels) {
544
+ if (getDataResult[versionedDataLabel]?.nodeProperties && Object.keys(getDataResult[versionedDataLabel].nodeProperties).length) {
545
+ let neededVersionedDataFieldNames = getDataDetail.versionedDatas[versionedDataLabel];
546
+
547
+ for (let neededVersionedDataFieldName of neededVersionedDataFieldNames) {
548
+ if (getDataResult[versionedDataLabel].nodeProperties[neededVersionedDataFieldName]) {
549
+ Object.assign(collectedData, { [neededVersionedDataFieldName]: getDataResult[versionedDataLabel].nodeProperties[neededVersionedDataFieldName] });
550
+ }
551
+ }
552
+ }
553
+ }
554
+ }
555
+
556
+ } else if (getDataDetail.storageType === consts.STORAGE_TYPES.dynamoDB) {
557
+
558
+ for (let [dynamoDbKey, dynamoDbValue] of Object.entries(getDataResult)) {
559
+ if (getDataDetail.fieldNames.includes(dynamoDbKey)) {
560
+ Object.assign(collectedData, { [dynamoDbKey]: dynamoDbValue });
561
+ }
562
+ }
563
+
564
+ } else {
565
+ throw new NoRetryError(`Unhandled storageType:${getDataDetail.storageType}`);
566
+ }
567
+
568
+ return collectedData
569
+ }
570
+
571
+
572
+
573
+
574
+ module.exports = {
575
+ sendMsgOutComplete,
576
+ messageToDlq,
577
+
578
+ validateSchemaMiddleware,
579
+ validateSchemaPerRecord,
580
+
581
+ createGetDataDetails,
582
+ generateDynamoDbIdentifiers,
583
+ generateDynamoDbIdentifiersWithCache,
584
+ dynamoDbIdentifiersByStorageResource,
585
+ collectGetData
586
+ }
587
+
588
+
589
+
590
+
591
+
592
+ // /**
593
+ // * filter request param depend on generatedValidatorSchema function
594
+ // * @param {object} _izContext
595
+ // * @param {object} requestParams - requestParams that need to filter
596
+ // * @param {string} action - use to match generateValidatorSchemaFunction
597
+ // * @param {string} objectType - objectType for search objectSchema
598
+ // * @param {string[]} specificFieldNames - setting of generateValidatorSchemaFunction
599
+ // */
600
+ // async function filterRequestParam(_izContext, requestParams, action, objectType, specificFieldNames) {
601
+
602
+ // if (!validatorSchema.schemaFunctionPerAction[action]) {
603
+ // throw new NoRetryError(`Not found function for generateValidatorSchema of action:${action}`);
604
+ // }
605
+
606
+ // // prepare variable
607
+ // const generateValidatorFunction = validatorSchema.schemaFunctionPerAction[action];
608
+
609
+ // const generatedValidatorSchema = await generateValidatorFunction(_izContext, objectType, specificFieldNames);
610
+
611
+ // // prepare new requestParams depend on properties of generatedValidatorSchema
612
+ // let newRequestParams = {}
613
+ // for (let validatorFieldName in generatedValidatorSchema.properties) {
614
+ // if (requestParams.hasOwnProperty(validatorFieldName)) {
615
+ // Object.assign(newRequestParams, { [validatorFieldName]: requestParams[validatorFieldName] })
616
+ // }
617
+ // }
618
+
619
+ // // add additionalRequest to requestParams
620
+ // if (requestParams.hasOwnProperty("additionalRequest") && Object.keys(requestParams.additionalRequest).length) {
621
+ // Object.assign(newRequestParams, { additionalRequest: requestParams.additionalRequest });
622
+ // }
623
+
624
+ // return newRequestParams
625
+ // }
626
+
627
+
628
+ // /**
629
+ // * reformat request for main function of each action
630
+ // * @param {Object} _izContext
631
+ // * @param {String} objectType
632
+ // * @param {String} action
633
+ // * @param {Object} requestParams
634
+ // * @returns
635
+ // */
636
+ // async function reformattedRequestParams(_izContext, objectType, action, requestParams) {
637
+ // _izContext.logger.debug("------ reformattedRequestParams ------");
638
+ // _izContext.logger.debug("objectType: ", objectType);
639
+ // _izContext.logger.debug("action: ", action);
640
+ // _izContext.logger.debug("requestParams: ", requestParams);
641
+
642
+ // const objectSchema = await getObjectSchema.getLocalObjectSchemasWithHierarchy(_izContext, objectType).then(data => data.records[0]);
643
+ // _izContext.logger.debug("objectSchema in reformatted: ", objectSchema);
644
+
645
+ // const identifierFieldNames = utils.getUsedFieldNamesOfIdentifiers(_izContext, objectSchema.identifiers);
646
+ // _izContext.logger.debug("identifierFieldNames: ", identifierFieldNames);
647
+
648
+ // let versionedDatas = [];
649
+ // if (objectSchema?.addOnDataStructure?.length) {
650
+ // for (let eachAddOn of objectSchema.addOnDataStructure) {
651
+ // if (eachAddOn.type === "versionedData") {
652
+ // versionedDatas.push(eachAddOn);
653
+ // }
654
+ // }
655
+ // }
656
+
657
+
658
+
659
+ // let reformattedReq
660
+
661
+ // // reformat request depend on action
662
+ // switch (action) {
663
+ // case consts.ACTIONS.create:
664
+ // _izContext.logger.debug("reformatted case create");
665
+
666
+ // // initial format
667
+ // reformattedReq = {
668
+ // identifiers: {},
669
+ // createFieldNames: {},
670
+ // relationships: []
671
+ // };
672
+
673
+ // let createFieldNames = Object.entries(objectSchema.fieldNames).reduce((returnFieldNames, [fieldName, fieldNameData]) => {
674
+ // if (identifierFieldNames.includes(fieldName)) {
675
+ // return returnFieldNames;
676
+ // }
677
+
678
+ // if (fieldNameData.requiredOnCreate === true || fieldNameData.optionalOnCreate === true) {
679
+ // returnFieldNames.push(fieldName);
680
+ // }
681
+ // return returnFieldNames;
682
+ // }, [])
683
+
684
+
685
+
686
+ // _izContext.logger.debug("createFieldNames: ", createFieldNames);
687
+
688
+
689
+ // for (const [reqFieldName, reqFieldData] of Object.entries(requestParams.fieldNames)) {
690
+ // if (identifierFieldNames.includes(reqFieldName)) {
691
+ // Object.assign(
692
+ // reformattedReq.identifiers,
693
+ // { [reqFieldName]: reqFieldData }
694
+ // );
695
+ // } else {
696
+ // if (createFieldNames.includes(reqFieldName)) {
697
+ // Object.assign(
698
+ // reformattedReq.createFieldNames,
699
+ // { [reqFieldName]: reqFieldData }
700
+ // );
701
+ // }
702
+ // }
703
+ // }
704
+
705
+ // if (requestParams?.relationships?.length) {
706
+ // reformattedReq.relationships = reformattedReq.relationships.concat(requestParams.relationships)
707
+ // }
708
+
709
+ // break;
710
+ // case consts.ACTIONS.update:
711
+ // // code block
712
+ // break;
713
+ // case consts.ACTIONS.get:
714
+ // // code block
715
+ // break;
716
+ // case consts.ACTIONS.delete:
717
+ // // code block
718
+ // break;
719
+ // default:
720
+ // throw new NoRetryError(`reformattedRequestParams:unhandled action:${action}`)
721
+ // }
722
+
723
+ // return reformattedReq;
724
+ // }
725
+
726
+ // const reformattedRequestParamsWithCache = inMemoryCacheLib.inMemoryCacheLib(
727
+ // reformattedRequestParams, // fn
728
+ // {
729
+ // max: 100, maxAge: 86400000, promise: true, profileName: 'reformattedRequestParams',
730
+ // normalizer: function (args) {
731
+ // return hash([args[1], args[2], args[3]]);
732
+ // }
733
+ // }
734
+ // )
735
+
736
+
737
+
738
+ // /**
739
+ // * filter identifiers from requestParams depend on objectSchema.identifiers
740
+ // * @param {object} _izContext
741
+ // * @param {object} objectSchema - objectSchema of objectType
742
+ // * @param {object} requestParams - requestParams from handler
743
+ // * @returns
744
+ // */
745
+ // function saperateIdentifierRequestParams(_izContext, objectSchema, requestParams) {
746
+
747
+ // let usedIdentifierTypes = utils.selectIdentifierTypeByPriority(_izContext, [], objectSchema);
748
+
749
+ // let identifierFieldNameList = utils.getUsedFieldNamesOfIdentifiers(_izContext, objectSchema.identifiers, usedIdentifierTypes);
750
+
751
+
752
+ // let identifiersObj = {};
753
+
754
+ // for (let identifierFieldName of identifierFieldNameList) {
755
+ // if (requestParams.hasOwnProperty(identifierFieldName)) {
756
+ // Object.assign(identifiersObj, { [identifierFieldName]: requestParams[identifierFieldName] });
757
+ // } else {
758
+ // throw new NoRetryError(`missing ${identifierFieldName} in requestParams`);
759
+ // }
760
+ // }
761
+
762
+
763
+ // return identifiersObj;
764
+ // }
765
+
766
+
767
+
768
+
769
+ // /*
770
+ // Q?
771
+ // - when perform action in dynamodb some table need to concatenate
772
+ // - need to generate new identifier of dynamodb depend on storageResource
773
+
774
+ // returnValue = {
775
+ // graph:{ // storageType
776
+ // graphHandler:{ // graph service name
777
+ // nodeLabel:"string" // generate node label here
778
+ // identifier: {
779
+ // prop1: value1,
780
+ // prop2: value2,
781
+ // },
782
+ // properties:{
783
+ // prop1: value1,
784
+ // prop2: value2,
785
+ // },
786
+ // versionedDataLabel:[
787
+ // // ...
788
+ // ],
789
+ // versionedDatas:[ // for [create | update] action
790
+ // {
791
+ // nodeLabel:"xxx",
792
+ // nodeProperties:{
793
+ // // ...versionedData node properties
794
+ // }
795
+ // hookProperties:["xxx", yyy]
796
+ // }
797
+ // ]
798
+ // nodePropertyLabel:{ // addOnDataStructure: type = nodePropertyLabel | attributeTree | , not implement yet
799
+ // // ...setting
800
+ // }
801
+ // },
802
+ // mediaGraph:{ // graph service name
803
+ // prop1:value1,
804
+ // prop2:value2,
805
+ // }
806
+ // },
807
+ // dynamoDb:{ // storageType
808
+ // table1:{ // tableName
809
+ // identifier: {
810
+ // prop1: value1,
811
+ // prop2: value2,
812
+ // },
813
+ // properties{
814
+ // prop1: value1,
815
+ // prop2: value2,
816
+ // }
817
+ // },
818
+ // table2:{ // tableName
819
+ // identifier: {
820
+ // prop1: value1,
821
+ // prop2: value2,
822
+ // },
823
+ // properties{
824
+ // prop1: value1,
825
+ // prop2: value2,
826
+ // }
827
+ // }
828
+ // }
829
+ // }
830
+ // */
831
+ // async function saperateRequestByStorageResources(_izContext, objectSchema, requestParams, action) {
832
+ // _izContext.logger.debug("Function: saperateRequestByStorageResources :", { requestParams, action })
833
+
834
+ // // -------------- initial return value --------------
835
+
836
+ // let returnValue = {}
837
+
838
+ // for (let storageType of consts.STORAGE_TYPE_LIST) {
839
+ // if (!returnValue.hasOwnProperty(storageType)) {
840
+ // returnValue[storageType] = {}
841
+ // }
842
+ // }
843
+
844
+ // _izContext.logger.debug("initial returnValue: ", returnValue);
845
+
846
+ // // -------------- initial return value --------------
847
+
848
+
849
+
850
+ // // create identifier object from requestParams
851
+ // let identifierObj = saperateIdentifierRequestParams(_izContext, objectSchema, requestParams);
852
+
853
+ // // separate requestParams by storageType
854
+ // for (let [storageTag, storageData] of Object.entries(objectSchema.storageResources)) {
855
+
856
+ // if (storageData.storageType === consts.STORAGE_TYPES.dynamoDB) {
857
+
858
+ // // separate by tableName
859
+ // let dynamoRequestParams = await separateRequestByDynamoDb(
860
+ // _izContext,
861
+ // objectSchema,
862
+ // requestParams,
863
+ // identifierObj,
864
+ // storageTag,
865
+ // storageData
866
+ // );
867
+ // _izContext.logger.debug("dynamoRequestParams: ", dynamoRequestParams);
868
+
869
+ // let tableName = storageData.tableName;
870
+ // if (returnValue[consts.STORAGE_TYPES.dynamoDB][tableName]) {
871
+ // throw new NoRetryError(`Have duplicate tableName in storageTag:${storageTag}`);
872
+ // }
873
+
874
+ // Object.assign(returnValue[consts.STORAGE_TYPES.dynamoDB], { [tableName]: dynamoRequestParams });
875
+
876
+ // } else if (storageData.storageType === consts.STORAGE_TYPES.graph) {
877
+
878
+ // // separate by GraphServiceName
879
+ // let graphRequestParams = await separateRequestByGraph(
880
+ // _izContext,
881
+ // objectSchema,
882
+ // requestParams,
883
+ // identifierObj,
884
+ // storageTag,
885
+ // storageData,
886
+ // action
887
+ // );
888
+ // _izContext.logger.debug("graphRequestParams: ", graphRequestParams);
889
+
890
+ // let graphServiceName = await serviceConfig.getGraphServiceNameFromGraphServerTagWithCache(_izContext, storageData.graphServerTag);
891
+
892
+
893
+ // if (returnValue[consts.STORAGE_TYPES.graph][graphServiceName]) {
894
+ // // have exists graphServiceName,
895
+ // // need to merge properties for multiple graphServerTag to one serviceName
896
+ // _izContext.logger.debug('exists serviceName');
897
+ // _izContext.logger.debug('graphRequestParams : ', graphRequestParams);
898
+ // _izContext.logger.debug('returnValue[consts.STORAGE_TYPES.graph][graphServiceName]: ',
899
+ // returnValue[consts.STORAGE_TYPES.graph][graphServiceName]
900
+ // );
901
+
902
+ // // merge node properties
903
+ // for (let graphProperty in graphRequestParams.properties) {
904
+ // if (!returnValue[consts.STORAGE_TYPES.graph][graphServiceName].properties.hasOwnProperty(graphProperty)) {
905
+ // Object.assign(
906
+ // returnValue[consts.STORAGE_TYPES.graph][graphServiceName].properties,
907
+ // { [graphProperty]: graphRequestParams.properties[graphProperty] }
908
+ // );
909
+ // }
910
+ // }
911
+
912
+
913
+ // /*
914
+ // if versionedDatas exists in graphRequestParams
915
+ // - check versionedDatas exists in returnValue[consts.STORAGE_TYPES.graph][graphServiceName]
916
+ // - if exists add versionedData in graphRequestParams to returnValue
917
+ // - if not exists create and add versionedDatas
918
+ // */
919
+
920
+ // // merge graph versionedData
921
+ // if (graphRequestParams.versionedDatas?.length) {
922
+ // if (Array.isArray(returnValue[consts.STORAGE_TYPES.graph][graphServiceName].versionedDatas)) {
923
+ // returnValue[consts.STORAGE_TYPES.graph][graphServiceName].versionedDatas =
924
+ // returnValue[consts.STORAGE_TYPES.graph][graphServiceName].versionedDatas.concat(graphRequestParams.versionedDatas)
925
+ // } else {
926
+ // returnValue[consts.STORAGE_TYPES.graph][graphServiceName].versionedDatas = graphRequestParams.versionedDatas
927
+ // }
928
+ // }
929
+
930
+
931
+ // } else {
932
+ // // not exists graphServiceName
933
+ // Object.assign(returnValue[consts.STORAGE_TYPES.graph], { [graphServiceName]: graphRequestParams });
934
+ // }
935
+
936
+ // } else {
937
+ // throw new NoRetryError(`Don't know storageType:${storageData.type} in storageTag:${storageTag}`);
938
+ // }
939
+ // }
940
+
941
+ // return returnValue
942
+
943
+ // }
944
+
945
+
946
+
947
+
948
+
949
+ // /**
950
+ // * helper function for separate requestParams depend on storageTag
951
+ // *
952
+ // * @param {Object} _izContext
953
+ // * @param {Object} objectSchema -
954
+ // * @param {Object} requestParams - requestParams from lambda
955
+ // * @param {Object} identifierObj - identifiers
956
+ // * @param {String} storageTag - storageTag of storageResource
957
+ // * @param {Object} storageData - data of storageResource
958
+ // * @returns {Object} - object of identifier and property for dynamodb
959
+ // */
960
+ // async function separateRequestByDynamoDb(_izContext, objectSchema, requestParams, identifierObj, storageTag, storageData) {
961
+ // _izContext.logger.debug('separateRequestByDynamoDb: ', {
962
+ // requestParams,
963
+ // identifierObj,
964
+ // storageTag,
965
+ // storageData
966
+ // });
967
+
968
+
969
+ // //----------------------- Filter requestParams ------------------------
970
+
971
+ // // filter requestParams that includes in storageTag
972
+ // let filteredRequestParams = {}
973
+ // for (let [fieldName, fieldNameData] of Object.entries(objectSchema.fieldNames)) {
974
+ // if (fieldNameData.storageResourceTags.includes(storageTag) && requestParams.hasOwnProperty(fieldName)) {
975
+ // Object.assign(filteredRequestParams, { [fieldName]: requestParams[fieldName] });
976
+ // }
977
+ // }
978
+
979
+ // //----------------------- End Filter requestParams ------------------------
980
+
981
+
982
+ // //----------------------- Create dynamoDb identifier object ------------------------
983
+
984
+ // // use identifierObj to prepare dynamodb identifiers
985
+ // let usedIdentifierTypes = utils.selectIdentifierTypeByPriority(_izContext, [], objectSchema);
986
+
987
+ // let deliminatorTree = await serviceSchemas.generateDeliminatorTree(_izContext, objectSchema, { objectType: objectSchema.objectType, serviceTag: process.env.iz_serviceTag }, usedIdentifierTypes);
988
+ // _izContext.logger.debug(`deliminatorTree objectType: ${objectSchema.objectType} : `, deliminatorTree)
989
+
990
+ // let dynamoDbIdentifier = {};
991
+ // for (let identifier of objectSchema.identifiers) {
992
+
993
+ // if (!usedIdentifierTypes.includes(identifier.type)) {
994
+ // continue;
995
+ // }
996
+
997
+ // if (identifier.hasOwnProperty("fieldName")) {
998
+
999
+ // Object.assign(dynamoDbIdentifier, { [identifier.fieldName]: identifierObj[identifier.fieldName] });
1000
+
1001
+ // } else if (identifier.hasOwnProperty("name") && identifier.hasOwnProperty("fieldNames")) {
1002
+
1003
+ // let deliminator = identifier.deliminator ? identifier.deliminator : "_";
1004
+
1005
+ // // if deliminatorList exists overwrite deliminator
1006
+ // if (deliminatorTree.identifiersToProcess?.[identifier.name]?.deliminatorList?.[deliminator]) {
1007
+ // let deliminatorAmount = deliminatorTree[identifier.name].deliminatorList[deliminator];
1008
+ // deliminator = deliminator.repeat(deliminatorAmount)
1009
+ // }
1010
+
1011
+ // let fieldNameDataList = [];
1012
+ // for (let identifierFieldName of identifier.fieldNames) {
1013
+ // fieldNameDataList.push(identifierObj[identifierFieldName]);
1014
+ // }
1015
+
1016
+ // Object.assign(dynamoDbIdentifier, { [identifier.name]: fieldNameDataList.join(deliminator) });
1017
+
1018
+ // } else {
1019
+ // throw new NoRetryError('separateRequestByDynamoDb: invalid identifier');
1020
+ // }
1021
+ // }
1022
+
1023
+ // //----------------------- End Create dynamoDb identifier object ------------------------
1024
+
1025
+
1026
+ // //----------------------- calculate composite deliminator amount ------------------------
1027
+
1028
+ // let compositeDeliminator = objectSchema.compositeKeyDeliminator ? objectSchema.compositeKeyDeliminator : "_";
1029
+
1030
+ // let compositeDeliminatorAmount = 0;
1031
+ // for (let deliminatorDetail of Object.values(deliminatorTree.identifiersToProcess)) {
1032
+ // if (deliminatorDetail?.deliminatorList?.[compositeDeliminator]) {
1033
+ // compositeDeliminatorAmount = Math.max(compositeDeliminatorAmount, deliminatorDetail.deliminatorList[compositeDeliminator]);
1034
+ // }
1035
+ // }
1036
+
1037
+ // compositeDeliminatorAmount + 1;
1038
+
1039
+ // //----------------------- End calculate composite deliminator amount ------------------------
1040
+
1041
+
1042
+ // //----------------------- create return value ------------------------
1043
+
1044
+ // // initial returnValue
1045
+ // let returnValue = {
1046
+ // identifiers: {},
1047
+ // properties: {}
1048
+ // }
1049
+
1050
+ // if (storageData.hasOwnProperty("groupByPartitionKeyField")) {
1051
+ // // concatenate identifierObj
1052
+ // let newIdentifier = Object.values(identifierObj).join(compositeDeliminator.repeat(compositeDeliminatorAmount));
1053
+
1054
+ // Object.assign(returnValue.identifiers, { [storageData.groupByPartitionKeyField]: newIdentifier });
1055
+ // Object.assign(returnValue.properties, filteredRequestParams);
1056
+
1057
+ // } else {
1058
+ // returnValue.identifiers = identifierObj;
1059
+
1060
+ // for (let requestParamProperty in filteredRequestParams) {
1061
+ // if (!identifierObj.hasOwnProperty(requestParamProperty)) {
1062
+ // Object.assign(returnValue.properties, { [requestParamProperty]: filteredRequestParams[requestParamProperty] });
1063
+ // }
1064
+ // }
1065
+
1066
+ // }
1067
+
1068
+ // //----------------------- End create return value ------------------------
1069
+
1070
+
1071
+ // return returnValue;
1072
+ // }
1073
+
1074
+
1075
+ // // helper function for separate requestParams fieldName per storageTag
1076
+ // async function separateRequestByGraph(_izContext, objectSchema, requestParams, identifierObj, storageTag, storageData, action) {
1077
+ // _izContext.logger.debug("separateRequestByGraph: ", {
1078
+ // requestParams,
1079
+ // identifierObj,
1080
+ // storageTag,
1081
+ // storageData,
1082
+ // action
1083
+ // });
1084
+
1085
+
1086
+ // //----------------------- Filter requestParams ------------------------
1087
+
1088
+ // // filter requestParams that includes in storageTag
1089
+ // let filteredRequestParams = {}
1090
+ // for (let [fieldName, fieldNameData] of Object.entries(objectSchema.fieldNames)) {
1091
+ // if (fieldNameData.storageResourceTags.includes(storageTag) && requestParams.hasOwnProperty(fieldName)) {
1092
+ // Object.assign(filteredRequestParams, { [fieldName]: requestParams[fieldName] });
1093
+ // }
1094
+ // }
1095
+
1096
+ // //----------------------- End Filter requestParams ------------------------
1097
+
1098
+
1099
+ // //----------------------- standard return value ------------------------
1100
+
1101
+ // // initial returnValue
1102
+ // let returnValue = {
1103
+ // identifiers: {},
1104
+ // properties: {}
1105
+ // }
1106
+
1107
+ // // add nodeLabel
1108
+ // if (objectSchema.hasOwnProperty("extendObjType")) {
1109
+ // let nodeLabel = `${objectSchema.objectType}:${objectSchema.extendObjType.objectType}`;
1110
+ // Object.assign(returnValue, { nodeLabel: nodeLabel });
1111
+ // } else {
1112
+ // Object.assign(returnValue, { nodeLabel: objectSchema.objectType });
1113
+ // }
1114
+
1115
+ // // add identifiers
1116
+ // returnValue.identifiers = identifierObj;
1117
+
1118
+ // // add properties from requestParams if not exists in identifierObj
1119
+ // for (let requestParamProperty in filteredRequestParams) {
1120
+ // if (!identifierObj.hasOwnProperty(requestParamProperty)) {
1121
+ // Object.assign(returnValue.properties, { [requestParamProperty]: filteredRequestParams[requestParamProperty] });
1122
+ // }
1123
+ // }
1124
+
1125
+ // //----------------------- End standard return value ------------------------
1126
+
1127
+
1128
+ // //----------------------- prepare additional return data per action ------------------------
1129
+
1130
+ // if (action === consts.ACTIONS.get) {
1131
+
1132
+ // if (
1133
+ // requestParams?.additionalRequest?.versionedDataLabel
1134
+ // && Array.isArray(requestParams.additionalRequest.versionedDataLabel)
1135
+ // && requestParams.additionalRequest.versionedDataLabel.length
1136
+ // && objectSchema.addOnDataStructure
1137
+ // && Array.isArray(objectSchema.addOnDataStructure)
1138
+ // ) {
1139
+ // // if versionedDataLabel exists in requestParams
1140
+ // // add versionedDataLabel to returnValue if exists in storageResourceTag
1141
+
1142
+ // // get addOnDataStructure versionedData depend on storageTag
1143
+ // let allAddOnVersionedDataPerStorageTag = objectSchema.addOnDataStructure.filter(
1144
+ // addOnVersionedData => (addOnVersionedData.type === "versionedData" && addOnVersionedData.storageResourceTag === storageTag)
1145
+ // );
1146
+
1147
+ // for (let addOnVersionedData of allAddOnVersionedDataPerStorageTag) {
1148
+ // if (requestParams.additionalRequest.versionedDataLabel.includes(addOnVersionedData.versionedDataLabel)) {
1149
+
1150
+ // if (!returnValue.hasOwnProperty("versionedDataLabel")) {
1151
+ // returnValue.versionedDataLabel = []
1152
+ // }
1153
+
1154
+ // returnValue.versionedDataLabel.push(addOnVersionedData.versionedDataLabel)
1155
+ // }
1156
+ // }
1157
+ // }
1158
+
1159
+ // } else if (action === consts.ACTIONS.create) {
1160
+
1161
+
1162
+ // } else if (action === consts.ACTIONS.update) {
1163
+ // _izContext.logger.debug("filter versionedData update")
1164
+ // _izContext.logger.debug("additionalReq: ", requestParams.additionalRequest.versionedDatas)
1165
+ // _izContext.logger.debug("addOnDataStructure: ", objectSchema.addOnDataStructure)
1166
+ // // {
1167
+ // // // ...properties
1168
+ // // additionalRequest: {
1169
+ // // versionedDatas: [
1170
+ // // {
1171
+ // // nodeLabel: "nodeLabelName",
1172
+ // // nodeProperties: {
1173
+ // // // ...properties of versionedData
1174
+ // // }
1175
+ // // }
1176
+ // // ]
1177
+ // // // ...other additional request
1178
+ // // }
1179
+ // // }
1180
+
1181
+ // // separate create versionedData request
1182
+ // if (
1183
+ // requestParams?.additionalRequest?.versionedDatas
1184
+ // && Array.isArray(requestParams.additionalRequest.versionedDatas)
1185
+ // && requestParams.additionalRequest.versionedDatas.length
1186
+ // && objectSchema.addOnDataStructure
1187
+ // && Array.isArray(objectSchema.addOnDataStructure)
1188
+ // ) {
1189
+
1190
+ // let versionedDataReqList = requestParams.additionalRequest.versionedDatas;
1191
+
1192
+ // // get addOnDataStructure versionedData depend on storageTag from objectSchema
1193
+ // let allAddOnVersionedDataPerStorageTag = objectSchema.addOnDataStructure.filter(
1194
+ // addOnVersionedData => (addOnVersionedData.type === "versionedData" && addOnVersionedData.storageResourceTag === storageTag)
1195
+ // );
1196
+
1197
+ // _izContext.logger.debug('allAddOnVersionedDataPerStorageTag update: ', allAddOnVersionedDataPerStorageTag);
1198
+
1199
+ // // check versionedData label in requestParams exists in allAddOnVersionedDataPerStorageTag
1200
+ // // if exists validate and add versionedData to return label
1201
+ // if (allAddOnVersionedDataPerStorageTag.length) {
1202
+ // for (let versionedDataReq of versionedDataReqList) {
1203
+ // // find exists versionedData Schema
1204
+ // let versionedDataSchema = allAddOnVersionedDataPerStorageTag.find(
1205
+ // addOnVersionedData => addOnVersionedData.versionedDataLabel === versionedDataReq.nodeLabel
1206
+ // );
1207
+
1208
+
1209
+
1210
+ // if (versionedDataSchema) {
1211
+ // _izContext.logger.debug('exists versionedDataSchema: ', versionedDataSchema);
1212
+
1213
+ // // validate versionedData
1214
+
1215
+ // let versionedDataValidatorSchema = generateValidatorSchemaForVersionedData(_izContext, versionedDataSchema, action);
1216
+ // _izContext.logger.debug("versionedData validator schema: ", versionedDataValidatorSchema);
1217
+
1218
+
1219
+ // _izContext.logger.debug("versionedDataReq before validate: ", versionedDataReq)
1220
+ // let validateVersionedDataStatus = validateObject(_izContext, versionedDataValidatorSchema, versionedDataReq);
1221
+ // _izContext.logger.debug("versionedData validate status: ", validateVersionedDataStatus);
1222
+
1223
+
1224
+ // if (validateVersionedDataStatus.pass === false) {
1225
+ // throw new NoRetryError("Function:separateRequestByGraph: ", validateVersionedDataStatus.error);
1226
+ // }
1227
+
1228
+ // if (!returnValue.hasOwnProperty("versionedDatas")) {
1229
+ // returnValue.versionedDatas = [];
1230
+ // }
1231
+ // // end validate versionedData
1232
+
1233
+
1234
+ // let hookProperties = [];
1235
+ // for (let fieldNameSetting of versionedDataSchema.fieldNames) {
1236
+ // hookProperties.push(fieldNameSetting.fieldName);
1237
+ // }
1238
+
1239
+ // Object.assign(versionedDataReq, { hookProperties });
1240
+
1241
+ // returnValue.versionedDatas.push(versionedDataReq);
1242
+ // }
1243
+ // }
1244
+ // }
1245
+
1246
+ // }
1247
+
1248
+
1249
+ // } else if (action === consts.ACTIONS.delete) {
1250
+
1251
+ // } else {
1252
+ // throw new NoRetryError("Function:separateRequestByGraph: invalid action")
1253
+ // }
1254
+
1255
+ // //----------------------- End prepare additional return data per action ------------------------
1256
+
1257
+
1258
+ // _izContext.logger.debug("Function:separateRequestByGraph: return value: ", returnValue);
1259
+ // return returnValue;
1260
+ // }
1261
+
1262
+
1263
+
1264
+ // function mergeReturnGetData(_izContext, dynamoDbData, graphData) {
1265
+ // let mergedData = {
1266
+ // properties: {}
1267
+ // };
1268
+
1269
+ // for (let dynamoDbDataDetail of dynamoDbData) {
1270
+ // for (let [dynamoDataProp, dynamoDataValue] of Object.entries(dynamoDbDataDetail)) {
1271
+ // if (!mergedData.properties.hasOwnProperty(dynamoDataProp)) {
1272
+ // Object.assign(mergedData.properties, { [dynamoDataProp]: dynamoDataValue })
1273
+ // }
1274
+ // }
1275
+
1276
+ // }
1277
+
1278
+ // for (let graphDataDetail of graphData) {
1279
+ // // add nodeProperties to mergedData
1280
+ // for (let [graphDataProp, graphDataValue] of Object.entries(graphDataDetail.nodeProperties)) {
1281
+ // if (!mergedData.properties.hasOwnProperty(graphDataProp)) {
1282
+ // Object.assign(mergedData.properties, { [graphDataProp]: graphDataValue })
1283
+ // }
1284
+ // }
1285
+
1286
+ // // add versionedData to mergedData
1287
+ // for (let [graphDataProp, graphDataValue] of Object.entries(graphDataDetail)) {
1288
+ // console.log({ graphDataProp, graphDataValue })
1289
+ // if (graphDataProp === "nodeLabels" || graphDataProp === "nodeProperties") {
1290
+ // continue;
1291
+ // }
1292
+
1293
+
1294
+ // if (Object.keys(graphDataValue.nodeProperties).length) {
1295
+
1296
+ // if (!mergedData.versionedDataLabel) {
1297
+ // mergedData.versionedDataLabel = {}
1298
+ // }
1299
+
1300
+ // Object.assign(mergedData.versionedDataLabel, { [graphDataValue.nodeLabels.join(":")]: graphDataValue.nodeProperties })
1301
+ // }
1302
+ // }
1303
+ // }
1304
+
1305
+ // return mergedData
1306
+ // }
1307
+
1308
+
1309
+
1310
+ // // this function not use for new version because versionedData will not saperate from request params
1311
+ // function generateValidatorSchemaForVersionedData(_izContext, versionedObjDataSchema, action) {
1312
+ // // input form of versionedData will be the same for create and update action
1313
+
1314
+ // // initial versionedData validatorSchema
1315
+ // let versionedDataValidatorSchema = {
1316
+ // type: "object",
1317
+ // required: ['nodeLabel', 'nodeProperties'],
1318
+ // properties: {
1319
+ // nodeLabel: {
1320
+ // type: 'string',
1321
+ // pattern: nodeLabelRegexPattern
1322
+ // },
1323
+ // nodeProperties: {
1324
+ // type: 'object',
1325
+ // required: [], // require fieldName
1326
+ // additionalProperties: false,
1327
+ // properties: {}
1328
+ // }
1329
+ // }
1330
+ // }
1331
+
1332
+ // // maybe not need to validate action get and delete because
1333
+ // if (action === consts.ACTIONS.create) {
1334
+ // for (let versionedFieldName of versionedObjDataSchema.fieldNames) {
1335
+ // if (versionedFieldName.requireOnCreate === true || versionedFieldName.optionalOnCreate === true) {
1336
+ // // add require fieldName to require array in validatorSchema
1337
+ // if (versionedFieldName.requireOnCreate === true) {
1338
+ // versionedDataValidatorSchema.properties.nodeProperties.required.push(versionedFieldName.fieldName)
1339
+ // }
1340
+
1341
+ // // add validation to properties
1342
+ // let versionedDataProperties = versionedDataValidatorSchema.properties.nodeProperties.properties;
1343
+ // Object.assign(versionedDataProperties, {
1344
+ // [versionedFieldName.fieldName]: {
1345
+ // type: versionedFieldName.type,
1346
+ // ...versionedFieldName.validation
1347
+ // }
1348
+ // })
1349
+
1350
+ // }
1351
+ // }
1352
+ // } else if (action === consts.ACTIONS.update) {
1353
+ // for (let versionedFieldName of versionedObjDataSchema.fieldNames) {
1354
+ // if (versionedFieldName.canUpdate === true || versionedFieldName.canUpdate === undefined) {
1355
+
1356
+ // // add validation to properties
1357
+ // let versionedDataProperties = versionedDataValidatorSchema.properties.nodeProperties.properties;
1358
+ // Object.assign(versionedDataProperties, {
1359
+ // [versionedFieldName.fieldName]: {
1360
+ // type: versionedFieldName.type,
1361
+ // ...versionedFieldName.validation
1362
+ // }
1363
+ // })
1364
+
1365
+ // }
1366
+ // }
1367
+ // } else {
1368
+ // throw new NoRetryError("Function:generateValidatorSchemaForVersionedData: invalid action")
1369
+ // }
1370
+
1371
+ // // return validator schema of versionedData
1372
+ // return versionedDataValidatorSchema;
1373
+ // }