@monorise/core 1.0.2 → 1.0.4-0
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/dist/mock/monorise/chapter.d.ts +1 -1
- package/dist/mock/monorise/course.d.ts +1 -1
- package/dist/mock/monorise/learning-journey-config.d.ts +1 -1
- package/dist/mock/monorise/module.d.ts +1 -1
- package/dist/mock/monorise/organization.d.ts +1 -1
- package/dist/services/entity.service.d.ts +2 -2
- package/dist/services/entity.service.d.ts.map +1 -1
- package/package.json +4 -1
- package/configs/service.config.ts +0 -14
- package/constants/table.ts +0 -3
- package/controllers/entity/create-entity.controller.ts +0 -51
- package/controllers/entity/delete-entity.controller.ts +0 -35
- package/controllers/entity/entity.http +0 -62
- package/controllers/entity/get-entity.controller.ts +0 -33
- package/controllers/entity/list-entities.controller.ts +0 -69
- package/controllers/entity/update-entity.controller.ts +0 -56
- package/controllers/entity/upsert-entity.controller.ts +0 -97
- package/controllers/mutual/create-mutual.controller.ts +0 -89
- package/controllers/mutual/delete-mutual.controller.ts +0 -40
- package/controllers/mutual/get-mutual.controller.ts +0 -38
- package/controllers/mutual/list-entities-by-entity.controller.ts +0 -76
- package/controllers/mutual/mutual.http +0 -88
- package/controllers/mutual/update-mutual.controller.ts +0 -50
- package/controllers/setupRoutes.ts +0 -73
- package/controllers/tag/list-tags.controller.ts +0 -57
- package/data/DbUtils.ts +0 -40
- package/data/Entity.ts +0 -499
- package/data/EventUtils.ts +0 -47
- package/data/FileObject.ts +0 -16
- package/data/Mutual.ts +0 -779
- package/data/ProjectionExpression.ts +0 -8
- package/data/Tag.ts +0 -470
- package/data/abstract/Item.base.ts +0 -19
- package/data/abstract/Repository.base.ts +0 -92
- package/errors/api-error.ts +0 -39
- package/errors/extendable-error.ts +0 -35
- package/errors/standard-error.ts +0 -29
- package/helpers/dependencies.ts +0 -10
- package/helpers/event.ts +0 -85
- package/helpers/fromLastKeyQuery.ts +0 -11
- package/helpers/sleep.ts +0 -1
- package/helpers/toLastKeyResponse.ts +0 -11
- package/index.ts +0 -23
- package/middlewares/entity-type-check.ts +0 -20
- package/middlewares/mutual-type-check.ts +0 -26
- package/mock/entity.ts +0 -12
- package/mock/monorise/admin.ts +0 -35
- package/mock/monorise/chapter.ts +0 -94
- package/mock/monorise/course.ts +0 -149
- package/mock/monorise/index.ts +0 -143
- package/mock/monorise/learner.ts +0 -66
- package/mock/monorise/learning-activity.ts +0 -62
- package/mock/monorise/learning-journey-config.ts +0 -34
- package/mock/monorise/module.ts +0 -108
- package/mock/monorise/organization.ts +0 -63
- package/mock/monorise/reference.ts +0 -28
- package/mock/monorise/video.ts +0 -36
- package/processors/create-entity-processor.ts +0 -55
- package/processors/mutual-processor.ts +0 -262
- package/processors/prejoin-processor.ts +0 -264
- package/processors/replication-processor.ts +0 -261
- package/processors/tag-processor.ts +0 -174
- package/services/DependencyContainer.ts +0 -208
- package/services/entity-service-lifecycle.ts +0 -41
- package/services/entity.service.ts +0 -201
- package/services/mutual.service.ts +0 -285
- package/tsconfig.json +0 -116
- package/types/entity.type.ts +0 -62
- package/types/event.ts +0 -84
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export type ProjectionExpressionValues =
|
|
2
|
-
(typeof PROJECTION_EXPRESSION)[keyof typeof PROJECTION_EXPRESSION];
|
|
3
|
-
|
|
4
|
-
export const PROJECTION_EXPRESSION = {
|
|
5
|
-
NO_DATA: 'byEntityType, byEntityId, entityType, entityId, mutualId',
|
|
6
|
-
MUTUAL_DATA_ONLY:
|
|
7
|
-
'byEntityType, byEntityId, entityType, entityId, mutualId, mutualData',
|
|
8
|
-
} as const;
|
package/data/Tag.ts
DELETED
|
@@ -1,470 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AttributeValue,
|
|
3
|
-
DynamoDB,
|
|
4
|
-
QueryCommandInput,
|
|
5
|
-
} from '@aws-sdk/client-dynamodb';
|
|
6
|
-
import { marshall, unmarshall } from '@aws-sdk/util-dynamodb';
|
|
7
|
-
import type { EntitySchemaMap, Entity as EntityType } from '@monorise/base';
|
|
8
|
-
import { StandardError } from '../errors/standard-error';
|
|
9
|
-
import { Entity } from './Entity';
|
|
10
|
-
import type { ProjectionExpressionValues } from './ProjectionExpression';
|
|
11
|
-
import { Repository } from './abstract/Repository.base';
|
|
12
|
-
|
|
13
|
-
export class TaggedEntity<T extends EntityType> extends Entity<T> {
|
|
14
|
-
public tagName: string;
|
|
15
|
-
public group?: string;
|
|
16
|
-
public sortValue?: string;
|
|
17
|
-
|
|
18
|
-
constructor({
|
|
19
|
-
tagName,
|
|
20
|
-
group,
|
|
21
|
-
sortValue,
|
|
22
|
-
entityType,
|
|
23
|
-
entityId,
|
|
24
|
-
data,
|
|
25
|
-
createdAt,
|
|
26
|
-
updatedAt,
|
|
27
|
-
}: {
|
|
28
|
-
tagName: string;
|
|
29
|
-
group?: string;
|
|
30
|
-
sortValue?: string;
|
|
31
|
-
entityType: T;
|
|
32
|
-
entityId: string;
|
|
33
|
-
data?: Partial<EntitySchemaMap[T]>;
|
|
34
|
-
createdAt?: Date;
|
|
35
|
-
updatedAt?: Date;
|
|
36
|
-
}) {
|
|
37
|
-
super(entityType, entityId, data, createdAt, updatedAt);
|
|
38
|
-
|
|
39
|
-
this.tagName = tagName;
|
|
40
|
-
this.group = group;
|
|
41
|
-
this.sortValue = sortValue;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
static fromItem<T extends EntityType>(
|
|
45
|
-
item?: Record<string, AttributeValue>,
|
|
46
|
-
): TaggedEntity<T> {
|
|
47
|
-
if (!item) throw new StandardError('TAG_IS_UNDEFINED', 'Tag item empty');
|
|
48
|
-
|
|
49
|
-
const parsedItem = unmarshall(item);
|
|
50
|
-
|
|
51
|
-
return new TaggedEntity<T>({
|
|
52
|
-
tagName: parsedItem.tagName,
|
|
53
|
-
group: parsedItem.group,
|
|
54
|
-
sortValue: parsedItem.sortValue,
|
|
55
|
-
entityType: parsedItem.entityType,
|
|
56
|
-
entityId: parsedItem.entityId,
|
|
57
|
-
data: parsedItem.data,
|
|
58
|
-
createdAt: parsedItem.createdAt
|
|
59
|
-
? new Date(parsedItem.createdAt)
|
|
60
|
-
: undefined,
|
|
61
|
-
updatedAt: parsedItem.updatedAt
|
|
62
|
-
? new Date(parsedItem.updatedAt)
|
|
63
|
-
: undefined,
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
get pk(): string {
|
|
68
|
-
return `TAG#${this.entityType}#${this.tagName}${this.group ? `#${this.group}` : ''}`;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
get sk(): string {
|
|
72
|
-
return `${this.sortValue ? `${this.sortValue}#` : ''}${this.entityType}#${this.entityId}`;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
reversedKeys(): Record<string, AttributeValue> {
|
|
76
|
-
return {
|
|
77
|
-
PK: { S: `${this.entityType}#${this.entityId}` },
|
|
78
|
-
SK: {
|
|
79
|
-
S: this.pk,
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
replicationKeys(): Record<string, AttributeValue> {
|
|
85
|
-
const keys = this.reversedKeys();
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
R1PK: keys.PK,
|
|
89
|
-
R1SK: keys.SK,
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
toItem(): Record<string, AttributeValue> {
|
|
94
|
-
return {
|
|
95
|
-
...marshall(this.toJSON(), { removeUndefinedValues: true }),
|
|
96
|
-
...this.keys(),
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
toJSON(): Record<string, unknown> {
|
|
101
|
-
return {
|
|
102
|
-
tagName: this.tagName,
|
|
103
|
-
group: this.group,
|
|
104
|
-
sortValue: this.sortValue,
|
|
105
|
-
entityType: this.entityType,
|
|
106
|
-
entityId: this.entityId,
|
|
107
|
-
data: this.data,
|
|
108
|
-
createdAt: this.createdAt,
|
|
109
|
-
updatedAt: this.updatedAt,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export class TagRepository extends Repository {
|
|
115
|
-
constructor(
|
|
116
|
-
private readonly TABLE_NAME: string,
|
|
117
|
-
private readonly dynamodbClient: DynamoDB,
|
|
118
|
-
) {
|
|
119
|
-
super();
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async getExistingTags<T extends EntityType>({
|
|
123
|
-
entityType,
|
|
124
|
-
entityId,
|
|
125
|
-
tagName,
|
|
126
|
-
}: {
|
|
127
|
-
entityType: T;
|
|
128
|
-
entityId: string;
|
|
129
|
-
tagName: string;
|
|
130
|
-
}): Promise<TaggedEntity<T>[]> {
|
|
131
|
-
const PK = `${entityType}#${entityId}`;
|
|
132
|
-
const SK = `TAG#${entityType}#${tagName}`;
|
|
133
|
-
|
|
134
|
-
const results = await this.dynamodbClient.query({
|
|
135
|
-
TableName: this.TABLE_NAME,
|
|
136
|
-
KeyConditionExpression: '#PK = :PK and begins_with(#SK, :SK)',
|
|
137
|
-
ExpressionAttributeNames: {
|
|
138
|
-
'#PK': 'PK',
|
|
139
|
-
'#SK': 'SK',
|
|
140
|
-
},
|
|
141
|
-
ExpressionAttributeValues: {
|
|
142
|
-
':PK': { S: PK },
|
|
143
|
-
':SK': { S: SK },
|
|
144
|
-
},
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
return (results.Items || []).map((item: any) => {
|
|
148
|
-
return TaggedEntity.fromItem(item);
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async deleteTag({
|
|
153
|
-
tagName,
|
|
154
|
-
group,
|
|
155
|
-
sortValue,
|
|
156
|
-
entityType,
|
|
157
|
-
entityId,
|
|
158
|
-
}: {
|
|
159
|
-
tagName: string;
|
|
160
|
-
group?: string;
|
|
161
|
-
sortValue?: string;
|
|
162
|
-
entityType: EntityType;
|
|
163
|
-
entityId: string;
|
|
164
|
-
}): Promise<void> {
|
|
165
|
-
const tag = new TaggedEntity({
|
|
166
|
-
tagName,
|
|
167
|
-
group,
|
|
168
|
-
sortValue,
|
|
169
|
-
entityType,
|
|
170
|
-
entityId,
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
await Promise.all([
|
|
174
|
-
this.dynamodbClient.deleteItem({
|
|
175
|
-
TableName: this.TABLE_NAME,
|
|
176
|
-
Key: tag.keys(),
|
|
177
|
-
}),
|
|
178
|
-
this.dynamodbClient.deleteItem({
|
|
179
|
-
TableName: this.TABLE_NAME,
|
|
180
|
-
Key: tag.reversedKeys(),
|
|
181
|
-
}),
|
|
182
|
-
]);
|
|
183
|
-
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
async createTag<T extends EntityType>({
|
|
188
|
-
tagName,
|
|
189
|
-
group,
|
|
190
|
-
sortValue,
|
|
191
|
-
entity,
|
|
192
|
-
}: {
|
|
193
|
-
tagName: string;
|
|
194
|
-
group?: string;
|
|
195
|
-
sortValue?: string;
|
|
196
|
-
entity: Entity<T>;
|
|
197
|
-
}): Promise<TaggedEntity<T>> {
|
|
198
|
-
if (!entity.entityId) {
|
|
199
|
-
throw new StandardError(
|
|
200
|
-
'ENTITY_ID_IS_UNDEFINED',
|
|
201
|
-
'entityId is undefined',
|
|
202
|
-
);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const tag = new TaggedEntity({
|
|
206
|
-
tagName,
|
|
207
|
-
group,
|
|
208
|
-
sortValue,
|
|
209
|
-
entityType: entity.entityType,
|
|
210
|
-
entityId: entity.entityId,
|
|
211
|
-
data: entity.data,
|
|
212
|
-
createdAt: entity.createdAt ? new Date(entity.createdAt) : new Date(),
|
|
213
|
-
updatedAt: entity.updatedAt ? new Date(entity.updatedAt) : new Date(),
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
await Promise.all([
|
|
217
|
-
this.dynamodbClient.putItem({
|
|
218
|
-
TableName: this.TABLE_NAME,
|
|
219
|
-
Item: {
|
|
220
|
-
...tag.toItem(),
|
|
221
|
-
...tag.replicationKeys(),
|
|
222
|
-
},
|
|
223
|
-
}),
|
|
224
|
-
this.dynamodbClient.putItem({
|
|
225
|
-
TableName: this.TABLE_NAME,
|
|
226
|
-
Item: {
|
|
227
|
-
...marshall(
|
|
228
|
-
{
|
|
229
|
-
tagName,
|
|
230
|
-
group,
|
|
231
|
-
sortValue,
|
|
232
|
-
},
|
|
233
|
-
{ removeUndefinedValues: true },
|
|
234
|
-
),
|
|
235
|
-
...tag.reversedKeys(),
|
|
236
|
-
...tag.replicationKeys(),
|
|
237
|
-
},
|
|
238
|
-
}),
|
|
239
|
-
]);
|
|
240
|
-
|
|
241
|
-
return tag;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
async listTags<T extends EntityType>({
|
|
245
|
-
entityType,
|
|
246
|
-
tagName,
|
|
247
|
-
limit, // if this is not set, it will return all items
|
|
248
|
-
query,
|
|
249
|
-
group,
|
|
250
|
-
start,
|
|
251
|
-
end,
|
|
252
|
-
options = {},
|
|
253
|
-
}: {
|
|
254
|
-
entityType: T;
|
|
255
|
-
tagName: string;
|
|
256
|
-
limit?: number;
|
|
257
|
-
start?: string;
|
|
258
|
-
end?: string;
|
|
259
|
-
query?: string;
|
|
260
|
-
group?: string;
|
|
261
|
-
options?: {
|
|
262
|
-
lastKey?: Record<string, AttributeValue>;
|
|
263
|
-
ProjectionExpression?: ProjectionExpressionValues;
|
|
264
|
-
};
|
|
265
|
-
}): Promise<{
|
|
266
|
-
items: Entity<T>[];
|
|
267
|
-
totalCount?: number;
|
|
268
|
-
lastKey?: Record<string, AttributeValue>;
|
|
269
|
-
}> {
|
|
270
|
-
const errorContext: Record<string, unknown> = {
|
|
271
|
-
entityType,
|
|
272
|
-
tagName,
|
|
273
|
-
limit,
|
|
274
|
-
query,
|
|
275
|
-
group,
|
|
276
|
-
start,
|
|
277
|
-
end,
|
|
278
|
-
options,
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
const tag = new TaggedEntity({
|
|
282
|
-
tagName,
|
|
283
|
-
entityType,
|
|
284
|
-
entityId: '',
|
|
285
|
-
group,
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
let expression: Pick<
|
|
289
|
-
QueryCommandInput,
|
|
290
|
-
| 'KeyConditionExpression'
|
|
291
|
-
| 'ExpressionAttributeNames'
|
|
292
|
-
| 'ExpressionAttributeValues'
|
|
293
|
-
> | null = null;
|
|
294
|
-
|
|
295
|
-
if (query && !start && !end) {
|
|
296
|
-
expression = {
|
|
297
|
-
KeyConditionExpression: '#PK = :PK and begins_with(#SK, :SK)',
|
|
298
|
-
ExpressionAttributeNames: {
|
|
299
|
-
'#PK': 'PK',
|
|
300
|
-
'#SK': 'SK',
|
|
301
|
-
},
|
|
302
|
-
ExpressionAttributeValues: {
|
|
303
|
-
':PK': {
|
|
304
|
-
S: tag.pk,
|
|
305
|
-
},
|
|
306
|
-
':SK': {
|
|
307
|
-
S: `${query}#`,
|
|
308
|
-
},
|
|
309
|
-
},
|
|
310
|
-
};
|
|
311
|
-
} else if (start && end) {
|
|
312
|
-
expression = {
|
|
313
|
-
KeyConditionExpression: '#PK = :PK and #SK between :SKStart and :SKEnd',
|
|
314
|
-
ExpressionAttributeNames: {
|
|
315
|
-
'#PK': 'PK',
|
|
316
|
-
'#SK': 'SK',
|
|
317
|
-
},
|
|
318
|
-
ExpressionAttributeValues: {
|
|
319
|
-
':PK': {
|
|
320
|
-
S: tag.pk,
|
|
321
|
-
},
|
|
322
|
-
':SKStart': {
|
|
323
|
-
S: `${start}#`,
|
|
324
|
-
},
|
|
325
|
-
':SKEnd': {
|
|
326
|
-
S: `${end}#`,
|
|
327
|
-
},
|
|
328
|
-
},
|
|
329
|
-
};
|
|
330
|
-
} else if (start && !end) {
|
|
331
|
-
expression = {
|
|
332
|
-
KeyConditionExpression: '#PK = :PK and #SK >= :SK',
|
|
333
|
-
ExpressionAttributeNames: {
|
|
334
|
-
'#PK': 'PK',
|
|
335
|
-
'#SK': 'SK',
|
|
336
|
-
},
|
|
337
|
-
ExpressionAttributeValues: {
|
|
338
|
-
':PK': {
|
|
339
|
-
S: tag.pk,
|
|
340
|
-
},
|
|
341
|
-
':SK': {
|
|
342
|
-
S: `${start}#`,
|
|
343
|
-
},
|
|
344
|
-
},
|
|
345
|
-
};
|
|
346
|
-
} else if (!start && end) {
|
|
347
|
-
expression = {
|
|
348
|
-
KeyConditionExpression: '#PK = :PK and #SK <= :SK',
|
|
349
|
-
ExpressionAttributeNames: {
|
|
350
|
-
'#PK': 'PK',
|
|
351
|
-
'#SK': 'SK',
|
|
352
|
-
},
|
|
353
|
-
ExpressionAttributeValues: {
|
|
354
|
-
':PK': {
|
|
355
|
-
S: tag.pk,
|
|
356
|
-
},
|
|
357
|
-
':SK': {
|
|
358
|
-
S: `${end}#`,
|
|
359
|
-
},
|
|
360
|
-
},
|
|
361
|
-
};
|
|
362
|
-
} else if (group && !query && !start && !end) {
|
|
363
|
-
expression = {
|
|
364
|
-
KeyConditionExpression: '#PK = :PK',
|
|
365
|
-
ExpressionAttributeNames: {
|
|
366
|
-
'#PK': 'PK',
|
|
367
|
-
},
|
|
368
|
-
ExpressionAttributeValues: {
|
|
369
|
-
':PK': {
|
|
370
|
-
S: tag.pk,
|
|
371
|
-
},
|
|
372
|
-
},
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
if (!expression) {
|
|
377
|
-
throw new StandardError(
|
|
378
|
-
'INVALID_QUERY',
|
|
379
|
-
'Invalid query. Please provide a valid query',
|
|
380
|
-
null,
|
|
381
|
-
errorContext,
|
|
382
|
-
);
|
|
383
|
-
}
|
|
384
|
-
const defaultListQuery: QueryCommandInput = {
|
|
385
|
-
TableName: this.TABLE_NAME,
|
|
386
|
-
Limit: limit,
|
|
387
|
-
ScanIndexForward: false,
|
|
388
|
-
ProjectionExpression: options?.ProjectionExpression,
|
|
389
|
-
...expression,
|
|
390
|
-
};
|
|
391
|
-
|
|
392
|
-
let lastKey = options.lastKey;
|
|
393
|
-
let items: Record<string, AttributeValue>[] = [];
|
|
394
|
-
let remainingCount = limit ?? 0;
|
|
395
|
-
do {
|
|
396
|
-
const resp = await this.dynamodbClient.query({
|
|
397
|
-
...defaultListQuery,
|
|
398
|
-
...(remainingCount && { Limit: remainingCount }),
|
|
399
|
-
...(lastKey && {
|
|
400
|
-
ExclusiveStartKey: lastKey,
|
|
401
|
-
}),
|
|
402
|
-
});
|
|
403
|
-
items = items.concat(resp.Items ?? []);
|
|
404
|
-
|
|
405
|
-
lastKey = resp.LastEvaluatedKey;
|
|
406
|
-
|
|
407
|
-
if (limit) {
|
|
408
|
-
remainingCount = remainingCount - (resp.Items?.length ?? 0);
|
|
409
|
-
}
|
|
410
|
-
} while (
|
|
411
|
-
// limit is given, haven't reach limit, and there are still items to retrieve
|
|
412
|
-
(limit && remainingCount && lastKey) ||
|
|
413
|
-
// no limit is given and there are still items to retrieve
|
|
414
|
-
(!limit && lastKey)
|
|
415
|
-
);
|
|
416
|
-
|
|
417
|
-
return {
|
|
418
|
-
items: (items || []).map(Entity.fromItem<T>),
|
|
419
|
-
totalCount: items.length,
|
|
420
|
-
lastKey,
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
async createLock({
|
|
425
|
-
entityType,
|
|
426
|
-
entityId,
|
|
427
|
-
}: {
|
|
428
|
-
entityType: EntityType;
|
|
429
|
-
entityId: string;
|
|
430
|
-
}): Promise<void> {
|
|
431
|
-
const oneMinuteLater = Math.floor(new Date().getTime() / 1000 + 1 * 60);
|
|
432
|
-
|
|
433
|
-
await this.dynamodbClient.putItem({
|
|
434
|
-
TableName: this.TABLE_NAME,
|
|
435
|
-
Item: {
|
|
436
|
-
PK: { S: `TAG#${entityType}#${entityId}` },
|
|
437
|
-
SK: { S: '#LOCK#' },
|
|
438
|
-
expiresAt: {
|
|
439
|
-
// auto delete lock after 1 minute
|
|
440
|
-
N: `${oneMinuteLater}`,
|
|
441
|
-
},
|
|
442
|
-
},
|
|
443
|
-
ConditionExpression: 'attribute_not_exists(PK)',
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
return;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
async deleteLock({
|
|
450
|
-
entityType,
|
|
451
|
-
entityId,
|
|
452
|
-
}: {
|
|
453
|
-
entityType: EntityType;
|
|
454
|
-
entityId: string;
|
|
455
|
-
}): Promise<void> {
|
|
456
|
-
try {
|
|
457
|
-
await this.dynamodbClient.deleteItem({
|
|
458
|
-
TableName: this.TABLE_NAME,
|
|
459
|
-
Key: {
|
|
460
|
-
PK: { S: `TAG#${entityType}#${entityId}` },
|
|
461
|
-
SK: { S: '#LOCK#' },
|
|
462
|
-
},
|
|
463
|
-
});
|
|
464
|
-
|
|
465
|
-
return;
|
|
466
|
-
} catch (error) {
|
|
467
|
-
// if lock is not found, it's okay
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { AttributeValue } from '@aws-sdk/client-dynamodb';
|
|
2
|
-
|
|
3
|
-
export abstract class Item {
|
|
4
|
-
abstract get pk(): string;
|
|
5
|
-
abstract get sk(): string;
|
|
6
|
-
abstract get createdAt(): string | undefined;
|
|
7
|
-
abstract get updatedAt(): string | undefined;
|
|
8
|
-
|
|
9
|
-
public keys(): Record<string, AttributeValue> {
|
|
10
|
-
return {
|
|
11
|
-
PK: { S: this.pk },
|
|
12
|
-
SK: { S: this.sk },
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
abstract toItem(): Record<string, AttributeValue>;
|
|
17
|
-
|
|
18
|
-
abstract toJSON(): Record<string, unknown>;
|
|
19
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import type { AttributeValue } from '@aws-sdk/client-dynamodb';
|
|
2
|
-
import { marshall } from '@aws-sdk/util-dynamodb';
|
|
3
|
-
|
|
4
|
-
function flattenObject(
|
|
5
|
-
obj: Record<string, unknown>,
|
|
6
|
-
parentKey = '',
|
|
7
|
-
result: Record<string, unknown> = {},
|
|
8
|
-
level = 1,
|
|
9
|
-
opts?: {
|
|
10
|
-
maxLevel?: number;
|
|
11
|
-
},
|
|
12
|
-
): Record<string, unknown> {
|
|
13
|
-
const MAX_LEVEL = opts?.maxLevel ?? 2;
|
|
14
|
-
|
|
15
|
-
for (const key in obj) {
|
|
16
|
-
if (obj.hasOwnProperty(key)) {
|
|
17
|
-
const propName = parentKey ? `${parentKey}.${key}` : key;
|
|
18
|
-
if (
|
|
19
|
-
typeof obj[key] === 'object' &&
|
|
20
|
-
obj[key] !== null &&
|
|
21
|
-
!Array.isArray(obj[key]) &&
|
|
22
|
-
level < MAX_LEVEL
|
|
23
|
-
) {
|
|
24
|
-
flattenObject(
|
|
25
|
-
obj[key] as Record<string, unknown>,
|
|
26
|
-
propName,
|
|
27
|
-
result,
|
|
28
|
-
level + 1,
|
|
29
|
-
opts,
|
|
30
|
-
);
|
|
31
|
-
} else {
|
|
32
|
-
result[propName] = obj[key];
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return result;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export abstract class Repository {
|
|
40
|
-
toUpdate(
|
|
41
|
-
parsedUpdateData: Record<string, unknown>,
|
|
42
|
-
opts?: {
|
|
43
|
-
// to limit the partial update depth for an object
|
|
44
|
-
// in some scenario, we have to ensure the object to be written must be an object instead of undefined/null
|
|
45
|
-
// eg, writing to data.cover.name must ensure data.cover is an object already else we will get error
|
|
46
|
-
maxLevel?: number;
|
|
47
|
-
},
|
|
48
|
-
): {
|
|
49
|
-
UpdateExpression: string;
|
|
50
|
-
ExpressionAttributeNames: Record<string, string>;
|
|
51
|
-
ExpressionAttributeValues: Record<string, AttributeValue>;
|
|
52
|
-
} {
|
|
53
|
-
const flattenedData = flattenObject(parsedUpdateData, '', {}, 1, opts);
|
|
54
|
-
|
|
55
|
-
let updateExpression = '';
|
|
56
|
-
const expressionAttributeNames: Record<string, string> = {};
|
|
57
|
-
const expressionAttributeValues: Record<string, unknown> = {};
|
|
58
|
-
|
|
59
|
-
for (const key in flattenedData) {
|
|
60
|
-
if (updateExpression.length > 0) {
|
|
61
|
-
updateExpression += ', ';
|
|
62
|
-
}
|
|
63
|
-
const attributePath = key
|
|
64
|
-
.split('.')
|
|
65
|
-
.map((part) => `#${part}`)
|
|
66
|
-
.join('.');
|
|
67
|
-
const valuePlaceholder = `:${key.replace(/\./g, '_')}`;
|
|
68
|
-
|
|
69
|
-
updateExpression += `${attributePath} = ${valuePlaceholder}`;
|
|
70
|
-
|
|
71
|
-
key.split('.').forEach((part) => {
|
|
72
|
-
expressionAttributeNames[`#${part}`] = part;
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
expressionAttributeValues[valuePlaceholder] = flattenedData[key];
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
updateExpression = `SET ${updateExpression}`;
|
|
79
|
-
|
|
80
|
-
const updateAttributes = {
|
|
81
|
-
UpdateExpression: updateExpression,
|
|
82
|
-
ExpressionAttributeNames: {
|
|
83
|
-
...expressionAttributeNames,
|
|
84
|
-
},
|
|
85
|
-
ExpressionAttributeValues: {
|
|
86
|
-
...marshall(expressionAttributeValues),
|
|
87
|
-
},
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
return updateAttributes;
|
|
91
|
-
}
|
|
92
|
-
}
|
package/errors/api-error.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import * as httpStatus from 'http-status';
|
|
2
|
-
import ExtendableError from './extendable-error';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Class representing an API error.
|
|
6
|
-
* @extends ExtendableError
|
|
7
|
-
*/
|
|
8
|
-
class APIError extends ExtendableError {
|
|
9
|
-
/**
|
|
10
|
-
* Creates an API error.
|
|
11
|
-
* @param {string} message - Error message.
|
|
12
|
-
* @param {number} status - HTTP status code of error.
|
|
13
|
-
* @param {boolean} isPublic - Whether the message should be visible to user or not.
|
|
14
|
-
* @param {string | undefined} stack - Stack trace.
|
|
15
|
-
*/
|
|
16
|
-
constructor({
|
|
17
|
-
message,
|
|
18
|
-
errors,
|
|
19
|
-
stack,
|
|
20
|
-
status = httpStatus.INTERNAL_SERVER_ERROR,
|
|
21
|
-
isPublic = false,
|
|
22
|
-
}: {
|
|
23
|
-
message: string;
|
|
24
|
-
errors?: any;
|
|
25
|
-
stack?: string;
|
|
26
|
-
status?: number;
|
|
27
|
-
isPublic?: boolean;
|
|
28
|
-
}) {
|
|
29
|
-
super({
|
|
30
|
-
message,
|
|
31
|
-
errors,
|
|
32
|
-
status,
|
|
33
|
-
isPublic,
|
|
34
|
-
stack,
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export default APIError;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
class ExtendableError extends Error {
|
|
2
|
-
public name: string;
|
|
3
|
-
public message: string;
|
|
4
|
-
public errors: any;
|
|
5
|
-
public status: number;
|
|
6
|
-
public isPublic: boolean;
|
|
7
|
-
public isOperational: boolean;
|
|
8
|
-
public stack?: string;
|
|
9
|
-
|
|
10
|
-
constructor({
|
|
11
|
-
message,
|
|
12
|
-
errors,
|
|
13
|
-
status,
|
|
14
|
-
isPublic,
|
|
15
|
-
stack,
|
|
16
|
-
}: {
|
|
17
|
-
message: string;
|
|
18
|
-
errors?: any;
|
|
19
|
-
status?: number;
|
|
20
|
-
isPublic?: boolean;
|
|
21
|
-
stack?: string;
|
|
22
|
-
}) {
|
|
23
|
-
super(message);
|
|
24
|
-
this.name = this.constructor.name;
|
|
25
|
-
this.message = message;
|
|
26
|
-
this.errors = errors;
|
|
27
|
-
this.status = status || 500; // Default value if status is not provided
|
|
28
|
-
this.isPublic = isPublic || false; // Default value if isPublic is not provided
|
|
29
|
-
this.isOperational = true; // This is required since bluebird 4 doesn't append it anymore.
|
|
30
|
-
this.stack = stack;
|
|
31
|
-
// Error.captureStackTrace(this, this.constructor.name);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export default ExtendableError;
|
package/errors/standard-error.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
export class StandardError extends Error {
|
|
2
|
-
public code: string;
|
|
3
|
-
public lastError?: object | null;
|
|
4
|
-
public context?: string | null;
|
|
5
|
-
|
|
6
|
-
constructor(
|
|
7
|
-
errorCode: string,
|
|
8
|
-
message: string,
|
|
9
|
-
lastError?: any,
|
|
10
|
-
context?: object | string | null,
|
|
11
|
-
) {
|
|
12
|
-
super(message);
|
|
13
|
-
|
|
14
|
-
// So you can do typeof CustomError
|
|
15
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
16
|
-
|
|
17
|
-
this.name = this.constructor.name;
|
|
18
|
-
this.code = errorCode;
|
|
19
|
-
this.lastError = lastError;
|
|
20
|
-
this.context = JSON.stringify(context, null, 2);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
public toJSON() {
|
|
24
|
-
return {
|
|
25
|
-
code: this.code,
|
|
26
|
-
message: this.message,
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
}
|