@travetto/model-dynamodb 2.1.5 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,7 +10,7 @@ npm install @travetto/model-dynamodb
10
10
 
11
11
  This module provides an [DynamoDB](https://aws.amazon.com/dynamodb/)-based implementation for the [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations."). This source allows the [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations.") module to read, write and query against [DynamoDB](https://aws.amazon.com/dynamodb/). The entire document is stored as a single value, so nothing is needed to handle schema updates in real time. Indices on the other hand are more complicated, and will not be retroactively computed for new values.
12
12
 
13
- Supported featrues:
13
+ Supported features:
14
14
 
15
15
  * [CRUD](https://github.com/travetto/travetto/tree/main/module/model/src/service/crud.ts#L11)
16
16
  * [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/service/expiry.ts#L11)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@travetto/model-dynamodb",
3
3
  "displayName": "DynamoDB Model Support",
4
- "version": "2.1.5",
4
+ "version": "2.2.2",
5
5
  "description": "DynamoDB backing for the travetto model module.",
6
6
  "keywords": [
7
7
  "typescript",
@@ -27,8 +27,8 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@aws-sdk/client-dynamodb": "^3.131.0",
30
- "@travetto/config": "^2.1.5",
31
- "@travetto/model": "^2.1.5"
30
+ "@travetto/config": "^2.2.2",
31
+ "@travetto/model": "^2.2.2"
32
32
  },
33
33
  "publishConfig": {
34
34
  "access": "public"
package/src/service.ts CHANGED
@@ -18,7 +18,7 @@ import { DynamoDBModelConfig } from './config';
18
18
 
19
19
  const EXP_ATTR = 'expires_at__';
20
20
 
21
- function simpleName(idx: string) {
21
+ function simpleName(idx: string): string {
22
22
  return idx.replace(/[^A-Za-z0-9]/g, '');
23
23
  }
24
24
 
@@ -27,6 +27,7 @@ function toValue(val: unknown, forceString?: boolean): dynamodb.AttributeValue |
27
27
  if (val === undefined || val === null || val === '') {
28
28
  return { NULL: true };
29
29
  } else if (typeof val === 'string' || forceString) {
30
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
30
31
  return { S: val as string };
31
32
  } else if (typeof val === 'number') {
32
33
  return { N: `${val}` };
@@ -60,7 +61,7 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
60
61
 
61
62
  constructor(public readonly config: DynamoDBModelConfig) { }
62
63
 
63
- #resolveTable(cls: Class) {
64
+ #resolveTable(cls: Class): string {
64
65
  let table = ModelRegistry.getStore(cls).toLowerCase().replace(/[^A-Za-z0-9_]+/g, '_');
65
66
  if (this.config.namespace) {
66
67
  table = `${this.config.namespace}_${table}`;
@@ -68,7 +69,7 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
68
69
  return table;
69
70
  }
70
71
 
71
- async #putItem<T extends ModelType>(cls: Class<T>, id: string, item: T, mode: 'create' | 'update' | 'upsert') {
72
+ async #putItem<T extends ModelType>(cls: Class<T>, id: string, item: T, mode: 'create' | 'update' | 'upsert'): Promise<dynamodb.PutItemCommandOutput> {
72
73
  const config = ModelRegistry.get(cls);
73
74
  let expiry: number | undefined;
74
75
 
@@ -101,7 +102,7 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
101
102
  },
102
103
  ReturnValues: 'NONE'
103
104
  };
104
- console.debug('Querying', { query } as unknown as Record<string, string>);
105
+ console.debug('Querying', { query });
105
106
  return await this.client.putItem(query);
106
107
  } else {
107
108
  const indices: Record<string, unknown> = {};
@@ -135,7 +136,7 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
135
136
  });
136
137
  }
137
138
  } catch (err) {
138
- if (err.name === 'ConditionalCheckFailedException') {
139
+ if (err instanceof Error && err.name === 'ConditionalCheckFailedException') {
139
140
  if (mode === 'create') {
140
141
  throw new ExistsError(cls, id);
141
142
  } else if (mode === 'update') {
@@ -146,7 +147,7 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
146
147
  }
147
148
  }
148
149
 
149
- #computeIndexConfig<T extends ModelType>(cls: Class<T>) {
150
+ #computeIndexConfig<T extends ModelType>(cls: Class<T>): { indices?: dynamodb.GlobalSecondaryIndex[], attributes: dynamodb.AttributeDefinition[] } {
150
151
  const config = ModelRegistry.get(cls);
151
152
  const attributes: dynamodb.AttributeDefinition[] = [];
152
153
  const indices: dynamodb.GlobalSecondaryIndex[] = [];
@@ -182,7 +183,7 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
182
183
  return { indices: indices.length ? indices : undefined, attributes };
183
184
  }
184
185
 
185
- async postConstruct() {
186
+ async postConstruct(): Promise<void> {
186
187
  this.client = new dynamodb.DynamoDB({ ...this.config.client });
187
188
  await ModelStorageUtil.registerModelChangeListener(this);
188
189
  ShutdownManager.onShutdown(this.constructor.ᚕid, () => this.client.destroy());
@@ -194,7 +195,7 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
194
195
  * Add a new model
195
196
  * @param cls
196
197
  */
197
- async createModel(cls: Class<ModelType>) {
198
+ async createModel(cls: Class<ModelType>): Promise<void> {
198
199
  const table = this.#resolveTable(cls);
199
200
  const idx = this.#computeIndexConfig(cls);
200
201
 
@@ -227,7 +228,7 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
227
228
  * Remove a model
228
229
  * @param cls
229
230
  */
230
- async deleteModel(cls: Class<ModelType>) {
231
+ async deleteModel(cls: Class<ModelType>): Promise<void> {
231
232
  const table = this.#resolveTable(cls);
232
233
  const { Table: verify } = (await this.client.describeTable({ TableName: table }).catch(err => ({ Table: undefined })));
233
234
  if (verify) {
@@ -239,7 +240,7 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
239
240
  * When the model changes
240
241
  * @param cls
241
242
  */
242
- async changeModel(cls: Class<ModelType>) {
243
+ async changeModel(cls: Class<ModelType>): Promise<void> {
243
244
  const table = this.#resolveTable(cls);
244
245
  const idx = this.#computeIndexConfig(cls);
245
246
  // const existing = await this.cl.describeTable({ TableName: table });
@@ -254,11 +255,11 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
254
255
  });
255
256
  }
256
257
 
257
- async createStorage() {
258
+ async createStorage(): Promise<void> {
258
259
  // Do nothing
259
260
  }
260
261
 
261
- async deleteStorage() {
262
+ async deleteStorage(): Promise<void> {
262
263
  for (const model of ModelRegistry.getClasses()) {
263
264
  await this.client.deleteTable({
264
265
  TableName: this.#resolveTable(model)
@@ -271,7 +272,7 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
271
272
  return Util.uuid();
272
273
  }
273
274
 
274
- async get<T extends ModelType>(cls: Class<T>, id: string) {
275
+ async get<T extends ModelType>(cls: Class<T>, id: string): Promise<T> {
275
276
  const res = await this.client.getItem({
276
277
  TableName: this.#resolveTable(cls),
277
278
  Key: { id: toValue(id) }
@@ -283,13 +284,13 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
283
284
  throw new NotFoundError(cls, id);
284
285
  }
285
286
 
286
- async create<T extends ModelType>(cls: Class<T>, item: OptionalId<T>) {
287
+ async create<T extends ModelType>(cls: Class<T>, item: OptionalId<T>): Promise<T> {
287
288
  const prepped = await ModelCrudUtil.preStore(cls, item, this);
288
289
  await this.#putItem(cls, prepped.id, prepped, 'create');
289
290
  return prepped;
290
291
  }
291
292
 
292
- async update<T extends ModelType>(cls: Class<T>, item: T) {
293
+ async update<T extends ModelType>(cls: Class<T>, item: T): Promise<T> {
293
294
  ModelCrudUtil.ensureNotSubType(cls);
294
295
  item = await ModelCrudUtil.preStore(cls, item, this);
295
296
  if (ModelRegistry.get(cls).expiresAt) {
@@ -299,22 +300,24 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
299
300
  return item;
300
301
  }
301
302
 
302
- async upsert<T extends ModelType>(cls: Class<T>, item: OptionalId<T>) {
303
+ async upsert<T extends ModelType>(cls: Class<T>, item: OptionalId<T>): Promise<T> {
303
304
  ModelCrudUtil.ensureNotSubType(cls);
304
305
  const prepped = await ModelCrudUtil.preStore(cls, item, this);
305
306
  await this.#putItem(cls, prepped.id, prepped, 'upsert');
306
307
  return prepped;
307
308
  }
308
309
 
309
- async updatePartial<T extends ModelType>(cls: Class<T>, item: Partial<T> & { id: string }, view?: string) {
310
+ async updatePartial<T extends ModelType>(cls: Class<T>, item: Partial<T> & { id: string }, view?: string): Promise<T> {
310
311
  ModelCrudUtil.ensureNotSubType(cls);
311
312
  const id = item.id;
312
- item = await ModelCrudUtil.naivePartialUpdate(cls, item, view, () => this.get(cls, id)) as T;
313
- await this.#putItem(cls, id, item as T, 'update');
314
- return item as T;
313
+ item = await ModelCrudUtil.naivePartialUpdate(cls, item, view, (): Promise<T> => this.get(cls, id));
314
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
315
+ const itemAsT = item as T;
316
+ await this.#putItem(cls, id, itemAsT, 'update');
317
+ return itemAsT;
315
318
  }
316
319
 
317
- async delete<T extends ModelType>(cls: Class<T>, id: string) {
320
+ async delete<T extends ModelType>(cls: Class<T>, id: string): Promise<void> {
318
321
  ModelCrudUtil.ensureNotSubType(cls);
319
322
  const res = await this.client.deleteItem({
320
323
  TableName: this.#resolveTable(cls),
@@ -326,7 +329,7 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
326
329
  }
327
330
  }
328
331
 
329
- async * list<T extends ModelType>(cls: Class<T>) {
332
+ async * list<T extends ModelType>(cls: Class<T>): AsyncIterable<T> {
330
333
  let done = false;
331
334
  let token: Record<string, dynamodb.AttributeValue> | undefined;
332
335
  while (!done) {
@@ -339,9 +342,9 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
339
342
  for (const el of batch.Items) {
340
343
  try {
341
344
  yield await loadAndCheckExpiry(cls, el.body.S!);
342
- } catch (e) {
343
- if (!(e instanceof NotFoundError)) {
344
- throw e;
345
+ } catch (err) {
346
+ if (!(err instanceof NotFoundError)) {
347
+ throw err;
345
348
  }
346
349
  }
347
350
  }
@@ -356,12 +359,12 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
356
359
  }
357
360
 
358
361
  // Expiry
359
- async deleteExpired<T extends ModelType>(cls: Class<T>) {
362
+ async deleteExpired<T extends ModelType>(cls: Class<T>): Promise<number> {
360
363
  return -1;
361
364
  }
362
365
 
363
366
  // Indexed
364
- async #getIdByIndex<T extends ModelType>(cls: Class<T>, idx: string, body: DeepPartial<T>) {
367
+ async #getIdByIndex<T extends ModelType>(cls: Class<T>, idx: string, body: DeepPartial<T>): Promise<string> {
365
368
  ModelCrudUtil.ensureNotSubType(cls);
366
369
 
367
370
  const idxCfg = ModelRegistry.getIndex(cls, idx, ['sorted', 'unsorted']);
@@ -394,11 +397,11 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
394
397
  }
395
398
 
396
399
  // Indexed
397
- async getByIndex<T extends ModelType>(cls: Class<T>, idx: string, body: DeepPartial<T>) {
400
+ async getByIndex<T extends ModelType>(cls: Class<T>, idx: string, body: DeepPartial<T>): Promise<T> {
398
401
  return this.get(cls, await this.#getIdByIndex(cls, idx, body));
399
402
  }
400
403
 
401
- async deleteByIndex<T extends ModelType>(cls: Class<T>, idx: string, body: DeepPartial<T>) {
404
+ async deleteByIndex<T extends ModelType>(cls: Class<T>, idx: string, body: DeepPartial<T>): Promise<void> {
402
405
  return this.delete(cls, await this.#getIdByIndex(cls, idx, body));
403
406
  }
404
407
 
@@ -406,7 +409,7 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
406
409
  return ModelIndexedUtil.naiveUpsert(this, cls, idx, body);
407
410
  }
408
411
 
409
- async * listByIndex<T extends ModelType>(cls: Class<T>, idx: string, body?: DeepPartial<T>) {
412
+ async * listByIndex<T extends ModelType>(cls: Class<T>, idx: string, body?: DeepPartial<T>): AsyncIterable<T> {
410
413
  ModelCrudUtil.ensureNotSubType(cls);
411
414
 
412
415
  const cfg = ModelRegistry.getIndex(cls, idx, ['sorted', 'unsorted']);
@@ -432,9 +435,9 @@ export class DynamoDBModelService implements ModelCrudSupport, ModelExpirySuppor
432
435
  for (const el of batch.Items) {
433
436
  try {
434
437
  yield await loadAndCheckExpiry(cls, el.body.S!);
435
- } catch (e) {
436
- if (!(e instanceof NotFoundError)) {
437
- throw e;
438
+ } catch (err) {
439
+ if (!(err instanceof NotFoundError)) {
440
+ throw err;
438
441
  }
439
442
  }
440
443
  }