@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.
- package/package.json +1 -1
- package/src/DynamoDBSharedLib.js +638 -343
package/src/DynamoDBSharedLib.js
CHANGED
|
@@ -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
|
|
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) {
|
|
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) {
|
|
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) {
|
|
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(
|
|
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(
|
|
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,
|
|
154
|
+
let conditionExpression,
|
|
155
|
+
expressionAttributeValues = null;
|
|
157
156
|
if (queryElements && queryElements.hasOwnProperty('logicalElements')) {
|
|
158
|
-
conditionExpression = processLogicalElements(
|
|
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(
|
|
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(
|
|
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(
|
|
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) {
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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 {
|
|
287
|
-
|
|
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(
|
|
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(
|
|
321
|
+
throw new NoRetryError(
|
|
322
|
+
'side-hand logic Invalid, should set "attribute".'
|
|
323
|
+
);
|
|
306
324
|
}
|
|
307
325
|
|
|
308
|
-
if (
|
|
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
|
-
|
|
333
|
+
} else if (
|
|
334
|
+
logicalElement.function.toLowerCase() == 'attribute_exists' ||
|
|
335
|
+
logicalElement.function.toLowerCase() == 'attributeexists'
|
|
336
|
+
) {
|
|
314
337
|
conditionalExpression += `attribute_exists (${logicalElement.attribute})`;
|
|
315
|
-
}
|
|
316
|
-
|
|
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(
|
|
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(
|
|
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 (
|
|
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(
|
|
365
|
+
conditionalExpression += processLogicalElements(
|
|
366
|
+
_izContext,
|
|
367
|
+
logicalElement.elements,
|
|
368
|
+
level + 1
|
|
369
|
+
); // ***recursion***
|
|
334
370
|
conditionalExpression += ')'; // close sub-group
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
throw new NoRetryError(
|
|
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 {
|
|
343
|
-
|
|
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
|
-
|
|
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
|
-
}
|
|
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(
|
|
370
|
-
|
|
408
|
+
async function getItem(
|
|
409
|
+
_izContext,
|
|
410
|
+
tableName,
|
|
411
|
+
keyValues,
|
|
412
|
+
queryElements = {},
|
|
413
|
+
settings = {}
|
|
414
|
+
) {
|
|
371
415
|
try {
|
|
372
|
-
console.log(
|
|
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:
|
|
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 (
|
|
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(
|
|
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) {
|
|
401
|
-
if
|
|
402
|
-
|
|
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(
|
|
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
|
-
}
|
|
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(
|
|
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 (
|
|
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 = [
|
|
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: {},
|
|
455
|
-
ReturnConsumedCapacity:
|
|
525
|
+
ExpressionAttributeValues: {}, // require value of partition key
|
|
526
|
+
ReturnConsumedCapacity: 'TOTAL' // NONE(default) | TOTAL | INDEXES
|
|
456
527
|
};
|
|
457
|
-
payload.ExpressionAttributeValues[`:partitionKeyValue`] =
|
|
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(
|
|
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`] =
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
} else {
|
|
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 (
|
|
503
|
-
|
|
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') {
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
607
|
+
} else if (
|
|
608
|
+
queryElements.sortKeyCondition.comparison == 'lessThanOrEqual'
|
|
609
|
+
) {
|
|
528
610
|
subKeyConditionalExpression = `${queryElements.sortKeyCondition.name} <= :${queryElements.sortKeyCondition.name}`;
|
|
529
|
-
}
|
|
530
|
-
|
|
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(
|
|
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[
|
|
539
|
-
|
|
540
|
-
|
|
624
|
+
payload.ExpressionAttributeValues[
|
|
625
|
+
`:${queryElements.sortKeyCondition.name}`
|
|
626
|
+
] = queryElements.sortKeyCondition.value;
|
|
627
|
+
} // end all comparisons
|
|
541
628
|
} else {
|
|
542
|
-
throw new NoRetryError(
|
|
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 (
|
|
548
|
-
|
|
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 (
|
|
554
|
-
|
|
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) {
|
|
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 (
|
|
563
|
-
|
|
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(
|
|
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 (
|
|
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(
|
|
610
|
-
await captureCapacityUsed(
|
|
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 {
|
|
725
|
+
} else {
|
|
726
|
+
// *** require numPagesToRequest
|
|
613
727
|
_izContext.logger.debug('CASE: numPagesToRequest > 1');
|
|
614
728
|
|
|
615
729
|
// ---- ExclusiveStartKey and Pagination ----
|
|
616
|
-
const getAllData = async
|
|
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(
|
|
624
|
-
await captureCapacityUsed(
|
|
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 {
|
|
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')) {
|
|
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) {
|
|
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(
|
|
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(
|
|
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:
|
|
862
|
+
ReturnConsumedCapacity: 'TOTAL' // NONE(default) | TOTAL | INDEXES
|
|
739
863
|
};
|
|
740
864
|
|
|
741
865
|
// set payload: ReturnValues
|
|
742
|
-
if (
|
|
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] =
|
|
873
|
+
const [conditionExpression, expressionAttributeValues] =
|
|
874
|
+
reformConditionExpression(_izContext, queryElements);
|
|
747
875
|
if (conditionExpression) payload.ConditionExpression = conditionExpression;
|
|
748
|
-
if (expressionAttributeValues)
|
|
876
|
+
if (expressionAttributeValues)
|
|
877
|
+
payload.ExpressionAttributeValues = expressionAttributeValues;
|
|
749
878
|
|
|
750
879
|
_izContext.logger.debug('conditionExpression', payload.ConditionExpression);
|
|
751
|
-
_izContext.logger.debug(
|
|
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:
|
|
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 (
|
|
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
|
-
|
|
774
|
-
|
|
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}`] =
|
|
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(
|
|
921
|
+
throw new NoRetryError(
|
|
922
|
+
'complexAttributes setting is true, attributes should be array and not empty.'
|
|
923
|
+
);
|
|
783
924
|
}
|
|
784
|
-
|
|
785
|
-
|
|
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[
|
|
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);
|
|
806
|
-
_izContext.logger.debug(
|
|
807
|
-
await captureCapacityUsed(
|
|
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
|
-
|
|
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') {
|
|
816
|
-
if
|
|
817
|
-
|
|
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 {
|
|
977
|
+
} else {
|
|
978
|
+
// e.g. ProvisionedThroughputExceededException
|
|
825
979
|
// throw new Error('Unhandled Error when putItem', err) // TT, if throw will stop
|
|
826
|
-
throw
|
|
980
|
+
throw err; // TT, if throw will stop
|
|
827
981
|
}
|
|
828
982
|
} //end catch err
|
|
829
|
-
|
|
830
|
-
|
|
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
|
-
}
|
|
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', {
|
|
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,
|
|
891
|
-
Key: keyValues,
|
|
892
|
-
UpdateExpression: '',
|
|
893
|
-
ExpressionAttributeValues: {},
|
|
894
|
-
ReturnValues: 'NONE',
|
|
895
|
-
ReturnConsumedCapacity: 'TOTAL'
|
|
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 =
|
|
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(
|
|
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(
|
|
939
|
-
|
|
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 ' +
|
|
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(
|
|
966
|
-
|
|
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 ' +
|
|
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 (
|
|
981
|
-
settings
|
|
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 (
|
|
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 (
|
|
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 (
|
|
1009
|
-
|
|
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(
|
|
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 {
|
|
1021
|
-
|
|
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 (
|
|
1025
|
-
|
|
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) +
|
|
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 (
|
|
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(' +
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
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 (
|
|
1263
|
+
if (
|
|
1264
|
+
typeof payload.ExpressionAttributeValues[addSide] !== 'number'
|
|
1265
|
+
) {
|
|
1055
1266
|
throw new NoRetryError('add_ value should be a number.');
|
|
1056
1267
|
}
|
|
1057
|
-
expression =
|
|
1058
|
-
|
|
1268
|
+
expression =
|
|
1269
|
+
item.attributeName + ' = ' + item.attributeName + ' + ' + addSide;
|
|
1059
1270
|
} else if (subtractSide) {
|
|
1060
|
-
if (
|
|
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 =
|
|
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(
|
|
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 (
|
|
1073
|
-
Object.prototype.hasOwnProperty.call(item, '
|
|
1074
|
-
|
|
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
|
-
|
|
1302
|
+
} else {
|
|
1303
|
+
// SET (default)
|
|
1082
1304
|
expression = item.attributeName + ' = :' + valueReference;
|
|
1083
1305
|
}
|
|
1084
1306
|
|
|
1085
1307
|
// attach value placeholders
|
|
1086
|
-
if (
|
|
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] =
|
|
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 (
|
|
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(
|
|
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 +=
|
|
1125
|
-
|
|
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'] =
|
|
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 (
|
|
1138
|
-
|
|
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' +
|
|
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) {
|
|
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)
|
|
1153
|
-
|
|
1154
|
-
if (payload.
|
|
1155
|
-
|
|
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', {
|
|
1191
|
-
|
|
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 =
|
|
1449
|
+
const errorOn =
|
|
1450
|
+
settings && settings.errorOnConditionalExpNotPass === true;
|
|
1198
1451
|
if (errorOn) {
|
|
1199
|
-
const retryOn =
|
|
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'
|
|
1252
|
-
ReturnConsumedCapacity:
|
|
1502
|
+
ReturnValues: 'NONE', // NONE | ALL_OLD
|
|
1503
|
+
ReturnConsumedCapacity: 'TOTAL' // NONE(default) | TOTAL | INDEXES
|
|
1253
1504
|
};
|
|
1254
1505
|
|
|
1255
1506
|
// set payload: ReturnValues
|
|
1256
|
-
if (
|
|
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] =
|
|
1514
|
+
const [conditionExpression, expressionAttributeValues] =
|
|
1515
|
+
reformConditionExpression(_izContext, queryElements);
|
|
1261
1516
|
if (conditionExpression) payload.ConditionExpression = conditionExpression;
|
|
1262
|
-
if (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);
|
|
1273
|
-
_izContext.logger.debug(
|
|
1274
|
-
await captureCapacityUsed(
|
|
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
|
-
|
|
1280
|
-
if (err.name == 'ConditionalCheckFailedException') {
|
|
1281
|
-
if
|
|
1282
|
-
|
|
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 {
|
|
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
|
-
|
|
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[
|
|
1588
|
+
additionalAttributes['test' + stringSetAttName] =
|
|
1589
|
+
oldRecord[stringSetAttName];
|
|
1323
1590
|
|
|
1324
1591
|
// --- add to logicalElements
|
|
1325
1592
|
logicalElement = {
|
|
1326
|
-
type:
|
|
1327
|
-
comparison:
|
|
1593
|
+
type: 'logical',
|
|
1594
|
+
comparison: 'equals',
|
|
1328
1595
|
lhsAttribute: stringSetAttName,
|
|
1329
|
-
rhsReference:
|
|
1596
|
+
rhsReference: 'test' + stringSetAttName
|
|
1330
1597
|
};
|
|
1331
|
-
|
|
1332
1598
|
} else {
|
|
1333
1599
|
// --- case if not have, just add to logicalElements
|
|
1334
|
-
_izContext.logger.debug(
|
|
1600
|
+
_izContext.logger.debug(
|
|
1601
|
+
`oldRecord NOT have property name: ${stringSetAttName}`
|
|
1602
|
+
);
|
|
1335
1603
|
logicalElement = {
|
|
1336
|
-
type:
|
|
1337
|
-
function:
|
|
1338
|
-
attribute: stringSetAttName
|
|
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:
|
|
1348
|
-
operator:
|
|
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(
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
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:
|
|
1646
|
+
type: 'function',
|
|
1378
1647
|
// function: "attribute_not_exists",
|
|
1379
|
-
function: existed,
|
|
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) {
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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', {
|
|
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', {
|
|
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]:
|
|
1571
|
-
|
|
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:
|
|
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(
|
|
1587
|
-
|
|
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:
|
|
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(
|
|
1673
|
-
|
|
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(
|
|
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
|
|
1700
|
-
await captureCapacityUsed(
|
|
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
|
-
|
|
1987
|
+
if (capacityStatus === 'read') {
|
|
1988
|
+
// hardcode capacityStatus in each query and here
|
|
1706
1989
|
capacityUsed.QueryOperation = queryOperation;
|
|
1707
|
-
await _izContext.resourceUse.setResourceUse(
|
|
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(
|
|
1998
|
+
await _izContext.resourceUse.setResourceUse(
|
|
1999
|
+
_izContext,
|
|
2000
|
+
'DynamoDbWrite',
|
|
2001
|
+
capacityUsed.CapacityUnits,
|
|
2002
|
+
capacityUsed
|
|
2003
|
+
);
|
|
1711
2004
|
} else {
|
|
1712
|
-
throw new NoRetryError(
|
|
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
|
+
};
|