lemon-core 4.1.14 → 4.2.0

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