@travetto/model 8.0.2 → 8.0.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model",
3
- "version": "8.0.2",
3
+ "version": "8.0.4",
4
4
  "description": "Datastore abstraction for core operations.",
5
5
  "keywords": [
6
6
  "datastore",
@@ -30,14 +30,14 @@
30
30
  "access": "public"
31
31
  },
32
32
  "dependencies": {
33
- "@travetto/config": "^8.0.2",
33
+ "@travetto/config": "^8.0.3",
34
34
  "@travetto/di": "^8.0.1",
35
35
  "@travetto/registry": "^8.0.1",
36
36
  "@travetto/schema": "^8.0.2"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@travetto/cli": "^8.0.2",
40
- "@travetto/test": "^8.0.1"
40
+ "@travetto/test": "^8.0.2"
41
41
  },
42
42
  "peerDependenciesMeta": {
43
43
  "@travetto/cli": {
@@ -38,11 +38,11 @@ export interface ModelStorageSupport {
38
38
  /**
39
39
  * Deletes model
40
40
  */
41
- deleteModel?<T extends ModelType>(cls: Class<T>): Promise<void>;
41
+ deleteModel<T extends ModelType>(cls: Class<T>): Promise<void>;
42
42
  /**
43
43
  * Removes all data from a model, but leaving the structure in place
44
44
  */
45
- truncateModel?<T extends ModelType>(cls: Class<T>): Promise<void>;
45
+ truncateModel<T extends ModelType>(cls: Class<T>): Promise<void>;
46
46
  /**
47
47
  * Truncate blob storage data
48
48
  */
@@ -46,4 +46,21 @@ export class ModelStorageUtil {
46
46
  }
47
47
  }
48
48
  }
49
+
50
+ /**
51
+ * Runs a storage operation and ignores errors matching the not-found predicate
52
+ */
53
+ static async runAndIgnoreNotFound<T = unknown>(
54
+ operation: () => Promise<T>,
55
+ notFoundPredicate: (error: unknown) => boolean
56
+ ): Promise<T | undefined> {
57
+ try {
58
+ return await operation();
59
+ } catch (error) {
60
+ if (notFoundPredicate(error)) {
61
+ return undefined;
62
+ }
63
+ throw error;
64
+ }
65
+ }
49
66
  }
@@ -1,6 +1,15 @@
1
1
  import assert from 'node:assert';
2
2
 
3
- import { Model, type ModelCrudSupport, ModelCrudUtil, NotFoundError, TransientField } from '@travetto/model';
3
+ import {
4
+ Model,
5
+ type ModelCrudSupport,
6
+ ModelCrudUtil,
7
+ ModelRegistryIndex,
8
+ ModelStorageUtil,
9
+ NotFoundError,
10
+ TransientField
11
+ } from '@travetto/model';
12
+ import { SchemaRegistryIndex } from '@travetto/schema';
4
13
  import { Suite, Test } from '@travetto/test';
5
14
 
6
15
  import { BaseModelSuite } from './base.ts';
@@ -25,6 +34,11 @@ class Person {
25
34
  gender: 'm' | 'f';
26
35
  }
27
36
 
37
+ @Model('basic_person_temp')
38
+ export class TempPerson {
39
+ id: string;
40
+ }
41
+
28
42
  @Suite()
29
43
  export abstract class ModelBasicSuite extends BaseModelSuite<ModelCrudSupport> {
30
44
  @Test('create, read, delete')
@@ -100,4 +114,33 @@ export abstract class ModelBasicSuite extends BaseModelSuite<ModelCrudSupport> {
100
114
  assert(prepared.nameUpper === undefined);
101
115
  assert(prepared.ignoredField === undefined);
102
116
  }
117
+
118
+ @Test('deleteModel should not fail when underlying storage item is not found')
119
+ async testDeleteModelNotExists() {
120
+ const service = await this.service;
121
+ if (ModelStorageUtil.isSupported(service)) {
122
+ await service.deleteModel(TempPerson);
123
+ // Run it again now that the storage item is definitely deleted/not found
124
+ await service.deleteModel(TempPerson);
125
+ if (service.upsertModel) {
126
+ await service.upsertModel(TempPerson);
127
+ }
128
+ }
129
+ }
130
+
131
+ @Test('deleteStorage should not fail when underlying storage is not found')
132
+ async testDeleteStorageNotExists() {
133
+ const service = await this.service;
134
+ if (ModelStorageUtil.isSupported(service)) {
135
+ await service.deleteStorage();
136
+ // Run it again now that storage has been deleted
137
+ await service.deleteStorage();
138
+ await service.createStorage();
139
+ if (service.upsertModel) {
140
+ for (const modelClass of ModelRegistryIndex.getClasses().filter(model => model === SchemaRegistryIndex.getBaseClass(model))) {
141
+ await service.upsertModel(modelClass);
142
+ }
143
+ }
144
+ }
145
+ }
103
146
  }
@@ -53,26 +53,18 @@ class ModelSuiteHandler<T extends { configClass: Class<ConfigType>; serviceClass
53
53
  await service.truncateBlob();
54
54
  }
55
55
 
56
- if (service.truncateModel) {
57
- await Promise.all(models.map(model => service.truncateModel!(model)));
58
- } else if (service.deleteModel) {
59
- await Promise.all(models.map(model => service.deleteModel!(model)));
60
- } else {
61
- await service.deleteStorage(); // Purge it all
62
- }
56
+ await Promise.all(models.map(model => service.truncateModel(model)));
63
57
  }
64
58
  }
65
59
 
66
60
  async afterAll(instance: T) {
67
61
  const service = await DependencyRegistryIndex.getInstance<T>(instance.serviceClass, this.qualifier);
68
62
  if (ModelStorageUtil.isSupported(service)) {
69
- if (service.deleteModel) {
70
- for (const model of ModelRegistryIndex.getClasses()) {
71
- if (model === SchemaRegistryIndex.getBaseClass(model)) {
72
- await service.deleteModel(model);
73
- }
74
- }
75
- }
63
+ await Promise.all(
64
+ ModelRegistryIndex.getClasses()
65
+ .filter(model => model === SchemaRegistryIndex.getBaseClass(model))
66
+ .map(model => service.deleteModel(model))
67
+ );
76
68
  await service.deleteStorage();
77
69
  }
78
70
  }