@travetto/model 7.0.0-rc.2 → 7.0.0-rc.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 +7 -7
- package/src/error/exists.ts +4 -1
- package/src/registry/registry-adapter.ts +5 -2
- package/src/registry/registry-index.ts +4 -18
- package/src/registry/types.ts +2 -2
- package/src/types/storage.ts +6 -15
- package/src/util/crud.ts +3 -5
- package/src/util/storage.ts +13 -28
- package/support/bin/install.ts +2 -2
- package/support/cli.model_install.ts +1 -1
- package/support/test/suite.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/model",
|
|
3
|
-
"version": "7.0.0-rc.
|
|
3
|
+
"version": "7.0.0-rc.4",
|
|
4
4
|
"description": "Datastore abstraction for core operations.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"datastore",
|
|
@@ -26,14 +26,14 @@
|
|
|
26
26
|
"directory": "module/model"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@travetto/config": "^7.0.0-rc.
|
|
30
|
-
"@travetto/di": "^7.0.0-rc.
|
|
31
|
-
"@travetto/registry": "^7.0.0-rc.
|
|
32
|
-
"@travetto/schema": "^7.0.0-rc.
|
|
29
|
+
"@travetto/config": "^7.0.0-rc.4",
|
|
30
|
+
"@travetto/di": "^7.0.0-rc.4",
|
|
31
|
+
"@travetto/registry": "^7.0.0-rc.4",
|
|
32
|
+
"@travetto/schema": "^7.0.0-rc.4"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@travetto/cli": "^7.0.0-rc.
|
|
36
|
-
"@travetto/test": "^7.0.0-rc.
|
|
35
|
+
"@travetto/cli": "^7.0.0-rc.4",
|
|
36
|
+
"@travetto/test": "^7.0.0-rc.4"
|
|
37
37
|
},
|
|
38
38
|
"peerDependenciesMeta": {
|
|
39
39
|
"@travetto/cli": {
|
package/src/error/exists.ts
CHANGED
|
@@ -5,6 +5,9 @@ import { Class, AppError } from '@travetto/runtime';
|
|
|
5
5
|
*/
|
|
6
6
|
export class ExistsError extends AppError {
|
|
7
7
|
constructor(cls: Class | string, id: string) {
|
|
8
|
-
super(`${typeof cls === 'string' ? cls : cls.name} with id ${id} already exists`, {
|
|
8
|
+
super(`${typeof cls === 'string' ? cls : cls.name} with id ${id} already exists`, {
|
|
9
|
+
category: 'data',
|
|
10
|
+
details: { id, type: typeof cls === 'string' ? cls : cls.name }
|
|
11
|
+
});
|
|
9
12
|
}
|
|
10
13
|
}
|
|
@@ -12,6 +12,9 @@ function combineClasses(target: ModelConfig, sources: Partial<ModelConfig>[]): M
|
|
|
12
12
|
prePersist: [...(target.prePersist || []), ...(source.prePersist || [])],
|
|
13
13
|
});
|
|
14
14
|
}
|
|
15
|
+
if (target.store) {
|
|
16
|
+
target.store = target.store.toLowerCase().replace(/[^A-Za-z0-9_]+/g, '_');
|
|
17
|
+
}
|
|
15
18
|
return target;
|
|
16
19
|
}
|
|
17
20
|
|
|
@@ -27,8 +30,8 @@ export class ModelRegistryAdapter implements RegistryAdapter<ModelConfig> {
|
|
|
27
30
|
const config = this.#config ??= {
|
|
28
31
|
class: this.#cls,
|
|
29
32
|
indices: [],
|
|
30
|
-
autoCreate:
|
|
31
|
-
store: this.#cls.name
|
|
33
|
+
autoCreate: 'development',
|
|
34
|
+
store: this.#cls.name,
|
|
32
35
|
postLoad: [],
|
|
33
36
|
prePersist: []
|
|
34
37
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RegistryIndex, RegistryIndexStore, Registry } from '@travetto/registry';
|
|
2
2
|
import { AppError, castTo, Class } from '@travetto/runtime';
|
|
3
3
|
import { SchemaRegistryIndex } from '@travetto/schema';
|
|
4
4
|
|
|
@@ -58,7 +58,9 @@ export class ModelRegistryIndex implements RegistryIndex {
|
|
|
58
58
|
|
|
59
59
|
store = new RegistryIndexStore(ModelRegistryAdapter);
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
/** @private */ constructor(source: unknown) { Registry.validateConstructor(source); }
|
|
62
|
+
|
|
63
|
+
onCreate(cls: Class): void {
|
|
62
64
|
const schema = SchemaRegistryIndex.getConfig(cls);
|
|
63
65
|
|
|
64
66
|
// Don't index on discriminated schemas
|
|
@@ -81,22 +83,6 @@ export class ModelRegistryIndex implements RegistryIndex {
|
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
85
|
|
|
84
|
-
#removeClass(cls: Class): void {
|
|
85
|
-
const { store } = this.store.get(cls).get();
|
|
86
|
-
this.#modelNameMapping.get(store)?.delete(cls.Ⲑid);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
process(events: ChangeEvent<Class>[]): void {
|
|
90
|
-
for (const event of events) {
|
|
91
|
-
if ('previous' in event) {
|
|
92
|
-
this.#removeClass(event.previous);
|
|
93
|
-
}
|
|
94
|
-
if ('current' in event) {
|
|
95
|
-
this.#addClass(event.current);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
86
|
getConfig(cls: Class): ModelConfig<ModelType> {
|
|
101
87
|
return this.store.get(cls).get();
|
|
102
88
|
}
|
package/src/registry/types.ts
CHANGED
|
@@ -41,9 +41,9 @@ export class ModelConfig<T extends ModelType = ModelType> {
|
|
|
41
41
|
*/
|
|
42
42
|
expiresAt?: string;
|
|
43
43
|
/**
|
|
44
|
-
*
|
|
44
|
+
* Allows auto creation of a model storage backing at runtime
|
|
45
45
|
*/
|
|
46
|
-
autoCreate?:
|
|
46
|
+
autoCreate?: 'production' | 'development' | 'off';
|
|
47
47
|
/**
|
|
48
48
|
* Pre-persist handlers
|
|
49
49
|
*/
|
package/src/types/storage.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Class } from '@travetto/runtime';
|
|
2
|
-
import { SchemaChange } from '@travetto/schema';
|
|
3
2
|
|
|
4
3
|
import { ModelType } from '../types/model.ts';
|
|
5
4
|
|
|
@@ -15,10 +14,10 @@ import { ModelType } from '../types/model.ts';
|
|
|
15
14
|
export interface ModelStorageSupport {
|
|
16
15
|
|
|
17
16
|
/**
|
|
18
|
-
* Should
|
|
17
|
+
* Should storage modification be allowed
|
|
19
18
|
*/
|
|
20
19
|
readonly config?: {
|
|
21
|
-
|
|
20
|
+
modifyStorage?: boolean;
|
|
22
21
|
};
|
|
23
22
|
|
|
24
23
|
/**
|
|
@@ -30,29 +29,21 @@ export interface ModelStorageSupport {
|
|
|
30
29
|
*/
|
|
31
30
|
deleteStorage(): Promise<void>;
|
|
32
31
|
/**
|
|
33
|
-
*
|
|
32
|
+
* Creates model
|
|
34
33
|
*/
|
|
35
|
-
|
|
34
|
+
upsertModel?<T extends ModelType>(cls: Class<T>): Promise<void>;
|
|
36
35
|
/**
|
|
37
|
-
*
|
|
36
|
+
* Exports model
|
|
38
37
|
*/
|
|
39
38
|
exportModel?<T extends ModelType>(cls: Class<T>): Promise<string>;
|
|
40
39
|
/**
|
|
41
|
-
*
|
|
40
|
+
* Deletes model
|
|
42
41
|
*/
|
|
43
42
|
deleteModel?<T extends ModelType>(cls: Class<T>): Promise<void>;
|
|
44
43
|
/**
|
|
45
44
|
* Removes all data from a model, but leaving the structure in place
|
|
46
45
|
*/
|
|
47
46
|
truncateModel?<T extends ModelType>(cls: Class<T>): Promise<void>;
|
|
48
|
-
/**
|
|
49
|
-
* Deals with model internals changing
|
|
50
|
-
*/
|
|
51
|
-
changeModel?<T extends ModelType>(cls: Class<T>): Promise<void>;
|
|
52
|
-
/**
|
|
53
|
-
* An event listener for whenever a model schema is changed
|
|
54
|
-
*/
|
|
55
|
-
changeSchema?(cls: Class, changes: SchemaChange): Promise<void>;
|
|
56
47
|
/**
|
|
57
48
|
* Truncate blob storage data
|
|
58
49
|
*/
|
package/src/util/crud.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { castTo, Class, Util, AppError, hasFunction } from '@travetto/runtime';
|
|
1
|
+
import { castTo, Class, Util, AppError, hasFunction, JSONUtil } from '@travetto/runtime';
|
|
2
2
|
import { DataUtil, SchemaRegistryIndex, SchemaValidator, ValidationError, ValidationResultError } from '@travetto/schema';
|
|
3
3
|
|
|
4
4
|
import { ModelRegistryIndex } from '../registry/registry-index.ts';
|
|
@@ -39,10 +39,8 @@ export class ModelCrudUtil {
|
|
|
39
39
|
*/
|
|
40
40
|
static async load<T extends ModelType>(cls: Class<T>, input: Buffer | string | object, onTypeMismatch: 'notfound' | 'exists' = 'notfound'): Promise<T> {
|
|
41
41
|
let resolvedInput: object;
|
|
42
|
-
if (typeof input === 'string') {
|
|
43
|
-
resolvedInput =
|
|
44
|
-
} else if (input instanceof Buffer) {
|
|
45
|
-
resolvedInput = JSON.parse(input.toString('utf8'));
|
|
42
|
+
if (typeof input === 'string' || input instanceof Buffer) {
|
|
43
|
+
resolvedInput = JSONUtil.parseSafe(input);
|
|
46
44
|
} else {
|
|
47
45
|
resolvedInput = input;
|
|
48
46
|
}
|
package/src/util/storage.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Class, hasFunction, Runtime } from '@travetto/runtime';
|
|
2
|
-
import {
|
|
3
|
-
import { Registry } from '@travetto/registry';
|
|
2
|
+
import { SchemaRegistryIndex } from '@travetto/schema';
|
|
4
3
|
|
|
5
4
|
import { ModelStorageSupport } from '../types/storage.ts';
|
|
6
5
|
import { ModelRegistryIndex } from '../registry/registry-index.ts';
|
|
@@ -16,10 +15,10 @@ export class ModelStorageUtil {
|
|
|
16
15
|
static isSupported = hasFunction<ModelStorageSupport>('createStorage');
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
|
-
*
|
|
18
|
+
* Storage Initialization
|
|
20
19
|
*/
|
|
21
|
-
static async
|
|
22
|
-
if (
|
|
20
|
+
static async storageInitialization(storage: ModelStorageSupport): Promise<void> {
|
|
21
|
+
if (storage.config?.modifyStorage === false) {
|
|
23
22
|
return;
|
|
24
23
|
}
|
|
25
24
|
|
|
@@ -27,39 +26,25 @@ export class ModelStorageUtil {
|
|
|
27
26
|
if (enforceBase && SchemaRegistryIndex.getBaseClass(cls) !== cls) {
|
|
28
27
|
return false;
|
|
29
28
|
}
|
|
29
|
+
|
|
30
30
|
const { autoCreate } = ModelRegistryIndex.getConfig(cls) ?? {};
|
|
31
|
-
return autoCreate ?? false;
|
|
32
|
-
};
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
case 'removing': checkType(event.previous) ? storage.deleteModel?.(event.previous) : undefined; break;
|
|
41
|
-
}
|
|
42
|
-
}, ModelRegistryIndex);
|
|
43
|
-
}
|
|
32
|
+
if (autoCreate === 'off') {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return (autoCreate === 'production' || !Runtime.production);
|
|
37
|
+
};
|
|
44
38
|
|
|
45
39
|
// Initialize on startup (test manages)
|
|
46
40
|
await storage.createStorage();
|
|
47
41
|
|
|
48
|
-
if (storage.
|
|
42
|
+
if (storage.upsertModel) {
|
|
49
43
|
for (const cls of ModelRegistryIndex.getClasses()) {
|
|
50
44
|
if (checkType(cls)) {
|
|
51
|
-
await storage.
|
|
45
|
+
await storage.upsertModel(cls);
|
|
52
46
|
}
|
|
53
47
|
}
|
|
54
48
|
}
|
|
55
|
-
|
|
56
|
-
// If listening for model add/removes/updates
|
|
57
|
-
if (storage.changeSchema) {
|
|
58
|
-
SchemaChangeListener.onSchemaChange(event => {
|
|
59
|
-
if (checkType(event.cls)) {
|
|
60
|
-
storage.changeSchema!(event.cls, event.change);
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
49
|
}
|
|
65
50
|
}
|
package/support/bin/install.ts
CHANGED
|
@@ -3,12 +3,12 @@ import type { ModelStorageSupport, ModelType } from '@travetto/model';
|
|
|
3
3
|
|
|
4
4
|
export class ModelInstallUtil {
|
|
5
5
|
static async run(provider: ModelStorageSupport, models: Class<ModelType>[]): Promise<void> {
|
|
6
|
-
if (!provider.
|
|
6
|
+
if (!provider.upsertModel) {
|
|
7
7
|
throw new Error(`${provider} does not support model installation`);
|
|
8
8
|
}
|
|
9
9
|
for (const cls of models) {
|
|
10
10
|
console.log('Installing', { name: cls.Ⲑid });
|
|
11
|
-
await provider.
|
|
11
|
+
await provider.upsertModel(cls);
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -10,7 +10,7 @@ import { ModelCandidateUtil } from './bin/candidate.ts';
|
|
|
10
10
|
@CliCommand({ with: { env: true, module: true } })
|
|
11
11
|
export class ModelInstallCommand extends BaseModelCommand {
|
|
12
12
|
|
|
13
|
-
getOperation(): '
|
|
13
|
+
getOperation(): 'upsertModel' { return 'upsertModel'; }
|
|
14
14
|
|
|
15
15
|
async main(provider: string, models: string[]): Promise<void> {
|
|
16
16
|
const resolved = await ModelCandidateUtil.resolve(provider, models);
|
package/support/test/suite.ts
CHANGED
|
@@ -39,10 +39,10 @@ export function ModelSuite<T extends { configClass: Class<{ autoCreate?: boolean
|
|
|
39
39
|
const service = await DependencyRegistryIndex.getInstance(this.serviceClass, qualifier);
|
|
40
40
|
if (ModelStorageUtil.isSupported(service)) {
|
|
41
41
|
await service.createStorage();
|
|
42
|
-
if (service.
|
|
42
|
+
if (service.upsertModel) {
|
|
43
43
|
await Promise.all(ModelRegistryIndex.getClasses()
|
|
44
44
|
.filter(x => x === SchemaRegistryIndex.getBaseClass(x))
|
|
45
|
-
.map(m => service.
|
|
45
|
+
.map(m => service.upsertModel!(m)));
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
}
|