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.
Files changed (156) hide show
  1. package/README.md +2 -0
  2. package/dist/common/test-helper.d.ts +2 -2
  3. package/dist/common/test-helper.js +24 -26
  4. package/dist/common/test-helper.js.map +1 -1
  5. package/dist/controllers/dummy-controller.js +39 -46
  6. package/dist/controllers/dummy-controller.js.map +1 -1
  7. package/dist/controllers/general-api-controller.js +95 -100
  8. package/dist/controllers/general-api-controller.js.map +1 -1
  9. package/dist/controllers/general-controller.js +81 -82
  10. package/dist/controllers/general-controller.js.map +1 -1
  11. package/dist/cores/api/api-service.d.ts +1 -1
  12. package/dist/cores/api/api-service.js +228 -269
  13. package/dist/cores/api/api-service.js.map +1 -1
  14. package/dist/cores/aws/aws-kms-service.d.ts +1 -2
  15. package/dist/cores/aws/aws-kms-service.js +143 -153
  16. package/dist/cores/aws/aws-kms-service.js.map +1 -1
  17. package/dist/cores/aws/aws-s3-service.d.ts +2 -4
  18. package/dist/cores/aws/aws-s3-service.js +306 -330
  19. package/dist/cores/aws/aws-s3-service.js.map +1 -1
  20. package/dist/cores/aws/aws-sns-service.js +147 -153
  21. package/dist/cores/aws/aws-sns-service.js.map +1 -1
  22. package/dist/cores/aws/aws-sqs-service.js +149 -170
  23. package/dist/cores/aws/aws-sqs-service.js.map +1 -1
  24. package/dist/cores/aws/index.js +10 -20
  25. package/dist/cores/aws/index.js.map +1 -1
  26. package/dist/cores/cache/cache-service.d.ts +2 -2
  27. package/dist/cores/cache/cache-service.js +435 -499
  28. package/dist/cores/cache/cache-service.js.map +1 -1
  29. package/dist/cores/config/config-service.d.ts +1 -1
  30. package/dist/cores/config/config-service.js +56 -63
  31. package/dist/cores/config/config-service.js.map +1 -1
  32. package/dist/cores/config/index.js +14 -24
  33. package/dist/cores/config/index.js.map +1 -1
  34. package/dist/cores/core-services.d.ts +1 -1
  35. package/dist/cores/dynamo/dynamo-query-service.js +37 -51
  36. package/dist/cores/dynamo/dynamo-query-service.js.map +1 -1
  37. package/dist/cores/dynamo/dynamo-scan-service.d.ts +2 -2
  38. package/dist/cores/dynamo/dynamo-scan-service.js +29 -40
  39. package/dist/cores/dynamo/dynamo-scan-service.js.map +1 -1
  40. package/dist/cores/dynamo/dynamo-service.d.ts +3 -3
  41. package/dist/cores/dynamo/dynamo-service.js +540 -605
  42. package/dist/cores/dynamo/dynamo-service.js.map +1 -1
  43. package/dist/cores/dynamo/tools/expressions.js +17 -7
  44. package/dist/cores/dynamo/tools/expressions.js.map +1 -1
  45. package/dist/cores/dynamo/tools/query.js +142 -127
  46. package/dist/cores/dynamo/tools/query.js.map +1 -1
  47. package/dist/cores/dynamo/tools/scan.js +111 -97
  48. package/dist/cores/dynamo/tools/scan.js.map +1 -1
  49. package/dist/cores/dynamo/tools/serializer.js +17 -7
  50. package/dist/cores/dynamo/tools/serializer.js.map +1 -1
  51. package/dist/cores/dynamo/tools/utils.d.ts +0 -2
  52. package/dist/cores/dynamo/tools/utils.js.map +1 -1
  53. package/dist/cores/elastic/elastic6-query-service.js +307 -324
  54. package/dist/cores/elastic/elastic6-query-service.js.map +1 -1
  55. package/dist/cores/elastic/elastic6-service.d.ts +3 -3
  56. package/dist/cores/elastic/elastic6-service.js +568 -647
  57. package/dist/cores/elastic/elastic6-service.js.map +1 -1
  58. package/dist/cores/elastic/hangul-service.js +52 -54
  59. package/dist/cores/elastic/hangul-service.js.map +1 -1
  60. package/dist/cores/lambda/index.js +42 -36
  61. package/dist/cores/lambda/index.js.map +1 -1
  62. package/dist/cores/lambda/lambda-alb-handler.d.ts +2 -2
  63. package/dist/cores/lambda/lambda-alb-handler.js +59 -72
  64. package/dist/cores/lambda/lambda-alb-handler.js.map +1 -1
  65. package/dist/cores/lambda/lambda-cognito-handler.js +10 -19
  66. package/dist/cores/lambda/lambda-cognito-handler.js.map +1 -1
  67. package/dist/cores/lambda/lambda-cron-handler.d.ts +1 -1
  68. package/dist/cores/lambda/lambda-cron-handler.js +14 -23
  69. package/dist/cores/lambda/lambda-cron-handler.js.map +1 -1
  70. package/dist/cores/lambda/lambda-dynamo-stream-handler.d.ts +2 -2
  71. package/dist/cores/lambda/lambda-dynamo-stream-handler.js +57 -67
  72. package/dist/cores/lambda/lambda-dynamo-stream-handler.js.map +1 -1
  73. package/dist/cores/lambda/lambda-handler.d.ts +22 -22
  74. package/dist/cores/lambda/lambda-handler.js +93 -106
  75. package/dist/cores/lambda/lambda-handler.js.map +1 -1
  76. package/dist/cores/lambda/lambda-notification-handler.d.ts +1 -1
  77. package/dist/cores/lambda/lambda-notification-handler.js +39 -50
  78. package/dist/cores/lambda/lambda-notification-handler.js.map +1 -1
  79. package/dist/cores/lambda/lambda-sns-handler.js +79 -88
  80. package/dist/cores/lambda/lambda-sns-handler.js.map +1 -1
  81. package/dist/cores/lambda/lambda-sqs-handler.js +79 -88
  82. package/dist/cores/lambda/lambda-sqs-handler.js.map +1 -1
  83. package/dist/cores/lambda/lambda-web-handler.d.ts +6 -6
  84. package/dist/cores/lambda/lambda-web-handler.js +387 -412
  85. package/dist/cores/lambda/lambda-web-handler.js.map +1 -1
  86. package/dist/cores/lambda/lambda-wss-handler.js +23 -32
  87. package/dist/cores/lambda/lambda-wss-handler.js.map +1 -1
  88. package/dist/cores/protocol/index.js +10 -20
  89. package/dist/cores/protocol/index.js.map +1 -1
  90. package/dist/cores/protocol/protocol-service.d.ts +3 -3
  91. package/dist/cores/protocol/protocol-service.js +235 -227
  92. package/dist/cores/protocol/protocol-service.js.map +1 -1
  93. package/dist/cores/storage/http-storage-service.js +65 -85
  94. package/dist/cores/storage/http-storage-service.js.map +1 -1
  95. package/dist/cores/storage/model-manager.js +66 -85
  96. package/dist/cores/storage/model-manager.js.map +1 -1
  97. package/dist/cores/storage/proxy-storage-service.d.ts +2 -2
  98. package/dist/cores/storage/proxy-storage-service.js +562 -599
  99. package/dist/cores/storage/proxy-storage-service.js.map +1 -1
  100. package/dist/cores/storage/redis-storage-service.js +163 -177
  101. package/dist/cores/storage/redis-storage-service.js.map +1 -1
  102. package/dist/cores/storage/storage-service.d.ts +8 -1
  103. package/dist/cores/storage/storage-service.js +359 -324
  104. package/dist/cores/storage/storage-service.js.map +1 -1
  105. package/dist/engine/builder.d.ts +1 -1
  106. package/dist/engine/builder.js +59 -63
  107. package/dist/engine/builder.js.map +1 -1
  108. package/dist/engine/engine.d.ts +4 -4
  109. package/dist/engine/engine.js +9 -18
  110. package/dist/engine/engine.js.map +1 -1
  111. package/dist/engine/types.d.ts +1 -1
  112. package/dist/engine/utilities.d.ts +5 -5
  113. package/dist/engine/utilities.js +301 -293
  114. package/dist/engine/utilities.js.map +1 -1
  115. package/dist/environ.js +4 -6
  116. package/dist/environ.js.map +1 -1
  117. package/dist/extended/abstract-service.js +595 -645
  118. package/dist/extended/abstract-service.js.map +1 -1
  119. package/dist/extended/libs/sig-v4.js.map +1 -1
  120. package/dist/generated/field-registry.d.ts +10 -0
  121. package/dist/generated/field-registry.js +17 -0
  122. package/dist/generated/field-registry.js.map +1 -0
  123. package/dist/helpers/helpers.d.ts +17 -9
  124. package/dist/helpers/helpers.js +88 -78
  125. package/dist/helpers/helpers.js.map +1 -1
  126. package/dist/index.js +17 -7
  127. package/dist/index.js.map +1 -1
  128. package/dist/lib/dynamodb-value.js +2 -3
  129. package/dist/lib/dynamodb-value.js.map +1 -1
  130. package/dist/tools/express.js +4 -5
  131. package/dist/tools/express.js.map +1 -1
  132. package/dist/tools/tools.d.ts +3 -1
  133. package/dist/tools/tools.js +14 -21
  134. package/dist/tools/tools.js.map +1 -1
  135. package/package.json +25 -24
  136. package/dist/exec-cli.d.ts +0 -2
  137. package/dist/exec-cli.js +0 -211
  138. package/dist/exec-cli.js.map +0 -1
  139. package/dist/lib/dynamo/expressions.d.ts +0 -14
  140. package/dist/lib/dynamo/expressions.js +0 -212
  141. package/dist/lib/dynamo/expressions.js.map +0 -1
  142. package/dist/lib/dynamo/query.d.ts +0 -43
  143. package/dist/lib/dynamo/query.js +0 -246
  144. package/dist/lib/dynamo/query.js.map +0 -1
  145. package/dist/lib/dynamo/scan.d.ts +0 -33
  146. package/dist/lib/dynamo/scan.js +0 -172
  147. package/dist/lib/dynamo/scan.js.map +0 -1
  148. package/dist/lib/dynamo/serializer.d.ts +0 -12
  149. package/dist/lib/dynamo/serializer.js +0 -243
  150. package/dist/lib/dynamo/serializer.js.map +0 -1
  151. package/dist/lib/dynamo/utils.d.ts +0 -15
  152. package/dist/lib/dynamo/utils.js +0 -129
  153. package/dist/lib/dynamo/utils.js.map +0 -1
  154. package/dist/tools/shared.d.ts +0 -28
  155. package/dist/tools/shared.js +0 -143
  156. package/dist/tools/shared.js.map +0 -1
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.UniqueFieldManager = exports.ModelUtil = exports.TypedStorageService = exports.ProxyStorageService = exports.GeneralModelFilter = exports.GeneralKeyMaker = void 0;
13
4
  /**
@@ -32,6 +23,8 @@ const NS = engine_1.$U.NS('PSTR', 'blue'); // NAMESPACE TO BE PRINTED.
32
23
  * - use ':' as delimiter to join [ns, type, id]
33
24
  */
