lemon-core 4.1.15 → 4.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/common/test-helper.d.ts +2 -2
- package/dist/common/test-helper.js +24 -26
- package/dist/common/test-helper.js.map +1 -1
- package/dist/controllers/dummy-controller.js +39 -46
- package/dist/controllers/dummy-controller.js.map +1 -1
- package/dist/controllers/general-api-controller.js +95 -100
- package/dist/controllers/general-api-controller.js.map +1 -1
- package/dist/controllers/general-controller.js +81 -82
- package/dist/controllers/general-controller.js.map +1 -1
- package/dist/cores/api/api-service.d.ts +1 -1
- package/dist/cores/api/api-service.js +228 -269
- package/dist/cores/api/api-service.js.map +1 -1
- package/dist/cores/aws/aws-kms-service.d.ts +1 -2
- package/dist/cores/aws/aws-kms-service.js +143 -153
- package/dist/cores/aws/aws-kms-service.js.map +1 -1
- package/dist/cores/aws/aws-s3-service.d.ts +2 -4
- package/dist/cores/aws/aws-s3-service.js +306 -330
- package/dist/cores/aws/aws-s3-service.js.map +1 -1
- package/dist/cores/aws/aws-sns-service.js +147 -153
- package/dist/cores/aws/aws-sns-service.js.map +1 -1
- package/dist/cores/aws/aws-sqs-service.js +149 -170
- package/dist/cores/aws/aws-sqs-service.js.map +1 -1
- package/dist/cores/aws/index.js +10 -20
- package/dist/cores/aws/index.js.map +1 -1
- package/dist/cores/cache/cache-service.d.ts +2 -2
- package/dist/cores/cache/cache-service.js +435 -499
- package/dist/cores/cache/cache-service.js.map +1 -1
- package/dist/cores/config/config-service.d.ts +1 -1
- package/dist/cores/config/config-service.js +56 -63
- package/dist/cores/config/config-service.js.map +1 -1
- package/dist/cores/config/index.js +14 -24
- package/dist/cores/config/index.js.map +1 -1
- package/dist/cores/core-services.d.ts +1 -1
- package/dist/cores/dynamo/dynamo-query-service.js +37 -51
- package/dist/cores/dynamo/dynamo-query-service.js.map +1 -1
- package/dist/cores/dynamo/dynamo-scan-service.d.ts +2 -2
- package/dist/cores/dynamo/dynamo-scan-service.js +29 -40
- package/dist/cores/dynamo/dynamo-scan-service.js.map +1 -1
- package/dist/cores/dynamo/dynamo-service.d.ts +3 -3
- package/dist/cores/dynamo/dynamo-service.js +540 -605
- package/dist/cores/dynamo/dynamo-service.js.map +1 -1
- package/dist/cores/dynamo/tools/expressions.js +17 -7
- package/dist/cores/dynamo/tools/expressions.js.map +1 -1
- package/dist/cores/dynamo/tools/query.js +142 -127
- package/dist/cores/dynamo/tools/query.js.map +1 -1
- package/dist/cores/dynamo/tools/scan.js +111 -97
- package/dist/cores/dynamo/tools/scan.js.map +1 -1
- package/dist/cores/dynamo/tools/serializer.js +17 -7
- package/dist/cores/dynamo/tools/serializer.js.map +1 -1
- package/dist/cores/dynamo/tools/utils.d.ts +0 -2
- package/dist/cores/dynamo/tools/utils.js.map +1 -1
- package/dist/cores/elastic/elastic6-query-service.js +307 -324
- package/dist/cores/elastic/elastic6-query-service.js.map +1 -1
- package/dist/cores/elastic/elastic6-service.d.ts +3 -3
- package/dist/cores/elastic/elastic6-service.js +568 -647
- package/dist/cores/elastic/elastic6-service.js.map +1 -1
- package/dist/cores/elastic/hangul-service.js +52 -54
- package/dist/cores/elastic/hangul-service.js.map +1 -1
- package/dist/cores/lambda/index.js +42 -36
- package/dist/cores/lambda/index.js.map +1 -1
- package/dist/cores/lambda/lambda-alb-handler.d.ts +2 -2
- package/dist/cores/lambda/lambda-alb-handler.js +59 -72
- package/dist/cores/lambda/lambda-alb-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-cognito-handler.js +10 -19
- package/dist/cores/lambda/lambda-cognito-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-cron-handler.d.ts +1 -1
- package/dist/cores/lambda/lambda-cron-handler.js +14 -23
- package/dist/cores/lambda/lambda-cron-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-dynamo-stream-handler.d.ts +2 -2
- package/dist/cores/lambda/lambda-dynamo-stream-handler.js +57 -67
- package/dist/cores/lambda/lambda-dynamo-stream-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-handler.d.ts +22 -22
- package/dist/cores/lambda/lambda-handler.js +93 -106
- package/dist/cores/lambda/lambda-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-notification-handler.d.ts +1 -1
- package/dist/cores/lambda/lambda-notification-handler.js +39 -50
- package/dist/cores/lambda/lambda-notification-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-sns-handler.js +79 -88
- package/dist/cores/lambda/lambda-sns-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-sqs-handler.js +79 -88
- package/dist/cores/lambda/lambda-sqs-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-web-handler.d.ts +6 -6
- package/dist/cores/lambda/lambda-web-handler.js +387 -412
- package/dist/cores/lambda/lambda-web-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-wss-handler.js +23 -32
- package/dist/cores/lambda/lambda-wss-handler.js.map +1 -1
- package/dist/cores/protocol/index.js +10 -20
- package/dist/cores/protocol/index.js.map +1 -1
- package/dist/cores/protocol/protocol-service.d.ts +3 -3
- package/dist/cores/protocol/protocol-service.js +235 -227
- package/dist/cores/protocol/protocol-service.js.map +1 -1
- package/dist/cores/storage/http-storage-service.js +65 -85
- package/dist/cores/storage/http-storage-service.js.map +1 -1
- package/dist/cores/storage/model-manager.js +66 -85
- package/dist/cores/storage/model-manager.js.map +1 -1
- package/dist/cores/storage/proxy-storage-service.d.ts +2 -2
- package/dist/cores/storage/proxy-storage-service.js +562 -599
- package/dist/cores/storage/proxy-storage-service.js.map +1 -1
- package/dist/cores/storage/redis-storage-service.js +163 -177
- package/dist/cores/storage/redis-storage-service.js.map +1 -1
- package/dist/cores/storage/storage-service.d.ts +8 -1
- package/dist/cores/storage/storage-service.js +359 -324
- package/dist/cores/storage/storage-service.js.map +1 -1
- package/dist/engine/builder.d.ts +1 -1
- package/dist/engine/builder.js +59 -63
- package/dist/engine/builder.js.map +1 -1
- package/dist/engine/engine.d.ts +4 -4
- package/dist/engine/engine.js +9 -18
- package/dist/engine/engine.js.map +1 -1
- package/dist/engine/types.d.ts +1 -1
- package/dist/engine/utilities.d.ts +5 -5
- package/dist/engine/utilities.js +301 -293
- package/dist/engine/utilities.js.map +1 -1
- package/dist/environ.js +4 -6
- package/dist/environ.js.map +1 -1
- package/dist/extended/abstract-service.js +595 -645
- package/dist/extended/abstract-service.js.map +1 -1
- package/dist/extended/libs/sig-v4.js.map +1 -1
- package/dist/generated/field-registry.d.ts +10 -0
- package/dist/generated/field-registry.js +17 -0
- package/dist/generated/field-registry.js.map +1 -0
- package/dist/helpers/helpers.d.ts +17 -9
- package/dist/helpers/helpers.js +88 -78
- package/dist/helpers/helpers.js.map +1 -1
- package/dist/index.js +17 -7
- package/dist/index.js.map +1 -1
- package/dist/lib/dynamodb-value.js +2 -3
- package/dist/lib/dynamodb-value.js.map +1 -1
- package/dist/tools/express.js +4 -5
- package/dist/tools/express.js.map +1 -1
- package/dist/tools/tools.d.ts +3 -1
- package/dist/tools/tools.js +14 -21
- package/dist/tools/tools.js.map +1 -1
- package/package.json +25 -24
- package/dist/exec-cli.d.ts +0 -2
- package/dist/exec-cli.js +0 -211
- package/dist/exec-cli.js.map +0 -1
- package/dist/lib/dynamo/expressions.d.ts +0 -14
- package/dist/lib/dynamo/expressions.js +0 -212
- package/dist/lib/dynamo/expressions.js.map +0 -1
- package/dist/lib/dynamo/query.d.ts +0 -43
- package/dist/lib/dynamo/query.js +0 -246
- package/dist/lib/dynamo/query.js.map +0 -1
- package/dist/lib/dynamo/scan.d.ts +0 -33
- package/dist/lib/dynamo/scan.js +0 -172
- package/dist/lib/dynamo/scan.js.map +0 -1
- package/dist/lib/dynamo/serializer.d.ts +0 -12
- package/dist/lib/dynamo/serializer.js +0 -243
- package/dist/lib/dynamo/serializer.js.map +0 -1
- package/dist/lib/dynamo/utils.d.ts +0 -15
- package/dist/lib/dynamo/utils.js +0 -129
- package/dist/lib/dynamo/utils.js.map +0 -1
- package/dist/tools/shared.d.ts +0 -28
- package/dist/tools/shared.js +0 -143
- package/dist/tools/shared.js.map +0 -1
|
@@ -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
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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
|
-
|
|
348
|
-
|
|
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
|
-
|
|
368
|
-
|
|
369
|
-
|
|
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
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
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
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
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
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
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
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
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
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
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
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
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
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
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
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
const {
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
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
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
|
|
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
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
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
|
-
|
|
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
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
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
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
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
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
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;
|