lemon-core 4.1.15 → 4.2.1
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/README.md +2 -0
- package/dist/common/test-helper.d.ts +2 -2
- package/dist/common/test-helper.js +24 -26
- package/dist/common/test-helper.js.map +1 -1
- package/dist/controllers/dummy-controller.js +39 -46
- package/dist/controllers/dummy-controller.js.map +1 -1
- package/dist/controllers/general-api-controller.js +95 -100
- package/dist/controllers/general-api-controller.js.map +1 -1
- package/dist/controllers/general-controller.js +81 -82
- package/dist/controllers/general-controller.js.map +1 -1
- package/dist/cores/api/api-service.d.ts +1 -1
- package/dist/cores/api/api-service.js +228 -269
- package/dist/cores/api/api-service.js.map +1 -1
- package/dist/cores/aws/aws-kms-service.d.ts +1 -2
- package/dist/cores/aws/aws-kms-service.js +143 -153
- package/dist/cores/aws/aws-kms-service.js.map +1 -1
- package/dist/cores/aws/aws-s3-service.d.ts +2 -4
- package/dist/cores/aws/aws-s3-service.js +306 -330
- package/dist/cores/aws/aws-s3-service.js.map +1 -1
- package/dist/cores/aws/aws-sns-service.js +147 -153
- package/dist/cores/aws/aws-sns-service.js.map +1 -1
- package/dist/cores/aws/aws-sqs-service.js +149 -170
- package/dist/cores/aws/aws-sqs-service.js.map +1 -1
- package/dist/cores/aws/index.js +10 -20
- package/dist/cores/aws/index.js.map +1 -1
- package/dist/cores/cache/cache-service.d.ts +2 -2
- package/dist/cores/cache/cache-service.js +435 -499
- package/dist/cores/cache/cache-service.js.map +1 -1
- package/dist/cores/config/config-service.d.ts +1 -1
- package/dist/cores/config/config-service.js +56 -63
- package/dist/cores/config/config-service.js.map +1 -1
- package/dist/cores/config/index.js +14 -24
- package/dist/cores/config/index.js.map +1 -1
- package/dist/cores/core-services.d.ts +1 -1
- package/dist/cores/dynamo/dynamo-query-service.js +37 -51
- package/dist/cores/dynamo/dynamo-query-service.js.map +1 -1
- package/dist/cores/dynamo/dynamo-scan-service.d.ts +2 -2
- package/dist/cores/dynamo/dynamo-scan-service.js +29 -40
- package/dist/cores/dynamo/dynamo-scan-service.js.map +1 -1
- package/dist/cores/dynamo/dynamo-service.d.ts +3 -3
- package/dist/cores/dynamo/dynamo-service.js +540 -605
- package/dist/cores/dynamo/dynamo-service.js.map +1 -1
- package/dist/cores/dynamo/tools/expressions.js +17 -7
- package/dist/cores/dynamo/tools/expressions.js.map +1 -1
- package/dist/cores/dynamo/tools/query.js +142 -127
- package/dist/cores/dynamo/tools/query.js.map +1 -1
- package/dist/cores/dynamo/tools/scan.js +111 -97
- package/dist/cores/dynamo/tools/scan.js.map +1 -1
- package/dist/cores/dynamo/tools/serializer.js +17 -7
- package/dist/cores/dynamo/tools/serializer.js.map +1 -1
- package/dist/cores/dynamo/tools/utils.d.ts +0 -2
- package/dist/cores/dynamo/tools/utils.js.map +1 -1
- package/dist/cores/elastic/elastic6-query-service.js +307 -324
- package/dist/cores/elastic/elastic6-query-service.js.map +1 -1
- package/dist/cores/elastic/elastic6-service.d.ts +3 -3
- package/dist/cores/elastic/elastic6-service.js +568 -647
- package/dist/cores/elastic/elastic6-service.js.map +1 -1
- package/dist/cores/elastic/hangul-service.js +52 -54
- package/dist/cores/elastic/hangul-service.js.map +1 -1
- package/dist/cores/lambda/index.js +42 -36
- package/dist/cores/lambda/index.js.map +1 -1
- package/dist/cores/lambda/lambda-alb-handler.d.ts +2 -2
- package/dist/cores/lambda/lambda-alb-handler.js +59 -72
- package/dist/cores/lambda/lambda-alb-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-cognito-handler.js +10 -19
- package/dist/cores/lambda/lambda-cognito-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-cron-handler.d.ts +1 -1
- package/dist/cores/lambda/lambda-cron-handler.js +14 -23
- package/dist/cores/lambda/lambda-cron-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-dynamo-stream-handler.d.ts +2 -2
- package/dist/cores/lambda/lambda-dynamo-stream-handler.js +57 -67
- package/dist/cores/lambda/lambda-dynamo-stream-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-handler.d.ts +22 -22
- package/dist/cores/lambda/lambda-handler.js +93 -106
- package/dist/cores/lambda/lambda-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-notification-handler.d.ts +1 -1
- package/dist/cores/lambda/lambda-notification-handler.js +39 -50
- package/dist/cores/lambda/lambda-notification-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-sns-handler.js +79 -88
- package/dist/cores/lambda/lambda-sns-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-sqs-handler.js +79 -88
- package/dist/cores/lambda/lambda-sqs-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-web-handler.d.ts +6 -6
- package/dist/cores/lambda/lambda-web-handler.js +387 -412
- package/dist/cores/lambda/lambda-web-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-wss-handler.js +23 -32
- package/dist/cores/lambda/lambda-wss-handler.js.map +1 -1
- package/dist/cores/protocol/index.js +10 -20
- package/dist/cores/protocol/index.js.map +1 -1
- package/dist/cores/protocol/protocol-service.d.ts +3 -3
- package/dist/cores/protocol/protocol-service.js +235 -227
- package/dist/cores/protocol/protocol-service.js.map +1 -1
- package/dist/cores/storage/http-storage-service.js +65 -85
- package/dist/cores/storage/http-storage-service.js.map +1 -1
- package/dist/cores/storage/model-manager.js +66 -85
- package/dist/cores/storage/model-manager.js.map +1 -1
- package/dist/cores/storage/proxy-storage-service.d.ts +2 -2
- package/dist/cores/storage/proxy-storage-service.js +562 -599
- package/dist/cores/storage/proxy-storage-service.js.map +1 -1
- package/dist/cores/storage/redis-storage-service.js +163 -177
- package/dist/cores/storage/redis-storage-service.js.map +1 -1
- package/dist/cores/storage/storage-service.d.ts +8 -1
- package/dist/cores/storage/storage-service.js +359 -324
- package/dist/cores/storage/storage-service.js.map +1 -1
- package/dist/engine/builder.d.ts +1 -1
- package/dist/engine/builder.js +59 -63
- package/dist/engine/builder.js.map +1 -1
- package/dist/engine/engine.d.ts +4 -4
- package/dist/engine/engine.js +9 -18
- package/dist/engine/engine.js.map +1 -1
- package/dist/engine/types.d.ts +1 -1
- package/dist/engine/utilities.d.ts +5 -5
- package/dist/engine/utilities.js +301 -293
- package/dist/engine/utilities.js.map +1 -1
- package/dist/environ.js +4 -6
- package/dist/environ.js.map +1 -1
- package/dist/extended/abstract-service.js +595 -645
- package/dist/extended/abstract-service.js.map +1 -1
- package/dist/extended/libs/sig-v4.js.map +1 -1
- package/dist/generated/field-registry.d.ts +10 -0
- package/dist/generated/field-registry.js +17 -0
- package/dist/generated/field-registry.js.map +1 -0
- package/dist/helpers/helpers.d.ts +17 -9
- package/dist/helpers/helpers.js +88 -78
- package/dist/helpers/helpers.js.map +1 -1
- package/dist/index.js +17 -7
- package/dist/index.js.map +1 -1
- package/dist/lib/dynamodb-value.js +2 -3
- package/dist/lib/dynamodb-value.js.map +1 -1
- package/dist/tools/express.js +4 -5
- package/dist/tools/express.js.map +1 -1
- package/dist/tools/tools.d.ts +3 -1
- package/dist/tools/tools.js +14 -21
- package/dist/tools/tools.js.map +1 -1
- package/package.json +25 -24
- package/dist/exec-cli.d.ts +0 -2
- package/dist/exec-cli.js +0 -211
- package/dist/exec-cli.js.map +0 -1
- package/dist/lib/dynamo/expressions.d.ts +0 -14
- package/dist/lib/dynamo/expressions.js +0 -212
- package/dist/lib/dynamo/expressions.js.map +0 -1
- package/dist/lib/dynamo/query.d.ts +0 -43
- package/dist/lib/dynamo/query.js +0 -246
- package/dist/lib/dynamo/query.js.map +0 -1
- package/dist/lib/dynamo/scan.d.ts +0 -33
- package/dist/lib/dynamo/scan.js +0 -172
- package/dist/lib/dynamo/scan.js.map +0 -1
- package/dist/lib/dynamo/serializer.d.ts +0 -12
- package/dist/lib/dynamo/serializer.js +0 -243
- package/dist/lib/dynamo/serializer.js.map +0 -1
- package/dist/lib/dynamo/utils.d.ts +0 -15
- package/dist/lib/dynamo/utils.js +0 -129
- package/dist/lib/dynamo/utils.js.map +0 -1
- package/dist/tools/shared.d.ts +0 -28
- package/dist/tools/shared.js +0 -143
- package/dist/tools/shared.js.map +0 -1
|
@@ -15,33 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
var t = {};
|
|
36
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
37
|
-
t[p] = s[p];
|
|
38
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
39
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
40
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
41
|
-
t[p[i]] = s[p[i]];
|
|
42
|
-
}
|
|
43
|
-
return t;
|
|
44
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
45
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
36
|
exports.DummyDynamoService = exports.DynamoService = void 0;
|
|
47
37
|
/**
|
|
@@ -95,11 +85,8 @@ const normalize = (data) => {
|
|
|
95
85
|
* - basic CRUD service for AWS DynamoDB.
|
|
96
86
|
*/
|
|
97
87
|
class DynamoService {
|
|
88
|
+
options;
|
|
98
89
|
constructor(options) {
|
|
99
|
-
/**
|
|
100
|
-
* say hello of identity.
|
|
101
|
-
*/
|
|
102
|
-
this.hello = () => `dynamo-service:${this.options.tableName}`;
|
|
103
90
|
// eslint-disable-next-line prettier/prettier
|
|
104
91
|
(0, engine_1._inf)(NS, `DynamoService(${options.tableName}/${options.idName}${options.sortName ? '/' : ''}${options.sortName || ''})...`);
|
|
105
92
|
if (!options.tableName)
|
|
@@ -108,32 +95,43 @@ class DynamoService {
|
|
|
108
95
|
throw new Error('.idName is required');
|
|
109
96
|
this.options = options;
|
|
110
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* say hello of identity.
|
|
100
|
+
*/
|
|
101
|
+
hello = () => `dynamo-service:${this.options.tableName}`;
|
|
102
|
+
static _dynamo = {};
|
|
103
|
+
static _dynamostr = {};
|
|
104
|
+
//TODO [Steve] why to use promise here to make DynamoDBDocumentClient? @251212
|
|
105
|
+
static _dynamodoc = {};
|
|
111
106
|
/**
|
|
112
107
|
* simple instance maker.
|
|
113
108
|
* @param region (default as `ap-northeast-2`)
|
|
114
109
|
*/
|
|
115
110
|
static instance(region) {
|
|
116
|
-
var _a, _b;
|
|
117
111
|
region = `${region || 'ap-northeast-2'}`;
|
|
118
112
|
const $cfg = (0, tools_1.awsConfig)(engine_1.default, region);
|
|
119
|
-
const dynamo =
|
|
120
|
-
const dynamostr =
|
|
113
|
+
const dynamo = DynamoService._dynamo[region] ?? new client_dynamodb_2.DynamoDBClient($cfg); // Low-level DynamoDB client
|
|
114
|
+
const dynamostr = DynamoService._dynamostr[region] ?? new client_dynamodb_streams_1.DynamoDBStreamsClient($cfg); // DynamoDB Streams client
|
|
121
115
|
// Create memoized function for dynamodoc
|
|
122
116
|
if (!DynamoService._dynamodoc[region]) {
|
|
123
117
|
const cache = { client: null };
|
|
124
|
-
DynamoService._dynamodoc[region] = () =>
|
|
118
|
+
DynamoService._dynamodoc[region] = async () => {
|
|
125
119
|
if (!cache.client) {
|
|
126
120
|
(0, engine_1._log)(NS, `! creating NEW DynamoDBDocumentClient for region[${region}]`);
|
|
127
121
|
const credentials = $cfg.credentials;
|
|
128
|
-
const dynamo = new client_dynamodb_2.DynamoDBClient(
|
|
122
|
+
const dynamo = new client_dynamodb_2.DynamoDBClient({ ...$cfg, credentials });
|
|
129
123
|
cache.client = lib_dynamodb_1.DynamoDBDocumentClient.from(dynamo);
|
|
130
124
|
}
|
|
131
125
|
return cache.client;
|
|
132
|
-
}
|
|
126
|
+
};
|
|
133
127
|
}
|
|
134
128
|
const dynamodoc = DynamoService._dynamodoc[region]; // High-level Document client
|
|
135
129
|
return { dynamo, dynamostr, dynamodoc };
|
|
136
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* export to test..
|
|
133
|
+
*/
|
|
134
|
+
static normalize = normalize;
|
|
137
135
|
/**
|
|
138
136
|
* prepare `CreateTable` payload.
|
|
139
137
|
*
|
|
@@ -206,13 +204,17 @@ class DynamoService {
|
|
|
206
204
|
*/
|
|
207
205
|
prepareSaveItem(id, item) {
|
|
208
206
|
const { tableName, idName, sortName } = this.options;
|
|
207
|
+
const errScope = `prepareSaveItem(${idName}:${id})`;
|
|
209
208
|
// _log(NS, `prepareSaveItem(${tableName})...`);
|
|
210
209
|
// item && _log(NS, '> item =', item);
|
|
211
210
|
if (sortName && item[sortName] === undefined)
|
|
212
|
-
throw new Error(`.${sortName} is required
|
|
211
|
+
throw new Error(`.${sortName} is required - ${errScope}`);
|
|
213
212
|
delete item[idName]; // clear the saved id.
|
|
214
213
|
const node = Object.assign({ [idName]: id }, item); // copy
|
|
215
214
|
const data = normalize(node);
|
|
215
|
+
//TODO [Steve] check if how works for undefined | null in real dynamo?!
|
|
216
|
+
// if (data === null) throw new Error(`@data[null] is invalid - ${errScope}`);
|
|
217
|
+
// if (data === undefined) throw new Error(`@data[null] is invalid - ${errScope}`);
|
|
216
218
|
//* prepare payload.
|
|
217
219
|
const payload = {
|
|
218
220
|
TableName: tableName,
|
|
@@ -228,8 +230,9 @@ class DynamoService {
|
|
|
228
230
|
*/
|
|
229
231
|
prepareItemKey(id, sort) {
|
|
230
232
|
const { tableName, idName, sortName } = this.options;
|
|
231
|
-
|
|
232
|
-
|
|
233
|
+
const errScope = `prepareItemKey(${tableName}/${idName}/${id ?? ''})`;
|
|
234
|
+
if (!id?.trim())
|
|
235
|
+
throw new Error(`@id (string) is required - ${errScope}`);
|
|
233
236
|
// _log(NS, `prepareItemKey(${tableName}/${id}/${sort || ''})...`);
|
|
234
237
|
//* prepare payload.
|
|
235
238
|
const payload = {
|
|
@@ -240,7 +243,7 @@ class DynamoService {
|
|
|
240
243
|
};
|
|
241
244
|
if (sortName) {
|
|
242
245
|
if (sort === undefined)
|
|
243
|
-
throw new Error(`@sort is required
|
|
246
|
+
throw new Error(`@sort (any) is required - ${errScope}`);
|
|
244
247
|
payload.Key[sortName] = sort;
|
|
245
248
|
}
|
|
246
249
|
return payload;
|
|
@@ -301,7 +304,7 @@ class DynamoService {
|
|
|
301
304
|
UpdateExpression: { SET: [], REMOVE: [], ADD: [], DELETE: [] },
|
|
302
305
|
ExpressionAttributeNames: {},
|
|
303
306
|
ExpressionAttributeValues: {},
|
|
304
|
-
ConditionExpression: null,
|
|
307
|
+
ConditionExpression: null, // "size(a) > :num "
|
|
305
308
|
ReturnValues: 'UPDATED_NEW',
|
|
306
309
|
});
|
|
307
310
|
//* prepare increment update.
|
|
@@ -342,32 +345,28 @@ class DynamoService {
|
|
|
342
345
|
* @param ReadCapacityUnits
|
|
343
346
|
* @param WriteCapacityUnits
|
|
344
347
|
*/
|
|
345
|
-
createTable(ReadCapacityUnits = 1, WriteCapacityUnits = 1) {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
return res;
|
|
354
|
-
});
|
|
348
|
+
async createTable(ReadCapacityUnits = 1, WriteCapacityUnits = 1) {
|
|
349
|
+
(0, engine_1._log)(NS, `createTable(${ReadCapacityUnits}, ${WriteCapacityUnits})...`);
|
|
350
|
+
const payload = this.prepareCreateTable(ReadCapacityUnits, WriteCapacityUnits);
|
|
351
|
+
return instance()
|
|
352
|
+
.dynamo.send(new client_dynamodb_2.CreateTableCommand(payload))
|
|
353
|
+
.then(res => {
|
|
354
|
+
(0, engine_1._log)(NS, '> createTable.res =', res);
|
|
355
|
+
return res;
|
|
355
356
|
});
|
|
356
357
|
}
|
|
357
358
|
/**
|
|
358
359
|
* delete-table
|
|
359
360
|
*
|
|
360
361
|
*/
|
|
361
|
-
deleteTable() {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
return res;
|
|
370
|
-
});
|
|
362
|
+
async deleteTable() {
|
|
363
|
+
(0, engine_1._log)(NS, `deleteTable()...`);
|
|
364
|
+
const payload = this.prepareDeleteTable();
|
|
365
|
+
return instance()
|
|
366
|
+
.dynamo.send(new client_dynamodb_2.DeleteTableCommand(payload))
|
|
367
|
+
.then(res => {
|
|
368
|
+
(0, engine_1._log)(NS, '> deleteTable.res =', res);
|
|
369
|
+
return res;
|
|
371
370
|
});
|
|
372
371
|
}
|
|
373
372
|
/**
|
|
@@ -377,26 +376,24 @@ class DynamoService {
|
|
|
377
376
|
* @param id
|
|
378
377
|
* @param sort
|
|
379
378
|
*/
|
|
380
|
-
readItem(id, sort) {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
throw e;
|
|
399
|
-
});
|
|
379
|
+
async readItem(id, sort) {
|
|
380
|
+
const { tableName, idName, sortName } = this.options;
|
|
381
|
+
// _log(NS, `readItem(${id})...`);
|
|
382
|
+
const itemKey = this.prepareItemKey(id, sort);
|
|
383
|
+
// _log(NS, `> pkey[${id}${sort ? '/' : ''}${sort || ''}] =`, $U.json(itemKey));
|
|
384
|
+
const dynamodoc = await instance().dynamodoc();
|
|
385
|
+
return dynamodoc
|
|
386
|
+
.send(new lib_dynamodb_1.GetCommand(itemKey))
|
|
387
|
+
.then(res => {
|
|
388
|
+
// _log(NS, '> readItem.res =', $U.json(res));
|
|
389
|
+
if (!res.Item)
|
|
390
|
+
throw new Error(`404 NOT FOUND - ${idName}:${id}${sort ? '/' : ''}${sort || ''}`);
|
|
391
|
+
return res.Item;
|
|
392
|
+
})
|
|
393
|
+
.catch((e) => {
|
|
394
|
+
if (`${e.message}` == 'Requested resource not found')
|
|
395
|
+
throw new Error(`404 NOT FOUND - ${idName}:${id}`);
|
|
396
|
+
throw e;
|
|
400
397
|
});
|
|
401
398
|
}
|
|
402
399
|
/**
|
|
@@ -406,127 +403,123 @@ class DynamoService {
|
|
|
406
403
|
* @param list array of items with { id, sort? }
|
|
407
404
|
* @returns BatchResult with success/failed items
|
|
408
405
|
*/
|
|
409
|
-
mreadItem(list) {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
const
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
const
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
const
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
if (`${e.message}`.includes('ResourceNotFoundException'))
|
|
447
|
-
throw new Error(`404 NOT FOUND - table:${tableName}`);
|
|
448
|
-
throw e;
|
|
449
|
-
});
|
|
450
|
-
const items = ((_d = (_c = response.Responses) === null || _c === void 0 ? void 0 : _c[tableName]) !== null && _d !== void 0 ? _d : []);
|
|
451
|
-
if (items.length > 0)
|
|
452
|
-
acc.push(...items);
|
|
453
|
-
const unprocessed = ((_g = (_f = (_e = response.UnprocessedKeys) === null || _e === void 0 ? void 0 : _e[tableName]) === null || _f === void 0 ? void 0 : _f.Keys) !== null && _g !== void 0 ? _g : []);
|
|
454
|
-
if (unprocessed.length > 0) {
|
|
455
|
-
if (attempt >= MAX_RETRIES)
|
|
456
|
-
return { items: acc, unprocessed };
|
|
457
|
-
//* exponential backoff
|
|
458
|
-
yield new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 100));
|
|
459
|
-
return _doBatchGet(unprocessed, attempt + 1, acc);
|
|
460
|
-
}
|
|
461
|
-
return { items: acc, unprocessed: [] };
|
|
406
|
+
async mreadItem(list) {
|
|
407
|
+
const { tableName, idName, sortName } = this.options;
|
|
408
|
+
const total = list?.length ?? 0;
|
|
409
|
+
const result = { success: [], failed: [], total };
|
|
410
|
+
if (!list || total === 0)
|
|
411
|
+
return result;
|
|
412
|
+
const dynamodoc = await DynamoService.instance().dynamodoc();
|
|
413
|
+
const _convertKeyToSig = (key) => {
|
|
414
|
+
const id = key[idName];
|
|
415
|
+
const sort = sortName ? key[sortName] : undefined;
|
|
416
|
+
return `${id}${sortName ? '/' + sort : ''}`;
|
|
417
|
+
};
|
|
418
|
+
const _convertItemToSig = (item) => {
|
|
419
|
+
const id = item[idName];
|
|
420
|
+
const sort = sortName ? item[sortName] : undefined;
|
|
421
|
+
return `${id}${sortName ? '/' + sort : ''}`;
|
|
422
|
+
};
|
|
423
|
+
//* Maps to preserve original order
|
|
424
|
+
const successMap = new Map();
|
|
425
|
+
const failedMap = new Map();
|
|
426
|
+
for (let i = 0; i < total; i += BATCH_GET_CHUNK) {
|
|
427
|
+
const chunk = list?.slice(i, i + BATCH_GET_CHUNK) ?? [];
|
|
428
|
+
const chunkKeyMap = new Map();
|
|
429
|
+
const chunkKeys = chunk.map(item => {
|
|
430
|
+
const key = this.prepareItemKey(item.id, item.sort).Key;
|
|
431
|
+
const sig = _convertKeyToSig(key);
|
|
432
|
+
if (!chunkKeyMap.has(sig))
|
|
433
|
+
chunkKeyMap.set(sig, key);
|
|
434
|
+
return key;
|
|
435
|
+
});
|
|
436
|
+
const _doBatchGet = async (keys, attempt, acc) => {
|
|
437
|
+
const response = await dynamodoc
|
|
438
|
+
.send(new lib_dynamodb_1.BatchGetCommand({ RequestItems: { [tableName]: { Keys: keys } } }))
|
|
439
|
+
.catch((e) => {
|
|
440
|
+
if (`${e.message}`.includes('ResourceNotFoundException'))
|
|
441
|
+
throw new Error(`404 NOT FOUND - table:${tableName}`);
|
|
442
|
+
throw e;
|
|
462
443
|
});
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
unprocessed.forEach(key => {
|
|
474
|
-
const sig = _convertKeyToSig(key);
|
|
475
|
-
const failedItem = Object.assign(Object.assign({}, key), { error });
|
|
476
|
-
failedMap.set(sig, failedItem);
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
//* Identify items not found (404)
|
|
480
|
-
const received = new Set(items.map(item => _convertItemToSig(item)));
|
|
481
|
-
const unprocessedSigs = new Set(unprocessed.map(key => _convertKeyToSig(key)));
|
|
482
|
-
Array.from(chunkKeyMap.entries())
|
|
483
|
-
.filter(([sig]) => !received.has(sig) && !unprocessedSigs.has(sig))
|
|
484
|
-
.forEach(([sig, key]) => {
|
|
485
|
-
const failedItem = Object.assign(Object.assign({}, key), { error: `404 NOT FOUND - ${idName}:${key[idName]}` });
|
|
486
|
-
failedMap.set(sig, failedItem);
|
|
487
|
-
});
|
|
444
|
+
const items = (response.Responses?.[tableName] ?? []);
|
|
445
|
+
if (items.length > 0)
|
|
446
|
+
acc.push(...items);
|
|
447
|
+
const unprocessed = (response.UnprocessedKeys?.[tableName]?.Keys ?? []);
|
|
448
|
+
if (unprocessed.length > 0) {
|
|
449
|
+
if (attempt >= MAX_RETRIES)
|
|
450
|
+
return { items: acc, unprocessed };
|
|
451
|
+
//* exponential backoff
|
|
452
|
+
await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 100));
|
|
453
|
+
return _doBatchGet(unprocessed, attempt + 1, acc);
|
|
488
454
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
455
|
+
return { items: acc, unprocessed: [] };
|
|
456
|
+
};
|
|
457
|
+
try {
|
|
458
|
+
const { items, unprocessed } = await _doBatchGet(chunkKeys, 1, []);
|
|
459
|
+
items.forEach(item => {
|
|
460
|
+
const sig = _convertItemToSig(item);
|
|
461
|
+
successMap.set(sig, item);
|
|
462
|
+
});
|
|
463
|
+
//* Handle unprocessed items (failed after retries)
|
|
464
|
+
if (unprocessed.length > 0) {
|
|
465
|
+
const error = `UNPROCESSED after ${MAX_RETRIES} retries`;
|
|
466
|
+
(0, engine_1._err)(NS, `! mreadItem unprocessed:`, { count: unprocessed.length, error });
|
|
467
|
+
unprocessed.forEach(key => {
|
|
468
|
+
const sig = _convertKeyToSig(key);
|
|
469
|
+
const failedItem = { ...key, error };
|
|
494
470
|
failedMap.set(sig, failedItem);
|
|
495
471
|
});
|
|
496
472
|
}
|
|
473
|
+
//* Identify items not found (404)
|
|
474
|
+
const received = new Set(items.map(item => _convertItemToSig(item)));
|
|
475
|
+
const unprocessedSigs = new Set(unprocessed.map(key => _convertKeyToSig(key)));
|
|
476
|
+
Array.from(chunkKeyMap.entries())
|
|
477
|
+
.filter(([sig]) => !received.has(sig) && !unprocessedSigs.has(sig))
|
|
478
|
+
.forEach(([sig, key]) => {
|
|
479
|
+
const failedItem = {
|
|
480
|
+
...key,
|
|
481
|
+
error: `404 NOT FOUND - ${idName}:${key[idName]}`,
|
|
482
|
+
};
|
|
483
|
+
failedMap.set(sig, failedItem);
|
|
484
|
+
});
|
|
497
485
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
if (successItem) {
|
|
505
|
-
result.success.push(successItem);
|
|
506
|
-
}
|
|
507
|
-
else if (failedItem) {
|
|
508
|
-
result.failed.push(failedItem);
|
|
509
|
-
}
|
|
510
|
-
});
|
|
511
|
-
if (result.failed.length > 0) {
|
|
512
|
-
(0, engine_1._err)(NS, `! mreadItem.failed =`, {
|
|
513
|
-
failed: result.failed.length,
|
|
514
|
-
sample_failed: result.failed.slice(0, 3).map((item) => {
|
|
515
|
-
var _a;
|
|
516
|
-
return ({
|
|
517
|
-
id: (_a = item === null || item === void 0 ? void 0 : item._id) !== null && _a !== void 0 ? _a : item === null || item === void 0 ? void 0 : item.id,
|
|
518
|
-
error: item === null || item === void 0 ? void 0 : item.error,
|
|
519
|
-
});
|
|
520
|
-
}),
|
|
486
|
+
catch (e) {
|
|
487
|
+
const error = e instanceof Error ? e.message : `${e}`;
|
|
488
|
+
(0, engine_1._err)(NS, `! mreadItem batch failed:`, error);
|
|
489
|
+
Array.from(chunkKeyMap.entries()).forEach(([sig, key]) => {
|
|
490
|
+
const failedItem = { ...key, error };
|
|
491
|
+
failedMap.set(sig, failedItem);
|
|
521
492
|
});
|
|
522
493
|
}
|
|
523
|
-
|
|
524
|
-
|
|
494
|
+
}
|
|
495
|
+
//* Preserve original order
|
|
496
|
+
list.forEach(item => {
|
|
497
|
+
const key = this.prepareItemKey(item.id, item.sort).Key;
|
|
498
|
+
const sig = _convertKeyToSig(key);
|
|
499
|
+
const successItem = successMap.get(sig);
|
|
500
|
+
const failedItem = failedMap.get(sig);
|
|
501
|
+
if (successItem) {
|
|
502
|
+
result.success.push(successItem);
|
|
503
|
+
}
|
|
504
|
+
else if (failedItem) {
|
|
505
|
+
result.failed.push(failedItem);
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
if (result.failed.length > 0) {
|
|
509
|
+
(0, engine_1._err)(NS, `! mreadItem.failed =`, {
|
|
525
510
|
failed: result.failed.length,
|
|
526
|
-
|
|
511
|
+
sample_failed: result.failed.slice(0, 3).map((item) => ({
|
|
512
|
+
id: item?._id ?? item?.id,
|
|
513
|
+
error: item?.error,
|
|
514
|
+
})),
|
|
527
515
|
});
|
|
528
|
-
|
|
516
|
+
}
|
|
517
|
+
(0, engine_1._log)(NS, `> mreadItem.res =`, {
|
|
518
|
+
success: result.success.length,
|
|
519
|
+
failed: result.failed.length,
|
|
520
|
+
total: result.total,
|
|
529
521
|
});
|
|
522
|
+
return result;
|
|
530
523
|
}
|
|
531
524
|
/**
|
|
532
525
|
* save-item
|
|
@@ -537,24 +530,22 @@ class DynamoService {
|
|
|
537
530
|
* @param id
|
|
538
531
|
* @param item
|
|
539
532
|
*/
|
|
540
|
-
saveItem(id, item) {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
throw e;
|
|
557
|
-
});
|
|
533
|
+
async saveItem(id, item) {
|
|
534
|
+
const { tableName, idName, sortName } = this.options;
|
|
535
|
+
// _log(NS, `saveItem(${id})...`);
|
|
536
|
+
const payload = this.prepareSaveItem(id, item);
|
|
537
|
+
// _log(NS, '> payload :=', payload);
|
|
538
|
+
const dynamodoc = await DynamoService.instance().dynamodoc();
|
|
539
|
+
return dynamodoc
|
|
540
|
+
.send(new lib_dynamodb_1.PutCommand(payload))
|
|
541
|
+
.then(res => {
|
|
542
|
+
(0, engine_1._log)(NS, '> saveItem.res =', engine_1.$U.json(res));
|
|
543
|
+
return payload.Item;
|
|
544
|
+
})
|
|
545
|
+
.catch((e) => {
|
|
546
|
+
if (`${e.message}` == 'Requested resource not found')
|
|
547
|
+
throw new Error(`404 NOT FOUND - ${idName}:${id}`);
|
|
548
|
+
throw e;
|
|
558
549
|
});
|
|
559
550
|
}
|
|
560
551
|
/**
|
|
@@ -565,112 +556,104 @@ class DynamoService {
|
|
|
565
556
|
* @param list array of items with { id, sort?, ...model }
|
|
566
557
|
* @returns BatchResult with success/failed items
|
|
567
558
|
*/
|
|
568
|
-
msaveItem(list) {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
const
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
const
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
559
|
+
async msaveItem(list) {
|
|
560
|
+
const { tableName } = this.options;
|
|
561
|
+
const total = list?.length ?? 0;
|
|
562
|
+
const result = { success: [], failed: [], total };
|
|
563
|
+
if (!list || total === 0)
|
|
564
|
+
return result;
|
|
565
|
+
const dynamodoc = await DynamoService.instance().dynamodoc();
|
|
566
|
+
for (let i = 0; i < total; i += BATCH_WRITE_CHUNK) {
|
|
567
|
+
const chunk = list?.slice(i, i + BATCH_WRITE_CHUNK) ?? [];
|
|
568
|
+
const chunkItems = [];
|
|
569
|
+
//* prepare batch write requests
|
|
570
|
+
const putRequests = chunk.map(item => {
|
|
571
|
+
const { id, ...rest } = item;
|
|
572
|
+
const payload = this.prepareSaveItem(id, rest);
|
|
573
|
+
chunkItems.push(payload.Item);
|
|
574
|
+
return {
|
|
575
|
+
PutRequest: {
|
|
576
|
+
Item: payload.Item,
|
|
577
|
+
},
|
|
578
|
+
};
|
|
579
|
+
});
|
|
580
|
+
//* execute batch write with retry for unprocessed items
|
|
581
|
+
const _doBatchWrite = async (requests, attempt) => {
|
|
582
|
+
const response = await dynamodoc
|
|
583
|
+
.send(new lib_dynamodb_1.BatchWriteCommand({ RequestItems: { [tableName]: requests } }))
|
|
584
|
+
.catch((e) => {
|
|
585
|
+
if (`${e.message}`.includes('ResourceNotFoundException'))
|
|
586
|
+
throw new Error(`404 NOT FOUND - table:${tableName}`);
|
|
587
|
+
throw e;
|
|
590
588
|
});
|
|
591
|
-
//*
|
|
592
|
-
const
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
.catch((e) => {
|
|
597
|
-
if (`${e.message}`.includes('ResourceNotFoundException'))
|
|
598
|
-
throw new Error(`404 NOT FOUND - table:${tableName}`);
|
|
599
|
-
throw e;
|
|
600
|
-
});
|
|
601
|
-
//* check for unprocessed items
|
|
602
|
-
const unprocessed = (_c = response.UnprocessedItems) === null || _c === void 0 ? void 0 : _c[tableName];
|
|
603
|
-
if (unprocessed && (unprocessed === null || unprocessed === void 0 ? void 0 : unprocessed.length) > 0) {
|
|
604
|
-
if (attempt >= MAX_RETRIES) {
|
|
605
|
-
return unprocessed;
|
|
606
|
-
}
|
|
607
|
-
//* exponential backoff
|
|
608
|
-
yield new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 100));
|
|
609
|
-
return _doBatchWrite(unprocessed, attempt + 1);
|
|
589
|
+
//* check for unprocessed items
|
|
590
|
+
const unprocessed = response.UnprocessedItems?.[tableName];
|
|
591
|
+
if (unprocessed && unprocessed?.length > 0) {
|
|
592
|
+
if (attempt >= MAX_RETRIES) {
|
|
593
|
+
return unprocessed;
|
|
610
594
|
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
595
|
+
//* exponential backoff
|
|
596
|
+
await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 100));
|
|
597
|
+
return _doBatchWrite(unprocessed, attempt + 1);
|
|
598
|
+
}
|
|
599
|
+
return [];
|
|
600
|
+
};
|
|
601
|
+
try {
|
|
602
|
+
const unprocessed = await _doBatchWrite(putRequests, 1);
|
|
603
|
+
//* Handle unprocessed items (failed after retries)
|
|
604
|
+
const unprocessedIds = new Set();
|
|
605
|
+
if (unprocessed?.length > 0) {
|
|
606
|
+
const error = `UNPROCESSED after ${MAX_RETRIES} retries`;
|
|
607
|
+
(0, engine_1._err)(NS, `! msaveItem unprocessed:`, { count: unprocessed.length, error });
|
|
608
|
+
unprocessed.forEach(req => {
|
|
609
|
+
const item = req.PutRequest?.Item;
|
|
610
|
+
if (item) {
|
|
611
|
+
const itemId = String(item[this.options.idName] || item.id);
|
|
612
|
+
unprocessedIds.add(itemId);
|
|
613
|
+
const chunkItem = chunkItems.find(ci => {
|
|
614
|
+
const chunkItemId = String(ci[this.options.idName] || ci.id);
|
|
615
|
+
return chunkItemId === itemId;
|
|
616
|
+
});
|
|
617
|
+
if (chunkItem) {
|
|
618
|
+
const failedItem = { ...chunkItem, error };
|
|
619
|
+
result.failed.push(failedItem);
|
|
634
620
|
}
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
//* Add successfully written items
|
|
638
|
-
chunkItems.forEach(item => {
|
|
639
|
-
const itemId = String(item[this.options.idName] || item.id);
|
|
640
|
-
if (!unprocessedIds.has(itemId)) {
|
|
641
|
-
result.success.push(item);
|
|
642
621
|
}
|
|
643
622
|
});
|
|
644
623
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
const
|
|
648
|
-
(
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
});
|
|
653
|
-
}
|
|
624
|
+
//* Add successfully written items
|
|
625
|
+
chunkItems.forEach(item => {
|
|
626
|
+
const itemId = String(item[this.options.idName] || item.id);
|
|
627
|
+
if (!unprocessedIds.has(itemId)) {
|
|
628
|
+
result.success.push(item);
|
|
629
|
+
}
|
|
630
|
+
});
|
|
654
631
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
error: item === null || item === void 0 ? void 0 : item.error,
|
|
663
|
-
});
|
|
664
|
-
}),
|
|
632
|
+
catch (e) {
|
|
633
|
+
//* Handle complete batch failure
|
|
634
|
+
const error = e instanceof Error ? e.message : `${e}`;
|
|
635
|
+
(0, engine_1._err)(NS, `! msaveItem batch failed:`, error);
|
|
636
|
+
chunkItems.forEach(item => {
|
|
637
|
+
const failedItem = { ...item, error };
|
|
638
|
+
result.failed.push(failedItem);
|
|
665
639
|
});
|
|
666
640
|
}
|
|
667
|
-
|
|
668
|
-
|
|
641
|
+
}
|
|
642
|
+
if (result.failed.length > 0) {
|
|
643
|
+
(0, engine_1._err)(NS, `! msaveItem.failed =`, {
|
|
669
644
|
failed: result.failed.length,
|
|
670
|
-
|
|
645
|
+
sample_failed: result.failed.slice(0, 3).map((item) => ({
|
|
646
|
+
id: item?._id ?? item?.id,
|
|
647
|
+
error: item?.error,
|
|
648
|
+
})),
|
|
671
649
|
});
|
|
672
|
-
|
|
650
|
+
}
|
|
651
|
+
(0, engine_1._log)(NS, `> msaveItem.res =`, {
|
|
652
|
+
success: result.success.length,
|
|
653
|
+
failed: result.failed.length,
|
|
654
|
+
total: result.total,
|
|
673
655
|
});
|
|
656
|
+
return result;
|
|
674
657
|
}
|
|
675
658
|
/**
|
|
676
659
|
* delete-item
|
|
@@ -679,22 +662,20 @@ class DynamoService {
|
|
|
679
662
|
* @param id
|
|
680
663
|
* @param sort
|
|
681
664
|
*/
|
|
682
|
-
deleteItem(id, sort) {
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
throw e;
|
|
697
|
-
});
|
|
665
|
+
async deleteItem(id, sort) {
|
|
666
|
+
// _log(NS, `deleteItem(${id})...`);
|
|
667
|
+
const payload = this.prepareItemKey(id, sort);
|
|
668
|
+
const dynamodoc = await DynamoService.instance().dynamodoc();
|
|
669
|
+
return dynamodoc
|
|
670
|
+
.send(new lib_dynamodb_1.DeleteCommand(payload))
|
|
671
|
+
.then(res => {
|
|
672
|
+
(0, engine_1._log)(NS, '> deleteItem.res =', engine_1.$U.json(res));
|
|
673
|
+
return null;
|
|
674
|
+
})
|
|
675
|
+
.catch((e) => {
|
|
676
|
+
if (`${e.message}` == 'Requested resource not found')
|
|
677
|
+
return {};
|
|
678
|
+
throw e;
|
|
698
679
|
});
|
|
699
680
|
}
|
|
700
681
|
/**
|
|
@@ -706,25 +687,23 @@ class DynamoService {
|
|
|
706
687
|
* @param updates
|
|
707
688
|
* @param increments
|
|
708
689
|
*/
|
|
709
|
-
updateItem(id, sort, updates, increments) {
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
throw e;
|
|
727
|
-
});
|
|
690
|
+
async updateItem(id, sort, updates, increments) {
|
|
691
|
+
const { idName } = this.options;
|
|
692
|
+
// _log(NS, `updateItem(${id})...`);
|
|
693
|
+
const payload = this.prepareUpdateItem(id, sort, updates, increments);
|
|
694
|
+
const dynamodoc = await DynamoService.instance().dynamodoc();
|
|
695
|
+
return dynamodoc
|
|
696
|
+
.send(new lib_dynamodb_1.UpdateCommand(payload))
|
|
697
|
+
.then(res => {
|
|
698
|
+
(0, engine_1._log)(NS, `> updateItem[${id}].res =`, engine_1.$U.json(res));
|
|
699
|
+
const attr = res.Attributes;
|
|
700
|
+
const $key = Object.assign({}, payload.Key);
|
|
701
|
+
return Object.assign(attr, $key);
|
|
702
|
+
})
|
|
703
|
+
.catch((e) => {
|
|
704
|
+
if (`${e.message}` == 'Requested resource not found')
|
|
705
|
+
throw new Error(`404 NOT FOUND - ${idName}:${id}`);
|
|
706
|
+
throw e;
|
|
728
707
|
});
|
|
729
708
|
}
|
|
730
709
|
/**
|
|
@@ -735,139 +714,123 @@ class DynamoService {
|
|
|
735
714
|
* @param list array of items with { id, sort?, ...model }
|
|
736
715
|
* @returns BatchResult with success/failed items
|
|
737
716
|
*/
|
|
738
|
-
mupdateItem(list) {
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
const
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
717
|
+
async mupdateItem(list) {
|
|
718
|
+
const { tableName, idName } = this.options;
|
|
719
|
+
const total = list?.length ?? 0;
|
|
720
|
+
const result = { success: [], failed: [], total };
|
|
721
|
+
if (!list || total === 0)
|
|
722
|
+
return result;
|
|
723
|
+
const dynamodoc = await DynamoService.instance().dynamodoc();
|
|
724
|
+
//* Maps to preserve original order
|
|
725
|
+
const successMap = new Map();
|
|
726
|
+
const failedMap = new Map();
|
|
727
|
+
for (let i = 0; i < total; i += BATCH_WRITE_CHUNK) {
|
|
728
|
+
const chunk = list?.slice(i, i + BATCH_WRITE_CHUNK) ?? [];
|
|
729
|
+
const chunkItemMap = new Map();
|
|
730
|
+
//* prepare batch write requests
|
|
731
|
+
const putRequests = chunk.map(item => {
|
|
732
|
+
const { id, ...rest } = item;
|
|
733
|
+
//* Use partition key field if available, otherwise use id
|
|
734
|
+
const actualId = rest[this.options.idName] || id;
|
|
735
|
+
const payload = this.prepareSaveItem(actualId, rest);
|
|
736
|
+
chunkItemMap.set(id, payload.Item);
|
|
737
|
+
return {
|
|
738
|
+
PutRequest: {
|
|
739
|
+
Item: payload.Item,
|
|
740
|
+
},
|
|
741
|
+
};
|
|
742
|
+
});
|
|
743
|
+
//* execute batch write with retry for unprocessed items
|
|
744
|
+
const _doBatchWrite = async (requests, attempt) => {
|
|
745
|
+
const response = await dynamodoc
|
|
746
|
+
.send(new lib_dynamodb_1.BatchWriteCommand({ RequestItems: { [tableName]: requests } }))
|
|
747
|
+
.catch((e) => {
|
|
748
|
+
if (`${e.message}`.includes('ResourceNotFoundException'))
|
|
749
|
+
throw new Error(`404 NOT FOUND - table:${tableName}`);
|
|
750
|
+
throw e;
|
|
765
751
|
});
|
|
766
|
-
//*
|
|
767
|
-
const
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
.catch((e) => {
|
|
772
|
-
if (`${e.message}`.includes('ResourceNotFoundException'))
|
|
773
|
-
throw new Error(`404 NOT FOUND - table:${tableName}`);
|
|
774
|
-
throw e;
|
|
775
|
-
});
|
|
776
|
-
//* check for unprocessed items
|
|
777
|
-
const unprocessed = (_c = response.UnprocessedItems) === null || _c === void 0 ? void 0 : _c[tableName];
|
|
778
|
-
if (unprocessed && (unprocessed === null || unprocessed === void 0 ? void 0 : unprocessed.length) > 0) {
|
|
779
|
-
if (attempt >= MAX_RETRIES) {
|
|
780
|
-
return unprocessed;
|
|
781
|
-
}
|
|
782
|
-
//* exponential backoff
|
|
783
|
-
yield new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 100));
|
|
784
|
-
return _doBatchWrite(unprocessed, attempt + 1);
|
|
752
|
+
//* check for unprocessed items
|
|
753
|
+
const unprocessed = response.UnprocessedItems?.[tableName];
|
|
754
|
+
if (unprocessed && unprocessed?.length > 0) {
|
|
755
|
+
if (attempt >= MAX_RETRIES) {
|
|
756
|
+
return unprocessed;
|
|
785
757
|
}
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
}
|
|
758
|
+
//* exponential backoff
|
|
759
|
+
await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 100));
|
|
760
|
+
return _doBatchWrite(unprocessed, attempt + 1);
|
|
761
|
+
}
|
|
762
|
+
return [];
|
|
763
|
+
};
|
|
764
|
+
try {
|
|
765
|
+
const unprocessed = await _doBatchWrite(putRequests, 1);
|
|
766
|
+
//* Handle unprocessed items (failed after retries)
|
|
767
|
+
const unprocessedIds = new Set();
|
|
768
|
+
if (unprocessed?.length > 0) {
|
|
769
|
+
const error = `UNPROCESSED after ${MAX_RETRIES} retries`;
|
|
770
|
+
(0, engine_1._err)(NS, `! mupdateItem unprocessed:`, { count: unprocessed.length, error });
|
|
771
|
+
unprocessed.forEach(req => {
|
|
772
|
+
const item = req.PutRequest?.Item;
|
|
773
|
+
if (item) {
|
|
774
|
+
const itemId = String(item[this.options.idName] || item.id);
|
|
775
|
+
for (const [id, chunkItem] of chunkItemMap.entries()) {
|
|
776
|
+
const chunkItemId = String(chunkItem[this.options.idName] || chunkItem.id);
|
|
777
|
+
if (chunkItemId === itemId) {
|
|
778
|
+
unprocessedIds.add(id);
|
|
779
|
+
const failedItem = { ...chunkItem, error };
|
|
780
|
+
failedMap.set(id, failedItem);
|
|
781
|
+
break;
|
|
808
782
|
}
|
|
809
783
|
}
|
|
810
|
-
});
|
|
811
|
-
}
|
|
812
|
-
//* Add successfully written items
|
|
813
|
-
chunkItemMap.forEach((item, id) => {
|
|
814
|
-
if (!unprocessedIds.has(id)) {
|
|
815
|
-
successMap.set(id, item);
|
|
816
784
|
}
|
|
817
785
|
});
|
|
818
786
|
}
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
failedMap.set(id, failedItem);
|
|
826
|
-
});
|
|
827
|
-
}
|
|
787
|
+
//* Add successfully written items
|
|
788
|
+
chunkItemMap.forEach((item, id) => {
|
|
789
|
+
if (!unprocessedIds.has(id)) {
|
|
790
|
+
successMap.set(id, item);
|
|
791
|
+
}
|
|
792
|
+
});
|
|
828
793
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
const
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
}
|
|
837
|
-
else if (failedItem) {
|
|
838
|
-
result.failed.push(failedItem);
|
|
839
|
-
}
|
|
840
|
-
});
|
|
841
|
-
if (result.failed.length > 0) {
|
|
842
|
-
(0, engine_1._err)(NS, `! mupdateItem.failed =`, {
|
|
843
|
-
failed: result.failed.length,
|
|
844
|
-
sample_failed: result.failed.slice(0, 3).map((item) => {
|
|
845
|
-
var _a;
|
|
846
|
-
return ({
|
|
847
|
-
id: (_a = item === null || item === void 0 ? void 0 : item._id) !== null && _a !== void 0 ? _a : item === null || item === void 0 ? void 0 : item.id,
|
|
848
|
-
error: item === null || item === void 0 ? void 0 : item.error,
|
|
849
|
-
});
|
|
850
|
-
}),
|
|
794
|
+
catch (e) {
|
|
795
|
+
//* Handle complete batch failure
|
|
796
|
+
const error = e instanceof Error ? e.message : `${e}`;
|
|
797
|
+
(0, engine_1._err)(NS, `! mupdateItem batch failed:`, error);
|
|
798
|
+
chunkItemMap.forEach((item, id) => {
|
|
799
|
+
const failedItem = { ...item, error };
|
|
800
|
+
failedMap.set(id, failedItem);
|
|
851
801
|
});
|
|
852
802
|
}
|
|
853
|
-
|
|
854
|
-
|
|
803
|
+
}
|
|
804
|
+
//* Preserve original order
|
|
805
|
+
list.forEach(item => {
|
|
806
|
+
const id = item.id;
|
|
807
|
+
const successItem = successMap.get(id);
|
|
808
|
+
const failedItem = failedMap.get(id);
|
|
809
|
+
if (successItem) {
|
|
810
|
+
result.success.push(successItem);
|
|
811
|
+
}
|
|
812
|
+
else if (failedItem) {
|
|
813
|
+
result.failed.push(failedItem);
|
|
814
|
+
}
|
|
815
|
+
});
|
|
816
|
+
if (result.failed.length > 0) {
|
|
817
|
+
(0, engine_1._err)(NS, `! mupdateItem.failed =`, {
|
|
855
818
|
failed: result.failed.length,
|
|
856
|
-
|
|
819
|
+
sample_failed: result.failed.slice(0, 3).map((item) => ({
|
|
820
|
+
id: item?._id ?? item?.id,
|
|
821
|
+
error: item?.error,
|
|
822
|
+
})),
|
|
857
823
|
});
|
|
858
|
-
|
|
824
|
+
}
|
|
825
|
+
(0, engine_1._log)(NS, `> mupdateItem.res =`, {
|
|
826
|
+
success: result.success.length,
|
|
827
|
+
failed: result.failed.length,
|
|
828
|
+
total: result.total,
|
|
859
829
|
});
|
|
830
|
+
return result;
|
|
860
831
|
}
|
|
861
832
|
}
|
|
862
833
|
exports.DynamoService = DynamoService;
|
|
863
|
-
DynamoService._dynamo = {};
|
|
864
|
-
DynamoService._dynamostr = {};
|
|
865
|
-
//TODO [Steve] why to use promise here to make DynamoDBDocumentClient? @251212
|
|
866
|
-
DynamoService._dynamodoc = {};
|
|
867
|
-
/**
|
|
868
|
-
* export to test..
|
|
869
|
-
*/
|
|
870
|
-
DynamoService.normalize = normalize;
|
|
871
834
|
/** ****************************************************************************************************************
|
|
872
835
|
* Dummy Dynamo Service
|
|
873
836
|
** ****************************************************************************************************************/
|
|
@@ -878,17 +841,13 @@ DynamoService.normalize = normalize;
|
|
|
878
841
|
class DummyDynamoService extends DynamoService {
|
|
879
842
|
constructor(dataFile, options) {
|
|
880
843
|
super(options);
|
|
881
|
-
this.buffer = {};
|
|
882
|
-
/**
|
|
883
|
-
* say hello()
|
|
884
|
-
*/
|
|
885
|
-
this.hello = () => `dummy-dynamo-service:${this.options.tableName}`;
|
|
886
844
|
(0, engine_1._log)(NS, `DummyDynamoService(${dataFile || ''})...`);
|
|
887
845
|
if (!dataFile)
|
|
888
846
|
throw new Error('@dataFile(string) is required!');
|
|
889
847
|
const dummy = (0, tools_1.loadDataYml)(dataFile);
|
|
890
848
|
this.load(dummy.data);
|
|
891
849
|
}
|
|
850
|
+
buffer = {};
|
|
892
851
|
load(data) {
|
|
893
852
|
const { idName } = this.options;
|
|
894
853
|
if (!data || !Array.isArray(data))
|
|
@@ -898,6 +857,10 @@ class DummyDynamoService extends DynamoService {
|
|
|
898
857
|
this.buffer[id] = item;
|
|
899
858
|
});
|
|
900
859
|
}
|
|
860
|
+
/**
|
|
861
|
+
* say hello()
|
|
862
|
+
*/
|
|
863
|
+
hello = () => `dummy-dynamo-service:${this.options.tableName}`;
|
|
901
864
|
/**
|
|
902
865
|
* ONLY FOR DUMMY
|
|
903
866
|
* - send list of data.
|
|
@@ -905,171 +868,143 @@ class DummyDynamoService extends DynamoService {
|
|
|
905
868
|
* @param page page number starts from 1
|
|
906
869
|
* @param limit limit of count.
|
|
907
870
|
*/
|
|
908
|
-
listItems(page, limit) {
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
return { page, limit, total, list };
|
|
916
|
-
});
|
|
871
|
+
async listItems(page, limit) {
|
|
872
|
+
page = engine_1.$U.N(page, 1);
|
|
873
|
+
limit = engine_1.$U.N(limit, 2);
|
|
874
|
+
const keys = Object.keys(this.buffer);
|
|
875
|
+
const total = keys.length;
|
|
876
|
+
const list = keys.slice((page - 1) * limit, page * limit).map(_ => this.buffer[_]);
|
|
877
|
+
return { page, limit, total, list };
|
|
917
878
|
}
|
|
918
|
-
readItem(id, sort) {
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
return Object.assign({ [idName]: id }, item);
|
|
925
|
-
});
|
|
879
|
+
async readItem(id, sort) {
|
|
880
|
+
const { idName } = this.options;
|
|
881
|
+
const item = this.buffer[id];
|
|
882
|
+
if (item === undefined)
|
|
883
|
+
throw new Error(`404 NOT FOUND - ${idName}:${id}`);
|
|
884
|
+
return { [idName]: id, ...item };
|
|
926
885
|
}
|
|
927
|
-
mreadItem(list) {
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
const
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
result.failed.push(failedItem);
|
|
942
|
-
continue;
|
|
943
|
-
}
|
|
944
|
-
result.success.push(Object.assign({ [idName]: item.id }, data));
|
|
945
|
-
}
|
|
946
|
-
if (result.failed.length > 0) {
|
|
947
|
-
(0, engine_1._err)(NS, `! mreadItem.failed =`, {
|
|
948
|
-
failed: result.failed.length,
|
|
949
|
-
sample_failed: result.failed.slice(0, 3).map((item) => {
|
|
950
|
-
var _a, _b;
|
|
951
|
-
return ({
|
|
952
|
-
id: (_b = (_a = item === null || item === void 0 ? void 0 : item._id) !== null && _a !== void 0 ? _a : item === null || item === void 0 ? void 0 : item.id) !== null && _b !== void 0 ? _b : item === null || item === void 0 ? void 0 : item[idName],
|
|
953
|
-
error: item === null || item === void 0 ? void 0 : item.error,
|
|
954
|
-
});
|
|
955
|
-
}),
|
|
956
|
-
});
|
|
886
|
+
async mreadItem(list) {
|
|
887
|
+
const { idName, sortName } = this.options;
|
|
888
|
+
const total = list?.length ?? 0;
|
|
889
|
+
const result = { success: [], failed: [], total };
|
|
890
|
+
if (!list || total === 0)
|
|
891
|
+
return result;
|
|
892
|
+
for (const item of list) {
|
|
893
|
+
const data = this.buffer[item.id];
|
|
894
|
+
if (data === undefined) {
|
|
895
|
+
const failedItem = (sortName
|
|
896
|
+
? { [idName]: item.id, [sortName]: item.sort, error: '404 NOT FOUND' }
|
|
897
|
+
: { [idName]: item.id, error: '404 NOT FOUND' });
|
|
898
|
+
result.failed.push(failedItem);
|
|
899
|
+
continue;
|
|
957
900
|
}
|
|
958
|
-
|
|
959
|
-
|
|
901
|
+
result.success.push({ [idName]: item.id, ...data });
|
|
902
|
+
}
|
|
903
|
+
if (result.failed.length > 0) {
|
|
904
|
+
(0, engine_1._err)(NS, `! mreadItem.failed =`, {
|
|
960
905
|
failed: result.failed.length,
|
|
961
|
-
|
|
906
|
+
sample_failed: result.failed.slice(0, 3).map((item) => ({
|
|
907
|
+
id: item?._id ?? item?.id ?? item?.[idName],
|
|
908
|
+
error: item?.error,
|
|
909
|
+
})),
|
|
962
910
|
});
|
|
963
|
-
|
|
911
|
+
}
|
|
912
|
+
(0, engine_1._log)(NS, `> mreadItem.res =`, {
|
|
913
|
+
success: result.success.length,
|
|
914
|
+
failed: result.failed.length,
|
|
915
|
+
total: result.total,
|
|
964
916
|
});
|
|
917
|
+
return result;
|
|
965
918
|
}
|
|
966
|
-
saveItem(id, item) {
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
return Object.assign({ [idName]: id }, this.buffer[id]);
|
|
971
|
-
});
|
|
919
|
+
async saveItem(id, item) {
|
|
920
|
+
const { idName } = this.options;
|
|
921
|
+
this.buffer[id] = normalize(item);
|
|
922
|
+
return { [idName]: id, ...this.buffer[id] };
|
|
972
923
|
}
|
|
973
|
-
msaveItem(list) {
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
this.buffer[id] = normalize(rest);
|
|
986
|
-
result.success.push(Object.assign({ [idName]: id }, this.buffer[id]));
|
|
987
|
-
}
|
|
988
|
-
catch (e) {
|
|
989
|
-
const error = e instanceof Error ? e.message : `${e}`;
|
|
990
|
-
(0, engine_1._err)(NS, `! msaveItem failed for id=${item === null || item === void 0 ? void 0 : item.id}:`, error);
|
|
991
|
-
const failedItem = Object.assign(Object.assign({}, item), { error });
|
|
992
|
-
result.failed.push(failedItem);
|
|
993
|
-
}
|
|
924
|
+
async msaveItem(list) {
|
|
925
|
+
const { idName } = this.options;
|
|
926
|
+
const total = list?.length ?? 0;
|
|
927
|
+
const result = { success: [], failed: [], total };
|
|
928
|
+
if (!list || total === 0)
|
|
929
|
+
return result;
|
|
930
|
+
//* process all saves using the in-memory buffer (overwrites entire items)
|
|
931
|
+
for (const item of list) {
|
|
932
|
+
try {
|
|
933
|
+
const { id, ...rest } = item;
|
|
934
|
+
this.buffer[id] = normalize(rest);
|
|
935
|
+
result.success.push({ [idName]: id, ...this.buffer[id] });
|
|
994
936
|
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
return ({
|
|
1001
|
-
id: (_b = (_a = item === null || item === void 0 ? void 0 : item._id) !== null && _a !== void 0 ? _a : item === null || item === void 0 ? void 0 : item.id) !== null && _b !== void 0 ? _b : item === null || item === void 0 ? void 0 : item[idName],
|
|
1002
|
-
error: item === null || item === void 0 ? void 0 : item.error,
|
|
1003
|
-
});
|
|
1004
|
-
}),
|
|
1005
|
-
});
|
|
937
|
+
catch (e) {
|
|
938
|
+
const error = e instanceof Error ? e.message : `${e}`;
|
|
939
|
+
(0, engine_1._err)(NS, `! msaveItem failed for id=${item?.id}:`, error);
|
|
940
|
+
const failedItem = { ...item, error };
|
|
941
|
+
result.failed.push(failedItem);
|
|
1006
942
|
}
|
|
1007
|
-
|
|
1008
|
-
|
|
943
|
+
}
|
|
944
|
+
if (result.failed.length > 0) {
|
|
945
|
+
(0, engine_1._err)(NS, `! msaveItem.failed =`, {
|
|
1009
946
|
failed: result.failed.length,
|
|
1010
|
-
|
|
947
|
+
sample_failed: result.failed.slice(0, 3).map((item) => ({
|
|
948
|
+
id: item?._id ?? item?.id ?? item?.[idName],
|
|
949
|
+
error: item?.error,
|
|
950
|
+
})),
|
|
1011
951
|
});
|
|
1012
|
-
|
|
952
|
+
}
|
|
953
|
+
(0, engine_1._log)(NS, `> msaveItem.res =`, {
|
|
954
|
+
success: result.success.length,
|
|
955
|
+
failed: result.failed.length,
|
|
956
|
+
total: result.total,
|
|
1013
957
|
});
|
|
958
|
+
return result;
|
|
1014
959
|
}
|
|
1015
|
-
deleteItem(id, sort) {
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
return null;
|
|
1019
|
-
});
|
|
960
|
+
async deleteItem(id, sort) {
|
|
961
|
+
delete this.buffer[id];
|
|
962
|
+
return null;
|
|
1020
963
|
}
|
|
1021
|
-
updateItem(id, sort, updates, increments) {
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
return Object.assign({ [idName]: id }, this.buffer[id]);
|
|
1029
|
-
});
|
|
964
|
+
async updateItem(id, sort, updates, increments) {
|
|
965
|
+
const { idName } = this.options;
|
|
966
|
+
const item = this.buffer[id];
|
|
967
|
+
if (item === undefined)
|
|
968
|
+
throw new Error(`404 NOT FOUND - ${idName}:${id}`);
|
|
969
|
+
this.buffer[id] = { ...item, ...normalize(updates) };
|
|
970
|
+
return { [idName]: id, ...this.buffer[id] };
|
|
1030
971
|
}
|
|
1031
|
-
mupdateItem(list) {
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
this.buffer[id] = normalize(rest);
|
|
1045
|
-
result.success.push(Object.assign({ [idName]: id }, this.buffer[id]));
|
|
1046
|
-
}
|
|
1047
|
-
catch (e) {
|
|
1048
|
-
const error = e instanceof Error ? e.message : `${e}`;
|
|
1049
|
-
(0, engine_1._err)(NS, `! mupdateItem failed for id=${item === null || item === void 0 ? void 0 : item.id}:`, error);
|
|
1050
|
-
const failedItem = { [idName]: item.id, error };
|
|
1051
|
-
result.failed.push(failedItem);
|
|
1052
|
-
}
|
|
972
|
+
async mupdateItem(list) {
|
|
973
|
+
const { idName } = this.options;
|
|
974
|
+
const total = list?.length ?? 0;
|
|
975
|
+
const result = { success: [], failed: [], total };
|
|
976
|
+
if (!list || total === 0)
|
|
977
|
+
return result;
|
|
978
|
+
//* process all updates using the in-memory buffer (overwrites entire items)
|
|
979
|
+
for (const item of list) {
|
|
980
|
+
try {
|
|
981
|
+
const { id, ...rest } = item;
|
|
982
|
+
//* overwrite entire item (same as PutItem behavior)
|
|
983
|
+
this.buffer[id] = normalize(rest);
|
|
984
|
+
result.success.push({ [idName]: id, ...this.buffer[id] });
|
|
1053
985
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
return ({
|
|
1060
|
-
id: (_b = (_a = item === null || item === void 0 ? void 0 : item._id) !== null && _a !== void 0 ? _a : item === null || item === void 0 ? void 0 : item.id) !== null && _b !== void 0 ? _b : item === null || item === void 0 ? void 0 : item[idName],
|
|
1061
|
-
error: item === null || item === void 0 ? void 0 : item.error,
|
|
1062
|
-
});
|
|
1063
|
-
}),
|
|
1064
|
-
});
|
|
986
|
+
catch (e) {
|
|
987
|
+
const error = e instanceof Error ? e.message : `${e}`;
|
|
988
|
+
(0, engine_1._err)(NS, `! mupdateItem failed for id=${item?.id}:`, error);
|
|
989
|
+
const failedItem = { [idName]: item.id, error };
|
|
990
|
+
result.failed.push(failedItem);
|
|
1065
991
|
}
|
|
1066
|
-
|
|
1067
|
-
|
|
992
|
+
}
|
|
993
|
+
if (result.failed.length > 0) {
|
|
994
|
+
(0, engine_1._err)(NS, `! mupdateItem.failed =`, {
|
|
1068
995
|
failed: result.failed.length,
|
|
1069
|
-
|
|
996
|
+
sample_failed: result.failed.slice(0, 3).map((item) => ({
|
|
997
|
+
id: item?._id ?? item?.id ?? item?.[idName],
|
|
998
|
+
error: item?.error,
|
|
999
|
+
})),
|
|
1070
1000
|
});
|
|
1071
|
-
|
|
1001
|
+
}
|
|
1002
|
+
(0, engine_1._log)(NS, `> mupdateItem.res =`, {
|
|
1003
|
+
success: result.success.length,
|
|
1004
|
+
failed: result.failed.length,
|
|
1005
|
+
total: result.total,
|
|
1072
1006
|
});
|
|
1007
|
+
return result;
|
|
1073
1008
|
}
|
|
1074
1009
|
}
|
|
1075
1010
|
exports.DummyDynamoService = DummyDynamoService;
|