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.DummyStorageService = exports.DynamoStorageService = void 0;
|
|
13
4
|
/**
|
|
@@ -39,16 +30,11 @@ const clearDuplicated = (arr) => arr.sort().reduce((L, val) => {
|
|
|
39
30
|
* - service via DynamoDB with id + json data.
|
|
40
31
|
*/
|
|
41
32
|
class DynamoStorageService {
|
|
33
|
+
_table; // target table-name
|
|
34
|
+
_idName; // target table-name
|
|
35
|
+
_fields; // fields set.
|
|
36
|
+
$dynamo;
|
|
42
37
|
constructor(table, fields, idName = 'id', idType = 'string') {
|
|
43
|
-
/**
|
|
44
|
-
* say hello()
|
|
45
|
-
* @param name (optional) given name
|
|
46
|
-
*/
|
|
47
|
-
this.hello = () => `dynamo-storage-service:${this._table}/${this._idName}/${this._fields.length}`;
|
|
48
|
-
/**
|
|
49
|
-
* (extended) get copy of fields.
|
|
50
|
-
*/
|
|
51
|
-
this.fields = () => [...this._fields];
|
|
52
38
|
if (!table)
|
|
53
39
|
throw new Error(`@table (table-name) is required!`);
|
|
54
40
|
this._table = table;
|
|
@@ -56,52 +42,56 @@ class DynamoStorageService {
|
|
|
56
42
|
this._fields = clearDuplicated(['id', 'type', 'stereo', 'meta', idName].concat(fields));
|
|
57
43
|
this.$dynamo = new dynamo_1.DynamoService({ tableName: this._table, idName, idType });
|
|
58
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* say hello()
|
|
47
|
+
* @param name (optional) given name
|
|
48
|
+
*/
|
|
49
|
+
hello = () => `dynamo-storage-service:${this._table}/${this._idName}/${this._fields.length}`;
|
|
50
|
+
/**
|
|
51
|
+
* (extended) get copy of fields.
|
|
52
|
+
*/
|
|
53
|
+
fields = () => [...this._fields];
|
|
59
54
|
/**
|
|
60
55
|
* Read whole model via database.
|
|
61
56
|
*
|
|
62
57
|
* @param id id
|
|
63
58
|
*/
|
|
64
|
-
read(id) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return item;
|
|
75
|
-
});
|
|
59
|
+
async read(id) {
|
|
60
|
+
const data = await this.$dynamo.readItem(id);
|
|
61
|
+
const fields = this._fields || [];
|
|
62
|
+
const item = fields.reduce((N, key) => {
|
|
63
|
+
const val = data[key];
|
|
64
|
+
if (val !== undefined)
|
|
65
|
+
N[key] = val;
|
|
66
|
+
return N;
|
|
67
|
+
}, {});
|
|
68
|
+
return item;
|
|
76
69
|
}
|
|
77
70
|
/**
|
|
78
71
|
* Read multiple models via database.
|
|
79
72
|
*
|
|
80
73
|
* @param ids ids
|
|
81
74
|
*/
|
|
82
|
-
mread(ids) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const result = { success: [], failed: [], total };
|
|
87
|
-
if (!ids || total === 0)
|
|
88
|
-
return result;
|
|
89
|
-
const list = ids.map(id => ({ id }));
|
|
90
|
-
const res = yield this.$dynamo.mreadItem(list);
|
|
91
|
-
const fields = this._fields || [];
|
|
92
|
-
const toModel = (data) => fields.reduce((N, key) => {
|
|
93
|
-
const val = data[key];
|
|
94
|
-
if (val !== undefined)
|
|
95
|
-
N[key] = val;
|
|
96
|
-
return N;
|
|
97
|
-
}, {});
|
|
98
|
-
result.success = (res.success || []).map(toModel);
|
|
99
|
-
result.failed = (res.failed || []).map(item => {
|
|
100
|
-
const model = toModel(item);
|
|
101
|
-
return Object.assign(Object.assign({}, model), { error: item.error || 'Unknown error' });
|
|
102
|
-
});
|
|
75
|
+
async mread(ids) {
|
|
76
|
+
const total = ids?.length ?? 0;
|
|
77
|
+
const result = { success: [], failed: [], total };
|
|
78
|
+
if (!ids || total === 0)
|
|
103
79
|
return result;
|
|
80
|
+
const list = ids.map(id => ({ id }));
|
|
81
|
+
const res = await this.$dynamo.mreadItem(list);
|
|
82
|
+
const fields = this._fields || [];
|
|
83
|
+
const toModel = (data) => fields.reduce((N, key) => {
|
|
84
|
+
const val = data[key];
|
|
85
|
+
if (val !== undefined)
|
|
86
|
+
N[key] = val;
|
|
87
|
+
return N;
|
|
88
|
+
}, {});
|
|
89
|
+
result.success = (res.success || []).map(toModel);
|
|
90
|
+
result.failed = (res.failed || []).map(item => {
|
|
91
|
+
const model = toModel(item);
|
|
92
|
+
return { ...model, error: item.error || 'Unknown error' };
|
|
104
93
|
});
|
|
94
|
+
return result;
|
|
105
95
|
}
|
|
106
96
|
/**
|
|
107
97
|
* auto-create if not found.
|
|
@@ -109,13 +99,11 @@ class DynamoStorageService {
|
|
|
109
99
|
* @param id
|
|
110
100
|
* @param model
|
|
111
101
|
*/
|
|
112
|
-
readOrCreate(id, model) {
|
|
113
|
-
return
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
throw e;
|
|
118
|
-
});
|
|
102
|
+
async readOrCreate(id, model) {
|
|
103
|
+
return this.read(id).catch((e) => {
|
|
104
|
+
if (`${e.message}`.startsWith('404 NOT FOUND'))
|
|
105
|
+
return this.update(id, model);
|
|
106
|
+
throw e;
|
|
119
107
|
});
|
|
120
108
|
}
|
|
121
109
|
/**
|
|
@@ -124,19 +112,17 @@ class DynamoStorageService {
|
|
|
124
112
|
* @param id id
|
|
125
113
|
* @param model whole object.
|
|
126
114
|
*/
|
|
127
|
-
save(id, model) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return item;
|
|
139
|
-
});
|
|
115
|
+
async save(id, model) {
|
|
116
|
+
const fields = this._fields || [];
|
|
117
|
+
const data = fields.reduce((N, key) => {
|
|
118
|
+
const val = model[key];
|
|
119
|
+
if (val !== undefined)
|
|
120
|
+
N[key] = val;
|
|
121
|
+
return N;
|
|
122
|
+
}, {});
|
|
123
|
+
await this.$dynamo.saveItem(id, data); // must be `{}`
|
|
124
|
+
const item = Object.assign({ [this._idName]: id }, data);
|
|
125
|
+
return item;
|
|
140
126
|
}
|
|
141
127
|
/**
|
|
142
128
|
* update some attributes
|
|
@@ -145,58 +131,53 @@ class DynamoStorageService {
|
|
|
145
131
|
* @param model attributes to update
|
|
146
132
|
* @param incrementals (optional) attributes to increment
|
|
147
133
|
*/
|
|
148
|
-
update(id, model, incrementals) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
return ret;
|
|
168
|
-
});
|
|
134
|
+
async update(id, model, incrementals) {
|
|
135
|
+
const fields = this._fields || [];
|
|
136
|
+
const $U = fields.reduce((N, key) => {
|
|
137
|
+
const val = model[key];
|
|
138
|
+
if (val !== undefined)
|
|
139
|
+
N[key] = val;
|
|
140
|
+
return N;
|
|
141
|
+
}, {});
|
|
142
|
+
/* eslint-disable prettier/prettier */
|
|
143
|
+
const $I = !incrementals ? null : Object.keys(incrementals).reduce((M, key) => {
|
|
144
|
+
const val = incrementals[key];
|
|
145
|
+
if (typeof val !== 'number')
|
|
146
|
+
throw new Error(`.${key} (${val}) should be number!`);
|
|
147
|
+
M[key] = val;
|
|
148
|
+
return M;
|
|
149
|
+
}, {});
|
|
150
|
+
/* eslint-enable prettier/prettier */
|
|
151
|
+
const ret = await this.$dynamo.updateItem(id, undefined, $U, $I);
|
|
152
|
+
return ret;
|
|
169
153
|
}
|
|
170
154
|
/**
|
|
171
155
|
* update multiple models
|
|
172
156
|
*
|
|
173
157
|
* @param list list of models (should include id)
|
|
174
158
|
*/
|
|
175
|
-
mupdate(list) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const result = { success: [], failed: [], total };
|
|
180
|
-
if (!list || total === 0)
|
|
181
|
-
return result;
|
|
182
|
-
const fields = this._fields || [];
|
|
183
|
-
const items = list.map((item) => {
|
|
184
|
-
const _id = item[this._idName] || item.id;
|
|
185
|
-
if (!_id)
|
|
186
|
-
throw new Error('@id is required!');
|
|
187
|
-
const data = fields.reduce((N, key) => {
|
|
188
|
-
const val = item[key];
|
|
189
|
-
if (val !== undefined)
|
|
190
|
-
N[key] = val;
|
|
191
|
-
return N;
|
|
192
|
-
}, {});
|
|
193
|
-
return Object.assign({ id: `${_id}` }, data);
|
|
194
|
-
});
|
|
195
|
-
const res = yield this.$dynamo.mupdateItem(items);
|
|
196
|
-
result.success = res.success || [];
|
|
197
|
-
result.failed = res.failed || [];
|
|
159
|
+
async mupdate(list) {
|
|
160
|
+
const total = list?.length ?? 0;
|
|
161
|
+
const result = { success: [], failed: [], total };
|
|
162
|
+
if (!list || total === 0)
|
|
198
163
|
return result;
|
|
164
|
+
const fields = this._fields || [];
|
|
165
|
+
const items = list.map((item) => {
|
|
166
|
+
const _id = item[this._idName] || item.id;
|
|
167
|
+
if (!_id)
|
|
168
|
+
throw new Error('@id is required!');
|
|
169
|
+
const data = fields.reduce((N, key) => {
|
|
170
|
+
const val = item[key];
|
|
171
|
+
if (val !== undefined)
|
|
172
|
+
N[key] = val;
|
|
173
|
+
return N;
|
|
174
|
+
}, {});
|
|
175
|
+
return { id: `${_id}`, ...data };
|
|
199
176
|
});
|
|
177
|
+
const res = await this.$dynamo.mupdateItem(items);
|
|
178
|
+
result.success = res.success || [];
|
|
179
|
+
result.failed = res.failed || [];
|
|
180
|
+
return result;
|
|
200
181
|
}
|
|
201
182
|
/**
|
|
202
183
|
* increment number attribute (or overwrite string field)
|
|
@@ -206,42 +187,40 @@ class DynamoStorageService {
|
|
|
206
187
|
* @param model attributes of number.
|
|
207
188
|
* @param $update (optional) update-set.
|
|
208
189
|
*/
|
|
209
|
-
increment(id, model, $update) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
throw e;
|
|
217
|
-
});
|
|
218
|
-
const fields = this._fields || [];
|
|
219
|
-
const $U = fields.reduce((N, key) => {
|
|
220
|
-
const val = $update ? $update[key] : undefined;
|
|
221
|
-
if (val !== undefined)
|
|
222
|
-
N[key] = val;
|
|
223
|
-
return N;
|
|
224
|
-
}, {});
|
|
225
|
-
const $I = fields.reduce((N, key) => {
|
|
226
|
-
const val = model[key];
|
|
227
|
-
if (val !== undefined) {
|
|
228
|
-
const org = $org[key];
|
|
229
|
-
//* check type matched!
|
|
230
|
-
if (org !== undefined && typeof org === 'number' && typeof val !== 'number')
|
|
231
|
-
throw new Error(`.${key} (${val}) should be number!`);
|
|
232
|
-
//* if not exists, update it.
|
|
233
|
-
if (org === undefined && typeof val === 'number')
|
|
234
|
-
N[key] = val;
|
|
235
|
-
else if (typeof val !== 'number' && !Array.isArray(val))
|
|
236
|
-
$U[key] = val;
|
|
237
|
-
else
|
|
238
|
-
N[key] = val;
|
|
239
|
-
}
|
|
240
|
-
return N;
|
|
241
|
-
}, {});
|
|
242
|
-
const ret = yield this.$dynamo.updateItem(id, undefined, $U, $I);
|
|
243
|
-
return ret;
|
|
190
|
+
async increment(id, model, $update) {
|
|
191
|
+
if (!model && !$update)
|
|
192
|
+
throw new Error('@item is required!');
|
|
193
|
+
const $org = await this.read(id).catch(e => {
|
|
194
|
+
if (`${e.message || e}`.startsWith('404 NOT FOUND'))
|
|
195
|
+
return { id };
|
|
196
|
+
throw e;
|
|
244
197
|
});
|
|
198
|
+
const fields = this._fields || [];
|
|
199
|
+
const $U = fields.reduce((N, key) => {
|
|
200
|
+
const val = $update ? $update[key] : undefined;
|
|
201
|
+
if (val !== undefined)
|
|
202
|
+
N[key] = val;
|
|
203
|
+
return N;
|
|
204
|
+
}, {});
|
|
205
|
+
const $I = fields.reduce((N, key) => {
|
|
206
|
+
const val = model[key];
|
|
207
|
+
if (val !== undefined) {
|
|
208
|
+
const org = $org[key];
|
|
209
|
+
//* check type matched!
|
|
210
|
+
if (org !== undefined && typeof org === 'number' && typeof val !== 'number')
|
|
211
|
+
throw new Error(`.${key} (${val}) should be number!`);
|
|
212
|
+
//* if not exists, update it.
|
|
213
|
+
if (org === undefined && typeof val === 'number')
|
|
214
|
+
N[key] = val;
|
|
215
|
+
else if (typeof val !== 'number' && !Array.isArray(val))
|
|
216
|
+
$U[key] = val;
|
|
217
|
+
else
|
|
218
|
+
N[key] = val;
|
|
219
|
+
}
|
|
220
|
+
return N;
|
|
221
|
+
}, {});
|
|
222
|
+
const ret = await this.$dynamo.updateItem(id, undefined, $U, $I);
|
|
223
|
+
return ret;
|
|
245
224
|
}
|
|
246
225
|
/**
|
|
247
226
|
* delete set.
|
|
@@ -249,12 +228,10 @@ class DynamoStorageService {
|
|
|
249
228
|
*
|
|
250
229
|
* @param id id
|
|
251
230
|
*/
|
|
252
|
-
delete(id) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
return $org;
|
|
257
|
-
});
|
|
231
|
+
async delete(id) {
|
|
232
|
+
const $org = await this.read(id);
|
|
233
|
+
await this.$dynamo.deleteItem(id);
|
|
234
|
+
return $org;
|
|
258
235
|
}
|
|
259
236
|
}
|
|
260
237
|
exports.DynamoStorageService = DynamoStorageService;
|
|
@@ -269,23 +246,23 @@ exports.DynamoStorageService = DynamoStorageService;
|
|
|
269
246
|
* - this dummy service should be replaceable with real service `DynamoStorageService`
|
|
270
247
|
*/
|
|
271
248
|
class DummyStorageService {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
* @param name (optional) given name
|
|
277
|
-
*/
|
|
278
|
-
this.hello = () => `dummy-storage-service:${this.name}/${this.idName}`;
|
|
279
|
-
this.$locks = {}; //* only for lock.
|
|
249
|
+
name;
|
|
250
|
+
idName;
|
|
251
|
+
_fields;
|
|
252
|
+
constructor(dataFile, name = 'memory', idName, fields) {
|
|
280
253
|
(0, engine_1._log)(NS, `DummyStorageService(${dataFile || ''})...`);
|
|
281
254
|
if (!dataFile)
|
|
282
255
|
throw new Error('@dataFile(string) is required!');
|
|
283
256
|
this.name = `${name || ''}`;
|
|
284
257
|
this.idName = `${idName || 'id'}`;
|
|
258
|
+
//* `undefined` keeps legacy "no filter" mode; `[]` opts into Dynamo's default whitelist.
|
|
259
|
+
this._fields =
|
|
260
|
+
fields === undefined ? null : clearDuplicated(['id', 'type', 'stereo', 'meta', this.idName].concat(fields));
|
|
285
261
|
// const loadDataYml = require('../express').loadDataYml;
|
|
286
262
|
const dummy = (0, tools_1.loadDataYml)(dataFile);
|
|
287
263
|
this.load(dummy.data);
|
|
288
264
|
}
|
|
265
|
+
buffer = {};
|
|
289
266
|
load(data) {
|
|
290
267
|
if (!data || !Array.isArray(data))
|
|
291
268
|
throw new Error('@data should be array!');
|
|
@@ -294,183 +271,241 @@ class DummyStorageService {
|
|
|
294
271
|
this.buffer[id] = item;
|
|
295
272
|
});
|
|
296
273
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
274
|
+
/**
|
|
275
|
+
* apply Dynamo-style field whitelist when configured; otherwise return a shallow copy.
|
|
276
|
+
*/
|
|
277
|
+
pick(obj) {
|
|
278
|
+
const source = dynamo_1.DynamoService.normalize(obj);
|
|
279
|
+
if (!this._fields)
|
|
280
|
+
return { ...source };
|
|
281
|
+
return this._fields.reduce((N, key) => {
|
|
282
|
+
const val = source[key];
|
|
283
|
+
if (val !== undefined)
|
|
284
|
+
N[key] = val;
|
|
285
|
+
return N;
|
|
286
|
+
}, {});
|
|
287
|
+
}
|
|
288
|
+
pickRaw(obj) {
|
|
289
|
+
if (!this._fields)
|
|
290
|
+
return { ...obj };
|
|
291
|
+
return this._fields.reduce((N, key) => {
|
|
292
|
+
const val = obj[key];
|
|
293
|
+
if (val !== undefined)
|
|
294
|
+
N[key] = val ?? '';
|
|
295
|
+
return N;
|
|
296
|
+
}, {});
|
|
297
|
+
}
|
|
298
|
+
applyDynamoAdd(key, org, val) {
|
|
299
|
+
if (Array.isArray(val)) {
|
|
300
|
+
if (org !== undefined && !Array.isArray(org))
|
|
301
|
+
throw new Error(`.${key} (${val}) cannot append to non-list existing value`);
|
|
302
|
+
return [...(Array.isArray(org) ? org : []), ...val];
|
|
303
|
+
}
|
|
304
|
+
if (typeof val === 'number') {
|
|
305
|
+
if (org !== undefined && typeof org !== 'number')
|
|
306
|
+
throw new Error(`.${key} (${val}) cannot ADD to non-number existing value`);
|
|
307
|
+
return engine_1.$U.N(org, 0) + val;
|
|
308
|
+
}
|
|
309
|
+
throw new Error(`.${key} (${val}) should be number!`);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* say hello()
|
|
313
|
+
* @param name (optional) given name
|
|
314
|
+
*/
|
|
315
|
+
hello = () => this._fields
|
|
316
|
+
? `dummy-storage-service:${this.name}/${this.idName}/${this._fields.length}`
|
|
317
|
+
: `dummy-storage-service:${this.name}/${this.idName}`;
|
|
318
|
+
async read(id) {
|
|
319
|
+
//* note: dummy-only validation; Dynamo's read does not short-circuit whitespace ids.
|
|
320
|
+
if (!id?.trim())
|
|
321
|
+
throw new Error('@id (string) is required!');
|
|
322
|
+
const item = this.buffer[id];
|
|
323
|
+
if (!item)
|
|
324
|
+
throw new Error(`404 NOT FOUND - ${this.idName}:${id}`);
|
|
325
|
+
return Object.assign(this.pick(item), { [this.idName]: id });
|
|
326
|
+
}
|
|
327
|
+
async mread(ids) {
|
|
328
|
+
const total = ids?.length ?? 0;
|
|
329
|
+
const result = { success: [], failed: [], total };
|
|
330
|
+
if (!ids || total === 0)
|
|
331
|
+
return result;
|
|
332
|
+
for (const id of ids) {
|
|
333
|
+
//* note: dummy-only validation; Dynamo's mread does not short-circuit whitespace ids.
|
|
334
|
+
if (!id || !`${id}`.trim())
|
|
300
335
|
throw new Error('@id (string) is required!');
|
|
301
336
|
const item = this.buffer[id];
|
|
302
|
-
if (!item)
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
337
|
+
if (!item) {
|
|
338
|
+
result.failed.push({
|
|
339
|
+
[this.idName]: id,
|
|
340
|
+
error: `404 NOT FOUND - ${this.idName}:${id}`,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
result.success.push(Object.assign(this.pick(item), { [this.idName]: id }));
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return result;
|
|
306
348
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
if (!ids || total === 0)
|
|
313
|
-
return result;
|
|
314
|
-
for (const id of ids) {
|
|
315
|
-
if (!id || !`${id}`.trim())
|
|
316
|
-
throw new Error('@id (string) is required!');
|
|
317
|
-
const item = this.buffer[id];
|
|
318
|
-
if (!item) {
|
|
319
|
-
result.failed.push({ [this.idName]: id, error: '404 NOT FOUND' });
|
|
320
|
-
}
|
|
321
|
-
else {
|
|
322
|
-
result.success.push(Object.assign(Object.assign({}, item), { [this.idName]: id }));
|
|
323
|
-
}
|
|
349
|
+
async readSafe(id) {
|
|
350
|
+
return this.read(id).catch(e => {
|
|
351
|
+
if (`${e.message || e}`.startsWith('404 NOT FOUND')) {
|
|
352
|
+
const $org = { [this.idName]: id };
|
|
353
|
+
return $org;
|
|
324
354
|
}
|
|
325
|
-
|
|
355
|
+
throw e;
|
|
326
356
|
});
|
|
327
357
|
}
|
|
328
|
-
|
|
329
|
-
return
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
return $org;
|
|
334
|
-
}
|
|
335
|
-
throw e;
|
|
336
|
-
});
|
|
358
|
+
async readOrCreate(id, model) {
|
|
359
|
+
return this.read(id).catch((e) => {
|
|
360
|
+
if (`${e.message}`.startsWith('404 NOT FOUND'))
|
|
361
|
+
return this.update(id, model);
|
|
362
|
+
throw e;
|
|
337
363
|
});
|
|
338
364
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
365
|
+
async save(id, item) {
|
|
366
|
+
if (!id)
|
|
367
|
+
throw new Error('@id is required!');
|
|
368
|
+
if (!id || !`${id}`.trim())
|
|
369
|
+
throw new Error('@id (string) is required!');
|
|
370
|
+
if (!item)
|
|
371
|
+
throw new Error('@item is required!');
|
|
372
|
+
if (typeof item.lock == 'number')
|
|
373
|
+
this.$locks[id] = item.lock;
|
|
374
|
+
const data = this.pick(item);
|
|
375
|
+
this.buffer[id] = data;
|
|
376
|
+
return Object.assign({ [this.idName]: id }, this.pickRaw(item));
|
|
347
377
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
378
|
+
$locks = {}; //* only for lock.
|
|
379
|
+
async update(id, item, $inc) {
|
|
380
|
+
if (!id)
|
|
381
|
+
throw new Error('@id is required!');
|
|
382
|
+
if (!id || !`${id}`.trim())
|
|
383
|
+
throw new Error('@id (string) is required!');
|
|
384
|
+
if (!item)
|
|
385
|
+
throw new Error('@item is required!');
|
|
386
|
+
//* atomic operation for `.lock` — dummy-only deviation; DynamoDB has no equivalent here.
|
|
387
|
+
const lock = (() => {
|
|
388
|
+
let lock = 0;
|
|
354
389
|
if (item && typeof item.lock == 'number')
|
|
355
|
-
this.$locks[id] = item.lock;
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
390
|
+
this.$locks[id] = lock = item.lock;
|
|
391
|
+
if ($inc && typeof $inc.lock == 'number')
|
|
392
|
+
this.$locks[id] = lock = $inc.lock + engine_1.$U.N(this.$locks[id], 0);
|
|
393
|
+
return lock;
|
|
394
|
+
})();
|
|
395
|
+
const $org = await this.readSafe(id);
|
|
396
|
+
//* whitelist `item` (matches Dynamo `update` $U); $inc is iterated by its own keys (matches Dynamo $I).
|
|
397
|
+
const filtered = this.pick(item);
|
|
398
|
+
const $new = Object.assign($org, filtered);
|
|
399
|
+
/* eslint-disable prettier/prettier */
|
|
400
|
+
const incremented = !$inc ? null : Object.keys($inc).reduce((M, key) => {
|
|
401
|
+
const val = $inc[key];
|
|
402
|
+
if (typeof val !== 'number')
|
|
403
|
+
throw new Error(`.${key} (${val}) should be number!`);
|
|
404
|
+
if (key == 'lock') {
|
|
405
|
+
M[key] = lock;
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
M[key] = this.applyDynamoAdd(key, $new[key], val);
|
|
409
|
+
}
|
|
410
|
+
return M;
|
|
411
|
+
}, {});
|
|
412
|
+
if (incremented)
|
|
413
|
+
Object.assign($new, incremented);
|
|
414
|
+
/* eslint-enable prettier/prettier */
|
|
415
|
+
await this.save(id, $new);
|
|
416
|
+
const $set = { ...filtered, ...incremented };
|
|
417
|
+
if (typeof $set.lock == 'number')
|
|
418
|
+
$set.lock = lock;
|
|
419
|
+
return Object.assign({ [this.idName]: id }, $set);
|
|
359
420
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
421
|
+
async mupdate(list) {
|
|
422
|
+
const total = list?.length ?? 0;
|
|
423
|
+
const result = { success: [], failed: [], total };
|
|
424
|
+
if (!list || total === 0)
|
|
425
|
+
return result;
|
|
426
|
+
//* Dynamo's mupdateItem is batch-PUT (overwrite, no merge). Mirror that here inline.
|
|
427
|
+
for (const item of list) {
|
|
428
|
+
const _id = item[this.idName] || item.id;
|
|
429
|
+
if (!_id)
|
|
363
430
|
throw new Error('@id is required!');
|
|
364
|
-
if (!
|
|
365
|
-
throw new Error('@
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
})();
|
|
375
|
-
const $org = yield this.readSafe(id);
|
|
376
|
-
const $new = Object.assign($org, item);
|
|
377
|
-
/* eslint-disable prettier/prettier */
|
|
378
|
-
const incremented = !$inc ? null : Object.keys($inc).reduce((M, key) => {
|
|
379
|
-
const val = $inc[key];
|
|
380
|
-
if (typeof val !== 'number')
|
|
381
|
-
throw new Error(`.${key} (${val}) should be number!`);
|
|
382
|
-
if (key == 'lock') {
|
|
383
|
-
M[key] = lock;
|
|
384
|
-
}
|
|
385
|
-
else {
|
|
386
|
-
M[key] = engine_1.$U.N($new[key], 0) + val;
|
|
387
|
-
}
|
|
388
|
-
return M;
|
|
389
|
-
}, {});
|
|
390
|
-
if (incremented)
|
|
391
|
-
Object.assign($new, incremented);
|
|
392
|
-
/* eslint-enable prettier/prettier */
|
|
393
|
-
yield this.save(id, $new);
|
|
394
|
-
const $set = Object.assign(Object.assign({}, item), incremented);
|
|
395
|
-
if (typeof $set.lock == 'number')
|
|
396
|
-
$set.lock = lock;
|
|
397
|
-
return Object.assign({ [this.idName]: id }, $set);
|
|
398
|
-
});
|
|
431
|
+
if (!_id || !`${_id}`.trim())
|
|
432
|
+
throw new Error('@id (string) is required!');
|
|
433
|
+
if (typeof item.lock == 'number')
|
|
434
|
+
this.$locks[_id] = item.lock;
|
|
435
|
+
const cleaned = this.idName !== 'id' ? (({ id: _drop, ...rest }) => rest)(item) : item;
|
|
436
|
+
const data = this.pick(cleaned);
|
|
437
|
+
this.buffer[_id] = data;
|
|
438
|
+
result.success.push(Object.assign({ [this.idName]: _id }, data));
|
|
439
|
+
}
|
|
440
|
+
return result;
|
|
399
441
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
this
|
|
414
|
-
|
|
442
|
+
async increment(id, $inc, $upt) {
|
|
443
|
+
if (!id)
|
|
444
|
+
throw new Error('@id is required!');
|
|
445
|
+
if (!id || !`${id}`.trim())
|
|
446
|
+
throw new Error('@id (string) is required!');
|
|
447
|
+
if (!$inc && !$upt)
|
|
448
|
+
throw new Error('@item is required!');
|
|
449
|
+
if (!$inc)
|
|
450
|
+
throw new TypeError('Cannot convert undefined or null to object');
|
|
451
|
+
//* atomic operation for `.lock` — dummy-only deviation; DynamoDB has no equivalent here.
|
|
452
|
+
const lock = (() => {
|
|
453
|
+
let lock = 0;
|
|
454
|
+
if ($upt && typeof $upt.lock == 'number')
|
|
455
|
+
this.$locks[id] = lock = $upt.lock;
|
|
456
|
+
if ($inc && typeof $inc.lock == 'number')
|
|
457
|
+
this.$locks[id] = lock = $inc.lock + engine_1.$U.N(this.$locks[id], 0);
|
|
458
|
+
return lock;
|
|
459
|
+
})();
|
|
460
|
+
const $org = await this.readSafe(id);
|
|
461
|
+
//* null-guard: previously `Object.keys($inc)` threw when only $upt was provided.
|
|
462
|
+
const inc = $inc ? dynamo_1.DynamoService.normalize($inc) : {};
|
|
463
|
+
const upt = $upt ? dynamo_1.DynamoService.normalize($upt) : {};
|
|
464
|
+
//* iterate over the whitelist when configured (parity with Dynamo at storage-service.ts:283-301);
|
|
465
|
+
//* otherwise fall back to the union of provided keys (legacy unfiltered behavior).
|
|
466
|
+
const keys = this._fields
|
|
467
|
+
? this._fields
|
|
468
|
+
: Array.from(new Set([...Object.keys(inc), ...Object.keys(upt)]));
|
|
469
|
+
const $set = {};
|
|
470
|
+
for (const key of keys) {
|
|
471
|
+
const uptVal = upt[key];
|
|
472
|
+
const incVal = inc[key];
|
|
473
|
+
const org = $org[key];
|
|
474
|
+
if (uptVal !== undefined) {
|
|
475
|
+
$set[key] = uptVal;
|
|
476
|
+
$org[key] = uptVal;
|
|
415
477
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
throw new Error('@id is required!');
|
|
423
|
-
if (!$inc && !$upt)
|
|
424
|
-
throw new Error('@item is required!');
|
|
425
|
-
//* atomic operation for `.lock`
|
|
426
|
-
const lock = (() => {
|
|
427
|
-
let lock = 0;
|
|
428
|
-
if ($upt && typeof $upt.lock == 'number')
|
|
429
|
-
this.$locks[id] = lock = $upt.lock;
|
|
430
|
-
if ($inc && typeof $inc.lock == 'number')
|
|
431
|
-
this.$locks[id] = lock = $inc.lock + engine_1.$U.N(this.$locks[id], 0);
|
|
432
|
-
return lock;
|
|
433
|
-
})();
|
|
434
|
-
const $org = yield this.readSafe(id);
|
|
435
|
-
const $set = Object.keys($inc)
|
|
436
|
-
.concat(Object.keys($upt || {}))
|
|
437
|
-
.reduce((N, key) => {
|
|
438
|
-
const val = $inc ? $inc[key] : undefined;
|
|
439
|
-
const upt = $upt ? $upt[key] : undefined;
|
|
440
|
-
const org = $org[key];
|
|
441
|
-
if (upt !== undefined) {
|
|
442
|
-
N[key] = upt;
|
|
478
|
+
else if (incVal !== undefined) {
|
|
479
|
+
if (org !== undefined && typeof org === 'number' && typeof incVal !== 'number')
|
|
480
|
+
throw new Error(`.${key} (${incVal}) should be number!`);
|
|
481
|
+
if (key === 'lock') {
|
|
482
|
+
$set[key] = lock;
|
|
483
|
+
$org[key] = lock;
|
|
443
484
|
}
|
|
444
|
-
else if (
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
N[key] = val;
|
|
449
|
-
}
|
|
450
|
-
else if (key == 'lock') {
|
|
451
|
-
N[key] = lock;
|
|
452
|
-
$org[key] = lock;
|
|
453
|
-
}
|
|
454
|
-
else {
|
|
455
|
-
N[key] = (org === undefined ? 0 : org) + val;
|
|
456
|
-
$org[key] = (org === undefined ? 0 : org) + val;
|
|
457
|
-
}
|
|
485
|
+
else if (typeof incVal !== 'number' && !Array.isArray(incVal)) {
|
|
486
|
+
//* non-number SET, matching DynamoStorage.increment's SET path.
|
|
487
|
+
$set[key] = incVal;
|
|
488
|
+
$org[key] = incVal;
|
|
458
489
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
}
|
|
490
|
+
else {
|
|
491
|
+
const newVal = this.applyDynamoAdd(key, org, incVal);
|
|
492
|
+
$set[key] = newVal;
|
|
493
|
+
$org[key] = newVal;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (typeof $set.lock == 'number')
|
|
498
|
+
$set.lock = lock;
|
|
499
|
+
await this.save(id, $org);
|
|
500
|
+
return Object.assign({ [this.idName]: id }, $set);
|
|
466
501
|
}
|
|
467
|
-
delete(id) {
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
502
|
+
async delete(id) {
|
|
503
|
+
if (!id || !`${id}`.trim())
|
|
504
|
+
throw new Error('@id (string) is required!');
|
|
505
|
+
const $org = await this.read(id);
|
|
506
|
+
delete this.buffer[id];
|
|
507
|
+
delete this.$locks[id];
|
|
508
|
+
return $org;
|
|
474
509
|
}
|
|
475
510
|
}
|
|
476
511
|
exports.DummyStorageService = DummyStorageService;
|