@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model",
3
- "version": "7.0.0-rc.2",
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.2",
30
- "@travetto/di": "^7.0.0-rc.2",
31
- "@travetto/registry": "^7.0.0-rc.2",
32
- "@travetto/schema": "^7.0.0-rc.2"
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.2",
36
- "@travetto/test": "^7.0.0-rc.2"
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": {
@@ -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`, { category: 'data' });
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: true,
31
- store: this.#cls.name.toLowerCase(),
33
+ autoCreate: 'development',
34
+ store: this.#cls.name,
32
35
  postLoad: [],
33
36
  prePersist: []
34
37
  };
@@ -1,4 +1,4 @@
1
- import { ChangeEvent, RegistryIndex, RegistryIndexStore, Registry } from '@travetto/registry';
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
- #addClass(cls: Class): void {
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
  }
@@ -41,9 +41,9 @@ export class ModelConfig<T extends ModelType = ModelType> {
41
41
  */
42
42
  expiresAt?: string;
43
43
  /**
44
- * Auto create in development mode
44
+ * Allows auto creation of a model storage backing at runtime
45
45
  */
46
- autoCreate?: boolean;
46
+ autoCreate?: 'production' | 'development' | 'off';
47
47
  /**
48
48
  * Pre-persist handlers
49
49
  */
@@ -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 auto-creation be allowed
17
+ * Should storage modification be allowed
19
18
  */
20
19
  readonly config?: {
21
- autoCreate?: boolean;
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
- * Installs model
32
+ * Creates model
34
33
  */
35
- createModel?<T extends ModelType>(cls: Class<T>): Promise<void>;
34
+ upsertModel?<T extends ModelType>(cls: Class<T>): Promise<void>;
36
35
  /**
37
- * Installs model
36
+ * Exports model
38
37
  */
39
38
  exportModel?<T extends ModelType>(cls: Class<T>): Promise<string>;
40
39
  /**
41
- * Installs model
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 = JSON.parse(input);
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
  }
@@ -1,6 +1,5 @@
1
1
  import { Class, hasFunction, Runtime } from '@travetto/runtime';
2
- import { SchemaChangeListener, SchemaRegistryIndex } from '@travetto/schema';
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
- * Register change listener on startup
18
+ * Storage Initialization
20
19
  */
21
- static async registerModelChangeListener(storage: ModelStorageSupport): Promise<void> {
22
- if (!Runtime.dynamic || !(storage?.config?.autoCreate ?? !Runtime.production)) {
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
- // If listening for model add/removes/updates
35
- if (storage.createModel || storage.deleteModel || storage.changeModel) {
36
- Registry.onClassChange(event => {
37
- switch (event.type) {
38
- case 'added': checkType(event.current) ? storage.createModel?.(event.current) : undefined; break;
39
- case 'changed': checkType(event.current, false) ? storage.changeModel?.(event.current) : undefined; break;
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.createModel) {
42
+ if (storage.upsertModel) {
49
43
  for (const cls of ModelRegistryIndex.getClasses()) {
50
44
  if (checkType(cls)) {
51
- await storage.createModel(cls);
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
  }
@@ -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.createModel) {
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.createModel(cls);
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(): 'createModel' { return 'createModel'; }
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);
@@ -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.createModel) {
42
+ if (service.upsertModel) {
43
43
  await Promise.all(ModelRegistryIndex.getClasses()
44
44
  .filter(x => x === SchemaRegistryIndex.getBaseClass(x))
45
- .map(m => service.createModel!(m)));
45
+ .map(m => service.upsertModel!(m)));
46
46
  }
47
47
  }
48
48
  }