@izara_project/izara-core-library-dynamodb 1.0.13 → 1.0.14

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.
@@ -34,7 +34,7 @@ const MAX_RECURSION_LEVEL = 20;
34
34
  const dynamodb = DynamoDBDocument.from(new DynamoDB(), {
35
35
  marshallOptions: {
36
36
  removeUndefinedValues: true
37
- },
37
+ }
38
38
  });
39
39
 
40
40
  // Commented imports and alternatives
@@ -42,7 +42,6 @@ const dynamodb = DynamoDBDocument.from(new DynamoDB(), {
42
42
  // const dynamodb = DynamoDBDocument.from(new DynamoDB());
43
43
  // const dynamodb = require('@izara_project/izara-core-library-external-request').dynamodb
44
44
 
45
-
46
45
  /**
47
46
  * create table name
48
47
  * @param {Object} _izContext
@@ -67,21 +66,18 @@ function tableName(_izContext, tableName, serviceTag = null) {
67
66
  */
68
67
  function arrayToStringSet(stringSetArray) {
69
68
  try {
70
-
71
69
  // let stringSet = dynamodb.createSet(stringSetArray) // not need async/await
72
70
  let stringSet = new Set(stringSetArray);
73
71
  if (!stringSet) {
74
72
  throw new Error('Cannot create stringSet');
75
73
  }
76
74
  return stringSet;
77
-
78
75
  } catch (e) {
79
76
  console.error('error arrayToStringSet:', e);
80
- throw (e);
77
+ throw e;
81
78
  }
82
79
  }
83
80
 
84
-
85
81
  /**
86
82
  * Marshalls StringSet from dynamo get/query into an array
87
83
  * @param {Object} stringSet
@@ -92,7 +88,6 @@ function stringSetToArray(stringSet) {
92
88
  return cloneDeep(stringSet.values);
93
89
  }
94
90
 
95
-
96
91
  function removeUndefined(attributes) {
97
92
  return unmarshall(marshall(attributes, { removeUndefinedValues: true }));
98
93
  }
@@ -104,14 +99,15 @@ function correlationIdValues(_izContext) {
104
99
  });
105
100
  }
106
101
 
107
-
108
102
  // ----- Helper function for reformConditionExpression
109
- function validateSideHand(logicalElement, prefixSide) { // helper function
103
+ function validateSideHand(logicalElement, prefixSide) {
104
+ // helper function
110
105
  // _izContext.logger.debug('logicalElement in prefixSide', prefixSide);
111
106
 
112
107
  let checkSides = [];
113
108
  // check duplicated properties side (want to throw noRetry)
114
- for (let side in logicalElement) { // method
109
+ for (let side in logicalElement) {
110
+ // method
115
111
  // _izContext.logger.debug('side ', side);
116
112
  // if ([`${prefixSide}Attribute`, `${prefixSide}Reference`, `${prefixSide}Value`].includes(side)) {
117
113
  if ([`${prefixSide}Attribute`, `${prefixSide}Reference`].includes(side)) {
@@ -119,7 +115,8 @@ function validateSideHand(logicalElement, prefixSide) { // helper function
119
115
  }
120
116
  }
121
117
 
122
- if (checkSides.length == 1) { // if more than one will error
118
+ if (checkSides.length == 1) {
119
+ // if more than one will error
123
120
  let sideHandResult = logicalElement[checkSides[0]];
124
121
  // add : if side type is reference for ExpressionAttributeValues
125
122
  // NOTE not sure about Attribute, will pull values from exist data db
@@ -130,7 +127,9 @@ function validateSideHand(logicalElement, prefixSide) { // helper function
130
127
  }
131
128
  // ***** if side is "lhsReference" not logic to handle for now, so will be throw err *****
132
129
  else if (checkSides[0] == 'lhsReference') {
133
- throw new NoRetryError(`"${checkSides[0]}" should not be set to Reference type for now!`);
130
+ throw new NoRetryError(
131
+ `"${checkSides[0]}" should not be set to Reference type for now!`
132
+ );
134
133
  // logicalElement[checkSides[0]] = '#' + logicalElement[checkSides[0]] // will add logic later
135
134
  }
136
135
  // if (checkSides[0].includes('Attribute')) {
@@ -139,23 +138,27 @@ function validateSideHand(logicalElement, prefixSide) { // helper function
139
138
 
140
139
  // return logicalElement[checkSides[0]] // return values eg. :product | product | 3
141
140
  return sideHandResult; // return values eg. :product | product | 3
142
-
143
141
  } else if (checkSides.length == 0) {
144
142
  throw new NoRetryError(`"${prefixSide}_" does not set!`);
145
-
146
143
  } else {
147
- throw new NoRetryError(`"${prefixSide}" side-hand logic duplicated set, should set only one per side!`);
144
+ throw new NoRetryError(
145
+ `"${prefixSide}" side-hand logic duplicated set, should set only one per side!`
146
+ );
148
147
  }
149
-
150
- }; // end validateSideHand
148
+ } // end validateSideHand
151
149
 
152
150
  // ----- Helper function for query dynamodb
153
151
  function reformConditionExpression(_izContext, queryElements) {
154
152
  // _izContext.logger.debug('queryElements', queryElements);
155
153
  // ----- add ConditionExpression to payload if queryElements has prop logicalElements
156
- let conditionExpression, expressionAttributeValues = null;
154
+ let conditionExpression,
155
+ expressionAttributeValues = null;
157
156
  if (queryElements && queryElements.hasOwnProperty('logicalElements')) {
158
- conditionExpression = processLogicalElements(_izContext, queryElements.logicalElements, 1);
157
+ conditionExpression = processLogicalElements(
158
+ _izContext,
159
+ queryElements.logicalElements,
160
+ 1
161
+ );
159
162
  }
160
163
 
161
164
  // ----- add ExpressionAttributeValues to payload
@@ -165,7 +168,9 @@ function reformConditionExpression(_izContext, queryElements) {
165
168
  // change structure to syntax dynamo
166
169
  /*NOTE: handler function will be validate ExpressionAttributeValues by themself,
167
170
  that should will be in CondiEx and if not have CondiEx and we set ExAttr will be error */
168
- for (let [propName, propVal] of Object.entries(queryElements.additionalAttributes)) {
171
+ for (let [propName, propVal] of Object.entries(
172
+ queryElements.additionalAttributes
173
+ )) {
169
174
  expressionAttributeValues[`:${propName}`] = propVal;
170
175
  }
171
176
  }
@@ -194,13 +199,18 @@ function processLogicalElements(_izContext, logicalElements, level) {
194
199
  */
195
200
 
196
201
  try {
197
-
198
202
  if (level > MAX_RECURSION_LEVEL) {
199
- throw new Error(`exceeded maximum recursion level for property checks: ` + MAX_RECURSION_LEVEL);
203
+ throw new Error(
204
+ `exceeded maximum recursion level for property checks: ` +
205
+ MAX_RECURSION_LEVEL
206
+ );
200
207
  }
201
208
 
202
209
  let conditionalExpression = '';
203
- _izContext.logger.debug('initial conditionalExpression :', conditionalExpression);
210
+ _izContext.logger.debug(
211
+ 'initial conditionalExpression :',
212
+ conditionalExpression
213
+ );
204
214
  _izContext.logger.debug('initial logicalElements', logicalElements);
205
215
 
206
216
  // validate logicalElements is array before running resursion
@@ -220,42 +230,42 @@ function processLogicalElements(_izContext, logicalElements, level) {
220
230
  }
221
231
 
222
232
  // main looping check each logical element
223
- for (const logicalElement of logicalElements) { // first-loop(outer)
233
+ for (const logicalElement of logicalElements) {
234
+ // first-loop(outer)
224
235
  // _izContext.logger.debug('logicalElement:', logicalElement);
225
236
 
226
237
  // -------- Check types: logical --------
227
238
 
228
239
  if (logicalElement.type == 'logical') {
229
240
  if (logicalElement.hasOwnProperty('comparison')) {
230
-
231
241
  // _izContext.logger.debug("I'm in logical comparison");
232
242
  let subConditionalExpression = null;
233
243
 
234
244
  let leftSide = validateSideHand(logicalElement, 'lhs'); //
235
245
 
236
246
  if (logicalElement.comparison == 'between') {
237
- let betweenStartSide = validateSideHand(logicalElement, 'betweenStart');
247
+ let betweenStartSide = validateSideHand(
248
+ logicalElement,
249
+ 'betweenStart'
250
+ );
238
251
  let betweenEndSide = validateSideHand(logicalElement, 'betweenEnd');
239
252
  // _izContext.logger.debug('betweenEndSide ff', betweenEndSide);
240
253
 
241
254
  subConditionalExpression = `${leftSide} between ${betweenStartSide} and ${betweenEndSide}`;
242
-
243
- } else { // others comparison
255
+ } else {
256
+ // others comparison
244
257
 
245
258
  let rightSide = validateSideHand(logicalElement, 'rhs');
246
259
 
247
260
  if (logicalElement.comparison == 'equals') {
248
261
  // _izContext.logger.debug("I'm in equals comparison");
249
262
  subConditionalExpression = `${leftSide} = ${rightSide}`;
250
-
251
263
  } else if (logicalElement.comparison == 'notEquals') {
252
264
  // _izContext.logger.debug("I'm in notEquals comparison");
253
265
  subConditionalExpression = `${leftSide} <> ${rightSide}`;
254
-
255
266
  } else if (logicalElement.comparison == 'greaterThan') {
256
267
  // _izContext.logger.debug("I'm in greaterThan comparison");
257
268
  subConditionalExpression = `${leftSide} > ${rightSide}`;
258
-
259
269
  } else if (logicalElement.comparison == 'lessThan') {
260
270
  // _izContext.logger.debug("I'm in lessThan comparison");
261
271
  subConditionalExpression = `${leftSide} < ${rightSide}`;
@@ -268,9 +278,10 @@ function processLogicalElements(_izContext, logicalElements, level) {
268
278
 
269
279
  // conditionalExpression += subConditionalExpression; // close sub-group
270
280
  conditionalExpression += '(' + subConditionalExpression + ')'; // close sub-group // NEED TO SYNTAX
271
-
272
281
  } else {
273
- throw new NoRetryError('Invalided "logical" type, logical type should have comparison.');
282
+ throw new NoRetryError(
283
+ 'Invalided "logical" type, logical type should have comparison.'
284
+ );
274
285
  }
275
286
  }
276
287
 
@@ -283,11 +294,16 @@ function processLogicalElements(_izContext, logicalElements, level) {
283
294
  conditionalExpression += ' or ';
284
295
  } else if (logicalElement.operator.toLowerCase() == 'and') {
285
296
  conditionalExpression += ' and ';
286
- } else { // and operator
287
- throw new NoRetryError('logicalOperator invalided, should be or/and');
297
+ } else {
298
+ // and operator
299
+ throw new NoRetryError(
300
+ 'logicalOperator invalided, should be or/and'
301
+ );
288
302
  }
289
303
  } else {
290
- throw new NoRetryError('Invalided "operator" type, operator type should have logicalOperator.');
304
+ throw new NoRetryError(
305
+ 'Invalided "operator" type, operator type should have logicalOperator.'
306
+ );
291
307
  }
292
308
  } // end logicalOperator
293
309
 
@@ -302,58 +318,81 @@ function processLogicalElements(_izContext, logicalElements, level) {
302
318
 
303
319
  // throw error if not have only one side.
304
320
  if (!logicalElement.hasOwnProperty('attribute')) {
305
- throw new NoRetryError('side-hand logic Invalid, should set "attribute".');
321
+ throw new NoRetryError(
322
+ 'side-hand logic Invalid, should set "attribute".'
323
+ );
306
324
  }
307
325
 
308
- if (logicalElement.function.toLowerCase() == 'begins_with' || logicalElement.function.toLowerCase() == 'beginswith') {
326
+ if (
327
+ logicalElement.function.toLowerCase() == 'begins_with' ||
328
+ logicalElement.function.toLowerCase() == 'beginswith'
329
+ ) {
309
330
  let substr = validateSideHand(logicalElement, 'substr');
310
331
 
311
332
  conditionalExpression += `begins_with (${logicalElement.attribute}, ${substr})`;
312
- }
313
- else if (logicalElement.function.toLowerCase() == 'attribute_exists' || logicalElement.function.toLowerCase() == 'attributeexists') {
333
+ } else if (
334
+ logicalElement.function.toLowerCase() == 'attribute_exists' ||
335
+ logicalElement.function.toLowerCase() == 'attributeexists'
336
+ ) {
314
337
  conditionalExpression += `attribute_exists (${logicalElement.attribute})`;
315
- }
316
- else if (logicalElement.function.toLowerCase() == 'attribute_not_exists' || logicalElement.function.toLowerCase() == 'attributenotexists') {
338
+ } else if (
339
+ logicalElement.function.toLowerCase() == 'attribute_not_exists' ||
340
+ logicalElement.function.toLowerCase() == 'attributenotexists'
341
+ ) {
317
342
  conditionalExpression += `attribute_not_exists (${logicalElement.attribute})`;
318
343
  } else {
319
- throw new NoRetryError('Invalided "function" type, function type should be begins_with/ attribute_exists/ attribute_not_exists .');
344
+ throw new NoRetryError(
345
+ 'Invalided "function" type, function type should be begins_with/ attribute_exists/ attribute_not_exists .'
346
+ );
320
347
  }
321
-
322
348
  } else {
323
- throw new NoRetryError('Invalided "function" type, function type should have function.');
349
+ throw new NoRetryError(
350
+ 'Invalided "function" type, function type should have function.'
351
+ );
324
352
  }
325
353
  } // end function
326
354
 
327
355
  // ----- Check types: group []( need to recursed) -----
328
356
  else if (logicalElement.type == 'group') {
329
- if (logicalElement.hasOwnProperty('elements') && Array.isArray(logicalElement.elements) && logicalElement.elements.length != 0) {
357
+ if (
358
+ logicalElement.hasOwnProperty('elements') &&
359
+ Array.isArray(logicalElement.elements) &&
360
+ logicalElement.elements.length != 0
361
+ ) {
330
362
  // _izContext.logger.debug("I'm going in recursion");
331
363
 
332
364
  conditionalExpression += '(';
333
- conditionalExpression += processLogicalElements(_izContext, logicalElement.elements, level + 1); // ***recursion***
365
+ conditionalExpression += processLogicalElements(
366
+ _izContext,
367
+ logicalElement.elements,
368
+ level + 1
369
+ ); // ***recursion***
334
370
  conditionalExpression += ')'; // close sub-group
335
-
336
- } else { // end group types
337
- throw new NoRetryError('Invalided "group" type, group type should have property elements[].');
371
+ } else {
372
+ // end group types
373
+ throw new NoRetryError(
374
+ 'Invalided "group" type, group type should have property elements[].'
375
+ );
338
376
  }
339
377
  }
340
378
 
341
379
  // ----- end check all types -----
342
- else { // Out of types, error
343
- throw new NoRetryError('Invalided config "type", logicalElement type should be "logical", "logicalOperator" or "group".');
380
+ else {
381
+ // Out of types, error
382
+ throw new NoRetryError(
383
+ 'Invalided config "type", logicalElement type should be "logical", "logicalOperator" or "group".'
384
+ );
344
385
  }
345
-
346
386
  } // end loop logicalElement
347
387
 
348
388
  // _izContext.logger.debug('conditionalExpression before return:', conditionalExpression);
349
389
  return conditionalExpression;
350
-
351
- } catch (err) { // just catch for debug not create new error
390
+ } catch (err) {
391
+ // just catch for debug not create new error
352
392
  console.warn('unhandled error', err);
353
393
  throw err;
354
394
  }
355
- }; // module processLogicalElements
356
-
395
+ } // module processLogicalElements
357
396
 
358
397
  /**
359
398
  * Executes a GetItem query to DynamoDB
@@ -366,10 +405,15 @@ function processLogicalElements(_izContext, logicalElements, level) {
366
405
  *
367
406
  * @returns {object} single record return value from the query, or Null if none found
368
407
  */
369
- async function getItem(_izContext, tableName, keyValues, queryElements = {}, settings = {}) {
370
-
408
+ async function getItem(
409
+ _izContext,
410
+ tableName,
411
+ keyValues,
412
+ queryElements = {},
413
+ settings = {}
414
+ ) {
371
415
  try {
372
- console.log("getItems: ", {
416
+ console.log('getItems: ', {
373
417
  tableName,
374
418
  keyValues,
375
419
  queryElements,
@@ -379,44 +423,60 @@ async function getItem(_izContext, tableName, keyValues, queryElements = {}, set
379
423
  let payload = {
380
424
  TableName: tableName,
381
425
  Key: keyValues,
382
- ReturnConsumedCapacity: "TOTAL" // NONE(default) | TOTAL | INDEXES
426
+ ReturnConsumedCapacity: 'TOTAL' // NONE(default) | TOTAL | INDEXES
383
427
  };
384
428
 
385
429
  // if (queryElements) { // add queryElements to payload if exist
386
430
  // NOTE: getItem NOT supported for GSI/LSI
387
- if (queryElements && queryElements.constructor === Object && Object.keys(queryElements).length != 0) { // varidate object not null, not empty, and is object.
431
+ if (
432
+ queryElements &&
433
+ queryElements.constructor === Object &&
434
+ Object.keys(queryElements).length != 0
435
+ ) {
436
+ // varidate object not null, not empty, and is object.
388
437
  for (const element in queryElements) {
389
438
  //waiting for use case...
390
439
  // payload[element] = queryElements[element]
391
440
  }
392
441
  }
393
- _izContext.logger.debug("payload before get items", payload);
442
+ _izContext.logger.debug('payload before get items', payload);
394
443
 
395
444
  const getItem = await dynamodb.get(payload); // ===== main query
396
445
 
397
446
  // const getItem = await izaraDynamodb.get(payload).promise(); // ===== main query
398
447
 
399
448
  // if record not found Null will be returned unless errorOnNoRecordFound set to true which will throw error
400
- if (!getItem.Item) { // if return undefined (NOTE---dynamodb will return .Item value or Item undifined)
401
- if (settings && settings.hasOwnProperty('errorOnNoRecordFound') && settings.errorOnNoRecordFound == true) {
402
- if (settings.hasOwnProperty('retryOnErrorNoRecordFound') && settings.retryOnErrorNoRecordFound == true) {
449
+ if (!getItem.Item) {
450
+ // if return undefined (NOTE---dynamodb will return .Item value or Item undifined)
451
+ if (
452
+ settings &&
453
+ settings.hasOwnProperty('errorOnNoRecordFound') &&
454
+ settings.errorOnNoRecordFound == true
455
+ ) {
456
+ if (
457
+ settings.hasOwnProperty('retryOnErrorNoRecordFound') &&
458
+ settings.retryOnErrorNoRecordFound == true
459
+ ) {
403
460
  throw new Error('retryOnErrorNoRecordFound'); // TT
404
461
  }
405
462
  throw new NoRetryError('errorOnNoRecordFound', payload); // TF
406
463
  }
407
464
  return null; // FF
408
465
  } else {
409
- await captureCapacityUsed(_izContext, getItem.ConsumedCapacity, 'read', 'get');
466
+ await captureCapacityUsed(
467
+ _izContext,
468
+ getItem.ConsumedCapacity,
469
+ 'read',
470
+ 'get'
471
+ );
410
472
  }
411
473
 
412
474
  return getItem.Item; // retuen Item, beware some function get value and use get.Item
413
-
414
475
  } catch (err) {
415
476
  console.warn('warning', err);
416
477
  throw err;
417
478
  }
418
- }; // end module getItem
419
-
479
+ } // end module getItem
420
480
 
421
481
  /**
422
482
  * Executes a Query on DynamoDB
@@ -435,26 +495,38 @@ async function getItem(_izContext, tableName, keyValues, queryElements = {}, set
435
495
  *
436
496
  * @returns {object[], object} array of records from .Items in query result, and queryInfo object with properties such as LastEvaluatedKey
437
497
  */
438
- async function query(_izContext, tableName, partitionKeyValue, queryElements = {}, settings = {}) {
439
-
498
+ async function query(
499
+ _izContext,
500
+ tableName,
501
+ partitionKeyValue,
502
+ queryElements = {},
503
+ settings = {}
504
+ ) {
440
505
  try {
441
-
442
506
  // validate partitionKeyValue, should have only one?
443
- if (typeof partitionKeyValue !== 'object' || Object.keys(partitionKeyValue).length !== 1) {
507
+ if (
508
+ typeof partitionKeyValue !== 'object' ||
509
+ Object.keys(partitionKeyValue).length !== 1
510
+ ) {
444
511
  throw new NoRetryError('partitionKeyValue should be "object" type.');
445
512
  }
446
513
 
447
- let attributeReservedNames = ['partitionKeyValue', 'betweenStartValue', 'betweenEndValue'];
514
+ let attributeReservedNames = [
515
+ 'partitionKeyValue',
516
+ 'betweenStartValue',
517
+ 'betweenEndValue'
518
+ ];
448
519
 
449
520
  // ------------ set payload ---------------
450
521
  let payload = {
451
522
  TableName: tableName, // require
452
523
  // KeyConditionExpression: '',
453
524
  KeyConditionExpression: `${Object.keys(partitionKeyValue)[0]} = :partitionKeyValue`, // require partition key
454
- ExpressionAttributeValues: {}, // require value of partition key
455
- ReturnConsumedCapacity: "TOTAL" // NONE(default) | TOTAL | INDEXES
525
+ ExpressionAttributeValues: {}, // require value of partition key
526
+ ReturnConsumedCapacity: 'TOTAL' // NONE(default) | TOTAL | INDEXES
456
527
  };
457
- payload.ExpressionAttributeValues[`:partitionKeyValue`] = partitionKeyValue[Object.keys(partitionKeyValue)[0]];
528
+ payload.ExpressionAttributeValues[`:partitionKeyValue`] =
529
+ partitionKeyValue[Object.keys(partitionKeyValue)[0]];
458
530
 
459
531
  // ---- sortKeyCondition ----
460
532
  /* NOTE: KeyConditionExpression
@@ -474,7 +546,9 @@ async function query(_izContext, tableName, partitionKeyValue, queryElements = {
474
546
  if (queryElements.sortKeyCondition.hasOwnProperty('comparison')) {
475
547
  //validate sortKeyCondition
476
548
  if (typeof queryElements.sortKeyCondition.comparison !== 'string') {
477
- throw new NoRetryError('comparison set in sortKeyCondition but type is not string');
549
+ throw new NoRetryError(
550
+ 'comparison set in sortKeyCondition but type is not string'
551
+ );
478
552
  }
479
553
  if (!queryElements.sortKeyCondition.name) {
480
554
  throw new NoRetryError('sortKeyCondition name property is required');
@@ -492,79 +566,110 @@ async function query(_izContext, tableName, partitionKeyValue, queryElements = {
492
566
  // }
493
567
  // sortKeyName BETWEEN :sortkeyval1 AND :sortkeyval2
494
568
  payload.KeyConditionExpression += `${queryElements.sortKeyCondition.name} BETWEEN :betweenStartValue AND :betweenEndValue`;
495
- payload.ExpressionAttributeValues[`:betweenStartValue`] = queryElements.sortKeyCondition.betweenStartValue;
496
- payload.ExpressionAttributeValues[`:betweenEndValue`] = queryElements.sortKeyCondition.betweenEndValue;
497
-
498
-
499
- } else { // others comparisons eg. < > <> = , has one side-hand
569
+ payload.ExpressionAttributeValues[`:betweenStartValue`] =
570
+ queryElements.sortKeyCondition.betweenStartValue;
571
+ payload.ExpressionAttributeValues[`:betweenEndValue`] =
572
+ queryElements.sortKeyCondition.betweenEndValue;
573
+ } else {
574
+ // others comparisons eg. < > <> = , has one side-hand
500
575
 
501
576
  // check does not use attributeReservedNames
502
- if (attributeReservedNames.includes(queryElements.sortKeyCondition.name)) {
503
- throw new NoRetryError(`sortKeyCondition.name cannot be a attributeReservedName (${queryElements.sortKeyCondition.name})`);
504
- };
577
+ if (
578
+ attributeReservedNames.includes(queryElements.sortKeyCondition.name)
579
+ ) {
580
+ throw new NoRetryError(
581
+ `sortKeyCondition.name cannot be a attributeReservedName (${queryElements.sortKeyCondition.name})`
582
+ );
583
+ }
505
584
 
506
585
  let subKeyConditionalExpression = null;
507
- if (queryElements.sortKeyCondition.comparison == 'begins_with') { // begins_with ( sortKeyName, :sortkeyval ) ***CANNOT USE WITH NUMBER TYPE
586
+ if (queryElements.sortKeyCondition.comparison == 'begins_with') {
587
+ // begins_with ( sortKeyName, :sortkeyval ) ***CANNOT USE WITH NUMBER TYPE
508
588
  if (typeof queryElements.sortKeyCondition.value !== 'string') {
509
589
  // throw new NoRetryError('begins_with operand "value" required the string to search for.')
510
590
  // queryElements.sortKeyCondition.value = Number(queryElements.sortKeyCondition.value)
511
- queryElements.sortKeyCondition.value = String(queryElements.sortKeyCondition.value); /// if not string ???
591
+ queryElements.sortKeyCondition.value = String(
592
+ queryElements.sortKeyCondition.value
593
+ ); /// if not string ???
512
594
  }
513
595
  subKeyConditionalExpression = `begins_with ( ${queryElements.sortKeyCondition.name}, :${queryElements.sortKeyCondition.name} )`;
514
- }
515
- else if (queryElements.sortKeyCondition.comparison == 'equals') { // sortKeyName = :sortkeyval
596
+ } else if (queryElements.sortKeyCondition.comparison == 'equals') {
597
+ // sortKeyName = :sortkeyval
516
598
  subKeyConditionalExpression = `${queryElements.sortKeyCondition.name} = :${queryElements.sortKeyCondition.name}`;
517
- }
518
- else if (queryElements.sortKeyCondition.comparison == 'notEquals') {
599
+ } else if (queryElements.sortKeyCondition.comparison == 'notEquals') {
519
600
  subKeyConditionalExpression = `${queryElements.sortKeyCondition.name} <> :${queryElements.sortKeyCondition.name}`;
520
- }
521
- else if (queryElements.sortKeyCondition.comparison == 'greaterThan') {
601
+ } else if (
602
+ queryElements.sortKeyCondition.comparison == 'greaterThan'
603
+ ) {
522
604
  subKeyConditionalExpression = `${queryElements.sortKeyCondition.name} > :${queryElements.sortKeyCondition.name}`;
523
- }
524
- else if (queryElements.sortKeyCondition.comparison == 'lessThan') {
605
+ } else if (queryElements.sortKeyCondition.comparison == 'lessThan') {
525
606
  subKeyConditionalExpression = `${queryElements.sortKeyCondition.name} < :${queryElements.sortKeyCondition.name}`;
526
- }
527
- else if (queryElements.sortKeyCondition.comparison == 'lessThanOrEqual') {
607
+ } else if (
608
+ queryElements.sortKeyCondition.comparison == 'lessThanOrEqual'
609
+ ) {
528
610
  subKeyConditionalExpression = `${queryElements.sortKeyCondition.name} <= :${queryElements.sortKeyCondition.name}`;
529
- }
530
- else if (queryElements.sortKeyCondition.comparison == 'greaterThanOrEqual') {
611
+ } else if (
612
+ queryElements.sortKeyCondition.comparison == 'greaterThanOrEqual'
613
+ ) {
531
614
  subKeyConditionalExpression = `${queryElements.sortKeyCondition.name} >= :${queryElements.sortKeyCondition.name}`;
532
615
  } else {
533
616
  //unrecognised comparison
534
- throw new NoRetryError('Unrecognised comparison in sortKeyCondition ' + queryElements.sortKeyCondition.comparison);
617
+ throw new NoRetryError(
618
+ 'Unrecognised comparison in sortKeyCondition ' +
619
+ queryElements.sortKeyCondition.comparison
620
+ );
535
621
  }
536
622
 
537
623
  payload.KeyConditionExpression += subKeyConditionalExpression;
538
- payload.ExpressionAttributeValues[`:${queryElements.sortKeyCondition.name}`] = queryElements.sortKeyCondition.value;
539
-
540
- }; // end all comparisons
624
+ payload.ExpressionAttributeValues[
625
+ `:${queryElements.sortKeyCondition.name}`
626
+ ] = queryElements.sortKeyCondition.value;
627
+ } // end all comparisons
541
628
  } else {
542
- throw new NoRetryError('sortKeyCondition should have "comparison" property.');
629
+ throw new NoRetryError(
630
+ 'sortKeyCondition should have "comparison" property.'
631
+ );
543
632
  }
544
633
  } // end sortKeyCondition
545
634
 
546
635
  // NOTE ***** we need to choose projectionExpression or select, not both! *****
547
- if (queryElements.projectionExpression && queryElements.select != 'SPECIFIC_ATTRIBUTES') {
548
- throw new NoRetryError('invalid setting, choose projectionExpression or select, or set projectionExpression with select is "SPECIFIC_ATTRIBUTES" ');
636
+ if (
637
+ queryElements.projectionExpression &&
638
+ queryElements.select != 'SPECIFIC_ATTRIBUTES'
639
+ ) {
640
+ throw new NoRetryError(
641
+ 'invalid setting, choose projectionExpression or select, or set projectionExpression with select is "SPECIFIC_ATTRIBUTES" '
642
+ );
549
643
  }
550
644
 
551
645
  // ---- projectionExpression : Return the specific attribute that we want ----
552
646
  // projection-expression "Description, RelatedItems[0], ProductReviews.FiveStar"
553
- if (queryElements.projectionExpression && Array.isArray(queryElements.projectionExpression) && queryElements.projectionExpression.length !== 0) {
554
- payload.ProjectionExpression = queryElements.projectionExpression.join(', ');
647
+ if (
648
+ queryElements.projectionExpression &&
649
+ Array.isArray(queryElements.projectionExpression) &&
650
+ queryElements.projectionExpression.length !== 0
651
+ ) {
652
+ payload.ProjectionExpression =
653
+ queryElements.projectionExpression.join(', ');
555
654
  }
556
655
 
557
656
  // ---- select : Return the specific item attributes, the count of matching items, or in the case of an index----
558
- if (queryElements.select) { // ALL_ATTRIBUTES | ALL_PROJECTED_ATTRIBUTES | COUNT
657
+ if (queryElements.select) {
658
+ // ALL_ATTRIBUTES | ALL_PROJECTED_ATTRIBUTES | COUNT
559
659
 
560
660
  _izContext.logger.debug('queryElements.select', queryElements.select);
561
661
  queryElements.select = queryElements.select.toUpperCase();
562
- if (queryElements.select == 'ALL_ATTRIBUTES' || queryElements.select == 'ALL_PROJECTED_ATTRIBUTES'
563
- || queryElements.select == 'COUNT' || queryElements.select == 'SPECIFIC_ATTRIBUTES'
662
+ if (
663
+ queryElements.select == 'ALL_ATTRIBUTES' ||
664
+ queryElements.select == 'ALL_PROJECTED_ATTRIBUTES' ||
665
+ queryElements.select == 'COUNT' ||
666
+ queryElements.select == 'SPECIFIC_ATTRIBUTES'
564
667
  ) {
565
668
  payload.Select = queryElements.select;
566
669
  } else {
567
- throw new NoRetryError('select invalid, should be "ALL_ATTRIBUTES" | "ALL_PROJECTED_ATTRIBUTES" | "COUNT" | "SPECIFIC_ATTRIBUTES".');
670
+ throw new NoRetryError(
671
+ 'select invalid, should be "ALL_ATTRIBUTES" | "ALL_PROJECTED_ATTRIBUTES" | "COUNT" | "SPECIFIC_ATTRIBUTES".'
672
+ );
568
673
  }
569
674
  }
570
675
 
@@ -601,27 +706,41 @@ async function query(_izContext, tableName, partitionKeyValue, queryElements = {
601
706
  _izContext.logger.debug('payload before query', payload);
602
707
 
603
708
  // ---- numPagesToRequest default = 1 page(hit limit at 1 Mb per page)
604
- if (!settings.hasOwnProperty('numPagesToRequest') || settings.numPagesToRequest == 1) {
709
+ if (
710
+ !settings.hasOwnProperty('numPagesToRequest') ||
711
+ settings.numPagesToRequest == 1
712
+ ) {
605
713
  // main query if not set numPagesToRequest, default is 1 page.
606
714
  _izContext.logger.debug('CASE: numPagesToRequest = 1');
607
715
 
608
716
  const returnValue = await dynamodb.query(payload);
609
- _izContext.logger.debug("query status: ", returnValue['$metadata']);
610
- await captureCapacityUsed(_izContext, returnValue.ConsumedCapacity, 'read', 'query');
717
+ _izContext.logger.debug('query status: ', returnValue['$metadata']);
718
+ await captureCapacityUsed(
719
+ _izContext,
720
+ returnValue.ConsumedCapacity,
721
+ 'read',
722
+ 'query'
723
+ );
611
724
  return returnValue; // return in syntax dynamodb
612
- } else { // *** require numPagesToRequest
725
+ } else {
726
+ // *** require numPagesToRequest
613
727
  _izContext.logger.debug('CASE: numPagesToRequest > 1');
614
728
 
615
729
  // ---- ExclusiveStartKey and Pagination ----
616
- const getAllData = async (payload) => {
730
+ const getAllData = async payload => {
617
731
  const _getAllData = async (payload, startKey) => {
618
732
  if (startKey) {
619
733
  payload.ExclusiveStartKey = startKey; // if LastEvaluatedKey existing
620
734
  }
621
735
  queryPage++;
622
736
  let data = dynamodb.query(payload); // ---- main query
623
- _izContext.logger.debug("query status: ", data['$metadata']);
624
- await captureCapacityUsed(_izContext, data.ConsumedCapacity, 'read', 'query');
737
+ _izContext.logger.debug('query status: ', data['$metadata']);
738
+ await captureCapacityUsed(
739
+ _izContext,
740
+ data.ConsumedCapacity,
741
+ 'read',
742
+ 'query'
743
+ );
625
744
  return data;
626
745
  };
627
746
 
@@ -633,7 +752,8 @@ async function query(_izContext, tableName, partitionKeyValue, queryElements = {
633
752
  let count = 0;
634
753
  let scannedCount = 0;
635
754
 
636
- do { // execute block do before check condition in first time, if condition true do it again and again.
755
+ do {
756
+ // execute block do before check condition in first time, if condition true do it again and again.
637
757
  const result = await _getAllData(payload, lastEvaluatedKey); // call function
638
758
  // _izContext.logger.debug('result: ', result);
639
759
  // _izContext.logger.debug('queryPage: ', queryPage);
@@ -644,15 +764,19 @@ async function query(_izContext, tableName, partitionKeyValue, queryElements = {
644
764
  lastEvaluatedKey = result.LastEvaluatedKey; // replace LastEvaluatedKey for check condiion
645
765
  lastEvaluatedKeyReturnValue = result.LastEvaluatedKey;
646
766
 
647
- if (result.hasOwnProperty('Items')) { // will be work with select setting
767
+ if (result.hasOwnProperty('Items')) {
768
+ // will be work with select setting
648
769
  rows = rows.concat(result.Items); // need to concat array, cannot use push(will be nested array)
649
770
  }
650
- if (queryPage >= settings.numPagesToRequest) { // if set numPagesToRequest, limit query = numPagesToRequest will stop query
771
+ if (queryPage >= settings.numPagesToRequest) {
772
+ // if set numPagesToRequest, limit query = numPagesToRequest will stop query
651
773
  lastEvaluatedKey = null; // out of loop, set condition is false
652
774
  }
653
775
 
654
776
  if (queryPage === 1000) {
655
- throw new NoRetryError('too many paginated database results, 1000 limit reached, stopped execution in dynamodb.query');
777
+ throw new NoRetryError(
778
+ 'too many paginated database results, 1000 limit reached, stopped execution in dynamodb.query'
779
+ );
656
780
  }
657
781
  } while (lastEvaluatedKey); // check condition after do block
658
782
  return {
@@ -668,10 +792,7 @@ async function query(_izContext, tableName, partitionKeyValue, queryElements = {
668
792
  _izContext.logger.warn('warning', err);
669
793
  throw new Error('Unhandled Error, query: ', err);
670
794
  }
671
- };
672
-
673
-
674
-
795
+ }
675
796
 
676
797
  /**
677
798
  * Executes a Query on DynamoDB and get only Items
@@ -688,8 +809,13 @@ async function query(_izContext, tableName, partitionKeyValue, queryElements = {
688
809
  *
689
810
  * @returns {object[], object} array of records from .Items in query result, and queryInfo object with properties such as LastEvaluatedKey
690
811
  */
691
- async function queryResults(_izContext, tableName, partitionKeyValue, queryElements = {}, settings = {}) {
692
-
812
+ async function queryResults(
813
+ _izContext,
814
+ tableName,
815
+ partitionKeyValue,
816
+ queryElements = {},
817
+ settings = {}
818
+ ) {
693
819
  const queryResults = await query(
694
820
  _izContext,
695
821
  tableName,
@@ -698,9 +824,7 @@ async function queryResults(_izContext, tableName, partitionKeyValue, queryEleme
698
824
  settings
699
825
  );
700
826
  return queryResults.Items;
701
- };
702
-
703
-
827
+ }
704
828
 
705
829
  /**
706
830
  * Executes a PutItem query on DynamoDB
@@ -735,60 +859,76 @@ async function putItem(
735
859
  TableName: tableName,
736
860
  Item: {}, // Item: attributes,
737
861
  ReturnValues: 'NONE', // NONE(default) | ALL_OLD
738
- ReturnConsumedCapacity: "TOTAL" // NONE(default) | TOTAL | INDEXES
862
+ ReturnConsumedCapacity: 'TOTAL' // NONE(default) | TOTAL | INDEXES
739
863
  };
740
864
 
741
865
  // set payload: ReturnValues
742
- if (queryElements.hasOwnProperty('returnValues') && queryElements.returnValues.toLocaleUpperCase() == 'ALL_OLD') {
866
+ if (
867
+ queryElements.hasOwnProperty('returnValues') &&
868
+ queryElements.returnValues.toLocaleUpperCase() == 'ALL_OLD'
869
+ ) {
743
870
  payload.ReturnValues = queryElements.returnValues.toLocaleUpperCase();
744
871
  }
745
872
  // set payload: ConditionExpression and/or ExpressionAttributeValues
746
- const [conditionExpression, expressionAttributeValues] = reformConditionExpression(_izContext, queryElements);
873
+ const [conditionExpression, expressionAttributeValues] =
874
+ reformConditionExpression(_izContext, queryElements);
747
875
  if (conditionExpression) payload.ConditionExpression = conditionExpression;
748
- if (expressionAttributeValues) payload.ExpressionAttributeValues = expressionAttributeValues;
876
+ if (expressionAttributeValues)
877
+ payload.ExpressionAttributeValues = expressionAttributeValues;
749
878
 
750
879
  _izContext.logger.debug('conditionExpression', payload.ConditionExpression);
751
- _izContext.logger.debug('expressionAttributeValues', payload.ExpressionAttributeValues);
880
+ _izContext.logger.debug(
881
+ 'expressionAttributeValues',
882
+ payload.ExpressionAttributeValues
883
+ );
752
884
 
753
885
  // ckeck complexAttributes and validate attributes
754
886
  if (settings.complexAttributes) {
755
887
  if (Array.isArray(attributes) && attributes.length !== 0) {
756
-
757
888
  // -- add _izContext to attributes
758
889
  attributes.push({
759
- attributeName: "izContext",
890
+ attributeName: 'izContext',
760
891
  value: correlationIdValues(_izContext)
761
892
  });
762
893
 
763
894
  // for (let idx = 0; idx < attributes.length; idx++) { // for loop more performance than for of
764
895
  for (let idx = 0, len = attributes.length; idx < len; idx++) {
765
- if (attributes[idx].action.toUpperCase() !== 'REMOVE' && attributes[idx].value === undefined) {
896
+ if (
897
+ attributes[idx].action.toUpperCase() !== 'REMOVE' &&
898
+ attributes[idx].value === undefined
899
+ ) {
766
900
  continue;
767
901
  }
768
902
 
769
903
  // _izContext.logger.debug('attributes[idx]', attributes[idx]);
770
904
  // if stringSet >> createStringSet >> put
771
905
  if (attributes[idx].isStringSet) {
772
-
773
- if (!Array.isArray(attributes[idx].value) || attributes[idx].value.length === 0) { // validate attributes value
774
- throw new NoRetryError('attributes value should be array and not empty.');
906
+ if (
907
+ !Array.isArray(attributes[idx].value) ||
908
+ attributes[idx].value.length === 0
909
+ ) {
910
+ // validate attributes value
911
+ throw new NoRetryError(
912
+ 'attributes value should be array and not empty.'
913
+ );
775
914
  }
776
915
  attributes[idx].value = arrayToStringSet(attributes[idx].value);
777
916
  }
778
- payload.Item[`${attributes[idx].attributeName}`] = attributes[idx].value;
779
-
780
- }// end for loop
917
+ payload.Item[`${attributes[idx].attributeName}`] =
918
+ attributes[idx].value;
919
+ } // end for loop
781
920
  } else {
782
- throw new NoRetryError('complexAttributes setting is true, attributes should be array and not empty.');
921
+ throw new NoRetryError(
922
+ 'complexAttributes setting is true, attributes should be array and not empty.'
923
+ );
783
924
  }
784
-
785
- } else { // if not set (default), will attributes keyVslue to Item
925
+ } else {
926
+ // if not set (default), will attributes keyVslue to Item
786
927
  _izContext.logger.debug('payload complex is false', payload);
787
928
 
788
929
  // payload.Item = attributes
789
930
  payload.Item = removeUndefined(attributes);
790
- payload.Item["izContext"] = correlationIdValues(_izContext);
791
-
931
+ payload.Item['izContext'] = correlationIdValues(_izContext);
792
932
  }
793
933
 
794
934
  _izContext.logger.debug('payload before putItem', payload);
@@ -802,38 +942,51 @@ async function putItem(
802
942
  return payload; // stop process in here not send to dymanodb
803
943
  }
804
944
 
805
- const returnValue = await dynamodb.put(payload); // ---- main query
806
- _izContext.logger.debug("putItem status: ", returnValue['$metadata']);
807
- await captureCapacityUsed(_izContext, returnValue.ConsumedCapacity, 'write', 'put');
945
+ const returnValue = await dynamodb.put(payload); // ---- main query
946
+ _izContext.logger.debug('putItem status: ', returnValue['$metadata']);
947
+ await captureCapacityUsed(
948
+ _izContext,
949
+ returnValue.ConsumedCapacity,
950
+ 'write',
951
+ 'put'
952
+ );
808
953
  if (payload.ReturnValues !== 'NONE' && returnValue.Attributes) {
809
954
  return returnValue.Attributes;
810
955
  }
811
-
812
- } catch (err) { // catch error when put and handle errors.
956
+ } catch (err) {
957
+ // catch error when put and handle errors.
813
958
 
814
959
  _izContext.logger.debug('err', err);
815
- if (err.name == 'ConditionalCheckFailedException') { // if return undefined (NOTE---dynamodb will return .Item value or Item undifined)
816
- if (settings && settings.hasOwnProperty('errorOnConditionalExpNotPass') && settings.errorOnConditionalExpNotPass == true) {
817
- if (settings.hasOwnProperty('retryOnErrorConditionalExpNotPass') && settings.retryOnErrorConditionalExpNotPass == true) {
960
+ if (err.name == 'ConditionalCheckFailedException') {
961
+ // if return undefined (NOTE---dynamodb will return .Item value or Item undifined)
962
+ if (
963
+ settings &&
964
+ settings.hasOwnProperty('errorOnConditionalExpNotPass') &&
965
+ settings.errorOnConditionalExpNotPass == true
966
+ ) {
967
+ if (
968
+ settings.hasOwnProperty('retryOnErrorConditionalExpNotPass') &&
969
+ settings.retryOnErrorConditionalExpNotPass == true
970
+ ) {
818
971
  console.error(err.name + ': ' + err.message);
819
972
  throw new Error('ConditionalExpNotPass'); // TT, if throw will stop
820
973
  }
821
974
  console.error(err.name + ': ' + err.message);
822
975
  throw new NoRetryError('ConditionalExpNotPass'); // TF
823
976
  }
824
- } else { // e.g. ProvisionedThroughputExceededException
977
+ } else {
978
+ // e.g. ProvisionedThroughputExceededException
825
979
  // throw new Error('Unhandled Error when putItem', err) // TT, if throw will stop
826
- throw (err); // TT, if throw will stop
980
+ throw err; // TT, if throw will stop
827
981
  }
828
982
  } //end catch err
829
-
830
- } catch (err) { // catch unhandled error
983
+ } catch (err) {
984
+ // catch unhandled error
831
985
  console.log('err', err);
832
986
  _izContext.logger.error(err.name + ': ' + err.message);
833
987
  throw err; // TT, if throw will stop
834
988
  }
835
- }; // end module putItem
836
-
989
+ } // end module putItem
837
990
 
838
991
  /**
839
992
  * Updates an item in DynamoDB (simple or complex mode).
@@ -875,7 +1028,9 @@ async function updateItem(
875
1028
  queryElements,
876
1029
  settings
877
1030
  ) {
878
- _izContext.logger.debug('iam in updateItem', { queryElements: queryElements });
1031
+ _izContext.logger.debug('iam in updateItem', {
1032
+ queryElements: queryElements
1033
+ });
879
1034
 
880
1035
  try {
881
1036
  if (!queryElements) {
@@ -887,12 +1042,12 @@ async function updateItem(
887
1042
 
888
1043
  // --- initial payload
889
1044
  let payload = {
890
- TableName: tableName, // required
891
- Key: keyValues, // required
892
- UpdateExpression: '', // will be built later
893
- ExpressionAttributeValues: {}, // placeholders for update/condition values
894
- ReturnValues: 'NONE', // NONE | ALL_OLD | UPDATED_OLD | ALL_NEW | UPDATED_NEW
895
- ReturnConsumedCapacity: 'TOTAL' // NONE(default) | TOTAL | INDEXES
1045
+ TableName: tableName, // required
1046
+ Key: keyValues, // required
1047
+ UpdateExpression: '', // will be built later
1048
+ ExpressionAttributeValues: {}, // placeholders for update/condition values
1049
+ ReturnValues: 'NONE', // NONE | ALL_OLD | UPDATED_OLD | ALL_NEW | UPDATED_NEW
1050
+ ReturnConsumedCapacity: 'TOTAL' // NONE(default) | TOTAL | INDEXES
896
1051
  };
897
1052
 
898
1053
  // optional ReturnValues override
@@ -912,7 +1067,8 @@ async function updateItem(
912
1067
  // ----- merge ConditionExpression + names/values from queryElements (primary path)
913
1068
  const merged = reformConditionExpression(_izContext, queryElements);
914
1069
  const conditionExpression = merged && merged[0] ? merged[0] : '';
915
- const expressionAttributeValuesFromCE = merged && merged[1] ? merged[1] : null;
1070
+ const expressionAttributeValuesFromCE =
1071
+ merged && merged[1] ? merged[1] : null;
916
1072
 
917
1073
  if (conditionExpression) {
918
1074
  payload.ConditionExpression = conditionExpression;
@@ -922,7 +1078,10 @@ async function updateItem(
922
1078
  if (
923
1079
  !payload.ConditionExpression &&
924
1080
  queryElements &&
925
- Object.prototype.hasOwnProperty.call(queryElements, 'conditionExpression') &&
1081
+ Object.prototype.hasOwnProperty.call(
1082
+ queryElements,
1083
+ 'conditionExpression'
1084
+ ) &&
926
1085
  queryElements.conditionExpression
927
1086
  ) {
928
1087
  payload.ConditionExpression = String(queryElements.conditionExpression);
@@ -935,11 +1094,17 @@ async function updateItem(
935
1094
  const k = entriesCE[i][0];
936
1095
  const v = entriesCE[i][1];
937
1096
  if (
938
- Object.prototype.hasOwnProperty.call(payload.ExpressionAttributeValues, k) &&
939
- JSON.stringify(payload.ExpressionAttributeValues[k]) !== JSON.stringify(v)
1097
+ Object.prototype.hasOwnProperty.call(
1098
+ payload.ExpressionAttributeValues,
1099
+ k
1100
+ ) &&
1101
+ JSON.stringify(payload.ExpressionAttributeValues[k]) !==
1102
+ JSON.stringify(v)
940
1103
  ) {
941
1104
  throw new NoRetryError(
942
- 'Placeholder ' + k + ' duplicated with different value (from ConditionExpression merge).'
1105
+ 'Placeholder ' +
1106
+ k +
1107
+ ' duplicated with different value (from ConditionExpression merge).'
943
1108
  );
944
1109
  }
945
1110
  payload.ExpressionAttributeValues[k] = v;
@@ -962,11 +1127,17 @@ async function updateItem(
962
1127
  const k = entriesQE[i][0];
963
1128
  const v = entriesQE[i][1];
964
1129
  if (
965
- Object.prototype.hasOwnProperty.call(payload.ExpressionAttributeValues, k) &&
966
- JSON.stringify(payload.ExpressionAttributeValues[k]) !== JSON.stringify(v)
1130
+ Object.prototype.hasOwnProperty.call(
1131
+ payload.ExpressionAttributeValues,
1132
+ k
1133
+ ) &&
1134
+ JSON.stringify(payload.ExpressionAttributeValues[k]) !==
1135
+ JSON.stringify(v)
967
1136
  ) {
968
1137
  throw new NoRetryError(
969
- 'Placeholder ' + k + ' duplicated with different value (from queryElements merge).'
1138
+ 'Placeholder ' +
1139
+ k +
1140
+ ' duplicated with different value (from queryElements merge).'
970
1141
  );
971
1142
  }
972
1143
  payload.ExpressionAttributeValues[k] = v;
@@ -977,8 +1148,10 @@ async function updateItem(
977
1148
  1) Group expressions by action (SET/REMOVE/ADD/DELETE)
978
1149
  2) Build UpdateExpression in fixed order: SET → REMOVE → ADD → DELETE
979
1150
  */
980
- if (Object.prototype.hasOwnProperty.call(settings, 'complexAttributes') &&
981
- settings.complexAttributes === true) {
1151
+ if (
1152
+ Object.prototype.hasOwnProperty.call(settings, 'complexAttributes') &&
1153
+ settings.complexAttributes === true
1154
+ ) {
982
1155
  if (Array.isArray(attributes) && attributes.length !== 0) {
983
1156
  // always include izContext as SET
984
1157
  attributes.push({
@@ -994,22 +1167,37 @@ async function updateItem(
994
1167
 
995
1168
  // default action is SET
996
1169
  let action = 'SET';
997
- if (Object.prototype.hasOwnProperty.call(item, 'action') && item.action) {
1170
+ if (
1171
+ Object.prototype.hasOwnProperty.call(item, 'action') &&
1172
+ item.action
1173
+ ) {
998
1174
  action = String(item.action).toUpperCase();
999
1175
  }
1000
1176
 
1001
1177
  // skip non-REMOVE entries that have no value or valueReference
1002
- if (action !== 'REMOVE' &&
1178
+ if (
1179
+ action !== 'REMOVE' &&
1003
1180
  !Object.prototype.hasOwnProperty.call(item, 'value') &&
1004
- !Object.prototype.hasOwnProperty.call(item, 'valueReference')) {
1181
+ !Object.prototype.hasOwnProperty.call(item, 'valueReference')
1182
+ ) {
1005
1183
  continue;
1006
1184
  }
1007
1185
 
1008
- if (action !== 'SET' && action !== 'REMOVE' && action !== 'ADD' && action !== 'DELETE') {
1009
- throw new NoRetryError('"action" should be one of: set | remove | add | delete');
1186
+ if (
1187
+ action !== 'SET' &&
1188
+ action !== 'REMOVE' &&
1189
+ action !== 'ADD' &&
1190
+ action !== 'DELETE'
1191
+ ) {
1192
+ throw new NoRetryError(
1193
+ '"action" should be one of: set | remove | add | delete'
1194
+ );
1010
1195
  }
1011
1196
 
1012
- const valueReference = Object.prototype.hasOwnProperty.call(item, 'valueReference')
1197
+ const valueReference = Object.prototype.hasOwnProperty.call(
1198
+ item,
1199
+ 'valueReference'
1200
+ )
1013
1201
  ? item.valueReference
1014
1202
  : item.attributeName;
1015
1203
 
@@ -1017,77 +1205,115 @@ async function updateItem(
1017
1205
  let addSide = null;
1018
1206
  let subtractSide = null;
1019
1207
 
1020
- try { addSide = validateSideHand(item, 'add'); } catch (e1) { }
1021
- try { subtractSide = validateSideHand(item, 'subtract'); } catch (e2) { }
1208
+ try {
1209
+ addSide = validateSideHand(item, 'add');
1210
+ } catch (e1) {}
1211
+ try {
1212
+ subtractSide = validateSideHand(item, 'subtract');
1213
+ } catch (e2) {}
1022
1214
 
1023
1215
  // listAppend/add/subtract must only be used with SET
1024
- if ((Object.prototype.hasOwnProperty.call(item, 'listAppend') && item.listAppend === true) ||
1025
- addSide || subtractSide) {
1216
+ if (
1217
+ (Object.prototype.hasOwnProperty.call(item, 'listAppend') &&
1218
+ item.listAppend === true) ||
1219
+ addSide ||
1220
+ subtractSide
1221
+ ) {
1026
1222
  if (action !== 'SET') {
1027
1223
  throw new NoRetryError(
1028
- JSON.stringify(item) + ': listAppend / add_ / subtract_ must be used with "SET" action.'
1224
+ JSON.stringify(item) +
1225
+ ': listAppend / add_ / subtract_ must be used with "SET" action.'
1029
1226
  );
1030
1227
  }
1031
1228
  }
1032
1229
 
1033
1230
  // build expression
1034
- if (Object.prototype.hasOwnProperty.call(item, 'listAppend') && item.listAppend === true) {
1231
+ if (
1232
+ Object.prototype.hasOwnProperty.call(item, 'listAppend') &&
1233
+ item.listAppend === true
1234
+ ) {
1035
1235
  if (!Array.isArray(item.value)) {
1036
1236
  throw new NoRetryError('listAppend value must be an array.');
1037
1237
  }
1038
1238
  expression =
1039
1239
  item.attributeName +
1040
- ' = list_append(if_not_exists(' + item.attributeName +
1041
- ', :iz_list_append_empty_list), :' + valueReference + ')';
1042
-
1043
- if (Object.prototype.hasOwnProperty.call(payload.ExpressionAttributeValues, ':iz_list_append_empty_list')) {
1044
- const existing = payload.ExpressionAttributeValues[':iz_list_append_empty_list'];
1240
+ ' = list_append(if_not_exists(' +
1241
+ item.attributeName +
1242
+ ', :iz_list_append_empty_list), :' +
1243
+ valueReference +
1244
+ ')';
1245
+
1246
+ if (
1247
+ Object.prototype.hasOwnProperty.call(
1248
+ payload.ExpressionAttributeValues,
1249
+ ':iz_list_append_empty_list'
1250
+ )
1251
+ ) {
1252
+ const existing =
1253
+ payload.ExpressionAttributeValues[':iz_list_append_empty_list'];
1045
1254
  if (Array.isArray(existing) && existing.length !== 0) {
1046
1255
  throw new NoRetryError(
1047
1256
  'iz_list_append_empty_list already exists and conflicts with auto-generated placeholder.'
1048
1257
  );
1049
1258
  }
1050
1259
  }
1051
- payload.ExpressionAttributeValues[':iz_list_append_empty_list'] = [];
1052
-
1260
+ payload.ExpressionAttributeValues[':iz_list_append_empty_list'] =
1261
+ [];
1053
1262
  } else if (addSide) {
1054
- if (typeof payload.ExpressionAttributeValues[addSide] !== 'number') {
1263
+ if (
1264
+ typeof payload.ExpressionAttributeValues[addSide] !== 'number'
1265
+ ) {
1055
1266
  throw new NoRetryError('add_ value should be a number.');
1056
1267
  }
1057
- expression = item.attributeName + ' = ' + item.attributeName + ' + ' + addSide;
1058
-
1268
+ expression =
1269
+ item.attributeName + ' = ' + item.attributeName + ' + ' + addSide;
1059
1270
  } else if (subtractSide) {
1060
- if (typeof payload.ExpressionAttributeValues[subtractSide] !== 'number') {
1271
+ if (
1272
+ typeof payload.ExpressionAttributeValues[subtractSide] !==
1273
+ 'number'
1274
+ ) {
1061
1275
  throw new NoRetryError('subtract_ value should be a number.');
1062
1276
  }
1063
- expression = item.attributeName + ' = ' + item.attributeName + ' - ' + subtractSide;
1064
-
1277
+ expression =
1278
+ item.attributeName +
1279
+ ' = ' +
1280
+ item.attributeName +
1281
+ ' - ' +
1282
+ subtractSide;
1065
1283
  } else if (action === 'ADD') {
1066
1284
  if (typeof item.value !== 'number' && !Array.isArray(item.value)) {
1067
- throw new NoRetryError('ADD action supports only number and set data types.');
1285
+ throw new NoRetryError(
1286
+ 'ADD action supports only number and set data types.'
1287
+ );
1068
1288
  }
1069
1289
  expression = item.attributeName + ' :' + valueReference;
1070
-
1071
1290
  } else if (action === 'REMOVE') {
1072
- if (Object.prototype.hasOwnProperty.call(item, 'valueReference') ||
1073
- Object.prototype.hasOwnProperty.call(item, 'value')) {
1074
- throw new NoRetryError('REMOVE action requires only attribute path.');
1291
+ if (
1292
+ Object.prototype.hasOwnProperty.call(item, 'valueReference') ||
1293
+ Object.prototype.hasOwnProperty.call(item, 'value')
1294
+ ) {
1295
+ throw new NoRetryError(
1296
+ 'REMOVE action requires only attribute path.'
1297
+ );
1075
1298
  }
1076
1299
  expression = item.attributeName;
1077
-
1078
1300
  } else if (action === 'DELETE') {
1079
1301
  expression = item.attributeName + ' :' + valueReference;
1080
-
1081
- } else { // SET (default)
1302
+ } else {
1303
+ // SET (default)
1082
1304
  expression = item.attributeName + ' = :' + valueReference;
1083
1305
  }
1084
1306
 
1085
1307
  // attach value placeholders
1086
- if (Object.prototype.hasOwnProperty.call(item, 'isStringSet') && item.isStringSet === true) {
1308
+ if (
1309
+ Object.prototype.hasOwnProperty.call(item, 'isStringSet') &&
1310
+ item.isStringSet === true
1311
+ ) {
1087
1312
  item.value = arrayToStringSet(item.value);
1088
1313
  }
1089
1314
  if (Object.prototype.hasOwnProperty.call(item, 'value')) {
1090
- payload.ExpressionAttributeValues[':' + valueReference] = item.value;
1315
+ payload.ExpressionAttributeValues[':' + valueReference] =
1316
+ item.value;
1091
1317
  }
1092
1318
 
1093
1319
  if (!Object.prototype.hasOwnProperty.call(attributeSets, action)) {
@@ -1101,7 +1327,10 @@ async function updateItem(
1101
1327
  payload.UpdateExpression = '';
1102
1328
  for (let i = 0; i < ORDER.length; i++) {
1103
1329
  const act = ORDER[i];
1104
- if (Object.prototype.hasOwnProperty.call(attributeSets, act) && attributeSets[act].length > 0) {
1330
+ if (
1331
+ Object.prototype.hasOwnProperty.call(attributeSets, act) &&
1332
+ attributeSets[act].length > 0
1333
+ ) {
1105
1334
  const block = act + ' ' + attributeSets[act].join(', ');
1106
1335
  payload.UpdateExpression = payload.UpdateExpression
1107
1336
  ? payload.UpdateExpression + ' ' + block
@@ -1109,11 +1338,11 @@ async function updateItem(
1109
1338
  }
1110
1339
  }
1111
1340
  payload.UpdateExpression = payload.UpdateExpression.trim();
1112
-
1113
1341
  } else {
1114
- throw new NoRetryError('complexAttributes=true requires attributes as non-empty array.');
1342
+ throw new NoRetryError(
1343
+ 'complexAttributes=true requires attributes as non-empty array.'
1344
+ );
1115
1345
  }
1116
-
1117
1346
  } else {
1118
1347
  // simple mode: default SET for flat key-value pairs
1119
1348
  payload.UpdateExpression = 'SET';
@@ -1121,38 +1350,54 @@ async function updateItem(
1121
1350
 
1122
1351
  for (const attribute in attributes) {
1123
1352
  if (Object.prototype.hasOwnProperty.call(attributes, attribute)) {
1124
- payload.UpdateExpression += ' ' + attribute + ' = :' + attribute + ',';
1125
- payload.ExpressionAttributeValues[':' + attribute] = attributes[attribute];
1353
+ payload.UpdateExpression +=
1354
+ ' ' + attribute + ' = :' + attribute + ',';
1355
+ payload.ExpressionAttributeValues[':' + attribute] =
1356
+ attributes[attribute];
1126
1357
  }
1127
1358
  }
1128
1359
 
1129
1360
  // always append izContext
1130
1361
  payload.UpdateExpression += ' izContext = :izContext,';
1131
- payload.ExpressionAttributeValues[':izContext'] = correlationIdValues(_izContext);
1362
+ payload.ExpressionAttributeValues[':izContext'] =
1363
+ correlationIdValues(_izContext);
1132
1364
 
1133
1365
  payload.UpdateExpression = payload.UpdateExpression.slice(0, -1);
1134
1366
  }
1135
1367
 
1136
1368
  // ensure izContext exists (even in complex mode)
1137
- if (!Object.prototype.hasOwnProperty.call(payload.ExpressionAttributeValues, ':izContext')) {
1138
- payload.ExpressionAttributeValues[':izContext'] = correlationIdValues(_izContext);
1369
+ if (
1370
+ !Object.prototype.hasOwnProperty.call(
1371
+ payload.ExpressionAttributeValues,
1372
+ ':izContext'
1373
+ )
1374
+ ) {
1375
+ payload.ExpressionAttributeValues[':izContext'] =
1376
+ correlationIdValues(_izContext);
1139
1377
  if (!/^SET\b/.test(payload.UpdateExpression)) {
1140
1378
  payload.UpdateExpression =
1141
- 'SET izContext = :izContext' + (payload.UpdateExpression ? ' ' + payload.UpdateExpression : '');
1379
+ 'SET izContext = :izContext' +
1380
+ (payload.UpdateExpression ? ' ' + payload.UpdateExpression : '');
1142
1381
  } else if (!/(\b|\s)izContext(\s|=|,)/.test(payload.UpdateExpression)) {
1143
1382
  payload.UpdateExpression = payload.UpdateExpression.replace(
1144
1383
  /^SET\s+/,
1145
- function (m) { return m + 'izContext = :izContext, '; }
1384
+ function (m) {
1385
+ return m + 'izContext = :izContext, ';
1386
+ }
1146
1387
  );
1147
1388
  }
1148
1389
  }
1149
1390
 
1150
1391
  // ---------- prune unused placeholders (#..., :...) ----------
1151
1392
  let exprJoin = '';
1152
- if (payload.ConditionExpression) exprJoin += ' ' + String(payload.ConditionExpression);
1153
- if (payload.UpdateExpression) exprJoin += ' ' + String(payload.UpdateExpression);
1154
- if (payload.ProjectionExpression) exprJoin += ' ' + String(payload.ProjectionExpression);
1155
- if (payload.KeyConditionExpression) exprJoin += ' ' + String(payload.KeyConditionExpression);
1393
+ if (payload.ConditionExpression)
1394
+ exprJoin += ' ' + String(payload.ConditionExpression);
1395
+ if (payload.UpdateExpression)
1396
+ exprJoin += ' ' + String(payload.UpdateExpression);
1397
+ if (payload.ProjectionExpression)
1398
+ exprJoin += ' ' + String(payload.ProjectionExpression);
1399
+ if (payload.KeyConditionExpression)
1400
+ exprJoin += ' ' + String(payload.KeyConditionExpression);
1156
1401
 
1157
1402
  if (payload.ExpressionAttributeNames) {
1158
1403
  const nameKeys = Object.keys(payload.ExpressionAttributeNames);
@@ -1187,16 +1432,25 @@ async function updateItem(
1187
1432
  // ---- call DynamoDB
1188
1433
  try {
1189
1434
  const returnValue = await dynamodb.update(payload);
1190
- _izContext.logger.debug('updateItem status', { metadata: returnValue['$metadata'] });
1191
- await captureCapacityUsed(_izContext, returnValue.ConsumedCapacity, 'write', 'update');
1435
+ _izContext.logger.debug('updateItem status', {
1436
+ metadata: returnValue['$metadata']
1437
+ });
1438
+ await captureCapacityUsed(
1439
+ _izContext,
1440
+ returnValue.ConsumedCapacity,
1441
+ 'write',
1442
+ 'update'
1443
+ );
1192
1444
  if (payload.ReturnValues !== 'NONE' && returnValue.Attributes) {
1193
1445
  return returnValue.Attributes;
1194
1446
  }
1195
1447
  } catch (err) {
1196
1448
  if (err && err.name === 'ConditionalCheckFailedException') {
1197
- const errorOn = (settings && settings.errorOnConditionalExpNotPass === true);
1449
+ const errorOn =
1450
+ settings && settings.errorOnConditionalExpNotPass === true;
1198
1451
  if (errorOn) {
1199
- const retryOn = (settings && settings.retryOnErrorConditionalExpNotPass === true);
1452
+ const retryOn =
1453
+ settings && settings.retryOnErrorConditionalExpNotPass === true;
1200
1454
  if (retryOn) {
1201
1455
  _izContext.logger.error(err.name + ': ' + err.message);
1202
1456
  throw new Error('ConditionalExpNotPass'); // retry upstream
@@ -1208,15 +1462,13 @@ async function updateItem(
1208
1462
  throw err;
1209
1463
  }
1210
1464
  }
1211
-
1212
1465
  } catch (err) {
1213
1466
  const name = err && err.name ? String(err.name) : '';
1214
1467
  const message = err && err.message ? String(err.message) : '';
1215
1468
  _izContext.logger.error(name + ': ' + message);
1216
1469
  throw err;
1217
1470
  }
1218
- };
1219
-
1471
+ }
1220
1472
 
1221
1473
  /**
1222
1474
  * Executes a DeleteItem query on DynamoDB
@@ -1244,22 +1496,26 @@ async function deleteItem(
1244
1496
  _izContext.logger.debug('settings ', settings);
1245
1497
 
1246
1498
  try {
1247
-
1248
1499
  let payload = {
1249
1500
  TableName: tableName,
1250
1501
  Key: keyValues,
1251
- ReturnValues: 'NONE',// NONE | ALL_OLD
1252
- ReturnConsumedCapacity: "TOTAL" // NONE(default) | TOTAL | INDEXES
1502
+ ReturnValues: 'NONE', // NONE | ALL_OLD
1503
+ ReturnConsumedCapacity: 'TOTAL' // NONE(default) | TOTAL | INDEXES
1253
1504
  };
1254
1505
 
1255
1506
  // set payload: ReturnValues
1256
- if (queryElements.hasOwnProperty('returnValues') && queryElements.returnValues.toLocaleUpperCase() == 'ALL_OLD') {
1507
+ if (
1508
+ queryElements.hasOwnProperty('returnValues') &&
1509
+ queryElements.returnValues.toLocaleUpperCase() == 'ALL_OLD'
1510
+ ) {
1257
1511
  payload.ReturnValues = queryElements.returnValues.toLocaleUpperCase();
1258
1512
  }
1259
1513
  // set payload: ConditionExpression and/or ExpressionAttributeValues
1260
- const [conditionExpression, expressionAttributeValues] = reformConditionExpression(_izContext, queryElements);
1514
+ const [conditionExpression, expressionAttributeValues] =
1515
+ reformConditionExpression(_izContext, queryElements);
1261
1516
  if (conditionExpression) payload.ConditionExpression = conditionExpression;
1262
- if (expressionAttributeValues) payload.ExpressionAttributeValues = expressionAttributeValues;
1517
+ if (expressionAttributeValues)
1518
+ payload.ExpressionAttributeValues = expressionAttributeValues;
1263
1519
 
1264
1520
  _izContext.logger.debug('payload before daleteItem', payload);
1265
1521
 
@@ -1269,17 +1525,30 @@ async function deleteItem(
1269
1525
  return payload; // stop process in here not send to dymanodb
1270
1526
  }
1271
1527
 
1272
- const returnValue = await dynamodb.delete(payload); // ===== main query
1273
- _izContext.logger.debug("deleteItem status: ", returnValue['$metadata']);
1274
- await captureCapacityUsed(_izContext, returnValue.ConsumedCapacity, 'write', 'delete');
1528
+ const returnValue = await dynamodb.delete(payload); // ===== main query
1529
+ _izContext.logger.debug('deleteItem status: ', returnValue['$metadata']);
1530
+ await captureCapacityUsed(
1531
+ _izContext,
1532
+ returnValue.ConsumedCapacity,
1533
+ 'write',
1534
+ 'delete'
1535
+ );
1275
1536
  if (payload.ReturnValues !== 'NONE' && returnValue) {
1276
1537
  return returnValue; // returnValue.ConsumedCapacity
1277
1538
  }
1278
-
1279
- } catch (err) { // catch error when put and handle errors.
1280
- if (err.name == 'ConditionalCheckFailedException') { // if return undefined (NOTE---dynamodb will return .Item value or Item undifined)
1281
- if (settings && settings.hasOwnProperty('errorOnConditionalExpNotPass') && settings.errorOnConditionalExpNotPass == true) {
1282
- if (settings.hasOwnProperty('retryOnErrorConditionalExpNotPass') && settings.retryOnErrorConditionalExpNotPass == true) {
1539
+ } catch (err) {
1540
+ // catch error when put and handle errors.
1541
+ if (err.name == 'ConditionalCheckFailedException') {
1542
+ // if return undefined (NOTE---dynamodb will return .Item value or Item undifined)
1543
+ if (
1544
+ settings &&
1545
+ settings.hasOwnProperty('errorOnConditionalExpNotPass') &&
1546
+ settings.errorOnConditionalExpNotPass == true
1547
+ ) {
1548
+ if (
1549
+ settings.hasOwnProperty('retryOnErrorConditionalExpNotPass') &&
1550
+ settings.retryOnErrorConditionalExpNotPass == true
1551
+ ) {
1283
1552
  _izContext.logger.error(err.name + ': ' + err.message);
1284
1553
  throw new Error('ConditionalExpNotPass'); // TT, if throw will stop
1285
1554
  }
@@ -1288,19 +1557,17 @@ async function deleteItem(
1288
1557
  }
1289
1558
  // FF just pass ??
1290
1559
  // ...
1291
- } else { // e.g. ProvisionedThroughputExceededException
1560
+ } else {
1561
+ // e.g. ProvisionedThroughputExceededException
1292
1562
  throw new Error('Unhandled Error when daleteItem', err); // TT, if throw will stop
1293
1563
  }
1294
1564
  } //end catch err
1295
-
1296
- } catch (err) { // catch unhandled error
1565
+ } catch (err) {
1566
+ // catch unhandled error
1297
1567
  _izContext.logger.error(err.name + ': ' + err.message);
1298
1568
  throw err; // TT, if throw will stop
1299
1569
  }
1300
-
1301
- };
1302
-
1303
-
1570
+ }
1304
1571
 
1305
1572
  // ----------- helper function -----------
1306
1573
 
@@ -1311,7 +1578,6 @@ function QueryElementConditionalCheckStringSetEquals(
1311
1578
  additionalAttributes = {},
1312
1579
  logicalElements = []
1313
1580
  ) {
1314
-
1315
1581
  // ---- declare variable to return value logicalElement
1316
1582
  let logicalElement = {};
1317
1583
 
@@ -1319,23 +1585,25 @@ function QueryElementConditionalCheckStringSetEquals(
1319
1585
  if (oldRecord.hasOwnProperty(stringSetAttName)) {
1320
1586
  // --- add to attribute
1321
1587
  // not sure what is type stringSetAttName in oldrecord ?
1322
- additionalAttributes["test" + stringSetAttName] = oldRecord[stringSetAttName];
1588
+ additionalAttributes['test' + stringSetAttName] =
1589
+ oldRecord[stringSetAttName];
1323
1590
 
1324
1591
  // --- add to logicalElements
1325
1592
  logicalElement = {
1326
- type: "logical",
1327
- comparison: "equals",
1593
+ type: 'logical',
1594
+ comparison: 'equals',
1328
1595
  lhsAttribute: stringSetAttName,
1329
- rhsReference: "test" + stringSetAttName
1596
+ rhsReference: 'test' + stringSetAttName
1330
1597
  };
1331
-
1332
1598
  } else {
1333
1599
  // --- case if not have, just add to logicalElements
1334
- _izContext.logger.debug(`oldRecord NOT have property name: ${stringSetAttName}`);
1600
+ _izContext.logger.debug(
1601
+ `oldRecord NOT have property name: ${stringSetAttName}`
1602
+ );
1335
1603
  logicalElement = {
1336
- type: "function",
1337
- function: "attribute_not_exists",
1338
- attribute: stringSetAttName, // require for function type
1604
+ type: 'function',
1605
+ function: 'attribute_not_exists',
1606
+ attribute: stringSetAttName // require for function type
1339
1607
  };
1340
1608
  }
1341
1609
 
@@ -1344,23 +1612,24 @@ function QueryElementConditionalCheckStringSetEquals(
1344
1612
  if (logicalElements.length > 0) {
1345
1613
  // concate with "and" then concat new logicalElement
1346
1614
  logicalElements.push({
1347
- type: "logicalOperator",
1348
- operator: "and"
1615
+ type: 'logicalOperator',
1616
+ operator: 'and'
1349
1617
  });
1350
1618
  }
1351
1619
  // combine logicalElement all cases
1352
1620
  logicalElements.push(logicalElement);
1353
1621
 
1354
- _izContext.logger.debug(`additionalAttributes before returnValue:`, additionalAttributes);
1355
- _izContext.logger.debug(`logicalElements before returnValue:`, logicalElements);
1356
-
1357
- return [
1358
- additionalAttributes,
1622
+ _izContext.logger.debug(
1623
+ `additionalAttributes before returnValue:`,
1624
+ additionalAttributes
1625
+ );
1626
+ _izContext.logger.debug(
1627
+ `logicalElements before returnValue:`,
1359
1628
  logicalElements
1360
- ];
1361
-
1362
- }; // end QueryElementConditionalCheckStringSetEquals
1629
+ );
1363
1630
 
1631
+ return [additionalAttributes, logicalElements];
1632
+ } // end QueryElementConditionalCheckStringSetEquals
1364
1633
 
1365
1634
  //---- Helper fucntion -----
1366
1635
  // module.exports.generateExistLogicalElements = (keyValues) => {
@@ -1374,22 +1643,20 @@ function generateNotExistLogicalElements(attributes, existed = false) {
1374
1643
  let logicalElements = [];
1375
1644
  for (let propName in attributes) {
1376
1645
  logicalElements.push({
1377
- type: "function",
1646
+ type: 'function',
1378
1647
  // function: "attribute_not_exists",
1379
- function: existed, // attribute_not_exists | attribute_exists
1380
- attribute: propName,
1648
+ function: existed, // attribute_not_exists | attribute_exists
1649
+ attribute: propName
1650
+ });
1651
+ logicalElements.push({
1652
+ type: 'logicalOperator',
1653
+ operator: 'and'
1381
1654
  });
1382
- logicalElements.push(
1383
- {
1384
- type: "logicalOperator",
1385
- operator: "and"
1386
- });
1387
1655
  }
1388
1656
  logicalElements.pop(); // delete last and conjunction element
1389
1657
 
1390
1658
  return logicalElements;
1391
- };
1392
-
1659
+ }
1393
1660
 
1394
1661
  function refractorAttributesToComplex(attributes, forPutQuery = false) {
1395
1662
  // only for SET update
@@ -1402,15 +1669,15 @@ function refractorAttributesToComplex(attributes, forPutQuery = false) {
1402
1669
  value: attributes[propName]
1403
1670
  };
1404
1671
 
1405
- if (!forPutQuery) { // case if want to use update syntax query
1672
+ if (!forPutQuery) {
1673
+ // case if want to use update syntax query
1406
1674
  addAttributes.action = 'set';
1407
1675
  }
1408
1676
 
1409
1677
  returnAttributes.push(addAttributes);
1410
1678
  }
1411
1679
  return returnAttributes;
1412
- };
1413
-
1680
+ }
1414
1681
 
1415
1682
  /**
1416
1683
  * Build and execute a DynamoDB TransactWrite from high-level writeItems.
@@ -1420,14 +1687,13 @@ function refractorAttributesToComplex(attributes, forPutQuery = false) {
1420
1687
  * @param {Array} writeItems
1421
1688
  * @returns {Promise<object>} DynamoDB response including $metadata/ConsumedCapacity
1422
1689
  */
1423
- async function transactWriteItems(
1424
- _izContext,
1425
- writeItems
1426
- ) {
1690
+ async function transactWriteItems(_izContext, writeItems) {
1427
1691
  try {
1428
1692
  // Validate top-level arguments
1429
1693
  if (!Array.isArray(writeItems)) {
1430
- throw new NoRetryError('transactWriteItems requires writeItems as an array.');
1694
+ throw new NoRetryError(
1695
+ 'transactWriteItems requires writeItems as an array.'
1696
+ );
1431
1697
  }
1432
1698
 
1433
1699
  _izContext.logger.debug('writeItems', { writeItems: writeItems });
@@ -1463,7 +1729,7 @@ async function transactWriteItems(
1463
1729
 
1464
1730
  // Dispatch per action
1465
1731
  if (action === 'put') {
1466
- const putReq = await module.exports.putItem(
1732
+ const putReq = await putItem(
1467
1733
  _izContext,
1468
1734
  item.params.tableName,
1469
1735
  item.params.attributes,
@@ -1472,7 +1738,7 @@ async function transactWriteItems(
1472
1738
  );
1473
1739
  transactItems.push({ Put: putReq });
1474
1740
  } else if (action === 'update') {
1475
- const updateReq = await module.exports.updateItem(
1741
+ const updateReq = await updateItem(
1476
1742
  _izContext,
1477
1743
  item.params.tableName,
1478
1744
  item.params.keyValues,
@@ -1482,7 +1748,7 @@ async function transactWriteItems(
1482
1748
  );
1483
1749
  transactItems.push({ Update: updateReq });
1484
1750
  } else if (action === 'delete') {
1485
- const deleteReq = await module.exports.deleteItem(
1751
+ const deleteReq = await deleteItem(
1486
1752
  _izContext,
1487
1753
  item.params.tableName,
1488
1754
  item.params.keyValues,
@@ -1493,7 +1759,9 @@ async function transactWriteItems(
1493
1759
  }
1494
1760
  }
1495
1761
 
1496
- _izContext.logger.debug('payload transactItems', { transactItems: transactItems });
1762
+ _izContext.logger.debug('payload transactItems', {
1763
+ transactItems: transactItems
1764
+ });
1497
1765
 
1498
1766
  // Execute TransactWrite
1499
1767
  const returnValue = await dynamodb.transactWrite({
@@ -1502,7 +1770,9 @@ async function transactWriteItems(
1502
1770
  });
1503
1771
 
1504
1772
  _izContext.logger.debug('returnValue', { returnValue: returnValue });
1505
- _izContext.logger.debug('transactWriteItems status', { metadata: returnValue['$metadata'] });
1773
+ _izContext.logger.debug('transactWriteItems status', {
1774
+ metadata: returnValue['$metadata']
1775
+ });
1506
1776
 
1507
1777
  // Track capacity usage
1508
1778
  await captureCapacityUsed(
@@ -1527,13 +1797,10 @@ async function transactWriteItems(
1527
1797
  });
1528
1798
  throw err;
1529
1799
  }
1530
- };
1531
-
1800
+ }
1532
1801
 
1533
1802
  // this.transactWriteItems()
1534
1803
 
1535
-
1536
-
1537
1804
  /* NOTE for batchWriteItems cannot perform multiple operations. you cannot put and delete the same item in the same BatchWriteItem request.
1538
1805
  Item not exceed more than 25 requests in the batch, and not batch exceeds 400 KB.The total request size exceeds 16 MB
1539
1806
  action: PutItem | DeleteItem
@@ -1548,13 +1815,11 @@ async function batchDeleteItems(
1548
1815
  keyFieldName
1549
1816
  ) {
1550
1817
  try {
1551
-
1552
1818
  let size = 25; // maybe should check size < 400 KB
1553
1819
  let chunked = [];
1554
1820
 
1555
1821
  for (let i = 0; i < writeItems.length; i += size) {
1556
- chunked.push(writeItems.slice(i, i + size)
1557
- );
1822
+ chunked.push(writeItems.slice(i, i + size));
1558
1823
  }
1559
1824
 
1560
1825
  // ---- perform each chuck < 25 ----
@@ -1567,8 +1832,10 @@ async function batchDeleteItems(
1567
1832
  requestItems.push({
1568
1833
  DeleteRequest: {
1569
1834
  Key: {
1570
- [keyFieldName.partitionKeyFieldName]: chunkSet[i][keyFieldName.partitionKeyFieldName],
1571
- [keyFieldName.sortKeyFieldName]: chunkSet[i][keyFieldName.sortKeyFieldName]
1835
+ [keyFieldName.partitionKeyFieldName]:
1836
+ chunkSet[i][keyFieldName.partitionKeyFieldName],
1837
+ [keyFieldName.sortKeyFieldName]:
1838
+ chunkSet[i][keyFieldName.sortKeyFieldName]
1572
1839
  }
1573
1840
  }
1574
1841
  });
@@ -1578,23 +1845,27 @@ async function batchDeleteItems(
1578
1845
  RequestItems: {
1579
1846
  [tableName]: requestItems
1580
1847
  },
1581
- ReturnConsumedCapacity: "TOTAL"
1848
+ ReturnConsumedCapacity: 'TOTAL'
1582
1849
  };
1583
1850
  _izContext.logger.debug('payload writeItems... ', payload);
1584
1851
 
1585
1852
  const returnValue = await dynamodb.batchWrite(payload);
1586
- _izContext.logger.debug("batchDeleteItems status: ", returnValue['$metadata']);
1587
- await captureCapacityUsed(_izContext, returnValue.ConsumedCapacity, 'write', 'delete');
1853
+ _izContext.logger.debug(
1854
+ 'batchDeleteItems status: ',
1855
+ returnValue['$metadata']
1856
+ );
1857
+ await captureCapacityUsed(
1858
+ _izContext,
1859
+ returnValue.ConsumedCapacity,
1860
+ 'write',
1861
+ 'delete'
1862
+ );
1588
1863
  } // end loop
1589
1864
  } catch (err) {
1590
1865
  throw ('Error:baatchDeleteItems', err);
1591
- };
1866
+ }
1592
1867
  _izContext.logger.info('----- finish all batchDeleteItems -----');
1593
-
1594
- };
1595
-
1596
-
1597
-
1868
+ }
1598
1869
 
1599
1870
  /*https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#batchWriteItem-property
1600
1871
  NOTE: Cannot use complex settings inside PutRequest
@@ -1625,10 +1896,8 @@ async function batchPutItems(
1625
1896
  // ]
1626
1897
  // ---------------------------------
1627
1898
 
1628
-
1629
1899
  for (let i = 0; i < writeItems.length; i += size) {
1630
- chunked.push(writeItems.slice(i, i + size)
1631
- );
1900
+ chunked.push(writeItems.slice(i, i + size));
1632
1901
  }
1633
1902
 
1634
1903
  // ---- perform each chuck < 25 ----
@@ -1638,7 +1907,6 @@ async function batchPutItems(
1638
1907
  // console.log('chunkSet', chunkSet);
1639
1908
 
1640
1909
  for (let i = 0; i < chunkSet.length; i++) {
1641
-
1642
1910
  // hard code set to return just query
1643
1911
  chunkSet[i].settings.returnQuery = true;
1644
1912
 
@@ -1659,24 +1927,30 @@ async function batchPutItems(
1659
1927
  });
1660
1928
  }
1661
1929
 
1662
-
1663
1930
  let payload = {
1664
1931
  RequestItems: {
1665
1932
  [tableNameData]: requestItems
1666
1933
  },
1667
- ReturnConsumedCapacity: "TOTAL"
1934
+ ReturnConsumedCapacity: 'TOTAL'
1668
1935
  };
1669
1936
  _izContext.logger.debug('payload writeItems... ', payload);
1670
1937
 
1671
1938
  const returnValue = await dynamodb.batchWrite(payload);
1672
- _izContext.logger.debug("batchPutItems status: ", returnValue['$metadata']);
1673
- await captureCapacityUsed(_izContext, returnValue.ConsumedCapacity, 'write', 'put');
1939
+ _izContext.logger.debug(
1940
+ 'batchPutItems status: ',
1941
+ returnValue['$metadata']
1942
+ );
1943
+ await captureCapacityUsed(
1944
+ _izContext,
1945
+ returnValue.ConsumedCapacity,
1946
+ 'write',
1947
+ 'put'
1948
+ );
1674
1949
  } // end loop
1675
1950
  } catch (err) {
1676
1951
  throw ('Error:baatchPutItems', err);
1677
1952
  }
1678
-
1679
- };
1953
+ }
1680
1954
 
1681
1955
  /**
1682
1956
  *
@@ -1689,27 +1963,48 @@ async function batchPutItems(
1689
1963
  * This function will collect capacity units and store in _izContext.resourceUse
1690
1964
  * Middleware will capture resourceUse and send to ResourceUse Service later
1691
1965
  */
1692
- async function captureCapacityUsed(_izContext, capacityUsed, capacityStatus, queryOperation) {
1966
+ async function captureCapacityUsed(
1967
+ _izContext,
1968
+ capacityUsed,
1969
+ capacityStatus,
1970
+ queryOperation
1971
+ ) {
1693
1972
  // validate capacityUsed and resourceUse instance in _izContext
1694
1973
  if (!capacityUsed || !_izContext.resourceUse) return;
1695
1974
 
1696
1975
  if (Array.isArray(capacityUsed)) {
1697
1976
  // In case call transectionWrite, ConsumedCapacity will return array instead of object
1698
1977
  // We need map through array before call captureCapacityUsed
1699
- capacityUsed.map(async (capacityRecord) => {
1700
- await captureCapacityUsed(_izContext, capacityRecord, capacityStatus, queryOperation);
1978
+ capacityUsed.map(async capacityRecord => {
1979
+ await captureCapacityUsed(
1980
+ _izContext,
1981
+ capacityRecord,
1982
+ capacityStatus,
1983
+ queryOperation
1984
+ );
1701
1985
  });
1702
-
1703
1986
  } else {
1704
-
1705
- if (capacityStatus === 'read') { // hardcode capacityStatus in each query and here
1987
+ if (capacityStatus === 'read') {
1988
+ // hardcode capacityStatus in each query and here
1706
1989
  capacityUsed.QueryOperation = queryOperation;
1707
- await _izContext.resourceUse.setResourceUse(_izContext, 'DynamoDbRead', capacityUsed.CapacityUnits, capacityUsed);
1990
+ await _izContext.resourceUse.setResourceUse(
1991
+ _izContext,
1992
+ 'DynamoDbRead',
1993
+ capacityUsed.CapacityUnits,
1994
+ capacityUsed
1995
+ );
1708
1996
  } else if (capacityStatus === 'write') {
1709
1997
  capacityUsed.QueryOperation = queryOperation;
1710
- await _izContext.resourceUse.setResourceUse(_izContext, 'DynamoDbWrite', capacityUsed.CapacityUnits, capacityUsed);
1998
+ await _izContext.resourceUse.setResourceUse(
1999
+ _izContext,
2000
+ 'DynamoDbWrite',
2001
+ capacityUsed.CapacityUnits,
2002
+ capacityUsed
2003
+ );
1711
2004
  } else {
1712
- throw new NoRetryError('captureCapacityUsed has wrong type of capacityStatus');
2005
+ throw new NoRetryError(
2006
+ 'captureCapacityUsed has wrong type of capacityStatus'
2007
+ );
1713
2008
  }
1714
2009
  }
1715
2010
  }
@@ -1743,4 +2038,4 @@ export default {
1743
2038
  QueryElementConditionalCheckStringSetEquals,
1744
2039
  generateNotExistLogicalElements,
1745
2040
  refractorAttributesToComplex
1746
- };
2041
+ };