@monorise/core 0.1.2 → 0.1.3

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 (69) hide show
  1. package/dist/base/utils/index.js +2 -9
  2. package/dist/base/utils/index.js.map +1 -1
  3. package/dist/core/controllers/entity/create-entity.controller.js +39 -32
  4. package/dist/core/controllers/entity/create-entity.controller.js.map +1 -1
  5. package/dist/core/controllers/entity/delete-entity.controller.js +26 -20
  6. package/dist/core/controllers/entity/delete-entity.controller.js.map +1 -1
  7. package/dist/core/controllers/entity/get-entity-by-unique-field-value.controller.js +25 -17
  8. package/dist/core/controllers/entity/get-entity-by-unique-field-value.controller.js.map +1 -1
  9. package/dist/core/controllers/entity/get-entity.controller.js +25 -17
  10. package/dist/core/controllers/entity/get-entity.controller.js.map +1 -1
  11. package/dist/core/controllers/entity/list-entities.controller.js +39 -36
  12. package/dist/core/controllers/entity/list-entities.controller.js.map +1 -1
  13. package/dist/core/controllers/entity/update-entity.controller.js +40 -33
  14. package/dist/core/controllers/entity/update-entity.controller.js.map +1 -1
  15. package/dist/core/controllers/entity/upsert-entity.controller.js +64 -59
  16. package/dist/core/controllers/entity/upsert-entity.controller.js.map +1 -1
  17. package/dist/core/controllers/mutual/create-mutual.controller.js +42 -38
  18. package/dist/core/controllers/mutual/create-mutual.controller.js.map +1 -1
  19. package/dist/core/controllers/mutual/delete-mutual.controller.js +28 -22
  20. package/dist/core/controllers/mutual/delete-mutual.controller.js.map +1 -1
  21. package/dist/core/controllers/mutual/get-mutual.controller.js +25 -17
  22. package/dist/core/controllers/mutual/get-mutual.controller.js.map +1 -1
  23. package/dist/core/controllers/mutual/list-entities-by-entity.controller.js +52 -44
  24. package/dist/core/controllers/mutual/list-entities-by-entity.controller.js.map +1 -1
  25. package/dist/core/controllers/mutual/update-mutual.controller.js +38 -32
  26. package/dist/core/controllers/mutual/update-mutual.controller.js.map +1 -1
  27. package/dist/core/controllers/tag/list-tags.controller.js +39 -31
  28. package/dist/core/controllers/tag/list-tags.controller.js.map +1 -1
  29. package/dist/core/data/DbUtils.js +23 -12
  30. package/dist/core/data/DbUtils.js.map +1 -1
  31. package/dist/core/data/Entity.js +298 -334
  32. package/dist/core/data/Entity.js.map +1 -1
  33. package/dist/core/data/EventUtils.js +35 -27
  34. package/dist/core/data/EventUtils.js.map +1 -1
  35. package/dist/core/data/Mutual.js +282 -342
  36. package/dist/core/data/Mutual.js.map +1 -1
  37. package/dist/core/data/Tag.js +225 -228
  38. package/dist/core/data/Tag.js.map +1 -1
  39. package/dist/core/data/abstract/Repository.base.js +4 -7
  40. package/dist/core/data/abstract/Repository.base.js.map +1 -1
  41. package/dist/core/errors/extendable-error.js +0 -7
  42. package/dist/core/errors/extendable-error.js.map +1 -1
  43. package/dist/core/errors/standard-error.js +0 -3
  44. package/dist/core/errors/standard-error.js.map +1 -1
  45. package/dist/core/helpers/event.js +35 -34
  46. package/dist/core/helpers/event.js.map +1 -1
  47. package/dist/core/helpers/test/test-utils.js +60 -58
  48. package/dist/core/helpers/test/test-utils.js.map +1 -1
  49. package/dist/core/index.js +0 -8
  50. package/dist/core/index.js.map +1 -1
  51. package/dist/core/processors/create-entity-processor.js +12 -3
  52. package/dist/core/processors/create-entity-processor.js.map +1 -1
  53. package/dist/core/processors/mutual-processor.js +33 -23
  54. package/dist/core/processors/mutual-processor.js.map +1 -1
  55. package/dist/core/processors/prejoin-processor.js +117 -105
  56. package/dist/core/processors/prejoin-processor.js.map +1 -1
  57. package/dist/core/processors/replication-processor.js +27 -26
  58. package/dist/core/processors/replication-processor.js.map +1 -1
  59. package/dist/core/processors/tag-processor.js +47 -35
  60. package/dist/core/processors/tag-processor.js.map +1 -1
  61. package/dist/core/services/DependencyContainer.js +0 -4
  62. package/dist/core/services/DependencyContainer.js.map +1 -1
  63. package/dist/core/services/entity-service-lifecycle.js +29 -20
  64. package/dist/core/services/entity-service-lifecycle.js.map +1 -1
  65. package/dist/core/services/entity.service.js +95 -92
  66. package/dist/core/services/entity.service.js.map +1 -1
  67. package/dist/core/services/mutual.service.js +117 -113
  68. package/dist/core/services/mutual.service.js.map +1 -1
  69. package/package.json +1 -1
@@ -1,3 +1,12 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
1
10
  import { BatchStatementErrorCodeEnum, TransactionCanceledException, } from '@aws-sdk/client-dynamodb';
