lemon-core 4.1.15 → 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/README.md +2 -0
  2. package/dist/common/test-helper.d.ts +2 -2
  3. package/dist/common/test-helper.js +24 -26
  4. package/dist/common/test-helper.js.map +1 -1
  5. package/dist/controllers/dummy-controller.js +39 -46
  6. package/dist/controllers/dummy-controller.js.map +1 -1
  7. package/dist/controllers/general-api-controller.js +95 -100
  8. package/dist/controllers/general-api-controller.js.map +1 -1
  9. package/dist/controllers/general-controller.js +81 -82
  10. package/dist/controllers/general-controller.js.map +1 -1
  11. package/dist/cores/api/api-service.d.ts +1 -1
  12. package/dist/cores/api/api-service.js +228 -269
  13. package/dist/cores/api/api-service.js.map +1 -1
  14. package/dist/cores/aws/aws-kms-service.d.ts +1 -2
  15. package/dist/cores/aws/aws-kms-service.js +143 -153
  16. package/dist/cores/aws/aws-kms-service.js.map +1 -1
  17. package/dist/cores/aws/aws-s3-service.d.ts +2 -4
  18. package/dist/cores/aws/aws-s3-service.js +306 -330
  19. package/dist/cores/aws/aws-s3-service.js.map +1 -1
  20. package/dist/cores/aws/aws-sns-service.js +147 -153
  21. package/dist/cores/aws/aws-sns-service.js.map +1 -1
  22. package/dist/cores/aws/aws-sqs-service.js +149 -170
  23. package/dist/cores/aws/aws-sqs-service.js.map +1 -1
  24. package/dist/cores/aws/index.js +10 -20
  25. package/dist/cores/aws/index.js.map +1 -1
  26. package/dist/cores/cache/cache-service.d.ts +2 -2
  27. package/dist/cores/cache/cache-service.js +435 -499
  28. package/dist/cores/cache/cache-service.js.map +1 -1
  29. package/dist/cores/config/config-service.d.ts +1 -1
  30. package/dist/cores/config/config-service.js +56 -63
  31. package/dist/cores/config/config-service.js.map +1 -1
  32. package/dist/cores/config/index.js +14 -24
  33. package/dist/cores/config/index.js.map +1 -1
  34. package/dist/cores/core-services.d.ts +1 -1
  35. package/dist/cores/dynamo/dynamo-query-service.js +37 -51
  36. package/dist/cores/dynamo/dynamo-query-service.js.map +1 -1
  37. package/dist/cores/dynamo/dynamo-scan-service.d.ts +2 -2
  38. package/dist/cores/dynamo/dynamo-scan-service.js +29 -40
  39. package/dist/cores/dynamo/dynamo-scan-service.js.map +1 -1
  40. package/dist/cores/dynamo/dynamo-service.d.ts +3 -3
  41. package/dist/cores/dynamo/dynamo-service.js +540 -605
  42. package/dist/cores/dynamo/dynamo-service.js.map +1 -1
  43. package/dist/cores/dynamo/tools/expressions.js +17 -7
  44. package/dist/cores/dynamo/tools/expressions.js.map +1 -1
  45. package/dist/cores/dynamo/tools/query.js +142 -127
  46. package/dist/cores/dynamo/tools/query.js.map +1 -1
  47. package/dist/cores/dynamo/tools/scan.js +111 -97
  48. package/dist/cores/dynamo/tools/scan.js.map +1 -1
  49. package/dist/cores/dynamo/tools/serializer.js +17 -7
  50. package/dist/cores/dynamo/tools/serializer.js.map +1 -1
  51. package/dist/cores/dynamo/tools/utils.d.ts +0 -2
  52. package/dist/cores/dynamo/tools/utils.js.map +1 -1
  53. package/dist/cores/elastic/elastic6-query-service.js +307 -324
  54. package/dist/cores/elastic/elastic6-query-service.js.map +1 -1
  55. package/dist/cores/elastic/elastic6-service.d.ts +3 -3
  56. package/dist/cores/elastic/elastic6-service.js +568 -647
  57. package/dist/cores/elastic/elastic6-service.js.map +1 -1
  58. package/dist/cores/elastic/hangul-service.js +52 -54
  59. package/dist/cores/elastic/hangul-service.js.map +1 -1
  60. package/dist/cores/lambda/index.js +42 -36
  61. package/dist/cores/lambda/index.js.map +1 -1
  62. package/dist/cores/lambda/lambda-alb-handler.d.ts +2 -2
  63. package/dist/cores/lambda/lambda-alb-handler.js +59 -72
  64. package/dist/cores/lambda/lambda-alb-handler.js.map +1 -1
  65. package/dist/cores/lambda/lambda-cognito-handler.js +10 -19
  66. package/dist/cores/lambda/lambda-cognito-handler.js.map +1 -1
  67. package/dist/cores/lambda/lambda-cron-handler.d.ts +1 -1
  68. package/dist/cores/lambda/lambda-cron-handler.js +14 -23
  69. package/dist/cores/lambda/lambda-cron-handler.js.map +1 -1
  70. package/dist/cores/lambda/lambda-dynamo-stream-handler.d.ts +2 -2
  71. package/dist/cores/lambda/lambda-dynamo-stream-handler.js +57 -67
  72. package/dist/cores/lambda/lambda-dynamo-stream-handler.js.map +1 -1
  73. package/dist/cores/lambda/lambda-handler.d.ts +22 -22
  74. package/dist/cores/lambda/lambda-handler.js +93 -106
  75. package/dist/cores/lambda/lambda-handler.js.map +1 -1
  76. package/dist/cores/lambda/lambda-notification-handler.d.ts +1 -1
  77. package/dist/cores/lambda/lambda-notification-handler.js +39 -50
  78. package/dist/cores/lambda/lambda-notification-handler.js.map +1 -1
  79. package/dist/cores/lambda/lambda-sns-handler.js +79 -88
  80. package/dist/cores/lambda/lambda-sns-handler.js.map +1 -1
  81. package/dist/cores/lambda/lambda-sqs-handler.js +79 -88
  82. package/dist/cores/lambda/lambda-sqs-handler.js.map +1 -1
  83. package/dist/cores/lambda/lambda-web-handler.d.ts +6 -6
  84. package/dist/cores/lambda/lambda-web-handler.js +387 -412
  85. package/dist/cores/lambda/lambda-web-handler.js.map +1 -1
  86. package/dist/cores/lambda/lambda-wss-handler.js +23 -32
  87. package/dist/cores/lambda/lambda-wss-handler.js.map +1 -1
  88. package/dist/cores/protocol/index.js +10 -20
  89. package/dist/cores/protocol/index.js.map +1 -1
  90. package/dist/cores/protocol/protocol-service.d.ts +3 -3
  91. package/dist/cores/protocol/protocol-service.js +235 -227
  92. package/dist/cores/protocol/protocol-service.js.map +1 -1
  93. package/dist/cores/storage/http-storage-service.js +65 -85
  94. package/dist/cores/storage/http-storage-service.js.map +1 -1
  95. package/dist/cores/storage/model-manager.js +66 -85
  96. package/dist/cores/storage/model-manager.js.map +1 -1
  97. package/dist/cores/storage/proxy-storage-service.d.ts +2 -2
  98. package/dist/cores/storage/proxy-storage-service.js +562 -599
  99. package/dist/cores/storage/proxy-storage-service.js.map +1 -1
  100. package/dist/cores/storage/redis-storage-service.js +163 -177
  101. package/dist/cores/storage/redis-storage-service.js.map +1 -1
  102. package/dist/cores/storage/storage-service.d.ts +8 -1
  103. package/dist/cores/storage/storage-service.js +359 -324
  104. package/dist/cores/storage/storage-service.js.map +1 -1
  105. package/dist/engine/builder.d.ts +1 -1
  106. package/dist/engine/builder.js +59 -63
  107. package/dist/engine/builder.js.map +1 -1
  108. package/dist/engine/engine.d.ts +4 -4
  109. package/dist/engine/engine.js +9 -18
  110. package/dist/engine/engine.js.map +1 -1
  111. package/dist/engine/types.d.ts +1 -1
  112. package/dist/engine/utilities.d.ts +5 -5
  113. package/dist/engine/utilities.js +301 -293
  114. package/dist/engine/utilities.js.map +1 -1
  115. package/dist/environ.js +4 -6
  116. package/dist/environ.js.map +1 -1
  117. package/dist/extended/abstract-service.js +595 -645
  118. package/dist/extended/abstract-service.js.map +1 -1
  119. package/dist/extended/libs/sig-v4.js.map +1 -1
  120. package/dist/generated/field-registry.d.ts +10 -0
  121. package/dist/generated/field-registry.js +17 -0
  122. package/dist/generated/field-registry.js.map +1 -0
  123. package/dist/helpers/helpers.d.ts +17 -9
  124. package/dist/helpers/helpers.js +88 -78
  125. package/dist/helpers/helpers.js.map +1 -1
  126. package/dist/index.js +17 -7
  127. package/dist/index.js.map +1 -1
  128. package/dist/lib/dynamodb-value.js +2 -3
  129. package/dist/lib/dynamodb-value.js.map +1 -1
  130. package/dist/tools/express.js +4 -5
  131. package/dist/tools/express.js.map +1 -1
  132. package/dist/tools/tools.d.ts +3 -1
  133. package/dist/tools/tools.js +14 -21
  134. package/dist/tools/tools.js.map +1 -1
  135. package/package.json +25 -24
  136. package/dist/exec-cli.d.ts +0 -2
  137. package/dist/exec-cli.js +0 -211
  138. package/dist/exec-cli.js.map +0 -1
  139. package/dist/lib/dynamo/expressions.d.ts +0 -14
  140. package/dist/lib/dynamo/expressions.js +0 -212
  141. package/dist/lib/dynamo/expressions.js.map +0 -1
  142. package/dist/lib/dynamo/query.d.ts +0 -43
  143. package/dist/lib/dynamo/query.js +0 -246
  144. package/dist/lib/dynamo/query.js.map +0 -1
  145. package/dist/lib/dynamo/scan.d.ts +0 -33
  146. package/dist/lib/dynamo/scan.js +0 -172
  147. package/dist/lib/dynamo/scan.js.map +0 -1
  148. package/dist/lib/dynamo/serializer.d.ts +0 -12
  149. package/dist/lib/dynamo/serializer.js +0 -243
  150. package/dist/lib/dynamo/serializer.js.map +0 -1
  151. package/dist/lib/dynamo/utils.d.ts +0 -15
  152. package/dist/lib/dynamo/utils.js +0 -129
  153. package/dist/lib/dynamo/utils.js.map +0 -1
  154. package/dist/tools/shared.d.ts +0 -28
  155. package/dist/tools/shared.js +0 -143
  156. package/dist/tools/shared.js.map +0 -1
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.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
- return __awaiter(this, void 0, void 0, function* () {
66
- const data = yield this.$dynamo.readItem(id);
67
- const fields = this._fields || [];
68
- const item = fields.reduce((N, key) => {
69
- const val = data[key];
70
- if (val !== undefined)
71
- N[key] = val;
72
- return N;
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
- var _a;
84
- return __awaiter(this, void 0, void 0, function* () {
85
- const total = (_a = ids === null || ids === void 0 ? void 0 : ids.length) !== null && _a !== void 0 ? _a : 0;
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 __awaiter(this, void 0, void 0, function* () {
114
- return this.read(id).catch((e) => {
115
- if (`${e.message}`.startsWith('404 NOT FOUND'))
116
- return this.update(id, model);
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
- return __awaiter(this, void 0, void 0, function* () {
129
- const fields = this._fields || [];
130
- const data = fields.reduce((N, key) => {
131
- const val = model[key];
132
- if (val !== undefined)
133
- N[key] = val;
134
- return N;
135
- }, {});
136
- yield this.$dynamo.saveItem(id, data); // must be `{}`
137
- const item = Object.assign({ [this._idName]: id }, data);
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
- return __awaiter(this, void 0, void 0, function* () {
150
- const fields = this._fields || [];
151
- const $U = fields.reduce((N, key) => {
152
- const val = model[key];
153
- if (val !== undefined)
154
- N[key] = val;
155
- return N;
156
- }, {});
157
- /* eslint-disable prettier/prettier */
158
- const $I = !incrementals ? null : Object.keys(incrementals).reduce((M, key) => {
159
- const val = incrementals[key];
160
- if (typeof val !== 'number')
161
- throw new Error(`.${key} (${val}) should be number!`);
162
- M[key] = val;
163
- return M;
164
- }, {});
165
- /* eslint-enable prettier/prettier */
166
- const ret = yield this.$dynamo.updateItem(id, undefined, $U, $I);
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
- var _a;
177
- return __awaiter(this, void 0, void 0, function* () {
178
- const total = (_a = list === null || list === void 0 ? void 0 : list.length) !== null && _a !== void 0 ? _a : 0;
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
- return __awaiter(this, void 0, void 0, function* () {
211
- if (!model && !$update)
212
- throw new Error('@item is required!');
213
- const $org = yield this.read(id).catch(e => {
214
- if (`${e.message || e}`.startsWith('404 NOT FOUND'))
215
- return { id };
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
- return __awaiter(this, void 0, void 0, function* () {
254
- const $org = yield this.read(id);
255
- yield this.$dynamo.deleteItem(id);
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
- constructor(dataFile, name = 'memory', idName) {
273
- this.buffer = {};
274
- /**
275
- * say hello()
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
- read(id) {
298
- return __awaiter(this, void 0, void 0, function* () {
299
- if (!id.trim())
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
- throw new Error(`404 NOT FOUND - ${this.idName}:${id}`);
304
- return Object.assign(Object.assign({}, item), { [this.idName]: id });
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
- mread(ids) {
308
- var _a;
309
- return __awaiter(this, void 0, void 0, function* () {
310
- const total = (_a = ids === null || ids === void 0 ? void 0 : ids.length) !== null && _a !== void 0 ? _a : 0;
311
- const result = { success: [], failed: [], total };
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
- return result;
355
+ throw e;
326
356
  });
327
357
  }
328
- readSafe(id) {
329
- return __awaiter(this, void 0, void 0, function* () {
330
- return this.read(id).catch(e => {
331
- if (`${e.message || e}`.startsWith('404 NOT FOUND')) {
332
- const $org = { [this.idName]: id };
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
- readOrCreate(id, model) {
340
- return __awaiter(this, void 0, void 0, function* () {
341
- return this.read(id).catch((e) => {
342
- if (`${e.message}`.startsWith('404 NOT FOUND'))
343
- return this.update(id, model);
344
- throw e;
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
- save(id, item) {
349
- return __awaiter(this, void 0, void 0, function* () {
350
- if (!id)
351
- throw new Error('@id is required!');
352
- if (!item)
353
- throw new Error('@item is required!');
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
- this.buffer[id] = item;
357
- return Object.assign({ [this.idName]: id }, item);
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
- update(id, item, $inc) {
361
- return __awaiter(this, void 0, void 0, function* () {
362
- if (!id)
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 (!item)
365
- throw new Error('@item is required!');
366
- //* atomic operation for `.lock`
367
- const lock = (() => {
368
- let lock = 0;
369
- if (item && typeof item.lock == 'number')
370
- this.$locks[id] = lock = item.lock;
371
- if ($inc && typeof $inc.lock == 'number')
372
- this.$locks[id] = lock = $inc.lock + engine_1.$U.N(this.$locks[id], 0);
373
- return lock;
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
- mupdate(list) {
401
- var _a;
402
- return __awaiter(this, void 0, void 0, function* () {
403
- const total = (_a = list === null || list === void 0 ? void 0 : list.length) !== null && _a !== void 0 ? _a : 0;
404
- const result = { success: [], failed: [], total };
405
- if (!list || total === 0)
406
- return result;
407
- for (const item of list) {
408
- const _id = item[this.idName] || item.id;
409
- if (!_id)
410
- throw new Error('@id is required!');
411
- if (item && typeof item.lock == 'number')
412
- this.$locks[_id] = item.lock;
413
- this.buffer[_id] = item;
414
- result.success.push(Object.assign(Object.assign({}, item), { [this.idName]: _id }));
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
- return result;
417
- });
418
- }
419
- increment(id, $inc, $upt) {
420
- return __awaiter(this, void 0, void 0, function* () {
421
- if (!id)
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 (val !== undefined) {
445
- if (org !== undefined && typeof org === 'number' && typeof val !== 'number')
446
- throw new Error(`.${key} (${val}) should be number!`);
447
- if (typeof val !== 'number') {
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
- return N;
460
- }, {});
461
- if (typeof $set.lock == 'number')
462
- $set.lock = lock;
463
- yield this.save(id, Object.assign($org, $set));
464
- return Object.assign({ [this.idName]: id }, $set);
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
- return __awaiter(this, void 0, void 0, function* () {
469
- const $org = yield this.read(id);
470
- delete this.buffer[id];
471
- delete this.$locks[id];
472
- return $org;
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;