34
25
  class GeneralKeyMaker {
26
+ NS;
27
+ DELIMITER;
35
28
  constructor(ns = '', delimiter = ':') {
36
29
  this.NS = ns;
37
30
  this.DELIMITER = delimiter;
@@ -53,6 +46,7 @@ exports.GeneralKeyMaker = GeneralKeyMaker;
53
46
  */
54
47
  // eslint-disable-next-line prettier/prettier
55
48
  class GeneralModelFilter {
49
+ FIELDS;
56
50
  /**
57
51
  * default constructor
58
52
  */
@@ -216,6 +210,12 @@ exports.GeneralModelFilter = GeneralModelFilter;
216
210
  */
217
211
  // eslint-disable-next-line prettier/prettier
218
212
  class ProxyStorageService {
213
+ static AUTO_SEQUENCE = 1000000;
214
+ static TYPE_SEQUENCE = 'sequence';
215
+ idName;
216
+ service;
217
+ storage;
218
+ filters;
219
219
  /**
220
220
  * create proxed storage-service.
221
221
  *
@@ -226,66 +226,6 @@ class ProxyStorageService {
226
226
  * @param idName (optional) internal partition-key (default as '_id')
227
227
  */
228
228
  constructor(service, storage, fields, filters, idName) {
229
- /**
230
- * say hello()
231
- */
232
- this.hello = () => `proxy-storage-service:${this.storage.hello()}`;
233
- /**
234
- * read by _id
235
- */
236
- this.read = (_id) => this.storage.read(_id);
237
- /**
238
- * read multiple models.
239
- */
240
- this.mread = (ids) => this.storage.mread(ids);
241
- /**
242
- * read or create by _id
243
- */
244
- this.readOrCreate = (_id, model) => this.storage.readOrCreate(_id, model);
245
- /**
246
- * save by _id
247
- */
248
- this.save = (_id, model) => this.storage.save(_id, model);
249
- /**
250
- * update by _id
251
- */
252
- this.update = (_id, model, incrementals) => this.storage.update(_id, model, incrementals);
253
- /**
254
- * update multiple models.
255
- */
256
- this.mupdate = (list) => this.storage.mupdate(list);
257
- /**
258
- * increment by _id
259
- */
260
- this.increment = (_id, model, $update) => this.storage.increment(_id, model, $update);
261
- /**
262
- * delete by _id
263
- */
264
- this.delete = (_id) => this.storage.delete(_id);
265
- /**
266
- * get key-id by type+id
267
- */
268
- this.asKey = (type, id) => {
269
- if (typeof this.service.asKey == 'function') {
270
- return this.service.asKey(type, `${id}`);
271
- }
272
- const $key = this.service.asKey$(type, `${id}`);
273
- return $key[this.idName];
274
- };
275
- /**
276
- * timer to generate the current-time (msec)
277
- */
278
- this.$timer = null;
279
- this.setTimer = (timer) => {
280
- const previous = this.$timer;
281
- this.$timer = timer;
282
- return previous;
283
- };
284
- this.getTime = () => {
285
- if (this.$timer)
286
- return this.$timer();
287
- return new Date().getTime();
288
- };
289
229
  this.idName = idName === undefined ? '_id' : `${idName || ''}`;
290
230
  this.service = service;
291
231
  this.storage =
@@ -305,6 +245,52 @@ class ProxyStorageService {
305
245
  const res = new ProxyStorageService(service, storage, fields, filters, idName);
306
246
  return res;
307
247
  }
248
+ /**
249
+ * say hello()
250
+ */
251
+ hello = () => `proxy-storage-service:${this.storage.hello()}`;
252
+ /**
253
+ * read by _id
254
+ */
255
+ read = (_id) => this.storage.read(_id);
256
+ /**
257
+ * read multiple models.
258
+ */
259
+ mread = (ids) => this.storage.mread(ids);
260
+ /**
261
+ * read or create by _id
262
+ */
263
+ readOrCreate = (_id, model) => this.storage.readOrCreate(_id, model);
264
+ /**
265
+ * save by _id
266
+ */
267
+ save = (_id, model) => this.storage.save(_id, model);
268
+ /**
269
+ * update by _id
270
+ */
271
+ update = (_id, model, incrementals) => this.storage.update(_id, model, incrementals);
272
+ /**
273
+ * update multiple models.
274
+ */
275
+ mupdate = (list) => this.storage.mupdate(list);
276
+ /**
277
+ * increment by _id
278
+ */
279
+ increment = (_id, model, $update) => this.storage.increment(_id, model, $update);
280
+ /**
281
+ * delete by _id
282
+ */
283
+ delete = (_id) => this.storage.delete(_id);
284
+ /**
285
+ * get key-id by type+id
286
+ */
287
+ asKey = (type, id) => {
288
+ if (typeof this.service.asKey == 'function') {
289
+ return this.service.asKey(type, `${id}`);
290
+ }
291
+ const $key = this.service.asKey$(type, `${id}`);
292
+ return $key[this.idName];
293
+ };
308
294
  /**
309
295
  * get next auto-sequence number.
310
296
  *
@@ -312,43 +298,53 @@ class ProxyStorageService {
312
298
  * @param nextInit (optional) initial next value if not exist.
313
299
  * @param nextStep (optional) the incremental step to get next. (default 1)
314
300
  */
315
- nextSeq(type, nextInit, nextStep = 1) {
316
- return __awaiter(this, void 0, void 0, function* () {
317
- const errScope = `nextSeq(${type !== null && type !== void 0 ? type : ''})`;
318
- (0, engine_1._log)(NS, `${errScope}...`);
319
- if (typeof nextInit === 'number' && nextInit < 0)
320
- throw new Error(`@nextInit[${nextInit}] is invalid - ${errScope}`);
321
- if (typeof nextStep !== 'number' || nextStep < 0)
322
- throw new Error(`@stepNext[${nextStep}] is invalid - ${errScope}`);
323
- const { createdAt, updatedAt } = this.asTime();
324
- const _id = this.asKey(ProxyStorageService.TYPE_SEQUENCE, `${type}`);
325
- const _next = () => __awaiter(this, void 0, void 0, function* () {
326
- // it will create new row if not exists. (like upset)
327
- //TODO - improve the initial `next` if not exits.
328
- const res = yield this.storage.increment(_id, { next: nextStep }, { updatedAt });
329
- if (res.next == 1) {
330
- const $key = this.service.asKey$(ProxyStorageService.TYPE_SEQUENCE, `${type}`);
331
- nextInit = nextInit === undefined || nextInit === null ? ProxyStorageService.AUTO_SEQUENCE : nextInit;
332
- const $upd = { next: nextInit };
333
- const $inc = Object.assign(Object.assign({}, $key), { createdAt, updatedAt });
334
- return this.storage.increment(_id, $upd, $inc); //* increment w/ update-set
335
- }
336
- return res;
337
- });
338
- const res = yield _next();
339
- return res.next;
340
- });
301
+ async nextSeq(type, nextInit, nextStep = 1) {
302
+ const errScope = `nextSeq(${type ?? ''})`;
303
+ (0, engine_1._log)(NS, `${errScope}...`);
304
+ if (typeof nextInit === 'number' && nextInit < 0)
305
+ throw new Error(`@nextInit[${nextInit}] is invalid - ${errScope}`);
306
+ if (typeof nextStep !== 'number' || nextStep < 0)
307
+ throw new Error(`@stepNext[${nextStep}] is invalid - ${errScope}`);
308
+ const { createdAt, updatedAt } = this.asTime();
309
+ const _id = this.asKey(ProxyStorageService.TYPE_SEQUENCE, `${type}`);
310
+ const _next = async () => {
311
+ // it will create new row if not exists. (like upset)
312
+ //TODO - improve the initial `next` if not exits.
313
+ const res = await this.storage.increment(_id, { next: nextStep }, { updatedAt });
314
+ if (res.next == 1) {
315
+ const $key = this.service.asKey$(ProxyStorageService.TYPE_SEQUENCE, `${type}`);
316
+ nextInit = nextInit === undefined || nextInit === null ? ProxyStorageService.AUTO_SEQUENCE : nextInit;
317
+ const $upd = { next: nextInit };
318
+ const $inc = { ...$key, createdAt, updatedAt };
319
+ return this.storage.increment(_id, $upd, $inc); //* increment w/ update-set
320
+ }
321
+ return res;
322
+ };
323
+ const res = await _next();
324
+ return res.next;
341
325
  }
342
326
  /**
343
327
  * get uuid by type.
344
328
  * @param type
345
329
  */
346
- nextUuid(type) {
347
- return __awaiter(this, void 0, void 0, function* () {
348
- (0, engine_1._log)(NS, `nextUuid(${type})..`);
349
- return engine_1.$U.uuid();
350
- });
330
+ async nextUuid(type) {
331
+ (0, engine_1._log)(NS, `nextUuid(${type})..`);
332
+ return engine_1.$U.uuid();
351
333
  }
334
+ /**
335
+ * timer to generate the current-time (msec)
336
+ */
337
+ $timer = null;
338
+ setTimer = (timer) => {
339
+ const previous = this.$timer;
340
+ this.$timer = timer;
341
+ return previous;
342
+ };
343
+ getTime = () => {
344
+ if (this.$timer)
345
+ return this.$timer();
346
+ return new Date().getTime();
347
+ };
352
348
  /**
353
349
  * get time-stamp as now.
354
350
  */
@@ -363,12 +359,10 @@ class ProxyStorageService {
363
359
  * delete sequence-key.
364
360
  * @param type type of seqeunce.
365
361
  */
366
- clearSeq(type) {
367
- return __awaiter(this, void 0, void 0, function* () {
368
- (0, engine_1._log)(NS, `nextSeq(${type})..`);
369
- const _id = this.asKey(ProxyStorageService.TYPE_SEQUENCE, `${type}`);
370
- yield this.storage.delete(_id);
371
- });
362
+ async clearSeq(type) {
363
+ (0, engine_1._log)(NS, `nextSeq(${type})..`);
364
+ const _id = this.asKey(ProxyStorageService.TYPE_SEQUENCE, `${type}`);
365
+ await this.storage.delete(_id);
372
366
  }
373
367
  /**
374
368
  * read model by key + id with optional auto creation.
@@ -377,22 +371,20 @@ class ProxyStorageService {
377
371
  * @param id node-id
378
372
  * @param $create (optional) initial model if not exist. (or throw 404 error)
379
373
  */
380
- doRead(type, id, $create) {
381
- return __awaiter(this, void 0, void 0, function* () {
382
- const $key = this.service.asKey$(type, id);
383
- const _id = this.asKey(type, id);
384
- const model = yield this.storage.read(_id).catch((e) => {
385
- if (`${e.message}`.startsWith('404 NOT FOUND') && $create) {
386
- const { createdAt, updatedAt } = this.asTime();
387
- return this.storage.update(_id, Object.assign(Object.assign(Object.assign({}, $create), $key), { createdAt, updatedAt, deletedAt: 0 }));
388
- }
389
- throw e;
390
- });
391
- //* make sure it has `_id`
392
- model[this.idName] = _id;
393
- const res = this.filters.afterRead(model);
394
- return res;
374
+ async doRead(type, id, $create) {
375
+ const $key = this.service.asKey$(type, id);
376
+ const _id = this.asKey(type, id);
377
+ const model = await this.storage.read(_id).catch((e) => {
378
+ if (`${e.message}`.startsWith('404 NOT FOUND') && $create) {
379
+ const { createdAt, updatedAt } = this.asTime();
380
+ return this.storage.update(_id, { ...$create, ...$key, createdAt, updatedAt, deletedAt: 0 });
381
+ }
382
+ throw e;
395
383
  });
384
+ //* make sure it has `_id`
385
+ model[this.idName] = _id;
386
+ const res = this.filters.afterRead(model);
387
+ return res;
396
388
  }
397
389
  /**
398
390
  * recursively remove undefined values from object.
@@ -433,37 +425,31 @@ class ProxyStorageService {
433
425
  * @param context (optional) next-context for reporting
434
426
  * @returns notify message-id (or error)
435
427
  */
436
- reportBatchError(operation, total, failed, context) {
437
- var _a;
438
- return __awaiter(this, void 0, void 0, function* () {
439
- const totalFailed = (_a = failed === null || failed === void 0 ? void 0 : failed.length) !== null && _a !== void 0 ? _a : 0;
440
- if (totalFailed <= 0)
441
- return;
442
- const successCount = total - totalFailed;
443
- const error = new Error(`Batch ${operation} failed: ${totalFailed}/${total} items`);
444
- const data = {
445
- dt: engine_1.$U.dt(),
446
- total_count: total,
447
- failed_count: totalFailed,
448
- success_count: successCount,
449
- failed_items: failed && Array.isArray(failed)
450
- ? failed
451
- .filter((item) => item != null)
452
- .map((item) => {
453
- var _a, _b;
454
- return ({
455
- 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 : 'unknown',
456
- error: (item === null || item === void 0 ? void 0 : item.error) ? `${item.error}`.substring(0, 100) : 'Unknown error',
457
- });
458
- })
459
- : failed,
460
- context,
461
- };
462
- // report error
463
- return (0, engine_1.doReportError)(error, context, null, data).catch(e => {
464
- (0, engine_1._err)(NS, `! failed to report ${operation} error via SNS:`, e);
465
- return `ERR: ${(0, test_helper_1.GETERR)(e)}`;
466
- });
428
+ async reportBatchError(operation, total, failed, context) {
429
+ const totalFailed = failed?.length ?? 0;
430
+ if (totalFailed <= 0)
431
+ return;
432
+ const successCount = total - totalFailed;
433
+ const error = new Error(`Batch ${operation} failed: ${totalFailed}/${total} items`);
434
+ const data = {
435
+ dt: engine_1.$U.dt(),
436
+ total_count: total,
437
+ failed_count: totalFailed,
438
+ success_count: successCount,
439
+ failed_items: failed && Array.isArray(failed)
440
+ ? failed
441
+ .filter((item) => item != null)
442
+ .map((item) => ({
443
+ id: item?.id ?? item?._id ?? 'unknown',
444
+ error: item?.error ? `${item.error}`.substring(0, 100) : 'Unknown error',
445
+ }))
446
+ : failed,
447
+ context,
448
+ };
449
+ // report error
450
+ return (0, engine_1.doReportError)(error, context, null, data).catch(e => {
451
+ (0, engine_1._err)(NS, `! failed to report ${operation} error via SNS:`, e);
452
+ return `ERR: ${(0, test_helper_1.GETERR)(e)}`;
467
453
  });
468
454
  }
469
455
  /**
@@ -473,30 +459,27 @@ class ProxyStorageService {
473
459
  * @param ids node-ids
474
460
  * @param options (optional) options for batch read error reporting
475
461
  */
476
- doReadMulti(type, ids, options) {
477
- var _a, _b;
478
- return __awaiter(this, void 0, void 0, function* () {
479
- const throwable = (_a = options === null || options === void 0 ? void 0 : options.throwable) !== null && _a !== void 0 ? _a : true;
480
- const total = (_b = ids === null || ids === void 0 ? void 0 : ids.length) !== null && _b !== void 0 ? _b : 0;
481
- const result = { success: [], failed: [], total };
482
- if (!ids || total === 0)
483
- return result;
484
- const _ids = ids.map(id => this.asKey(type, id));
485
- const res = yield this.storage.mread(_ids);
486
- result.success = (res.success || []).map((model) => {
487
- const res = this.filters.afterRead(model);
488
- return res;
489
- });
490
- result.failed = (res.failed || []).map((model) => {
491
- const res = this.filters.afterRead(model);
492
- return res;
493
- });
494
- //* send Slack notification if there are failed items
495
- if (result.failed.length > 0 && throwable) {
496
- yield this.reportBatchError('read', total, result.failed, options === null || options === void 0 ? void 0 : options.context);
497
- }
462
+ async doReadMulti(type, ids, options) {
463
+ const throwable = options?.throwable ?? true;
464
+ const total = ids?.length ?? 0;
465
+ const result = { success: [], failed: [], total };
466
+ if (!ids || total === 0)
498
467
  return result;
468
+ const _ids = ids.map(id => this.asKey(type, id));
469
+ const res = await this.storage.mread(_ids);
470
+ result.success = (res.success || []).map((model) => {
471
+ const res = this.filters.afterRead(model);
472
+ return res;
499
473
  });
474
+ result.failed = (res.failed || []).map((model) => {
475
+ const res = this.filters.afterRead(model);
476
+ return res;
477
+ });
478
+ //* send Slack notification if there are failed items
479
+ if (result.failed.length > 0 && throwable) {
480
+ await this.reportBatchError('read', total, result.failed, options?.context);
481
+ }
482
+ return result;
500
483
  }
501
484
  /**
502
485
  * delete model by id.
@@ -505,18 +488,16 @@ class ProxyStorageService {
505
488
  * @param id node-id
506
489
  * @param destroy flag to destroy (real delete)
507
490
  */
508
- doDelete(type, id, destroy = true) {
509
- return __awaiter(this, void 0, void 0, function* () {
510
- const _id = this.asKey(type, id);
511
- if (destroy === undefined || destroy === true)
512
- return this.storage.delete(_id);
513
- const { createdAt, updatedAt, deletedAt } = this.asTime();
514
- const $up = { updatedAt, deletedAt };
515
- const $org = yield this.read(_id); //* it will make 404 if not found.
516
- if (!$org.createdAt)
517
- $up.createdAt = createdAt;
518
- return this.update(_id, $up);
519
- });
491
+ async doDelete(type, id, destroy = true) {
492
+ const _id = this.asKey(type, id);
493
+ if (destroy === undefined || destroy === true)
494
+ return this.storage.delete(_id);
495
+ const { createdAt, updatedAt, deletedAt } = this.asTime();
496
+ const $up = { updatedAt, deletedAt };
497
+ const $org = await this.read(_id); //* it will make 404 if not found.
498
+ if (!$org.createdAt)
499
+ $up.createdAt = createdAt;
500
+ return this.update(_id, $up);
520
501
  }
521
502
  /**
522
503
  * update model (or it will create automatically)
@@ -527,21 +508,18 @@ class ProxyStorageService {
527
508
  * @param incrementals (optional) fields to increment
528
509
  * @param options (optional) options for update
529
510
  */
530
- doUpdate(type, id, node, incrementals, options) {
531
- var _a;
532
- return __awaiter(this, void 0, void 0, function* () {
533
- const onlyValid = (_a = options === null || options === void 0 ? void 0 : options.onlyValid) !== null && _a !== void 0 ? _a : true;
534
- const $inc = this.removeUndefined(Object.assign({}, incrementals), onlyValid); //* make copy & clean.
535
- const _id = this.asKey(type, id);
536
- // const $key = this.service.asKey$(type, id);
537
- const node2 = this.filters.beforeUpdate(Object.assign(Object.assign({}, node), { [this.idName]: _id }), $inc);
538
- delete node2['_id'];
539
- const { updatedAt } = this.asTime();
540
- // remove undefined values before saving to DynamoDB
541
- const cleaned = this.removeUndefined(Object.assign(Object.assign({}, node2), { updatedAt }), onlyValid);
542
- const model = yield this.update(_id, cleaned, $inc);
543
- return this.filters.afterUpdate(model);
544
- });
511
+ async doUpdate(type, id, node, incrementals, options) {
512
+ const onlyValid = options?.onlyValid ?? true;
513
+ const $inc = this.removeUndefined({ ...incrementals }, onlyValid); //* make copy & clean.
514
+ const _id = this.asKey(type, id);
515
+ // const $key = this.service.asKey$(type, id);
516
+ const node2 = this.filters.beforeUpdate({ ...node, [this.idName]: _id }, $inc);
517
+ delete node2['_id'];
518
+ const { updatedAt } = this.asTime();
519
+ // remove undefined values before saving to DynamoDB
520
+ const cleaned = this.removeUndefined({ ...node2, updatedAt }, onlyValid);
521
+ const model = await this.update(_id, cleaned, $inc);
522
+ return this.filters.afterUpdate(model);
545
523
  }
546
524
  /**
547
525
  * update multiple models (or it will create automatically)
@@ -550,42 +528,39 @@ class ProxyStorageService {
550
528
  * @param list list of models (should include id)
551
529
  * @param options (optional) options for batch update
552
530
  */
553
- doUpdateMulti(type, list, options) {
554
- var _a, _b, _c;
555
- return __awaiter(this, void 0, void 0, function* () {
556
- const onlyValid = (_a = options === null || options === void 0 ? void 0 : options.onlyValid) !== null && _a !== void 0 ? _a : true;
557
- const throwable = (_b = options === null || options === void 0 ? void 0 : options.throwable) !== null && _b !== void 0 ? _b : true;
558
- const total = (_c = list === null || list === void 0 ? void 0 : list.length) !== null && _c !== void 0 ? _c : 0;
559
- const result = { success: [], failed: [], total };
560
- if (!list || total === 0)
561
- return result;
562
- const { updatedAt } = this.asTime();
563
- const items = list.map((node) => {
564
- const id = node.id;
565
- if (!id)
566
- throw new Error('@id is required!');
567
- const _id = this.asKey(type, id);
568
- const node2 = this.filters.beforeUpdate(Object.assign(Object.assign({}, node), { [this.idName]: _id }), undefined);
569
- delete node2['_id'];
570
- // remove undefined values before saving to DynamoDB
571
- const cleaned = this.removeUndefined(Object.assign(Object.assign({}, node2), { [this.idName]: _id, updatedAt }), onlyValid);
572
- return cleaned;
573
- });
574
- const res = yield this.storage.mupdate(items);
575
- result.success = (res.success || []).map((model) => {
576
- const res = this.filters.afterUpdate(model);
577
- return res;
578
- });
579
- result.failed = (res.failed || []).map((model) => {
580
- const res = this.filters.afterUpdate(model);
581
- return res;
582
- });
583
- //* send Slack notification if there are failed items
584
- if (result.failed.length > 0 && throwable) {
585
- yield this.reportBatchError('update', total, result.failed, options === null || options === void 0 ? void 0 : options.context);
586
- }
531
+ async doUpdateMulti(type, list, options) {
532
+ const onlyValid = options?.onlyValid ?? true;
533
+ const throwable = options?.throwable ?? true;
534
+ const total = list?.length ?? 0;
535
+ const result = { success: [], failed: [], total };
536
+ if (!list || total === 0)
587
537
  return result;
538
+ const { updatedAt } = this.asTime();
539
+ const items = list.map((node) => {
540
+ const id = node.id;
541
+ if (!id)
542
+ throw new Error('@id is required!');
543
+ const _id = this.asKey(type, id);
544
+ const node2 = this.filters.beforeUpdate({ ...node, [this.idName]: _id }, undefined);
545
+ delete node2['_id'];
546
+ // remove undefined values before saving to DynamoDB
547
+ const cleaned = this.removeUndefined({ ...node2, [this.idName]: _id, updatedAt }, onlyValid);
548
+ return cleaned;
588
549
  });
550
+ const res = await this.storage.mupdate(items);
551
+ result.success = (res.success || []).map((model) => {
552
+ const res = this.filters.afterUpdate(model);
553
+ return res;
554
+ });
555
+ result.failed = (res.failed || []).map((model) => {
556
+ const res = this.filters.afterUpdate(model);
557
+ return res;
558
+ });
559
+ //* send Slack notification if there are failed items
560
+ if (result.failed.length > 0 && throwable) {
561
+ await this.reportBatchError('update', total, result.failed, options?.context);
562
+ }
563
+ return result;
589
564
  }
590
565
  /**
591
566
  * update model (or it will create automatically)
@@ -593,13 +568,11 @@ class ProxyStorageService {
593
568
  * @param type model-type
594
569
  * @param id node-id
595
570
  */
596
- doIncrement(type, id, $inc, $up) {
597
- return __awaiter(this, void 0, void 0, function* () {
598
- const _id = this.asKey(type, id);
599
- const { updatedAt } = this.asTime();
600
- const model = yield this.increment(_id, Object.assign({}, $inc), Object.assign(Object.assign({}, $up), { updatedAt }));
601
- return this.filters.afterUpdate(model);
602
- });
571
+ async doIncrement(type, id, $inc, $up) {
572
+ const _id = this.asKey(type, id);
573
+ const { updatedAt } = this.asTime();
574
+ const model = await this.increment(_id, { ...$inc }, { ...$up, updatedAt });
575
+ return this.filters.afterUpdate(model);
603
576
  }
604
577
  /**
605
578
  * save model by checking origin node.
@@ -612,44 +585,41 @@ class ProxyStorageService {
612
585
  * @param $create (optional) initial creation model if not found.
613
586
  * @param options (optional) options for save
614
587
  */
615
- doSave(type, id, node, $create, options) {
616
- var _a;
617
- return __awaiter(this, void 0, void 0, function* () {
618
- const onlyValid = (_a = options === null || options === void 0 ? void 0 : options.onlyValid) !== null && _a !== void 0 ? _a : true;
619
- //* read origin model w/o error.
620
- const $org = (yield this.doRead(type, id, null).catch(e => {
621
- if (`${e.message}`.startsWith('404 NOT FOUND'))
622
- return null; // mark null to create later.
623
- throw e;
624
- }));
625
- //* if `$create` is undefined, create it with default $key.
626
- const _id = this.asKey(type, id);
627
- const model = Object.assign({}, node); // copy from param.
628
- model[this.idName] = _id; //* make sure the internal id
629
- //* apply filter.
630
- const $ups = this.filters.beforeSave(model, $org); //* `$org` should be null if create.
631
- (0, engine_1._log)(NS, `> ${type}[${id}].update =`, engine_1.$U.json($ups));
632
- //* if null, then nothing to update.
633
- if (!$ups) {
634
- const res = { [this.idName]: _id };
635
- return res;
636
- }
637
- //* determine of create or update.
638
- const { createdAt, updatedAt } = this.asTime();
639
- if ($org) {
640
- const $save = Object.assign(Object.assign({}, $ups), { updatedAt });
641
- const res = yield this.doUpdate(type, id, $save, undefined, { onlyValid });
642
- return this.filters.afterSave(res, $org); //* `$org` should be valid if update.
643
- }
644
- else {
645
- const $key = this.service.asKey$(type, id);
646
- const $save = Object.assign(Object.assign(Object.assign(Object.assign({}, $ups), $create), $key), { createdAt, updatedAt: createdAt, deletedAt: 0 });
647
- // remove undefined values before saving to DynamoDB
648
- const cleaned = this.removeUndefined($save, onlyValid);
649
- const res = yield this.storage.save(_id, cleaned);
650
- return this.filters.afterSave(res, null); //* `$org` should be null if create.
651
- }
652
- });
588
+ async doSave(type, id, node, $create, options) {
589
+ const onlyValid = options?.onlyValid ?? true;
590
+ //* read origin model w/o error.
591
+ const $org = (await this.doRead(type, id, null).catch(e => {
592
+ if (`${e.message}`.startsWith('404 NOT FOUND'))
593
+ return null; // mark null to create later.
594
+ throw e;
595
+ }));
596
+ //* if `$create` is undefined, create it with default $key.
597
+ const _id = this.asKey(type, id);
598
+ const model = { ...node }; // copy from param.
599
+ model[this.idName] = _id; //* make sure the internal id
600
+ //* apply filter.
601
+ const $ups = this.filters.beforeSave(model, $org); //* `$org` should be null if create.
602
+ (0, engine_1._log)(NS, `> ${type}[${id}].update =`, engine_1.$U.json($ups));
603
+ //* if null, then nothing to update.
604
+ if (!$ups) {
605
+ const res = { [this.idName]: _id };
606
+ return res;
607
+ }
608
+ //* determine of create or update.
609
+ const { createdAt, updatedAt } = this.asTime();
610
+ if ($org) {
611
+ const $save = { ...$ups, updatedAt };
612
+ const res = await this.doUpdate(type, id, $save, undefined, { onlyValid });
613
+ return this.filters.afterSave(res, $org); //* `$org` should be valid if update.
614
+ }
615
+ else {
616
+ const $key = this.service.asKey$(type, id);
617
+ const $save = { ...$ups, ...$create, ...$key, createdAt, updatedAt: createdAt, deletedAt: 0 };
618
+ // remove undefined values before saving to DynamoDB
619
+ const cleaned = this.removeUndefined($save, onlyValid);
620
+ const res = await this.storage.save(_id, cleaned);
621
+ return this.filters.afterSave(res, null); //* `$org` should be null if create.
622
+ }
653
623
  }
654
624
  /**
655
625
  * lock data-entry by type+id w/ limited time tick
@@ -662,56 +632,52 @@ class ProxyStorageService {
662
632
  * @param tick tick count to wait.
663
633
  * @param interval timeout interval per each tick (in msec, default 1000 = 1sec)
664
634
  */
665
- doLock(type, id, tick, interval) {
666
- return __awaiter(this, void 0, void 0, function* () {
667
- tick = engine_1.$U.N(tick, 30);
668
- interval = engine_1.$U.N(interval, 1000);
669
- if (typeof tick != 'number' || tick < 0)
670
- throw new Error(`@tick (${tick}) is not valid!`);
671
- if (typeof interval != 'number' || interval < 1)
672
- throw new Error(`@interval (${interval}) is not valid!`);
673
- const _id = this.asKey(type, id);
674
- //* WARN! DO NOT MAKE ANY MODEL CREATION IN HERE.
675
- // const $org = await this.storage.readOrCreate(_id, { lock: 0, ...$key } as any);
676
- // _log(NS, `> $org[${type}/${id}].lock =`, $org.lock);
677
- const thiz = this;
678
- //* wait some time.
679
- const wait = (timeout) => __awaiter(this, void 0, void 0, function* () {
680
- return new Promise(resolve => {
681
- setTimeout(() => {
682
- resolve(timeout);
683
- }, timeout);
684
- });
685
- });
686
- const incLock = (_id, lock) => __awaiter(this, void 0, void 0, function* () {
687
- const $up = {};
688
- const $in = { lock };
689
- return thiz.storage.update(_id, $up, $in).then($t2 => {
690
- return engine_1.$U.N($t2.lock, 1);
691
- });
635
+ async doLock(type, id, tick, interval) {
636
+ tick = engine_1.$U.N(tick, 30);
637
+ interval = engine_1.$U.N(interval, 1000);
638
+ if (typeof tick != 'number' || tick < 0)
639
+ throw new Error(`@tick (${tick}) is not valid!`);
640
+ if (typeof interval != 'number' || interval < 1)
641
+ throw new Error(`@interval (${interval}) is not valid!`);
642
+ const _id = this.asKey(type, id);
643
+ //* WARN! DO NOT MAKE ANY MODEL CREATION IN HERE.
644
+ // const $org = await this.storage.readOrCreate(_id, { lock: 0, ...$key } as any);
645
+ // _log(NS, `> $org[${type}/${id}].lock =`, $org.lock);
646
+ const thiz = this;
647
+ //* wait some time.
648
+ const wait = async (timeout) => new Promise(resolve => {
649
+ setTimeout(() => {
650
+ resolve(timeout);
651
+ }, timeout);
652
+ });
653
+ const incLock = async (_id, lock) => {
654
+ const $up = {};
655
+ const $in = { lock };
656
+ return thiz.storage.update(_id, $up, $in).then($t2 => {
657
+ return engine_1.$U.N($t2.lock, 1);
692
658
  });
693
- //* recursive to wait lock()
694
- const waitLock = (_id, ttl, int) => __awaiter(this, void 0, void 0, function* () {
695
- //* try to check the current value.....
696
- const lock = yield incLock(_id, 0).then(n => {
697
- if (n > 1)
698
- return n;
699
- //* then, try to increment the lock
700
- return incLock(_id, ttl > 0 ? 1 : 0);
701
- });
702
- (0, engine_1._log)(NS, `! waitLock(${_id}, ${ttl}). lock =`, lock);
703
- if (lock == 1 || lock == 0) {
704
- return true;
705
- }
706
- else if (ttl > 0 && lock > 1) {
707
- return wait(int).then(() => waitLock(_id, ttl - 1, int));
708
- }
709
- else {
710
- throw new Error(`400 TIMEOUT - model[${_id}].lock = ${lock}`);
711
- }
659
+ };
660
+ //* recursive to wait lock()
661
+ const waitLock = async (_id, ttl, int) => {
662
+ //* try to check the current value.....
663
+ const lock = await incLock(_id, 0).then(n => {
664
+ if (n > 1)
665
+ return n;
666
+ //* then, try to increment the lock
667
+ return incLock(_id, ttl > 0 ? 1 : 0);
712
668
  });
713
- return waitLock(_id, tick, interval);
714
- });
669
+ (0, engine_1._log)(NS, `! waitLock(${_id}, ${ttl}). lock =`, lock);
670
+ if (lock == 1 || lock == 0) {
671
+ return true;
672
+ }
673
+ else if (ttl > 0 && lock > 1) {
674
+ return wait(int).then(() => waitLock(_id, ttl - 1, int));
675
+ }
676
+ else {
677
+ throw new Error(`400 TIMEOUT - model[${_id}].lock = ${lock}`);
678
+ }
679
+ };
680
+ return waitLock(_id, tick, interval);
715
681
  }
716
682
  /**
717
683
  * release lock by resetting lock = 0.
@@ -719,15 +685,13 @@ class ProxyStorageService {
719
685
  * @param type model-type
720
686
  * @param id model-id
721
687
  */
722
- doRelease(type, id) {
723
- return __awaiter(this, void 0, void 0, function* () {
724
- (0, engine_1._log)(NS, `doRelease(${type}, ${id})... `);
725
- const _id = this.asKey(type, id);
726
- const $up = { lock: 0 };
727
- const node = yield this.storage.update(_id, $up).catch(() => ({ lock: 0 }));
728
- const lock = engine_1.$U.N(node.lock, 1);
729
- return lock === 0 ? true : false;
730
- });
688
+ async doRelease(type, id) {
689
+ (0, engine_1._log)(NS, `doRelease(${type}, ${id})... `);
690
+ const _id = this.asKey(type, id);
691
+ const $up = { lock: 0 };
692
+ const node = await this.storage.update(_id, $up).catch(() => ({ lock: 0 }));
693
+ const lock = engine_1.$U.N(node.lock, 1);
694
+ return lock === 0 ? true : false;
731
695
  }
732
696
  /**
733
697
  * create storage-service w/ fields list.
@@ -771,178 +735,178 @@ class ProxyStorageService {
771
735
  }
772
736
  }
773
737
  exports.ProxyStorageService = ProxyStorageService;
774
- ProxyStorageService.AUTO_SEQUENCE = 1000000;
775
- ProxyStorageService.TYPE_SEQUENCE = 'sequence';
776
738
  /**
777
739
  * class: `TypedStorageService`
778
740
  * - wrap id with type + id.
779
741
  */
780
742
  // eslint-disable-next-line prettier/prettier
781
743
  class TypedStorageService {
744
+ type;
745
+ storage;
782
746
  constructor(service, type) {
783
- /**
784
- * show self service name
785
- */
786
- this.hello = () => `typed-storage-service:${this.type}/${this.storage.hello()}`;
787
- /**
788
- * get next auto-sequence id in number like `1000003`.
789
- *
790
- * @param step (optional) next step value (must be >0) (`0` means getting the current value)
791
- */
792
- this.nextId = (step) => {
793
- return this.storage.nextSeq(this.type, undefined, step);
794
- };
795
- /**
796
- * get uuid like `d01764cd-9ef2-41e2-9e88-68e79555c979`
797
- */
798
- this.nextUuid = () => this.storage.nextUuid(this.type);
799
- /**
800
- * read model by key + id with optional auto creation.
801
- * - throws '404 NOT FOUND' if not found.
802
- *
803
- * @param id node-id
804
- */
805
- this.read = (id) => this.storage.doRead(this.type, `${id || ''}`);
806
- /**
807
- * read multiple models (batch).
808
- *
809
- * @param ids list of node-id
810
- * @param options (optional) options for batch read error reporting
811
- */
812
- this.mread = (ids, options) => this.storage.doReadMulti(this.type, ids, options);
813
- /**
814
- * read model by key + id with optional auto creation.
815
- *
816
- * @param id node-id
817
- * @param model initial model if not exist. (or throw 404 error)
818
- */
819
- this.readOrCreate = (id, model) => this.storage.doRead(this.type, `${id || ''}`, model);
820
- /**
821
- * update model (or it will create automatically)
822
- *
823
- * @param id node-id
824
- * @param model model to update
825
- * @param incrementals (optional) fields to increment.
826
- * @param options (optional) options for update
827
- */
828
- this.update = (id, model, incrementals, options) => this.storage.doUpdate(this.type, `${id || ''}`, model, incrementals, options);
829
- /**
830
- * update multiple models in batch (or it will create automatically)
831
- * - automatically removes undefined values (DynamoDB does not support undefined)
832
- *
833
- * @param list list of models (should include id)
834
- * @param options (optional) options for batch update error reporting
835
- */
836
- this.mupdate = (list, options) => this.storage.doUpdateMulti(this.type, list, options);
837
- /**
838
- * insert model w/ auto generated id
839
- *
840
- * @param model model to insert
841
- */
842
- this.insert = (node) => __awaiter(this, void 0, void 0, function* () {
843
- return this.nextId().then(_ => {
844
- const id = `${_}`;
845
- (0, engine_1._log)(NS, `> next-id[${this.type}] =`, id);
846
- return this.readOrCreate(id, Object.assign(Object.assign({}, node), { id }));
847
- });
848
- });
849
- /**
850
- * update model (or it will create automatically)
851
- *
852
- * ```ts
853
- * //before: { count: 1 };
854
- * const res = await storage.increment(1, { count: 2 }, { total: 2 });
855
- * //after : { count: 3, total: 2 }
856
- * ```
857
- *
858
- * @param id node-id
859
- * @param $increments model only with numbers
860
- */
861
- this.increment = (id, $increments, $update) => this.storage.doIncrement(this.type, `${id || ''}`, $increments, $update);
862
- /**
863
- * delete model by id.
864
- *
865
- * @param id node-id
866
- * @param destroy flag to destroy (real delete)
867
- */
868
- this.delete = (id, destroy) => this.storage.doDelete(this.type, `${id || ''}`, destroy === undefined ? true : destroy);
869
- /**
870
- * save model by checking origin node.
871
- * - use `doSave()` rather than `doUpdate()` for both create & update.
872
- * - if `$create` is null, throw 404 error it if not found.
873
- *
874
- * @param id node-id
875
- * @param node node to save (or update)
876
- * @param $create (optional) initial creation model.
877
- */
878
- this.save = (id, model, $create) => this.storage.doSave(this.type, `${id || ''}`, model, $create);
879
- /**
880
- * lock data-entry by type+id w/ limited time tick
881
- * - WARN! must release lock by `release(id)`
882
- *
883
- * `total-waited-time = tick * interval (msec)`
884
- *
885
- * **[UPDATES]**
886
- * 1. read original node (or, throw 404 error)
887
- * 2. use internal lock.
888
- *
889
- * @param id model-id to lock
890
- * @param tick tick count to wait.
891
- * @param interval timeout interval per each tick (in msec, default 1000 = 1sec)
892
- */
893
- this.lock = (id, tick, interval) => this.storage
894
- .doRead(this.type, `${id || ''}`, null)
895
- .then(node => this.storage.doLock(this.type, node.id, tick, interval));
896
- /**
897
- * release lock by resetting lock = 0.
898
- * @param id model-id
899
- */
900
- this.release = (id) => this.storage.doRelease(this.type, `${id || ''}`);
901
- /**
902
- * using `lock()`, guard func with auto lock & release.
903
- *
904
- * ```ts
905
- * const res = await storage.guard(async ()=>{
906
- * return 'abc';
907
- * });
908
- * // res === 'abc'
909
- * ```
910
- */
911
- this.guard = (id, handler, tick, interval) => __awaiter(this, void 0, void 0, function* () {
912
- let locked = false;
913
- return this.lock(id, tick, interval)
914
- .then((_) => {
915
- locked = _;
916
- try {
917
- return handler();
918
- }
919
- catch (e) {
920
- return Promise.reject(e);
921
- }
922
- })
923
- .then((_) => {
924
- if (locked)
925
- return this.release(id).then(() => _);
926
- return _;
927
- })
928
- .catch((e) => {
929
- if (locked)
930
- return this.release(id).then(() => Promise.reject(e));
931
- // throw e;
932
- return Promise.reject(e);
933
- });
934
- });
935
- /**
936
- * make `UniqueFieldManager` for field.
937
- */
938
- this.makeUniqueFieldManager = (field) => new UniqueFieldManager(this, field);
939
- /**
940
- * make `GeneralAPIController` for REST API w/ supporting basic CRUD
941
- */
942
- this.makeGeneralAPIController = (search, uniqueField) => new general_api_controller_1.GeneralAPIController(this.type, this, search, uniqueField);
943
747
  this.storage = service;
944
748
  this.type = type;
945
749
  }
750
+ /**
751
+ * show self service name
752
+ */
753
+ hello = () => `typed-storage-service:${this.type}/${this.storage.hello()}`;
754
+ /**
755
+ * get next auto-sequence id in number like `1000003`.
756
+ *
757
+ * @param step (optional) next step value (must be >0) (`0` means getting the current value)
758
+ */
759
+ nextId = (step) => {
760
+ return this.storage.nextSeq(this.type, undefined, step);
761
+ };
762
+ /**
763
+ * get uuid like `d01764cd-9ef2-41e2-9e88-68e79555c979`
764
+ */
765
+ nextUuid = () => this.storage.nextUuid(this.type);
766
+ /**
767
+ * read model by key + id with optional auto creation.
768
+ * - throws '404 NOT FOUND' if not found.
769
+ *
770
+ * @param id node-id
771
+ */
772
+ read = (id) => this.storage.doRead(this.type, `${id || ''}`);
773
+ /**
774
+ * read multiple models (batch).
775
+ *
776
+ * @param ids list of node-id
777
+ * @param options (optional) options for batch read error reporting
778
+ */
779
+ mread = (ids, options) => this.storage.doReadMulti(this.type, ids, options);
780
+ /**
781
+ * read model by key + id with optional auto creation.
782
+ *
783
+ * @param id node-id
784
+ * @param model initial model if not exist. (or throw 404 error)
785
+ */
786
+ readOrCreate = (id, model) => this.storage.doRead(this.type, `${id || ''}`, model);
787
+ /**
788
+ * update model (or it will create automatically)
789
+ *
790
+ * @param id node-id
791
+ * @param model model to update
792
+ * @param incrementals (optional) fields to increment.
793
+ * @param options (optional) options for update
794
+ */
795
+ update = (id, model, incrementals, options) => this.storage.doUpdate(this.type, `${id || ''}`, model, incrementals, options);
796
+ /**
797
+ * update multiple models in batch (or it will create automatically)
798
+ * - automatically removes undefined values (DynamoDB does not support undefined)
799
+ *
800
+ * @param list list of models (should include id)
801
+ * @param options (optional) options for batch update error reporting
802
+ */
803
+ mupdate = (list, options) => this.storage.doUpdateMulti(this.type, list, options);
804
+ /**
805
+ * insert model w/ auto generated id
806
+ *
807
+ * @param model model to insert
808
+ */
809
+ insert = async (node) => {
810
+ return this.nextId().then(_ => {
811
+ const id = `${_}`;
812
+ (0, engine_1._log)(NS, `> next-id[${this.type}] =`, id);
813
+ return this.readOrCreate(id, { ...node, id });
814
+ });
815
+ };
816
+ /**
817
+ * update model (or it will create automatically)
818
+ *
819
+ * ```ts
820
+ * //before: { count: 1 };
821
+ * const res = await storage.increment(1, { count: 2 }, { total: 2 });
822
+ * //after : { count: 3, total: 2 }
823
+ * ```
824
+ *
825
+ * @param id node-id
826
+ * @param $increments model only with numbers
827
+ */
828
+ increment = (id, $increments, $update) => this.storage.doIncrement(this.type, `${id || ''}`, $increments, $update);
829
+ /**
830
+ * delete model by id.
831
+ *
832
+ * @param id node-id
833
+ * @param destroy flag to destroy (real delete)
834
+ */
835
+ delete = (id, destroy) => this.storage.doDelete(this.type, `${id || ''}`, destroy === undefined ? true : destroy);
836
+ /**
837
+ * save model by checking origin node.
838
+ * - use `doSave()` rather than `doUpdate()` for both create & update.
839
+ * - if `$create` is null, throw 404 error it if not found.
840
+ *
841
+ * @param id node-id
842
+ * @param node node to save (or update)
843
+ * @param $create (optional) initial creation model.
844
+ */
845
+ save = (id, model, $create) => this.storage.doSave(this.type, `${id || ''}`, model, $create);
846
+ /**
847
+ * lock data-entry by type+id w/ limited time tick
848
+ * - WARN! must release lock by `release(id)`
849
+ *
850
+ * `total-waited-time = tick * interval (msec)`
851
+ *
852
+ * **[UPDATES]**
853
+ * 1. read original node (or, throw 404 error)
854
+ * 2. use internal lock.
855
+ *
856
+ * @param id model-id to lock
857
+ * @param tick tick count to wait.
858
+ * @param interval timeout interval per each tick (in msec, default 1000 = 1sec)
859
+ */
860
+ lock = (id, tick, interval) => this.storage
861
+ .doRead(this.type, `${id || ''}`, null)
862
+ .then(node => this.storage.doLock(this.type, node.id, tick, interval));
863
+ /**
864
+ * release lock by resetting lock = 0.
865
+ * @param id model-id
866
+ */
867
+ release = (id) => this.storage.doRelease(this.type, `${id || ''}`);
868
+ /**
869
+ * using `lock()`, guard func with auto lock & release.
870
+ *
871
+ * ```ts
872
+ * const res = await storage.guard(async ()=>{
873
+ * return 'abc';
874
+ * });
875
+ * // res === 'abc'
876
+ * ```
877
+ */
878
+ guard = async (id, handler, tick, interval) => {
879
+ let locked = false;
880
+ return this.lock(id, tick, interval)
881
+ .then((_) => {
882
+ locked = _;
883
+ try {
884
+ return handler();
885
+ }
886
+ catch (e) {
887
+ return Promise.reject(e);
888
+ }
889
+ })
890
+ .then((_) => {
891
+ if (locked)
892
+ return this.release(id).then(() => _);
893
+ return _;
894
+ })
895
+ .catch((e) => {
896
+ if (locked)
897
+ return this.release(id).then(() => Promise.reject(e));
898
+ // throw e;
899
+ return Promise.reject(e);
900
+ });
901
+ };
902
+ /**
903
+ * make `UniqueFieldManager` for field.
904
+ */
905
+ makeUniqueFieldManager = (field) => new UniqueFieldManager(this, field);
906
+ /**
907
+ * make `GeneralAPIController` for REST API w/ supporting basic CRUD
908
+ */
909
+ makeGeneralAPIController = (search, uniqueField) => new general_api_controller_1.GeneralAPIController(this.type, this, search, uniqueField);
946
910
  }
947
911
  exports.TypedStorageService = TypedStorageService;
948
912
  /**
@@ -950,43 +914,43 @@ exports.TypedStorageService = TypedStorageService;
950
914
  * - Helper functions for model.
951
915
  */
952
916
  class ModelUtil {
917
+ static selfRead = (self, key, defValue) => {
918
+ const value = self[key];
919
+ return value === undefined ? defValue : value;
920
+ };
921
+ static selfPop = (self, key, defValue) => {
922
+ const value = ModelUtil.selfRead(self, key, defValue);
923
+ delete self[key];
924
+ return value;
925
+ };
926
+ /**
927
+ * attach `.pop()` method to object.
928
+ *
929
+ * ```js
930
+ * const data = CoreModelUtil.buildPop({'a':1});
931
+ * assert( 1 === data.pop('a) );
932
+ * const final = data.pop();
933
+ * assert( final == data );
934
+ */
935
+ static buildPop = (thiz, popName = 'pop') => {
936
+ if (!thiz)
937
+ throw new Error('@thiz (object) is required!');
938
+ if (typeof thiz[popName] != 'undefined')
939
+ throw new Error(`.[${popName}] is duplicated!`);
940
+ thiz[popName] = function (key, defValue) {
941
+ if (!key) {
942
+ //* clear pop() if key is null.
943
+ delete this[popName];
944
+ return this;
945
+ }
946
+ else {
947
+ return ModelUtil.selfPop(this, key, defValue);
948
+ }
949
+ };
950
+ return thiz;
951
+ };
953
952
  }
954
953
  exports.ModelUtil = ModelUtil;
955
- ModelUtil.selfRead = (self, key, defValue) => {
956
- const value = self[key];
957
- return value === undefined ? defValue : value;
958
- };
959
- ModelUtil.selfPop = (self, key, defValue) => {
960
- const value = ModelUtil.selfRead(self, key, defValue);
961
- delete self[key];
962
- return value;
963
- };
964
- /**
965
- * attach `.pop()` method to object.
966
- *
967
- * ```js
968
- * const data = CoreModelUtil.buildPop({'a':1});
969
- * assert( 1 === data.pop('a) );
970
- * const final = data.pop();
971
- * assert( final == data );
972
- */
973
- ModelUtil.buildPop = (thiz, popName = 'pop') => {
974
- if (!thiz)
975
- throw new Error('@thiz (object) is required!');
976
- if (typeof thiz[popName] != 'undefined')
977
- throw new Error(`.[${popName}] is duplicated!`);
978
- thiz[popName] = function (key, defValue) {
979
- if (!key) {
980
- //* clear pop() if key is null.
981
- delete this[popName];
982
- return this;
983
- }
984
- else {
985
- return ModelUtil.selfPop(this, key, defValue);
986
- }
987
- };
988
- return thiz;
989
- };
990
954
  /**
991
955
  * class: `UniqueFieldManager`
992
956
  * - support `.{field}` is unique in typed-storage-service.
@@ -996,12 +960,15 @@ ModelUtil.buildPop = (thiz, popName = 'pop') => {
996
960
  * - set `.meta` as origin id.
997
961
  */
998
962
  class UniqueFieldManager {
963
+ type;
964
+ field;
965
+ storage;
999
966
  constructor(storage, field = 'name') {
1000
- this.hello = () => `unique-field-manager:${this.type}/${this.field}:${this.storage.hello()}`;
1001
967
  this.type = storage.type;
1002
968
  this.storage = storage;
1003
969
  this.field = field;
1004
970
  }
971
+ hello = () => `unique-field-manager:${this.type}/${this.field}:${this.storage.hello()}`;
1005
972
  /**
1006
973
  * validate value format
1007
974
  * - just check empty string.
@@ -1026,51 +993,49 @@ class UniqueFieldManager {
1026
993
  * @param value unique value in same type group.
1027
994
  * @param $creates (optional) create-set if not found.
1028
995
  */
1029
- findOrCreate(value, $creates) {
1030
- return __awaiter(this, void 0, void 0, function* () {
1031
- if (!value || typeof value != 'string')
1032
- throw new Error(`@${this.field} (string) is required!`);
1033
- if (!this.validate(value))
1034
- throw new Error(`@${this.field} (${value || ''}) is not valid!`);
1035
- const ID = this.asLookupId(value);
1036
- const field = `${this.field}`;
1037
- if (!$creates) {
1038
- // STEP.1 read the origin name map
1039
- const $map = yield this.storage.read(ID).catch(test_helper_1.NUL404);
1040
- const rid = $map && $map.meta;
1041
- if (!rid)
1042
- throw new Error(`404 NOT FOUND - ${this.type}:${field}/${value}`);
1043
- // STEP.2 read the target node by stereo key.
1044
- const model = yield this.storage.read(rid);
1045
- return model;
1046
- }
1047
- else {
1048
- // STEP.0 validate if value is same
1049
- const $any = $creates || {};
1050
- if ($any[field] !== undefined && $any[field] !== value)
1051
- throw new Error(`@${this.field} (${value}) is not same as (${$any[field]})!`);
1052
- // STEP.1 read the origin value map
1053
- const $new = { stereo: '#', meta: `${$creates.id || ''}`, [field]: value };
1054
- const $map = yield this.storage.readOrCreate(ID, $new);
1055
- const rid = ($map && $map.meta) || $creates.id;
1056
- //* check if already saved, and id is differ.
1057
- if ($any['id'] && $any['id'] != rid)
1058
- throw new Error(`@id (${rid}) is not same as (${$any['id']})`);
1059
- // STEP.2 read the target node or create.
1060
- const $temp = Object.assign(Object.assign({}, $creates), { [field]: value });
1061
- const model = rid ? yield this.storage.readOrCreate(rid, $temp) : yield this.storage.insert($temp);
1062
- model[field] = value;
1063
- // STEP.3 update lookup key.
1064
- const newId = `${rid || model.id || ''}`;
1065
- if ($map.meta != newId) {
1066
- const $upt = { meta: newId };
1067
- yield this.storage.update(ID, $upt);
1068
- $map.meta = newId;
1069
- }
1070
- //* returns.
1071
- return model;
996
+ async findOrCreate(value, $creates) {
997
+ if (!value || typeof value != 'string')
998
+ throw new Error(`@${this.field} (string) is required!`);
999
+ if (!this.validate(value))
1000
+ throw new Error(`@${this.field} (${value || ''}) is not valid!`);
1001
+ const ID = this.asLookupId(value);
1002
+ const field = `${this.field}`;
1003
+ if (!$creates) {
1004
+ // STEP.1 read the origin name map
1005
+ const $map = await this.storage.read(ID).catch(test_helper_1.NUL404);
1006
+ const rid = $map && $map.meta;
1007
+ if (!rid)
1008
+ throw new Error(`404 NOT FOUND - ${this.type}:${field}/${value}`);
1009
+ // STEP.2 read the target node by stereo key.
1010
+ const model = await this.storage.read(rid);
1011
+ return model;
1012
+ }
1013
+ else {
1014
+ // STEP.0 validate if value is same
1015
+ const $any = $creates || {};
1016
+ if ($any[field] !== undefined && $any[field] !== value)
1017
+ throw new Error(`@${this.field} (${value}) is not same as (${$any[field]})!`);
1018
+ // STEP.1 read the origin value map
1019
+ const $new = { stereo: '#', meta: `${$creates.id || ''}`, [field]: value };
1020
+ const $map = await this.storage.readOrCreate(ID, $new);
1021
+ const rid = ($map && $map.meta) || $creates.id;
1022
+ //* check if already saved, and id is differ.
1023
+ if ($any['id'] && $any['id'] != rid)
1024
+ throw new Error(`@id (${rid}) is not same as (${$any['id']})`);
1025
+ // STEP.2 read the target node or create.
1026
+ const $temp = { ...$creates, [field]: value };
1027
+ const model = rid ? await this.storage.readOrCreate(rid, $temp) : await this.storage.insert($temp);
1028
+ model[field] = value;
1029
+ // STEP.3 update lookup key.
1030
+ const newId = `${rid || model.id || ''}`;
1031
+ if ($map.meta != newId) {
1032
+ const $upt = { meta: newId };
1033
+ await this.storage.update(ID, $upt);
1034
+ $map.meta = newId;
1072
1035
  }
1073
- });
1036
+ //* returns.
1037
+ return model;
1038
+ }
1074
1039
  }
1075
1040
  /**
1076
1041
  * update lookup table (or create)
@@ -1078,26 +1043,24 @@ class UniqueFieldManager {
1078
1043
  * @param model target model
1079
1044
  * @param value (optional) new value of model.
1080
1045
  */
1081
- updateLookup(model, value) {
1082
- return __awaiter(this, void 0, void 0, function* () {
1083
- value = value || model[this.field];
1084
- if (!this.validate(value))
1085
- throw new Error(`@${this.field} (${value || ''}) is not valid!`);
1086
- const ID = this.asLookupId(value);
1087
- const field = `${this.field}`;
1088
- // STEP.0 validate if value has changed
1089
- const $any = model;
1090
- if ($any[field] && $any[field] !== value)
1091
- throw new Error(`@${this.field} (${value}) is not same as (${$any[field]})!`);
1092
- // STEP.1 check if value is duplicated.
1093
- const $org = yield this.storage.read(ID).catch(test_helper_1.NUL404);
1094
- const rid = $org && $org.meta;
1095
- if ($org && rid != model.id)
1096
- throw new Error(`400 DUPLICATED NAME - ${field}[${value}] is duplicated to ${this.type}[${rid}]`);
1097
- // STEP.2 save the name mapping.
1098
- const $new = Object.assign(Object.assign({}, model), { [field]: value, id: model.id });
1099
- return yield this.findOrCreate(value, $new);
1100
- });
1046
+ async updateLookup(model, value) {
1047
+ value = value || model[this.field];
1048
+ if (!this.validate(value))
1049
+ throw new Error(`@${this.field} (${value || ''}) is not valid!`);
1050
+ const ID = this.asLookupId(value);
1051
+ const field = `${this.field}`;
1052
+ // STEP.0 validate if value has changed
1053
+ const $any = model;
1054
+ if ($any[field] && $any[field] !== value)
1055
+ throw new Error(`@${this.field} (${value}) is not same as (${$any[field]})!`);
1056
+ // STEP.1 check if value is duplicated.
1057
+ const $org = await this.storage.read(ID).catch(test_helper_1.NUL404);
1058
+ const rid = $org && $org.meta;
1059
+ if ($org && rid != model.id)
1060
+ throw new Error(`400 DUPLICATED NAME - ${field}[${value}] is duplicated to ${this.type}[${rid}]`);
1061
+ // STEP.2 save the name mapping.
1062
+ const $new = { ...model, [field]: value, id: model.id };
1063
+ return await this.findOrCreate(value, $new);
1101
1064
  }
1102
1065
  }
1103
1066
  exports.UniqueFieldManager = UniqueFieldManager;