@izara_project/izara-core-library-service-schemas 1.0.106 → 1.0.107

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/index.js CHANGED
@@ -25,6 +25,8 @@ import uploadUseCase from './src/libs/UploadUseCase.js';
25
25
  import relSchemaLib from './src/libs/RelSchemaLib.js';
26
26
  import s3Utils from './src/libs/s3Utils.js';
27
27
  import createNodeLib from './src/libs/CreateNodeLib.js';
28
+ import dataDetailsLib from './src/libs/DataDetailsLib.js';
29
+ import checkPermission from './src/libs/CheckPermission.js';
28
30
 
29
31
  import consts from './src/Consts.js';
30
32
  import getObjectSchema from './src/GetObjectSchema.js';
@@ -43,6 +45,8 @@ export {
43
45
  relSchemaLib,
44
46
  s3Utils,
45
47
  createNodeLib,
48
+ dataDetailsLib,
49
+ checkPermission,
46
50
 
47
51
  // ./src/
48
52
  consts,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@izara_project/izara-core-library-service-schemas",
3
- "version": "1.0.106",
3
+ "version": "1.0.107",
4
4
  "description": "Schemas for the service and objects it controls",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -30,6 +30,7 @@
30
30
  "@izara_project/izara-core-library-lambda": "^1.0.6",
31
31
  "@izara_project/izara-core-library-logger": "^1.0.8",
32
32
  "@izara_project/izara-core-library-s3": "^1.0.5",
33
+ "@izara_project/izara-core-library-sqs": "^1.0.5",
33
34
  "@izara_project/izara-shared-core": "^1.0.8",
34
35
  "@izara_project/izara-shared-service-schemas": "^1.0.35",
35
36
  "glob": "^13.0.0",
@@ -507,6 +507,164 @@ async function explodedNestedIdentifiersConcat(
507
507
  return concatIdentifier.split(deliminator.repeat(compositeDeliminatorAmount + level));
508
508
  }
509
509
 
510
+ /**
511
+ * create dynamoDb identifiers using request param and objectSchema
512
+ *
513
+ * @param {Object} _izContext
514
+ * @param {Object} objectSchema
515
+ * @param {Object} reqIdentifiers - input identifier from calling function
516
+ */
517
+ async function generateDynamoDbIdentifiers(
518
+ _izContext,
519
+ objectSchema,
520
+ reqIdentifiers,
521
+ bucketName = process.env.iz_serviceSchemaBucketName
522
+ ) {
523
+ // start create identifiers for dynamo
524
+ let dynamoIdentifiers = {};
525
+
526
+ for (let identifier of objectSchema.identifiers) {
527
+ if (identifier.name) {
528
+ let deliminator =
529
+ identifier.deliminator || coreConsts.DEFAULT_IDENTIFIER_DELIMINATOR;
530
+ let currentDeliminatorAmount = 0;
531
+
532
+ let concatenateValue = [];
533
+ for (let fieldName of identifier.fieldNames) {
534
+ concatenateValue.push(reqIdentifiers[fieldName]);
535
+
536
+ let deliminatorTreeFieldName =
537
+ await deliminatorTree.generateDeliminatorTreePerFieldName(
538
+ _izContext,
539
+ fieldName,
540
+ objectSchema.fieldNames[fieldName],
541
+ {},
542
+ bucketName
543
+ );
544
+ _izContext.logger.debug(
545
+ 'deliminatorTreeFieldName: ',
546
+ deliminatorTreeFieldName
547
+ );
548
+
549
+ if (
550
+ deliminatorTreeFieldName[fieldName]?.deliminatorList?.[deliminator]
551
+ ) {
552
+ currentDeliminatorAmount = Math.max(
553
+ currentDeliminatorAmount,
554
+ deliminatorTreeFieldName[fieldName].deliminatorList[deliminator]
555
+ );
556
+ }
557
+ }
558
+
559
+ Object.assign(dynamoIdentifiers, {
560
+ [identifier.name]: concatenateValue.join(
561
+ deliminator.repeat(currentDeliminatorAmount + 1)
562
+ )
563
+ });
564
+ } else {
565
+ Object.assign(dynamoIdentifiers, {
566
+ [identifier.fieldName]: reqIdentifiers[identifier.fieldName]
567
+ });
568
+ }
569
+ }
570
+
571
+ _izContext.logger.debug('dynamoIdentifiers: ', dynamoIdentifiers);
572
+
573
+ return dynamoIdentifiers;
574
+ }
575
+
576
+ /**
577
+ * create dynamoDb identifiers using request param and objectSchema
578
+ *
579
+ * @param {Object} _izContext
580
+ * @param {Object} objectSchema
581
+ * @param {Object} reqIdentifiers - input identifier from calling function
582
+ */
583
+ const generateDynamoDbIdentifiersWithCache = inMemoryCacheLib(
584
+ generateDynamoDbIdentifiers, // fn
585
+ {
586
+ // setting
587
+ max: 20,
588
+ maxAge: 86400000,
589
+ promise: true,
590
+ profileName: 'generateDynamoDbIdentifiers',
591
+ normalizer: function (args) {
592
+ return hash([args[1], args[2]]);
593
+ }
594
+ }
595
+ );
596
+
597
+
598
+ /**
599
+ *
600
+ * @param {Object} _izContext
601
+ * @param {Object} objectSchema
602
+ * @param {Object} dynamoStorageResource
603
+ * @param {Object} reqIdentifiers
604
+ */
605
+ async function dynamoDbIdentifiersByStorageResource(
606
+ _izContext,
607
+ objectSchema,
608
+ dynamoStorageResource,
609
+ reqIdentifiers,
610
+ bucketName = process.env.iz_serviceSchemaBucketName
611
+ ) {
612
+ let dynamoIdentifiers = await generateDynamoDbIdentifiersWithCache(
613
+ _izContext,
614
+ objectSchema,
615
+ reqIdentifiers,
616
+ bucketName
617
+ );
618
+
619
+ let identifiersByStorageResource = {};
620
+
621
+ if (dynamoStorageResource.groupByPartitionKeyField) {
622
+ let deliminatorTreeIdentifiers =
623
+ await deliminatorTree.generateDeliminatorTreeIdentifier(
624
+ _izContext,
625
+ objectSchema,
626
+ bucketName
627
+ );
628
+ _izContext.logger.debug('deliminatorTree: ', deliminatorTreeIdentifiers);
629
+
630
+ let compositeKeyDeliminator =
631
+ objectSchema.compositeKeyDeliminator ||
632
+ coreConsts.DEFAULT_IDENTIFIER_DELIMINATOR;
633
+
634
+ let currentDeliminatorAmount = 0;
635
+
636
+ for (let currentDeliminator of Object.values(deliminatorTreeIdentifiers)) {
637
+ if (currentDeliminator.deliminator === compositeKeyDeliminator) {
638
+ if (
639
+ currentDeliminatorAmount <
640
+ currentDeliminator.deliminatorList[compositeKeyDeliminator]
641
+ ) {
642
+ currentDeliminatorAmount =
643
+ currentDeliminator.deliminatorList[compositeKeyDeliminator];
644
+ }
645
+ }
646
+ }
647
+
648
+ // sort dynamoDbIdentifiers data by objectSchema
649
+ let sortedIdentifiersValue = [];
650
+ for (let identifier of objectSchema.identifiers) {
651
+ let identifierName = identifier.fieldName || identifier.name;
652
+ sortedIdentifiersValue.push(dynamoIdentifiers[identifierName]);
653
+ }
654
+
655
+ let newIdentifierValue = sortedIdentifiersValue.join(
656
+ compositeKeyDeliminator.repeat(currentDeliminatorAmount + 1)
657
+ );
658
+
659
+ identifiersByStorageResource = {
660
+ [dynamoStorageResource.groupByPartitionKeyField]: newIdentifierValue
661
+ };
662
+ } else {
663
+ identifiersByStorageResource = dynamoIdentifiers;
664
+ }
665
+
666
+ return identifiersByStorageResource;
667
+ }
510
668
 
511
669
 
512
670
  export default {
@@ -517,5 +675,10 @@ export default {
517
675
  identifiersFromIdentifiersConcat, // identifiersObjectFromCompositeIdentifier
518
676
 
519
677
  createNestedIdentifiersConcat, // createConcatIdentifier
520
- explodedNestedIdentifiersConcat // explodedConcatIdentifier
678
+ explodedNestedIdentifiersConcat, // explodedConcatIdentifier
679
+
680
+ generateDynamoDbIdentifiers,
681
+ generateDynamoDbIdentifiersWithCache,
682
+
683
+ dynamoDbIdentifiersByStorageResource
521
684
  }
package/src/Utils.js CHANGED
@@ -766,6 +766,75 @@ async function getApiLinksV2(objectTypes) {
766
766
  }
767
767
  }
768
768
 
769
+
770
+ function createFieldForUpdateDynamoDb(
771
+ _izContext,
772
+ objectSchema,
773
+ dynamoDataDetail,
774
+ fields
775
+ ) {
776
+ _izContext.logger.debug('createFieldForUpdateDynamoDb', {
777
+ objectSchema,
778
+ dynamoDataDetail,
779
+ fields
780
+ });
781
+
782
+ let fieldsForUpdateDynamo = {};
783
+
784
+ for (let [fieldName, fieldSetting] of Object.entries(
785
+ objectSchema.fieldNames
786
+ )) {
787
+ if (
788
+ fieldSetting.canUpdate == true ||
789
+ !fieldSetting.hasOwnProperty('canUpdate')
790
+ ) {
791
+ if (dynamoDataDetail.fieldNames.includes(fieldName)) {
792
+ if (fields[fieldName]) {
793
+ if (!fieldsForUpdateDynamo.hasOwnProperty(fields[fieldName])) {
794
+ _izContext.logger.debug('assign new fieldName', fields[fieldName]);
795
+ Object.assign(fieldsForUpdateDynamo, {
796
+ [fieldName]: fields[fieldName]
797
+ });
798
+ }
799
+ }
800
+ }
801
+ }
802
+ }
803
+ return fieldsForUpdateDynamo;
804
+ }
805
+
806
+ /**
807
+ * @param {object} record - One record from sqs.
808
+ * @param {string} messageFailError - The message error.
809
+ * @param {object} lambdaFunctionName - Queue anme what to send to dlq./name of Lambda being invoked, used to build SQS/DLQ
810
+ *
811
+ */
812
+ async function messageToDlq(record, messageFailError, queueUrl) {
813
+ let messageBody = record.body;
814
+
815
+ let params = {
816
+ QueueUrl: queueUrl,
817
+ MessageAttributes: {
818
+ messageFailError: {
819
+ DataType: 'String',
820
+ StringValue: messageFailError
821
+ }
822
+ },
823
+ MessageBody: JSON.stringify(messageBody)
824
+ };
825
+
826
+ record._izContext.logger.debug(
827
+ 'messageToDlq, params before sending DLQ',
828
+ params
829
+ );
830
+
831
+ await sqs.sendMessage(record._izContext, params);
832
+ record._izContext.logger.debug(
833
+ '----- messageToDlq sendMessage success -----'
834
+ );
835
+ }
836
+
837
+
769
838
  export default {
770
839
  createObjType,
771
840
  getIdentifierTypeByPriority,
@@ -792,5 +861,8 @@ export default {
792
861
 
793
862
  createLinkTypeId,
794
863
  getApiLinksV1,
795
- getApiLinksV2
864
+ getApiLinksV2,
865
+
866
+ createFieldForUpdateDynamoDb,
867
+ messageToDlq
796
868
  }
@@ -24,31 +24,30 @@ import { objectHash as hash } from '@izara_project/izara-shared-core';
24
24
  import Logger from '@izara_project/izara-core-library-logger';
25
25
  import uploadUseCase from './libs/UploadUseCase.js';
26
26
 
27
+ import { validateObjType } from '@izara_project/izara-shared-service-schemas';
28
+ import { validator as validateObject } from '@izara_project/izara-core-library-core';
29
+ import sqsSharedLib from '@izara_project/izara-core-library-sqs';
30
+ import explodedReqParams from './libs/ExplodedReqParams.js';
31
+ import getObjectSchema from './GetObjectSchema.js';
27
32
  import serviceConfig from './ServiceConfig.js';
33
+ import consts from './Consts.js';
28
34
  import utils from './Utils.js';
29
- import getObjectSchema from './GetObjectSchema.js';
30
- import consts from './Consts.js'
31
- import { validateObjType } from '@izara_project/izara-shared-service-schemas';
32
-
33
- // module.exports.createFieldNameUniqueRequestId = (prefix = 'cache') => {
34
- // return prefix + "UniqueRequestId";
35
- // }
36
35
 
37
- // module.exports.createFieldNameStatus = (prefix = 'cache') => {
38
- // return prefix + 'Status';
39
- // }
40
36
 
41
- // module.exports.createFieldNameErrorsFound = (prefix = 'cache') => {
42
- // return prefix + 'ErrorsFound';
43
- // }
37
+ const schemaFunctionPerAction = {
38
+ [consts.ACTIONS.create]: generateValidatorSchemaForCreate,
39
+ [consts.ACTIONS.update]: generateValidatorSchemaForUpdate,
40
+ [consts.ACTIONS.get]: generateValidatorSchemaForIdentifier,
41
+ [consts.ACTIONS.delete]: generateValidatorSchemaForIdentifier
42
+ };
44
43
 
45
- // module.exports.createFieldNameCacheComplete = (prefix = 'cache') => { // timeStamp
46
- // return prefix + 'CacheComplete';
47
- // }
44
+ const explodeDataPerAction = {
45
+ [consts.ACTIONS.create]: explodedReqParams.explodedDataForCreate,
46
+ [consts.ACTIONS.get]: explodedReqParams.explodedDataForIdentifiers,
47
+ [consts.ACTIONS.update]: explodedReqParams.explodedDataForUpdate,
48
+ [consts.ACTIONS.delete]: explodedReqParams.explodedDataForIdentifiers
49
+ };
48
50
 
49
- // module.exports.createFlowParamsFieldName = (prefix = 'cache') => {
50
- // return prefix + 'FlowParams';
51
- // }
52
51
 
53
52
  function createSpecificFieldNameForCacheTable(prefix = 'cache', statusType) {
54
53
  return {
@@ -1375,11 +1374,112 @@ async function validateLocalSchema(_izContext, schemasPath, serviceConfigPath) {
1375
1374
  }
1376
1375
  }
1377
1376
 
1377
+ /**
1378
+ * use to validate record for Lambda handler hdrSqs/hdrDsq
1379
+ * Note!: cannot throw error when use this function outside recordHandler
1380
+ *
1381
+ * @param {object} record - one record from sqs
1382
+ * @param {string} lambdaFunctionName - name of Lambda used to build SQS/DLQ // QueueName
1383
+ * @param {string} objectType - name of ObjectType
1384
+ * @param {string} action - action type of Lambda create | update | get | delete
1385
+ * @param {object} [setting]
1386
+ * @param {string[]} [setting.specificFieldNames] - optional - specific fieldNames use as param in generateValidatorFunction
1387
+ */
1388
+ async function validateSchemaPerRecord(
1389
+ record,
1390
+ lambdaFunctionName,
1391
+ objType,
1392
+ action,
1393
+ setting = {
1394
+ bucketName: process.env.iz_serviceSchemaBucketName,
1395
+ specificFieldNames: []
1396
+ }
1397
+ ) {
1398
+ try {
1399
+ record._izContext.logger.debug(
1400
+ 'validateSchemaPerRecord: ',
1401
+ record,
1402
+ lambdaFunctionName,
1403
+ objType,
1404
+ action,
1405
+ setting
1406
+ );
1407
+
1408
+ if (!schemaFunctionPerAction[action] || !explodeDataPerAction[action]) {
1409
+ throw new Error(
1410
+ `Not found function for generateValidatorSchema or function for explodeData of action:${action}`
1411
+ );
1412
+ }
1413
+
1414
+ const objectSchema = await getObjectSchema.getObjSchemaS3WithHierarchy(
1415
+ record._izContext,
1416
+ objType
1417
+ );
1418
+
1419
+ if (!objectSchema) {
1420
+ throw new Error('not have objectSchema in service');
1421
+ }
1422
+
1423
+ const generateValidatorFunction = schemaFunctionPerAction[action];
1424
+ const explodeDataFunction = explodeDataPerAction[action];
1425
+
1426
+ const generatedSchema = await generateValidatorFunction(
1427
+ record._izContext,
1428
+ objType,
1429
+ setting
1430
+ );
1431
+ record._izContext.logger.debug(
1432
+ `generatedSchema in validateSchemaPerRecord : `,
1433
+ generatedSchema
1434
+ );
1435
+
1436
+ const explodedDataRequestParams = await explodeDataFunction(
1437
+ record._izContext,
1438
+ record.body.Message,
1439
+ objectSchema,
1440
+ setting
1441
+ );
1442
+
1443
+ record._izContext.logger.debug(
1444
+ 'explodedDataRequestParams in validateSchemaPerRecord : ',
1445
+ JSON.stringify(explodedDataRequestParams)
1446
+ );
1447
+
1448
+ let validateStatus = validateObject(
1449
+ generatedSchema,
1450
+ explodedDataRequestParams
1451
+ );
1452
+ record._izContext.logger.debug('validateStatus : ', validateStatus);
1453
+
1454
+ // if not pass validate will sent message to dlq and throw NoRetryError
1455
+ if (!validateStatus.pass) {
1456
+ await utils.messageToDlq(
1457
+ record,
1458
+ `Invalid: ${validateStatus.error}`,
1459
+ await sqsSharedLib.sqsQueueUrlDLQ(record._izContext, lambdaFunctionName)
1460
+ );
1461
+ record._izError = new Error(validateStatus.error);
1462
+ }
1463
+ } catch (error) {
1464
+ record._izContext.logger.debug('validate PerSchema Record error', error);
1465
+ await utils.messageToDlq(
1466
+ record,
1467
+ error.message,
1468
+ await sqsSharedLib.sqsQueueUrlDLQ(record._izContext, lambdaFunctionName)
1469
+ );
1470
+ record._izError = new Error(error);
1471
+ }
1472
+ }
1473
+
1474
+
1475
+
1378
1476
  export default {
1379
1477
  generateValidatorSchemaForCreate,
1380
1478
  generateValidatorSchemaForUpdate,
1381
1479
  generateValidatorSchemaForIdentifier,
1382
1480
 
1383
1481
  generateValidatorSchemaForExplodedData,
1384
- validateLocalSchema
1482
+ validateLocalSchema,
1483
+
1484
+ validateSchemaPerRecord,
1385
1485
  }
@@ -0,0 +1,122 @@
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
+ import lambdaSharedLib from '@izara_project/izara-core-library-lambda';
19
+ import { lambda } from '@izara_project/izara-core-library-external-request';
20
+ import { consts } from '@izara_project/izara-core-library-core';
21
+
22
+ /**
23
+ * Checks a user's permission by invoking another Lambda function.
24
+ * Adheres to Izara.io backend syntax guidelines.
25
+ *
26
+ * @param {object} _izContext - The context object containing logger, credentials, etc.
27
+ * @param {object} payload - The data payload for the permission check.
28
+ * @param {string} [payload.objectType] - The type of the object (e.g., 'INVOICE'). Must be used with `action`.
29
+ * @param {string} [payload.action] - The action to perform (e.g., 'READ', 'APPROVE'). Must be used with `objectType`.
30
+ * @param {string} [payload.flowTag] - The tag for a flow-based permission check. Used instead of `objectType`/`action`.
31
+ * @param {string} [payload.serviceName] - The name of the calling service (optional).
32
+ * @returns {Promise<{status: boolean, errorFound?: string}>}
33
+ * Resolves with the result of the permission check:
34
+ * - `status`: Whether the user has permission.
35
+ * - `errorFound`: Optional error message if the permission check failed.
36
+ *
37
+ * @throws {Error} If the payload is invalid or Lambda invocation fails.
38
+ */
39
+ async function checkPermission(_izContext, payload) {
40
+ // Validate that the payload object itself is provided.
41
+ if (!payload || typeof payload !== 'object') {
42
+ const error = new Error('Payload object is required.');
43
+ _izContext.logger.error(error.message);
44
+ throw error;
45
+ }
46
+
47
+ const userId = _izContext.correlationIds.get(consts.BASE_USER_ID);
48
+ const targetId = _izContext.correlationIds.get(consts.TARGET_ID);
49
+
50
+ // Validate the required 'userId' field.
51
+ if (!userId || typeof userId !== 'string' || userId.trim() === '') {
52
+ const error = new Error(
53
+ 'userId is required and must be a non-empty string.'
54
+ );
55
+ _izContext.logger.error(error.message);
56
+ throw error;
57
+ } else {
58
+ payload.userId = userId;
59
+ }
60
+
61
+ if (targetId) {
62
+ payload.targetId = targetId;
63
+ }
64
+
65
+ // Define validation flags for business rules.
66
+ const hasObjectParams = payload.objectType || payload.action;
67
+ const hasFlowTag = payload.flowTag;
68
+
69
+ // Rule: Cannot mix object-based and flow-based parameters.
70
+ if (hasObjectParams && hasFlowTag) {
71
+ const error = new Error(
72
+ 'Invalid payload: Cannot provide flowTag together with objectType or action.'
73
+ );
74
+ _izContext.logger.error(error.message, { payload });
75
+ throw error;
76
+ }
77
+
78
+ // Rule: If using object-based, both objectType and action are required.
79
+ if (hasObjectParams && (!payload.objectType || !payload.action)) {
80
+ const error = new Error(
81
+ 'Invalid payload: Both objectType and action must be provided together.'
82
+ );
83
+ _izContext.logger.error(error.message, { payload });
84
+ throw error;
85
+ }
86
+
87
+ // Rule: Must provide at least one of the two valid schemas.
88
+ if (!hasObjectParams && !hasFlowTag) {
89
+ const error = new Error(
90
+ 'Invalid payload: Must provide either (objectType and action) or flowTag.'
91
+ );
92
+ _izContext.logger.error(error.message, { payload });
93
+ throw error;
94
+ }
95
+
96
+ // Log the payload for debugging before invoking the next service.
97
+ _izContext.logger.debug('Checking permission with payload:', payload);
98
+
99
+ try {
100
+ const lambdaName = lambdaSharedLib.lambdaFunctionName(
101
+ _izContext,
102
+ 'CheckPermissionHdrInv',
103
+ 'UserAccount'
104
+ );
105
+
106
+ const result = await lambda.invokeSync(_izContext, lambdaName, payload);
107
+
108
+ _izContext.logger.info('Permission check invoked successfully.');
109
+
110
+ // example result = { status: boolean , errorFound: string }
111
+ return result;
112
+ } catch (err) {
113
+ // Log the full error object for better traceability.
114
+ _izContext.logger.error(
115
+ 'Error invoking CheckPermissionHdrInv Lambda: ',
116
+ err
117
+ );
118
+ throw err;
119
+ }
120
+ }
121
+
122
+ export default checkPermission;
@@ -0,0 +1,642 @@
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
+ import { NoRetryError } from "@izara_project/izara-core-library-core";
19
+ import serviceConfig from "../ServiceConfig.js";
20
+ import utils from "../Utils.js";
21
+
22
+ /**
23
+ * helper function for get endpoint
24
+ * create get data detail for each storageTag
25
+ *
26
+ * @param {Object} _izContext
27
+ * @param {Object} objectSchema
28
+ */
29
+ async function createGetDataDetails(
30
+ _izContext,
31
+ objectSchema,
32
+ settings = { bucketName: process.env.iz_serviceSchemaBucketName }
33
+ ) {
34
+ // group versionedData per storageTag
35
+ // or should group versionedData per graph serviceTag
36
+ let versionedDataPerStorageTag = {};
37
+ if (objectSchema?.addOnDataStructure?.length) {
38
+ for (let addOn of objectSchema.addOnDataStructure) {
39
+ if (addOn.type !== 'versionedData') {
40
+ continue;
41
+ }
42
+
43
+ if (
44
+ !versionedDataPerStorageTag.hasOwnProperty(addOn.storageResourceTag)
45
+ ) {
46
+ versionedDataPerStorageTag[addOn.storageResourceTag] = [];
47
+ }
48
+
49
+ versionedDataPerStorageTag[addOn.storageResourceTag].push(addOn);
50
+ }
51
+ }
52
+
53
+ _izContext.logger.debug(
54
+ 'versionedDataPerStorageTag: ',
55
+ versionedDataPerStorageTag
56
+ );
57
+
58
+ let getGraphDataDetails = {};
59
+ let getDynamoDbDataDetails = {};
60
+
61
+ // reference to graph serviceTag that already used
62
+ let graphStorageTagPerGraphServiceTag = {}; // {serviceTag:storageTag,... }
63
+
64
+ for (let [storageTag, storageData] of Object.entries(
65
+ objectSchema.storageResources
66
+ )) {
67
+ // collect fieldNames per storageTag
68
+ let storageTagFieldNames = [];
69
+ for (let [fieldName, fieldNameData] of Object.entries(
70
+ objectSchema.fieldNames
71
+ )) {
72
+ // if (fieldName.startsWith("versionedDataField")) {
73
+ // continue;
74
+ // }
75
+
76
+ if (fieldNameData.storageResourceTags.includes(storageTag)) {
77
+ storageTagFieldNames.push(fieldName);
78
+ }
79
+ }
80
+
81
+ if (storageData.storageType === coreConsts.STORAGE_TYPES.graph) {
82
+ let useStorageTag = storageTag;
83
+ let graphServiceTag = await serviceConfig.getGraphServiceTagWithCache(
84
+ _izContext,
85
+ storageData.graphServerTag,
86
+ settings.bucketName
87
+ );
88
+
89
+ // check duplicate graph serviceTag
90
+ if (!graphStorageTagPerGraphServiceTag.hasOwnProperty(graphServiceTag)) {
91
+ graphStorageTagPerGraphServiceTag[graphServiceTag] = storageTag;
92
+ } else {
93
+ // overwrite useStorageTag if graphServiceTag already used
94
+ _izContext.logger.debug('current storageTag: ', storageTag);
95
+ _izContext.logger.debug('use storageTag: ', useStorageTag);
96
+
97
+ useStorageTag = graphStorageTagPerGraphServiceTag[graphServiceTag];
98
+ }
99
+
100
+ if (!getGraphDataDetails.hasOwnProperty(useStorageTag)) {
101
+ getGraphDataDetails[useStorageTag] = {
102
+ storageType: storageData.storageType,
103
+ graphServiceTag: graphServiceTag,
104
+ fieldNames: storageTagFieldNames
105
+ };
106
+ } else {
107
+ getGraphDataDetails[useStorageTag].fieldNames = [
108
+ ...new Set(
109
+ getGraphDataDetails[useStorageTag].fieldNames.concat(
110
+ storageTagFieldNames
111
+ )
112
+ )
113
+ ];
114
+ }
115
+
116
+ // add versionedData fieldNames
117
+ if (versionedDataPerStorageTag.hasOwnProperty(storageTag)) {
118
+ if (
119
+ !getGraphDataDetails[useStorageTag].hasOwnProperty('versionedDatas')
120
+ ) {
121
+ getGraphDataDetails[useStorageTag].versionedDatas = {};
122
+ }
123
+
124
+ for (let versionedData of versionedDataPerStorageTag[storageTag]) {
125
+ _izContext.logger.debug(
126
+ 'versionedData.fieldNames',
127
+ versionedData.fieldNames
128
+ );
129
+ let versionedDataFieldNames = Object.keys(versionedData.fieldNames);
130
+ Object.assign(getGraphDataDetails[useStorageTag].versionedDatas, {
131
+ [versionedData.versionedDataLabel]: versionedDataFieldNames
132
+ });
133
+ }
134
+ }
135
+ } else if (storageData.storageType === coreConsts.STORAGE_TYPES.dynamoDB) {
136
+ let serviceTag = storageData.serviceTag || process.env.iz_serviceTag;
137
+ Object.assign(getDynamoDbDataDetails, {
138
+ [storageTag]: {
139
+ storageType: storageData.storageType,
140
+ tableName: storageData.tableName,
141
+ serviceTag: serviceTag,
142
+ fieldNames: storageTagFieldNames
143
+ }
144
+ });
145
+
146
+ if (storageData.groupByPartitionKeyField) {
147
+ Object.assign(getDynamoDbDataDetails[storageTag], {
148
+ groupByPartitionKeyField: storageData.groupByPartitionKeyField
149
+ });
150
+ }
151
+ } else {
152
+ throw new NoRetryError('Unhanled storageType');
153
+ }
154
+ }
155
+
156
+ _izContext.logger.debug('getGraphDataDetail: ', getGraphDataDetails);
157
+ _izContext.logger.debug('getDynamoDbData: ', getDynamoDbDataDetails);
158
+
159
+ //-------- sort descending order of fieldNames.length --------
160
+ let sortedGetGraphWithVersionedData = Object.entries(getGraphDataDetails)
161
+ .filter(getGraphDetail =>
162
+ getGraphDetail[1].hasOwnProperty('versionedDatas')
163
+ )
164
+ .sort(
165
+ (storageDataA, storageDataB) =>
166
+ storageDataB[1].fieldNames.length - storageDataA[1].fieldNames.length
167
+ );
168
+
169
+ _izContext.logger.debug(
170
+ 'sortedGetGraphWithVersionedData: ',
171
+ sortedGetGraphWithVersionedData
172
+ );
173
+
174
+ let sortedGetGraphWithoutVersionedData = Object.entries(getGraphDataDetails)
175
+ .filter(
176
+ getGraphDetail => !getGraphDetail[1].hasOwnProperty('versionedDatas')
177
+ )
178
+ .sort(
179
+ (storageDataA, storageDataB) =>
180
+ storageDataB[1].fieldNames.length - storageDataA[1].fieldNames.length
181
+ );
182
+
183
+ _izContext.logger.debug(
184
+ 'sortedGetGraphWithoutVersionedData: ',
185
+ sortedGetGraphWithoutVersionedData
186
+ );
187
+
188
+ let sortedGetDynamoDbData = Object.entries(getDynamoDbDataDetails).sort(
189
+ (storageDataA, storageDataB) =>
190
+ storageDataB[1].fieldNames.length - storageDataA[1].fieldNames.length
191
+ );
192
+
193
+ _izContext.logger.debug('sortedGetDynamoDbData: ', sortedGetDynamoDbData);
194
+
195
+ // after sort data then filter duplicate fieldName
196
+ let allSortedGetDataDetails = [
197
+ ...sortedGetGraphWithVersionedData,
198
+ ...sortedGetDynamoDbData,
199
+ ...sortedGetGraphWithoutVersionedData
200
+ ];
201
+ _izContext.logger.debug('allSortedGetDataDetails: ', allSortedGetDataDetails);
202
+
203
+ let usedFieldName = [];
204
+ for (let [storageTag, getDataDetail] of allSortedGetDataDetails) {
205
+ let remainsFieldNames = [];
206
+ while (getDataDetail.fieldNames.length) {
207
+ let checkedFiedName = getDataDetail.fieldNames.pop();
208
+ if (!usedFieldName.includes(checkedFiedName)) {
209
+ usedFieldName.push(checkedFiedName);
210
+ remainsFieldNames.push(checkedFiedName);
211
+ }
212
+ }
213
+
214
+ getDataDetail.fieldNames = remainsFieldNames;
215
+ }
216
+
217
+ _izContext.logger.debug('newSortedArray after: ', allSortedGetDataDetails);
218
+
219
+ let getDataDetailResults = Object.fromEntries(
220
+ allSortedGetDataDetails.filter(([storageTag, getDataDetail]) => {
221
+ return (
222
+ getDataDetail.fieldNames.length ||
223
+ getDataDetail.hasOwnProperty('versionedDatas')
224
+ );
225
+ })
226
+ );
227
+
228
+ _izContext.logger.debug('getDataDetailResults: ', getDataDetailResults);
229
+
230
+ for (const getDataDetail of Object.values(getDataDetailResults)) {
231
+ if (getDataDetail.hasOwnProperty('versionedDatas')) {
232
+ getDataDetail.versionedDataLabels = [];
233
+ for (let [versionedDataLabel, fieldNames] of Object.entries(
234
+ getDataDetail.versionedDatas
235
+ )) {
236
+ getDataDetail.versionedDataLabels.push(versionedDataLabel);
237
+ getDataDetail.fieldNames.push(...fieldNames);
238
+ }
239
+ }
240
+ }
241
+
242
+ return getDataDetailResults;
243
+ }
244
+
245
+ /**
246
+ * receive result from multiple database and create data format depend on returnFormat setting
247
+ *
248
+ * @param {object} _izContext
249
+ * @param {object[]} getResults
250
+ * @param {object} objectSchema
251
+ * @returns
252
+ */
253
+ function collectGetData(
254
+ _izContext,
255
+ getResults,
256
+ objectSchema,
257
+ returnSystemFieldsName
258
+ ) {
259
+ _izContext.logger.debug('collectGetData: ', {
260
+ getResults,
261
+ objectSchema,
262
+ returnSystemFieldsName
263
+ });
264
+
265
+ let collectedData = {
266
+ identifiers: {},
267
+ fields: {}
268
+ };
269
+
270
+ if (returnSystemFieldsName) {
271
+ Object.assign(collectedData, { versionDataSystemFields: {} });
272
+ }
273
+ const identifierFieldNames = new Set(
274
+ utils.getUsedFieldNamesOfIdentifiers(_izContext, objectSchema.identifiers)
275
+ );
276
+
277
+ let addedFieldNames = new Set();
278
+
279
+ // if isFound === true then return null from this function
280
+ let isFound = false;
281
+
282
+ for (const [getData, getDataDetail] of getResults) {
283
+ if (!getData || !Object.keys(getData).length) {
284
+ continue;
285
+ }
286
+
287
+ // this process will add result from graph and dynamo to collectedData object by add identifiers and fieldName from getData
288
+ if (getDataDetail.storageType === coreConsts.STORAGE_TYPES.graph) {
289
+ if (
290
+ getData.returnValue.queryResults.refactoredNodes.objInstanceFull &&
291
+ Object.keys(
292
+ getData.returnValue.queryResults.refactoredNodes.objInstanceFull
293
+ ).length
294
+ ) {
295
+ for (const getDetailFieldName of getDataDetail.fieldNames) {
296
+ if (addedFieldNames.has(getDetailFieldName)) {
297
+ continue;
298
+ }
299
+
300
+ if (
301
+ getData.returnValue.queryResults.refactoredNodes.objInstanceFull.identifiers.hasOwnProperty(
302
+ getDetailFieldName
303
+ )
304
+ ) {
305
+ Object.assign(collectedData.identifiers, {
306
+ [getDetailFieldName]:
307
+ getData.returnValue.queryResults.refactoredNodes.objInstanceFull
308
+ .identifiers[getDetailFieldName]
309
+ });
310
+ addedFieldNames.add(getDetailFieldName);
311
+ isFound = true;
312
+ } else if (
313
+ getData.returnValue.queryResults.refactoredNodes.objInstanceFull.fields.hasOwnProperty(
314
+ getDetailFieldName
315
+ )
316
+ ) {
317
+ Object.assign(collectedData.fields, {
318
+ [getDetailFieldName]:
319
+ getData.returnValue.queryResults.refactoredNodes.objInstanceFull
320
+ .fields[getDetailFieldName]
321
+ });
322
+ addedFieldNames.add(getDetailFieldName);
323
+ isFound = true;
324
+ }
325
+ }
326
+ }
327
+ if (
328
+ getData.returnValue.queryResults.refactoredNodes
329
+ .versionDataSystemFields ||
330
+ returnSystemFieldsName == true
331
+ ) {
332
+ Object.assign(
333
+ collectedData.versionDataSystemFields,
334
+ getData.returnValue.queryResults.refactoredNodes
335
+ .versionDataSystemFields
336
+ );
337
+ }
338
+ } else if (
339
+ getDataDetail.storageType === coreConsts.STORAGE_TYPES.dynamoDB
340
+ ) {
341
+ for (const getDetailFieldName of getDataDetail.fieldNames) {
342
+ if (addedFieldNames.has(getDetailFieldName)) {
343
+ continue;
344
+ }
345
+
346
+ if (getData.hasOwnProperty(getDetailFieldName)) {
347
+ if (identifierFieldNames.has(getDetailFieldName)) {
348
+ Object.assign(collectedData.identifiers, {
349
+ [getDetailFieldName]: getData[getDetailFieldName]
350
+ });
351
+ addedFieldNames.add(getDetailFieldName);
352
+ isFound = true;
353
+ } else {
354
+ Object.assign(collectedData.fields, {
355
+ [getDetailFieldName]: getData[getDetailFieldName]
356
+ });
357
+ addedFieldNames.add(getDetailFieldName);
358
+ isFound = true;
359
+ }
360
+ }
361
+ }
362
+ } else {
363
+ throw new NoRetryError('collectGetData unhandled storageType');
364
+ }
365
+ }
366
+
367
+ if (isFound) {
368
+ return collectedData;
369
+ } else {
370
+ return null;
371
+ }
372
+ }
373
+
374
+ async function createUpdateDataDetail(
375
+ _izContext,
376
+ objectSchema,
377
+ settings = { bucketName: process.env.iz_serviceSchemaBucketName }
378
+ ) {
379
+ let getGraphDataDetails = {};
380
+ let getDynamoDbDataDetails = {};
381
+ let allUpdateDataDetail = {};
382
+ for (let [storageTag, storageProperties] of Object.entries(
383
+ objectSchema.storageResources
384
+ )) {
385
+ let storageFieldNames = [];
386
+ for (let [fieldName, fieldNameProperties] of Object.entries(
387
+ objectSchema.fieldNames
388
+ )) {
389
+ if (fieldNameProperties.storageResourceTags.includes(storageTag)) {
390
+ let versionedDataLabel = fieldNameProperties.versionedDataLabel;
391
+ if (!fieldName.includes(versionedDataLabel)) {
392
+ // not get fieldNames VersionedData_VersionedDataLabel_VersionedDataFieldNames
393
+ storageFieldNames.push(fieldName);
394
+ }
395
+ }
396
+ }
397
+ if (storageProperties.storageType === coreConsts.STORAGE_TYPES.graph) {
398
+ let graphStorageTagPerGraphServiceTag = {};
399
+ let useStorageTag = storageTag;
400
+ let graphServiceName = await serviceConfig.getGraphServiceTagWithCache(
401
+ _izContext,
402
+ storageProperties.graphServerTag,
403
+ settings.bucketName
404
+ );
405
+ if (!graphStorageTagPerGraphServiceTag.hasOwnProperty(graphServiceName)) {
406
+ graphStorageTagPerGraphServiceTag[graphServiceName] = storageTag;
407
+ _izContext.logger.debug(
408
+ 'graphStorageTagPerGraphServiceTag',
409
+ graphStorageTagPerGraphServiceTag
410
+ );
411
+ } else {
412
+ _izContext.logger.debug('current storageTag', storageTag);
413
+ _izContext.logger.debug('used storageTag', useStorageTag);
414
+ useStorageTag = graphStorageTagPerGraphServiceTag[graphServiceName];
415
+ }
416
+ if (!getGraphDataDetails.hasOwnProperty(useStorageTag)) {
417
+ getGraphDataDetails[graphServiceName] = {
418
+ storageType: storageProperties.storageType,
419
+ fieldNames: storageFieldNames
420
+ };
421
+ } else {
422
+ getGraphDataDetails[graphServiceName].fieldNames = [
423
+ ...new Set(
424
+ getGraphDataDetails[useStorageTag].fieldNames.concat(
425
+ storageFieldNames
426
+ )
427
+ )
428
+ ];
429
+ }
430
+ } else if (
431
+ storageProperties.storageType === coreConsts.STORAGE_TYPES.dynamoDB
432
+ ) {
433
+ let serviceTag =
434
+ storageProperties.serviceTag || process.env.iz_serviceTag;
435
+ Object.assign(getDynamoDbDataDetails, {
436
+ [storageTag]: {
437
+ storageType: storageProperties.storageType,
438
+ tableName: storageProperties.tableName,
439
+ serviceTag: serviceTag,
440
+ fieldNames: storageFieldNames
441
+ }
442
+ });
443
+
444
+ if (storageTag.groupByPartitionKeyField) {
445
+ Object.assign(getDynamoDbDataDetails[storageTag], {
446
+ groupByPartitionKeyField: storageProperties.groupByPartitionKeyField
447
+ });
448
+ }
449
+ }
450
+ }
451
+
452
+ _izContext.logger.debug('getGraphDataDetails', getGraphDataDetails);
453
+ _izContext.logger.debug('getDynamoDataDetail', getDynamoDbDataDetails);
454
+
455
+ Object.assign(
456
+ allUpdateDataDetail,
457
+ getDynamoDbDataDetails,
458
+ getGraphDataDetails
459
+ );
460
+ return allUpdateDataDetail;
461
+ }
462
+
463
+ async function createDataDetailsLib(
464
+ _izContext,
465
+ objectSchemas,
466
+ settings = { bucketName: process.env.iz_serviceSchemaBucketName }
467
+ ) {
468
+ _izContext.logger.debug('Lib: createDataDetailsLib:', {
469
+ objectSchemas: objectSchemas
470
+ });
471
+
472
+ let createDataDetails = {};
473
+
474
+ let storageResources = objectSchemas.storageResources;
475
+ _izContext.logger.debug('storageResources:', storageResources);
476
+
477
+ for (let [keyFieldName, settingFieldName] of Object.entries(
478
+ objectSchemas.fieldNames
479
+ )) {
480
+ // _izContext.logger.debug("Loop fieldNamesObjectSchemas", { keyFieldName });
481
+
482
+ for (let eachStorageResourceTag of settingFieldName.storageResourceTags) {
483
+ // _izContext.logger.debug("Loop eachStorageResourceTags", eachStorageResourceTag);
484
+
485
+ if (!storageResources.hasOwnProperty(eachStorageResourceTag)) {
486
+ throw new Error("storageResources is'n exist"); // should be validate in step upload in s3
487
+ } else {
488
+ if (
489
+ storageResources[eachStorageResourceTag].storageType ==
490
+ coreConsts.STORAGE_TYPES.dynamoDB
491
+ ) {
492
+ if (createDataDetails.hasOwnProperty(eachStorageResourceTag)) {
493
+ // _izContext.logger.debug("SAME STG DB", eachStorageResourceTag);
494
+ createDataDetails[eachStorageResourceTag].fieldNames.push(
495
+ keyFieldName
496
+ );
497
+ } else {
498
+ Object.assign(createDataDetails, {
499
+ [eachStorageResourceTag]: {
500
+ storageType: coreConsts.STORAGE_TYPES.dynamoDB,
501
+ tableName: storageResources[eachStorageResourceTag].tableName,
502
+ serviceTag:
503
+ storageResources[eachStorageResourceTag].serviceTag ||
504
+ process.env.iz_serviceTag,
505
+ fieldNames: [keyFieldName]
506
+ }
507
+ });
508
+
509
+ if (
510
+ storageResources[eachStorageResourceTag].hasOwnProperty(
511
+ 'groupByPartitionKeyField'
512
+ )
513
+ ) {
514
+ Object.assign(createDataDetails[eachStorageResourceTag], {
515
+ groupByPartitionKeyField:
516
+ storageResources[eachStorageResourceTag]
517
+ .groupByPartitionKeyField
518
+ });
519
+ }
520
+ }
521
+ } else if (
522
+ storageResources[eachStorageResourceTag].storageType ==
523
+ coreConsts.STORAGE_TYPES.graph
524
+ ) {
525
+ let checkGraphServerTags =
526
+ await serviceConfig.getGraphServiceTagWithCache(
527
+ _izContext,
528
+ storageResources[eachStorageResourceTag].graphServerTag,
529
+ settings.bucketName
530
+ );
531
+ if (checkGraphServerTags) {
532
+ if (createDataDetails.hasOwnProperty(checkGraphServerTags)) {
533
+ // _izContext.logger.debug("SAME STG", checkGraphServerTags);
534
+ createDataDetails[checkGraphServerTags].fieldNames.push(
535
+ keyFieldName
536
+ );
537
+ } else {
538
+ // _izContext.logger.debug("NEW STG", checkGraphServerTags);
539
+ Object.assign(createDataDetails, {
540
+ [checkGraphServerTags]: {
541
+ storageType: coreConsts.STORAGE_TYPES.graph,
542
+ fieldNames: [keyFieldName]
543
+ }
544
+ });
545
+ }
546
+ }
547
+ } else if (
548
+ storageResources[eachStorageResourceTag].storageType ===
549
+ coreConsts.STORAGE_TYPES.externalTopic
550
+ ) {
551
+ let topicName =
552
+ storageResources[eachStorageResourceTag].serviceTag +
553
+ storageResources[eachStorageResourceTag].stage +
554
+ storageResources[eachStorageResourceTag].topicName;
555
+ Object.assign(createDataDetails, {
556
+ [topicName]: {
557
+ storageType: coreConsts.STORAGE_TYPES.externalTopic,
558
+ fieldNames: [keyFieldName],
559
+ accountId: storageResources[eachStorageResourceTag].accountId,
560
+ region: storageResources[eachStorageResourceTag].region,
561
+ serviceTag: storageResources[eachStorageResourceTag].serviceTag,
562
+ stage: storageResources[eachStorageResourceTag].stage
563
+ }
564
+ });
565
+ }
566
+ }
567
+ } // end loop storageResourceTags
568
+ } // end loop
569
+
570
+ return createDataDetails;
571
+ }
572
+
573
+ async function createDeleteDataDetail(
574
+ _izContext,
575
+ objectSchema,
576
+ settings = { bucketName: process.env.iz_serviceSchemaBucketName }
577
+ ) {
578
+ let deleteDynamoDataDetail = {};
579
+ let deleteGraphDataDetail = {};
580
+ let allDeleteDataDetail = {};
581
+
582
+ for (let [storageTag, storageProperties] of Object.entries(
583
+ objectSchema.storageResources
584
+ )) {
585
+ if (storageProperties.storageType === coreConsts.STORAGE_TYPES.dynamoDB) {
586
+ let serviceTag =
587
+ storageProperties.serviceTag || process.env.iz_serviceTag;
588
+ Object.assign(deleteDynamoDataDetail, {
589
+ [storageTag]: {
590
+ storageType: storageProperties.storageType,
591
+ serviceTag: serviceTag,
592
+ tableName: storageProperties.tableName
593
+ }
594
+ });
595
+ if (storageProperties.groupByPartitionKeyField) {
596
+ Object.assign(deleteDynamoDataDetail[storageTag], {
597
+ groupByPartitionKeyField: storageProperties.groupByPartitionKeyField
598
+ });
599
+ }
600
+ } else if (
601
+ storageProperties.storageType === coreConsts.STORAGE_TYPES.graph
602
+ ) {
603
+ let dataDetailPerGraphStorage = {};
604
+ let useStorageTag = storageTag;
605
+ let graphServiceName = await serviceConfig.getGraphServiceTagWithCache(
606
+ _izContext,
607
+ storageProperties.graphServerTag,
608
+ settings.bucketName
609
+ );
610
+ if (!dataDetailPerGraphStorage.hasOwnProperty(graphServiceName)) {
611
+ dataDetailPerGraphStorage[graphServiceName] = storageTag;
612
+ } else {
613
+ useStorageTag = dataDetailPerGraphStorage[graphServiceName];
614
+ }
615
+ if (!deleteGraphDataDetail.hasOwnProperty(useStorageTag)) {
616
+ deleteGraphDataDetail[graphServiceName] = {
617
+ storageType: storageProperties.storageType
618
+ };
619
+ }
620
+ }
621
+ }
622
+ _izContext.logger.debug('deleteGraphDataDetail', deleteGraphDataDetail);
623
+ _izContext.logger.debug('deleteDynamoDataDetail', deleteDynamoDataDetail);
624
+ Object.assign(
625
+ allDeleteDataDetail,
626
+ deleteGraphDataDetail,
627
+ deleteDynamoDataDetail
628
+ );
629
+
630
+ _izContext.logger.debug('allDeleteDataDetail', allDeleteDataDetail);
631
+ return allDeleteDataDetail;
632
+ }
633
+
634
+
635
+ export default {
636
+ createUpdateDataDetail,
637
+ createDataDetailsLib,
638
+ createDeleteDataDetail,
639
+
640
+ createGetDataDetails,
641
+ collectGetData,
642
+ }