2
11
  import { marshall, unmarshall } from '@aws-sdk/util-dynamodb';
3
12
  import { ulid } from 'ulid';
@@ -6,18 +15,6 @@ import { sleep } from '../helpers/sleep';
6
15
  import { PROJECTION_EXPRESSION, } from './ProjectionExpression';
7
16
  import { Repository } from './abstract/Repository.base';
8
17
  export class Mutual {
9
- byEntityType;
10
- byEntityId;
11
- byData;
12
- entityType;
13
- entityId;
14
- data;
15
- mutualData;
16
- mutualId;
17
- _createdAt;
18
- _updatedAt;
19
- _mutualUpdatedAt;
20
- _expiresAt;
21
18
  constructor(byEntityType, byEntityId, byData, entityType, entityId, data, mutualData, mutualId, _createdAt, _updatedAt, _mutualUpdatedAt, _expiresAt) {
22
19
  this.byEntityType = byEntityType;
23
20
  this.byEntityId = byEntityId;
@@ -68,37 +65,28 @@ export class Mutual {
68
65
  return '#METADATA#';
69
66
  }
70
67
  get createdAt() {
71
- return this._createdAt?.toISOString();
68
+ var _a;
69
+ return (_a = this._createdAt) === null || _a === void 0 ? void 0 : _a.toISOString();
72
70
  }
73
71
  get updatedAt() {
74
- return this._updatedAt?.toISOString();
72
+ var _a;
73
+ return (_a = this._updatedAt) === null || _a === void 0 ? void 0 : _a.toISOString();
75
74
  }
76
75
  get mutualUpdatedAt() {
77
- return this._mutualUpdatedAt?.toISOString();
76
+ var _a;
77
+ return (_a = this._mutualUpdatedAt) === null || _a === void 0 ? void 0 : _a.toISOString();
78
78
  }
79
79
  get expiresAt() {
80
- return this._expiresAt?.toISOString();
80
+ var _a;
81
+ return (_a = this._expiresAt) === null || _a === void 0 ? void 0 : _a.toISOString();
81
82
  }
82
83
  toItem() {
83
- return {
84
- ...marshall(this.toJSON(), { removeUndefinedValues: true }),
85
- ...this.mainKeys(),
86
- };
84
+ return Object.assign(Object.assign({}, marshall(this.toJSON(), { removeUndefinedValues: true })), this.mainKeys());
87
85
  }
88
86
  toReversedItem() {
89
87
  const item = this.toJSON();
90
- const reversedMutual = {
91
- ...item,
92
- byEntityType: item.entityType,
93
- byEntityId: item.entityId,
94
- entityType: item.byEntityType,
95
- entityId: item.byEntityId,
96
- data: this.byData,
97
- };
98
- return {
99
- ...marshall(reversedMutual, { removeUndefinedValues: true }),
100
- ...this.mainKeys(),
101
- };
88
+ const reversedMutual = Object.assign(Object.assign({}, item), { byEntityType: item.entityType, byEntityId: item.entityId, entityType: item.byEntityType, entityId: item.byEntityId, data: this.byData });
89
+ return Object.assign(Object.assign({}, marshall(reversedMutual, { removeUndefinedValues: true })), this.mainKeys());
102
90
  }
103
91
  toJSON() {
104
92
  return {
@@ -117,380 +105,332 @@ export class Mutual {
117
105
  }
118
106
  }
119
107
  export class MutualRepository extends Repository {
120
- TABLE_NAME;
121
- dynamodbClient;
122
- ddbUtils;
123
108
  constructor(TABLE_NAME, dynamodbClient, ddbUtils) {
124
109
  super();
125
110
  this.TABLE_NAME = TABLE_NAME;
126
111
  this.dynamodbClient = dynamodbClient;
127
112
  this.ddbUtils = ddbUtils;
128
113
  }
129
- async listEntitiesByEntity(byEntityType, byEntityId, entityType, opts = {}) {
130
- const mutual = new Mutual(byEntityType, byEntityId, {}, entityType, 'list_by_only', {}, {});
131
- const listAssociationsQuery = {
132
- TableName: this.TABLE_NAME,
133
- KeyConditionExpression: '#PK = :PK and begins_with(#SK, :SK)',
134
- FilterExpression: 'attribute_not_exists(#expiresAt) or attribute_type(#expiresAt, :nullType)',
135
- ExpressionAttributeNames: {
136
- '#PK': 'PK',
137
- '#SK': 'SK',
138
- '#expiresAt': 'expiresAt',
139
- },
140
- ExpressionAttributeValues: {
141
- ':PK': {
142
- S: mutual.byFullEntityId,
114
+ listEntitiesByEntity(byEntityType_1, byEntityId_1, entityType_1) {
115
+ return __awaiter(this, arguments, void 0, function* (byEntityType, byEntityId, entityType, opts = {}) {
116
+ var _a, _b, _c, _d;
117
+ const mutual = new Mutual(byEntityType, byEntityId, {}, entityType, 'list_by_only', {}, {});
118
+ const listAssociationsQuery = {
119
+ TableName: this.TABLE_NAME,
120
+ KeyConditionExpression: '#PK = :PK and begins_with(#SK, :SK)',
121
+ FilterExpression: 'attribute_not_exists(#expiresAt) or attribute_type(#expiresAt, :nullType)',
122
+ ExpressionAttributeNames: {
123
+ '#PK': 'PK',
124
+ '#SK': 'SK',
125
+ '#expiresAt': 'expiresAt',
143
126
  },
144
- ':SK': {
145
- S: `${mutual.listEntitySK}#`,
127
+ ExpressionAttributeValues: {
128
+ ':PK': {
129
+ S: mutual.byFullEntityId,
130
+ },
131
+ ':SK': {
132
+ S: `${mutual.listEntitySK}#`,
133
+ },
134
+ ':nullType': { S: 'NULL' },
146
135
  },
147
- ':nullType': { S: 'NULL' },
148
- },
149
- ProjectionExpression: opts.ProjectionExpression,
150
- };
151
- let lastKey = opts.lastKey;
152
- let items = [];
153
- let remainingCount = opts.limit ?? 0;
154
- do {
155
- const resp = await this.dynamodbClient.query({
156
- ...listAssociationsQuery,
157
- ...(remainingCount && { Limit: remainingCount }),
158
- ...(lastKey && {
136
+ ProjectionExpression: opts.ProjectionExpression,
137
+ };
138
+ let lastKey = opts.lastKey;
139
+ let items = [];
140
+ let remainingCount = (_a = opts.limit) !== null && _a !== void 0 ? _a : 0;
141
+ do {
142
+ const resp = yield this.dynamodbClient.query(Object.assign(Object.assign(Object.assign({}, listAssociationsQuery), (remainingCount && { Limit: remainingCount })), (lastKey && {
159
143
  ExclusiveStartKey: lastKey,
160
- }),
144
+ })));
145
+ items = items.concat(((_b = resp.Items) === null || _b === void 0 ? void 0 : _b.map((item) => Mutual.fromItem(item))) || []);
146
+ lastKey = resp.LastEvaluatedKey;
147
+ if (opts.limit) {
148
+ remainingCount = remainingCount - ((_d = (_c = resp.Items) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0);
149
+ }
150
+ } while (
151
+ // limit is given, haven't reach limit, and there are still items to retrieve
152
+ (opts.limit && remainingCount && lastKey) ||
153
+ // no limit is given and there are still items to retrieve
154
+ (!opts.limit && lastKey));
155
+ return {
156
+ items,
157
+ lastKey,
158
+ };
159
+ });
160
+ }
161
+ getMutual(byEntityType, byEntityId, entityType, entityId, opts) {
162
+ return __awaiter(this, void 0, void 0, function* () {
163
+ var _a, _b;
164
+ const mutual = new Mutual(byEntityType, byEntityId, {}, entityType, entityId, {}, {});
165
+ const resp = yield this.dynamodbClient.query({
166
+ TableName: this.TABLE_NAME,
167
+ KeyConditionExpression: '#PK = :PK and begins_with(#SK, :SK)',
168
+ FilterExpression: 'attribute_not_exists(#expiresAt) or attribute_type(#expiresAt, :nullType)',
169
+ ExpressionAttributeNames: {
170
+ '#PK': 'PK',
171
+ '#SK': 'SK',
172
+ '#expiresAt': 'expiresAt',
173
+ },
174
+ ExpressionAttributeValues: {
175
+ ':PK': { S: mutual.byFullEntityId },
176
+ ':SK': { S: mutual.fullEntityId },
177
+ ':nullType': { S: 'NULL' },
178
+ },
179
+ Limit: 1,
161
180
  });
162
- items = items.concat(resp.Items?.map((item) => Mutual.fromItem(item)) || []);
163
- lastKey = resp.LastEvaluatedKey;
164
- if (opts.limit) {
165
- remainingCount = remainingCount - (resp.Items?.length ?? 0);
181
+ let mutualMetadata = null;
182
+ if (opts === null || opts === void 0 ? void 0 : opts.isFromMetadata) {
183
+ const tempMutual = Mutual.fromItem((_a = resp.Items) === null || _a === void 0 ? void 0 : _a[0]);
184
+ const respMetadataMutual = yield this.dynamodbClient.getItem({
185
+ TableName: this.TABLE_NAME,
186
+ Key: tempMutual.mainKeys(),
187
+ ProjectionExpression: opts === null || opts === void 0 ? void 0 : opts.ProjectionExpression,
188
+ });
189
+ mutualMetadata = Mutual.fromItem(respMetadataMutual.Item);
166
190
  }
167
- } while (
168
- // limit is given, haven't reach limit, and there are still items to retrieve
169
- (opts.limit && remainingCount && lastKey) ||
170
- // no limit is given and there are still items to retrieve
171
- (!opts.limit && lastKey));
172
- return {
173
- items,
174
- lastKey,
175
- };
176
- }
177
- async getMutual(byEntityType, byEntityId, entityType, entityId, opts) {
178
- const mutual = new Mutual(byEntityType, byEntityId, {}, entityType, entityId, {}, {});
179
- const resp = await this.dynamodbClient.query({
180
- TableName: this.TABLE_NAME,
181
- KeyConditionExpression: '#PK = :PK and begins_with(#SK, :SK)',
182
- FilterExpression: 'attribute_not_exists(#expiresAt) or attribute_type(#expiresAt, :nullType)',
183
- ExpressionAttributeNames: {
184
- '#PK': 'PK',
185
- '#SK': 'SK',
186
- '#expiresAt': 'expiresAt',
187
- },
188
- ExpressionAttributeValues: {
189
- ':PK': { S: mutual.byFullEntityId },
190
- ':SK': { S: mutual.fullEntityId },
191
- ':nullType': { S: 'NULL' },
192
- },
193
- Limit: 1,
191
+ return mutualMetadata || Mutual.fromItem((_b = resp.Items) === null || _b === void 0 ? void 0 : _b[0]);
194
192
  });
195
- let mutualMetadata = null;
196
- if (opts?.isFromMetadata) {
197
- const tempMutual = Mutual.fromItem(resp.Items?.[0]);
198
- const respMetadataMutual = await this.dynamodbClient.getItem({
193
+ }
194
+ checkMutualExist(byEntityType, byEntityId, entityType, entityId) {
195
+ return __awaiter(this, void 0, void 0, function* () {
196
+ var _a;
197
+ const mutual = new Mutual(byEntityType, byEntityId, {}, entityType, entityId, {}, {});
198
+ const resp = yield this.dynamodbClient.getItem({
199
199
  TableName: this.TABLE_NAME,
200
- Key: tempMutual.mainKeys(),
201
- ProjectionExpression: opts?.ProjectionExpression,
200
+ Key: mutual.subKeys(),
201
+ ProjectionExpression: 'PK, SK, expiresAt',
202
202
  });
203
- mutualMetadata = Mutual.fromItem(respMetadataMutual.Item);
204
- }
205
- return mutualMetadata || Mutual.fromItem(resp.Items?.[0]);
206
- }
207
- async checkMutualExist(byEntityType, byEntityId, entityType, entityId) {
208
- const mutual = new Mutual(byEntityType, byEntityId, {}, entityType, entityId, {}, {});
209
- const resp = await this.dynamodbClient.getItem({
210
- TableName: this.TABLE_NAME,
211
- Key: mutual.subKeys(),
212
- ProjectionExpression: 'PK, SK, expiresAt',
203
+ if (resp.Item && !((_a = resp.Item) === null || _a === void 0 ? void 0 : _a.expiresAt)) {
204
+ throw new StandardError('MUTUAL_EXISTS', 'Entities are already linked');
205
+ }
206
+ return;
213
207
  });
214
- if (resp.Item && !resp.Item?.expiresAt) {
215
- throw new StandardError('MUTUAL_EXISTS', 'Entities are already linked');
216
- }
217
- return;
218
208
  }
219
209
  createMutualTransactItems(mutual, opts) {
220
210
  const TransactItems = [
221
211
  {
222
212
  Put: {
223
213
  TableName: this.TABLE_NAME,
224
- ConditionExpression: opts?.ConditionExpression ||
214
+ ConditionExpression: (opts === null || opts === void 0 ? void 0 : opts.ConditionExpression) ||
225
215
  'attribute_not_exists(PK) OR attribute_exists(expiresAt)',
226
- ExpressionAttributeNames: opts?.ExpressionAttributeNames,
227
- ExpressionAttributeValues: opts?.ExpressionAttributeValues,
216
+ ExpressionAttributeNames: opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeNames,
217
+ ExpressionAttributeValues: opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeValues,
228
218
  Item: mutual.toItem(),
229
219
  },
230
220
  },
231
221
  {
232
222
  Put: {
233
223
  TableName: this.TABLE_NAME,
234
- ConditionExpression: opts?.ConditionExpression ||
224
+ ConditionExpression: (opts === null || opts === void 0 ? void 0 : opts.ConditionExpression) ||
235
225
  'attribute_not_exists(PK) OR attribute_exists(expiresAt)',
236
- ExpressionAttributeNames: opts?.ExpressionAttributeNames,
237
- ExpressionAttributeValues: opts?.ExpressionAttributeValues,
238
- Item: {
239
- ...mutual.toItem(),
240
- PK: { S: mutual.byFullEntityId },
241
- SK: { S: mutual.fullEntityId },
242
- R1PK: { S: mutual.fullEntityId },
243
- R1SK: { S: mutual.byFullEntityId },
244
- R2PK: { S: mutual.mainPk },
245
- R2SK: { S: mutual.byFullEntityId },
246
- },
226
+ ExpressionAttributeNames: opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeNames,
227
+ ExpressionAttributeValues: opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeValues,
228
+ Item: Object.assign(Object.assign({}, mutual.toItem()), { PK: { S: mutual.byFullEntityId }, SK: { S: mutual.fullEntityId }, R1PK: { S: mutual.fullEntityId }, R1SK: { S: mutual.byFullEntityId }, R2PK: { S: mutual.mainPk }, R2SK: { S: mutual.byFullEntityId } }),
247
229
  },
248
230
  },
249
231
  {
250
232
  Put: {
251
233
  TableName: this.TABLE_NAME,
252
- ConditionExpression: opts?.ConditionExpression ||
234
+ ConditionExpression: (opts === null || opts === void 0 ? void 0 : opts.ConditionExpression) ||
253
235
  'attribute_not_exists(PK) OR attribute_exists(expiresAt)',
254
- ExpressionAttributeNames: opts?.ExpressionAttributeNames,
255
- ExpressionAttributeValues: opts?.ExpressionAttributeValues,
256
- Item: {
257
- ...mutual.toReversedItem(),
258
- PK: { S: mutual.fullEntityId },
259
- SK: { S: mutual.byFullEntityId },
260
- R1PK: { S: mutual.byFullEntityId },
261
- R1SK: { S: mutual.fullEntityId },
262
- R2PK: { S: mutual.mainPk },
263
- R2SK: { S: mutual.fullEntityId },
264
- },
236
+ ExpressionAttributeNames: opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeNames,
237
+ ExpressionAttributeValues: opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeValues,
238
+ Item: Object.assign(Object.assign({}, mutual.toReversedItem()), { PK: { S: mutual.fullEntityId }, SK: { S: mutual.byFullEntityId }, R1PK: { S: mutual.byFullEntityId }, R1SK: { S: mutual.fullEntityId }, R2PK: { S: mutual.mainPk }, R2SK: { S: mutual.fullEntityId } }),
265
239
  },
266
240
  },
267
241
  ];
268
242
  return TransactItems;
269
243
  }
270
- async createMutual(byEntityType, byEntityId, byData, entityType, entityId, data, mutualData = {}, opts) {
271
- const errorContext = {};
272
- const currentDatetime = opts?.createAndUpdateDatetime || new Date();
273
- const mutual = new Mutual(byEntityType, byEntityId, byData, entityType, entityId, data, mutualData, ulid(), currentDatetime, currentDatetime, currentDatetime);
274
- const TransactItems = this.createMutualTransactItems(mutual, {
275
- ConditionExpression: opts?.ConditionExpression,
276
- ExpressionAttributeNames: opts?.ExpressionAttributeNames,
277
- ExpressionAttributeValues: opts?.ExpressionAttributeValues,
244
+ createMutual(byEntityType_1, byEntityId_1, byData_1, entityType_1, entityId_1, data_1) {
245
+ return __awaiter(this, arguments, void 0, function* (byEntityType, byEntityId, byData, entityType, entityId, data, mutualData = {}, opts) {
246
+ const errorContext = {};
247
+ const currentDatetime = (opts === null || opts === void 0 ? void 0 : opts.createAndUpdateDatetime) || new Date();
248
+ const mutual = new Mutual(byEntityType, byEntityId, byData, entityType, entityId, data, mutualData, ulid(), currentDatetime, currentDatetime, currentDatetime);
249
+ const TransactItems = this.createMutualTransactItems(mutual, {
250
+ ConditionExpression: opts === null || opts === void 0 ? void 0 : opts.ConditionExpression,
251
+ ExpressionAttributeNames: opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeNames,
252
+ ExpressionAttributeValues: opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeValues,
253
+ });
254
+ errorContext.TransactItems = TransactItems;
255
+ yield this.dynamodbClient.transactWriteItems({ TransactItems });
256
+ return mutual;
278
257
  });
279
- errorContext.TransactItems = TransactItems;
280
- await this.dynamodbClient.transactWriteItems({ TransactItems });
281
- return mutual;
282
258
  }
283
- async updateMutual(byEntityType, byEntityId, entityType, entityId, toUpdate, opts) {
284
- const returnUpdatedValue = opts?.returnUpdatedValue ?? false;
285
- const errorContext = {};
286
- try {
287
- const mutual = await this.getMutual(byEntityType, byEntityId, entityType, entityId, { ProjectionExpression: PROJECTION_EXPRESSION.NO_DATA });
288
- const currentDatetime = new Date().toISOString();
289
- const toUpdateExpressions = this.toUpdate({
290
- mutualUpdatedAt: currentDatetime,
291
- ...toUpdate,
292
- }, { maxLevel: opts?.maxObjectUpdateLevel });
293
- const updateExpression = {
294
- ConditionExpression: opts?.ConditionExpression || 'attribute_exists(PK)',
295
- UpdateExpression: toUpdateExpressions.UpdateExpression,
296
- ExpressionAttributeNames: {
297
- ...toUpdateExpressions.ExpressionAttributeNames,
298
- ...opts?.ExpressionAttributeNames,
299
- },
300
- ExpressionAttributeValues: {
301
- ...toUpdateExpressions.ExpressionAttributeValues,
302
- ...opts?.ExpressionAttributeValues,
303
- },
304
- };
305
- const TransactItems = [
306
- {
307
- Update: {
308
- TableName: this.TABLE_NAME,
309
- Key: mutual.mainKeys(),
310
- ...updateExpression,
259
+ updateMutual(byEntityType, byEntityId, entityType, entityId, toUpdate, opts) {
260
+ return __awaiter(this, void 0, void 0, function* () {
261
+ var _a;
262
+ const returnUpdatedValue = (_a = opts === null || opts === void 0 ? void 0 : opts.returnUpdatedValue) !== null && _a !== void 0 ? _a : false;
263
+ const errorContext = {};
264
+ try {
265
+ const mutual = yield this.getMutual(byEntityType, byEntityId, entityType, entityId, { ProjectionExpression: PROJECTION_EXPRESSION.NO_DATA });
266
+ const currentDatetime = new Date().toISOString();
267
+ const toUpdateExpressions = this.toUpdate(Object.assign({ mutualUpdatedAt: currentDatetime }, toUpdate), { maxLevel: opts === null || opts === void 0 ? void 0 : opts.maxObjectUpdateLevel });
268
+ const updateExpression = {
269
+ ConditionExpression: (opts === null || opts === void 0 ? void 0 : opts.ConditionExpression) || 'attribute_exists(PK)',
270
+ UpdateExpression: toUpdateExpressions.UpdateExpression,
271
+ ExpressionAttributeNames: Object.assign(Object.assign({}, toUpdateExpressions.ExpressionAttributeNames), opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeNames),
272
+ ExpressionAttributeValues: Object.assign(Object.assign({}, toUpdateExpressions.ExpressionAttributeValues), opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeValues),
273
+ };
274
+ const TransactItems = [
275
+ {
276
+ Update: Object.assign({ TableName: this.TABLE_NAME, Key: mutual.mainKeys() }, updateExpression),
311
277
  },
312
- },
313
- {
314
- Update: {
315
- TableName: this.TABLE_NAME,
316
- Key: {
317
- PK: { S: mutual.byFullEntityId },
318
- SK: { S: mutual.fullEntityId },
319
- },
320
- ...updateExpression,
278
+ {
279
+ Update: Object.assign({ TableName: this.TABLE_NAME, Key: {
280
+ PK: { S: mutual.byFullEntityId },
281
+ SK: { S: mutual.fullEntityId },
282
+ } }, updateExpression),
321
283
  },
322
- },
323
- {
324
- Update: {
325
- TableName: this.TABLE_NAME,
326
- Key: {
327
- PK: { S: mutual.fullEntityId },
328
- SK: { S: mutual.byFullEntityId },
329
- },
330
- ...updateExpression,
284
+ {
285
+ Update: Object.assign({ TableName: this.TABLE_NAME, Key: {
286
+ PK: { S: mutual.fullEntityId },
287
+ SK: { S: mutual.byFullEntityId },
288
+ } }, updateExpression),
331
289
  },
332
- },
333
- ];
334
- errorContext.TransactItems = TransactItems;
335
- await this.ddbUtils.executeTransactWrite({ TransactItems });
336
- if (!returnUpdatedValue) {
337
- return;
290
+ ];
291
+ errorContext.TransactItems = TransactItems;
292
+ yield this.ddbUtils.executeTransactWrite({ TransactItems });
293
+ if (!returnUpdatedValue) {
294
+ return;
295
+ }
296
+ const updatedMutual = yield this.getMutual(byEntityType, byEntityId, entityType, entityId);
297
+ return updatedMutual;
338
298
  }
339
- const updatedMutual = await this.getMutual(byEntityType, byEntityId, entityType, entityId);
340
- return updatedMutual;
341
- }
342
- catch (err) {
343
- if (err instanceof StandardError &&
344
- err.code === 'CONDITIONAL_CHECK_FAILED') {
345
- throw new StandardError('MUTUAL_NOT_FOUND', 'Mutual not found', err, {
346
- errorContext,
347
- });
299
+ catch (err) {
300
+ if (err instanceof StandardError &&
301
+ err.code === 'CONDITIONAL_CHECK_FAILED') {
302
+ throw new StandardError('MUTUAL_NOT_FOUND', 'Mutual not found', err, {
303
+ errorContext,
304
+ });
305
+ }
306
+ throw err;
348
307
  }
349
- throw err;
350
- }
308
+ });
351
309
  }
352
- async deleteMutual(byEntityType, byEntityId, entityType, entityId, opts) {
353
- const errorContext = {
354
- byEntityType,
355
- byEntityId,
356
- entityType,
357
- entityId,
358
- };
359
- try {
360
- const mutual = await this.getMutual(byEntityType, byEntityId, entityType, entityId, { ProjectionExpression: PROJECTION_EXPRESSION.NO_DATA });
361
- const tenMinsLater = Math.floor(new Date().getTime() / 1000 + 10 * 60);
362
- const expressions = {
363
- UpdateExpression: 'SET #expiresAt = :expiresAt, #mutualUpdatedAt = :mutualUpdatedAt, #updatedAt = :mutualUpdatedAt',
364
- ConditionExpression: opts?.ConditionExpression ||
365
- 'attribute_exists(PK) AND attribute_not_exists(#expiresAt)',
366
- ExpressionAttributeNames: {
367
- '#expiresAt': 'expiresAt',
368
- '#mutualUpdatedAt': 'mutualUpdatedAt',
369
- '#updatedAt': 'updatedAt',
370
- ...opts?.ExpressionAttributeNames,
371
- },
372
- ExpressionAttributeValues: {
373
- ':expiresAt': { N: String(tenMinsLater) },
374
- ':mutualUpdatedAt': { S: new Date().toISOString() },
375
- ...opts?.ExpressionAttributeValues,
376
- },
310
+ deleteMutual(byEntityType, byEntityId, entityType, entityId, opts) {
311
+ return __awaiter(this, void 0, void 0, function* () {
312
+ var _a;
313
+ const errorContext = {
314
+ byEntityType,
315
+ byEntityId,
316
+ entityType,
317
+ entityId,
377
318
  };
378
- const TransactItems = [
379
- {
380
- Update: {
381
- TableName: this.TABLE_NAME,
382
- Key: mutual.mainKeys(),
383
- ...expressions,
319
+ try {
320
+ const mutual = yield this.getMutual(byEntityType, byEntityId, entityType, entityId, { ProjectionExpression: PROJECTION_EXPRESSION.NO_DATA });
321
+ const tenMinsLater = Math.floor(new Date().getTime() / 1000 + 10 * 60);
322
+ const expressions = {
323
+ UpdateExpression: 'SET #expiresAt = :expiresAt, #mutualUpdatedAt = :mutualUpdatedAt, #updatedAt = :mutualUpdatedAt',
324
+ ConditionExpression: (opts === null || opts === void 0 ? void 0 : opts.ConditionExpression) ||
325
+ 'attribute_exists(PK) AND attribute_not_exists(#expiresAt)',
326
+ ExpressionAttributeNames: Object.assign({ '#expiresAt': 'expiresAt', '#mutualUpdatedAt': 'mutualUpdatedAt', '#updatedAt': 'updatedAt' }, opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeNames),
327
+ ExpressionAttributeValues: Object.assign({ ':expiresAt': { N: String(tenMinsLater) }, ':mutualUpdatedAt': { S: new Date().toISOString() } }, opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeValues),
328
+ };
329
+ const TransactItems = [
330
+ {
331
+ Update: Object.assign({ TableName: this.TABLE_NAME, Key: mutual.mainKeys() }, expressions),
384
332
  },
385
- },
386
- {
387
- Update: {
388
- TableName: this.TABLE_NAME,
389
- Key: {
390
- PK: { S: mutual.byFullEntityId },
391
- SK: { S: mutual.fullEntityId },
392
- },
393
- ...expressions,
333
+ {
334
+ Update: Object.assign({ TableName: this.TABLE_NAME, Key: {
335
+ PK: { S: mutual.byFullEntityId },
336
+ SK: { S: mutual.fullEntityId },
337
+ } }, expressions),
394
338
  },
339
+ {
340
+ Update: Object.assign({ TableName: this.TABLE_NAME, Key: {
341
+ PK: { S: mutual.fullEntityId },
342
+ SK: { S: mutual.byFullEntityId },
343
+ } }, expressions),
344
+ },
345
+ ];
346
+ errorContext.TransactItems = TransactItems;
347
+ yield this.dynamodbClient.transactWriteItems({ TransactItems });
348
+ return mutual;
349
+ }
350
+ catch (err) {
351
+ const isConditionalCheckFailed = err instanceof TransactionCanceledException &&
352
+ ((_a = err.CancellationReasons) === null || _a === void 0 ? void 0 : _a.some((reason) => reason.Code === BatchStatementErrorCodeEnum.ConditionalCheckFailed));
353
+ const isMutualIsUndefined = err instanceof StandardError && err.code === 'MUTUAL_IS_UNDEFINED';
354
+ if (isConditionalCheckFailed || isMutualIsUndefined) {
355
+ throw new StandardError('MUTUAL_NOT_FOUND', 'Mutual not found', err, {
356
+ errorContext,
357
+ });
358
+ }
359
+ throw err;
360
+ }
361
+ });
362
+ }
363
+ createMutualLock(_a) {
364
+ return __awaiter(this, arguments, void 0, function* ({ byEntityType, byEntityId, entityType, version, }) {
365
+ var _b, _c, _d;
366
+ let retryCount = 2;
367
+ const itemKey = {
368
+ PK: {
369
+ S: `MUTUAL#${byEntityType}#${byEntityId}#${entityType}`,
395
370
  },
396
- {
397
- Update: {
371
+ SK: { S: '#LOCK#' },
372
+ };
373
+ do {
374
+ try {
375
+ const fiveMinsLater = Math.floor(new Date().getTime() / 1000 + 5 * 60);
376
+ yield this.dynamodbClient.putItem({
398
377
  TableName: this.TABLE_NAME,
399
- Key: {
400
- PK: { S: mutual.fullEntityId },
401
- SK: { S: mutual.byFullEntityId },
378
+ Item: Object.assign(Object.assign({}, itemKey), { version: { S: version }, status: { S: 'LOCK' }, expiresAt: {
379
+ // auto release lock in case the mutual logic gone wrong to prevent dead lock
380
+ N: `${fiveMinsLater}`,
381
+ } }),
382
+ ConditionExpression: 'attribute_not_exists(PK) OR version < :version AND #status <> :status',
383
+ ExpressionAttributeNames: { '#status': 'status' },
384
+ ExpressionAttributeValues: {
385
+ ':version': { S: version },
386
+ ':status': { S: 'LOCK' },
402
387
  },
403
- ...expressions,
404
- },
405
- },
406
- ];
407
- errorContext.TransactItems = TransactItems;
408
- await this.dynamodbClient.transactWriteItems({ TransactItems });
409
- return mutual;
410
- }
411
- catch (err) {
412
- const isConditionalCheckFailed = err instanceof TransactionCanceledException &&
413
- err.CancellationReasons?.some((reason) => reason.Code === BatchStatementErrorCodeEnum.ConditionalCheckFailed);
414
- const isMutualIsUndefined = err instanceof StandardError && err.code === 'MUTUAL_IS_UNDEFINED';
415
- if (isConditionalCheckFailed || isMutualIsUndefined) {
416
- throw new StandardError('MUTUAL_NOT_FOUND', 'Mutual not found', err, {
417
- errorContext,
418
- });
419
- }
420
- throw err;
421
- }
388
+ });
389
+ return;
390
+ }
391
+ catch (err) {
392
+ console.log('=====CATCHED_MUTUAL_LOCK_CONFLICT=====');
393
+ const lock = yield this.dynamodbClient.getItem({
394
+ TableName: this.TABLE_NAME,
395
+ Key: itemKey,
396
+ });
397
+ // if version is lower, throw not retryable error to skip
398
+ const existingVersion = (_d = (_c = (_b = lock.Item) === null || _b === void 0 ? void 0 : _b.version) === null || _c === void 0 ? void 0 : _c.S) !== null && _d !== void 0 ? _d : '';
399
+ const isExistingVersionGreaterThanNewVersion = existingVersion >= version;
400
+ if (isExistingVersionGreaterThanNewVersion) {
401
+ throw new StandardError('MUTUAL_LOCK_CONFLICT', 'Lock conflict', err, { lock: lock.Item });
402
+ }
403
+ // default behaviour
404
+ // if version is higher, retry
405
+ // if lock not found, retry
406
+ yield sleep(2000);
407
+ console.log('=====RETRY_MUTUAL_LOCK=====');
408
+ }
409
+ } while (retryCount-- > 0);
410
+ // catch real unhandled error, so it can reach DLQ for inspection
411
+ throw new StandardError('RETRYABLE_MUTUAL_LOCK_CONFLICT', 'Retryable lock conflict');
412
+ });
422
413
  }
423
- async createMutualLock({ byEntityType, byEntityId, entityType, version, }) {
424
- let retryCount = 2;
425
- const itemKey = {
426
- PK: {
427
- S: `MUTUAL#${byEntityType}#${byEntityId}#${entityType}`,
428
- },
429
- SK: { S: '#LOCK#' },
430
- };
431
- do {
414
+ deleteMutualLock(_a) {
415
+ return __awaiter(this, arguments, void 0, function* ({ byEntityType, byEntityId, entityType, }) {
432
416
  try {
433
- const fiveMinsLater = Math.floor(new Date().getTime() / 1000 + 5 * 60);
434
- await this.dynamodbClient.putItem({
417
+ yield this.dynamodbClient.updateItem({
435
418
  TableName: this.TABLE_NAME,
436
- Item: {
437
- ...itemKey,
438
- version: { S: version },
439
- status: { S: 'LOCK' },
440
- expiresAt: {
441
- // auto release lock in case the mutual logic gone wrong to prevent dead lock
442
- N: `${fiveMinsLater}`,
419
+ Key: {
420
+ PK: {
421
+ S: `MUTUAL#${byEntityType}#${byEntityId}#${entityType}`,
443
422
  },
423
+ SK: { S: '#LOCK#' },
444
424
  },
445
- ConditionExpression: 'attribute_not_exists(PK) OR version < :version AND #status <> :status',
425
+ UpdateExpression: 'REMOVE #status',
446
426
  ExpressionAttributeNames: { '#status': 'status' },
447
- ExpressionAttributeValues: {
448
- ':version': { S: version },
449
- ':status': { S: 'LOCK' },
450
- },
451
427
  });
452
428
  return;
453
429
  }
454
- catch (err) {
455
- console.log('=====CATCHED_MUTUAL_LOCK_CONFLICT=====');
456
- const lock = await this.dynamodbClient.getItem({
457
- TableName: this.TABLE_NAME,
458
- Key: itemKey,
459
- });
460
- // if version is lower, throw not retryable error to skip
461
- const existingVersion = lock.Item?.version?.S ?? '';
462
- const isExistingVersionGreaterThanNewVersion = existingVersion >= version;
463
- if (isExistingVersionGreaterThanNewVersion) {
464
- throw new StandardError('MUTUAL_LOCK_CONFLICT', 'Lock conflict', err, { lock: lock.Item });
465
- }
466
- // default behaviour
467
- // if version is higher, retry
468
- // if lock not found, retry
469
- await sleep(2000);
470
- console.log('=====RETRY_MUTUAL_LOCK=====');
430
+ catch (error) {
431
+ // if lock is not found, it's okay
471
432
  }
472
- } while (retryCount-- > 0);
473
- // catch real unhandled error, so it can reach DLQ for inspection
474
- throw new StandardError('RETRYABLE_MUTUAL_LOCK_CONFLICT', 'Retryable lock conflict');
475
- }
476
- async deleteMutualLock({ byEntityType, byEntityId, entityType, }) {
477
- try {
478
- await this.dynamodbClient.updateItem({
479
- TableName: this.TABLE_NAME,
480
- Key: {
481
- PK: {
482
- S: `MUTUAL#${byEntityType}#${byEntityId}#${entityType}`,
483
- },
484
- SK: { S: '#LOCK#' },
485
- },
486
- UpdateExpression: 'REMOVE #status',
487
- ExpressionAttributeNames: { '#status': 'status' },
488
- });
489
- return;
490
- }
491
- catch (error) {
492
- // if lock is not found, it's okay
493
- }
433
+ });
494
434
  }
495
435
  }
496
436
  //# sourceMappingURL=Mutual.js.map