@travetto/model 3.0.0-rc.2 → 3.0.0-rc.21
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 +15 -15
- package/package.json +16 -11
- package/src/internal/service/crud.ts +5 -5
- package/src/internal/service/expiry.ts +6 -7
- package/src/internal/service/indexed.ts +1 -1
- package/src/internal/service/storage.ts +2 -3
- package/src/internal/util.ts +7 -0
- package/src/provider/file.ts +25 -26
- package/src/provider/memory.ts +11 -11
- package/src/registry/decorator.ts +2 -2
- package/src/registry/model.ts +5 -4
- package/src/registry/types.ts +1 -2
- package/src/service/bulk.ts +1 -6
- package/{bin/lib → support/bin}/candidate.ts +23 -12
- package/{bin/lib → support/bin}/install.ts +3 -3
- package/support/cli.base-command.ts +54 -0
- package/{bin/cli-model_export.ts → support/cli.model_export.ts} +12 -3
- package/support/cli.model_install.ts +31 -0
- package/support/doc.support.ts +46 -0
- package/{test-support → support/test}/base.ts +2 -2
- package/{test-support → support/test}/basic.ts +2 -2
- package/{test-support → support/test}/bulk.ts +3 -3
- package/{test-support → support/test}/crud.ts +2 -2
- package/{test-support → support/test}/expiry.ts +8 -8
- package/{test-support → support/test}/indexed.ts +10 -9
- package/{test-support → support/test}/polymorphism.ts +10 -6
- package/{test-support → support/test}/stream.ts +15 -23
- package/{test-support → support/test}/suite.ts +8 -9
- package/bin/candidate.ts +0 -23
- package/bin/cli-model_install.ts +0 -23
- package/bin/lib/base-command.ts +0 -67
- /package/{index.ts → __index__.ts} +0 -0
- /package/{bin/lib → support/bin}/export.ts +0 -0
- /package/{test-support/resources → support/fixtures}/asset.yml +0 -0
- /package/{test-support/resources → support/fixtures}/google +0 -0
- /package/{test-support/resources → support/fixtures}/google.png +0 -0
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!-- This file was generated by @travetto/doc and should not be modified directly -->
|
|
2
|
-
<!-- Please modify https://github.com/travetto/travetto/tree/main/module/model/
|
|
2
|
+
<!-- Please modify https://github.com/travetto/travetto/tree/main/module/model/DOC.ts and execute "npx trv doc" to rebuild -->
|
|
3
3
|
# Data Modeling Support
|
|
4
4
|
## Datastore abstraction for core operations.
|
|
5
5
|
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
npm install @travetto/model
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
This module provides a set of contracts/interfaces to data model persistence, modification and retrieval. This module builds heavily upon the [Schema](https://github.com/travetto/travetto/tree/main/module/schema#readme "Data type registry for runtime validation, reflection and binding.
|
|
11
|
+
This module provides a set of contracts/interfaces to data model persistence, modification and retrieval. This module builds heavily upon the [Schema](https://github.com/travetto/travetto/tree/main/module/schema#readme "Data type registry for runtime validation, reflection and binding."), which is used for data model validation.
|
|
12
12
|
|
|
13
13
|
## Contracts
|
|
14
14
|
|
|
15
|
-
The module is mainly composed of contracts. The contracts define the expected interface for various model patterns. The primary contracts are [Basic](https://github.com/travetto/travetto/tree/main/module/model/src/service/basic.ts#L9), [CRUD](https://github.com/travetto/travetto/tree/main/module/model/src/service/crud.ts#L11), [Indexed](https://github.com/travetto/travetto/tree/main/module/model/src/service/indexed.ts#L12), [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/service/expiry.ts#L11), [Streaming](https://github.com/travetto/travetto/tree/main/module/model/src/service/stream.ts#L3) and [Bulk](https://github.com/travetto/travetto/tree/main/module/model/src/service/bulk.ts#
|
|
15
|
+
The module is mainly composed of contracts. The contracts define the expected interface for various model patterns. The primary contracts are [Basic](https://github.com/travetto/travetto/tree/main/module/model/src/service/basic.ts#L9), [CRUD](https://github.com/travetto/travetto/tree/main/module/model/src/service/crud.ts#L11), [Indexed](https://github.com/travetto/travetto/tree/main/module/model/src/service/indexed.ts#L12), [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/service/expiry.ts#L11), [Streaming](https://github.com/travetto/travetto/tree/main/module/model/src/service/stream.ts#L3) and [Bulk](https://github.com/travetto/travetto/tree/main/module/model/src/service/bulk.ts#L19).
|
|
16
16
|
|
|
17
17
|
### [Basic](https://github.com/travetto/travetto/tree/main/module/model/src/service/basic.ts#L9)
|
|
18
18
|
All [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations.") implementations, must honor the BasicCrud contract to be able to participate in the model ecosystem. This contract represents the bare minimum for a model service.
|
|
@@ -184,7 +184,7 @@ export interface ModelStreamSupport {
|
|
|
184
184
|
}
|
|
185
185
|
```
|
|
186
186
|
|
|
187
|
-
### [Bulk](https://github.com/travetto/travetto/tree/main/module/model/src/service/bulk.ts#
|
|
187
|
+
### [Bulk](https://github.com/travetto/travetto/tree/main/module/model/src/service/bulk.ts#L19)
|
|
188
188
|
|
|
189
189
|
Finally, there is support for bulk operations. This is not to simply imply issuing many commands at in parallel, but implementation support for an atomic/bulk operation. This should allow for higher throughput on data ingest, and potentially for atomic support on transactions.
|
|
190
190
|
|
|
@@ -222,7 +222,7 @@ export interface ModelType {
|
|
|
222
222
|
}
|
|
223
223
|
```
|
|
224
224
|
|
|
225
|
-
All fields are optional, but the `id` and `type` are important as those field types are unable to be changed. This may make using existing data models impossible if types other than strings are required. Additionally, the type field, is intended to record the base model type and cannot be remapped. This is important to support polymorphism, not only in [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations."), but also in [Schema](https://github.com/travetto/travetto/tree/main/module/schema#readme "Data type registry for runtime validation, reflection and binding.
|
|
225
|
+
All fields are optional, but the `id` and `type` are important as those field types are unable to be changed. This may make using existing data models impossible if types other than strings are required. Additionally, the type field, is intended to record the base model type and cannot be remapped. This is important to support polymorphism, not only in [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations."), but also in [Schema](https://github.com/travetto/travetto/tree/main/module/schema#readme "Data type registry for runtime validation, reflection and binding.").
|
|
226
226
|
|
|
227
227
|
## Implementations
|
|
228
228
|
|
|
@@ -236,7 +236,7 @@ All fields are optional, but the `id` and `type` are important as those field ty
|
|
|
236
236
|
|[S3 Model Support](https://github.com/travetto/travetto/tree/main/module/model-s3#readme "S3 backing for the travetto model module.")|X|X| |X|X| |
|
|
237
237
|
|[SQL Model Service](https://github.com/travetto/travetto/tree/main/module/model-sql#readme "SQL backing for the travetto model module, with real-time modeling support for SQL schemas.")|X|X|X|X| |X|
|
|
238
238
|
|[MemoryModelService](https://github.com/travetto/travetto/tree/main/module/model/src/provider/memory.ts#L54)|X|X|X|X|X|X|
|
|
239
|
-
|[FileModelService](https://github.com/travetto/travetto/tree/main/module/model/src/provider/file.ts#
|
|
239
|
+
|[FileModelService](https://github.com/travetto/travetto/tree/main/module/model/src/provider/file.ts#L51)|X|X| |X|X|X|
|
|
240
240
|
|
|
241
241
|
## Custom Model Service
|
|
242
242
|
In addition to the provided contracts, the module also provides common utilities and shared test suites. The common utilities are useful for
|
|
@@ -245,8 +245,7 @@ repetitive functionality, that is unable to be shared due to not relying upon in
|
|
|
245
245
|
**Code: Memory Service**
|
|
246
246
|
```typescript
|
|
247
247
|
import { Readable } from 'stream';
|
|
248
|
-
import { StreamUtil } from '@travetto/
|
|
249
|
-
import { Util, Class, TimeSpan } from '@travetto/base';
|
|
248
|
+
import { StreamUtil, Class, TimeSpan } from '@travetto/base';
|
|
250
249
|
import { DeepPartial } from '@travetto/schema';
|
|
251
250
|
import { Injectable } from '@travetto/di';
|
|
252
251
|
import { Config } from '@travetto/config';
|
|
@@ -265,6 +264,7 @@ import { ModelIndexedUtil } from '../internal/service/indexed';
|
|
|
265
264
|
import { ModelStorageUtil } from '../internal/service/storage';
|
|
266
265
|
import { StreamModel, STREAMS } from '../internal/service/stream';
|
|
267
266
|
import { IndexConfig } from '../registry/types';
|
|
267
|
+
import { ModelUtil } from '../internal/util';
|
|
268
268
|
const STREAM_META = `${STREAMS}_meta`;
|
|
269
269
|
type StoreType = Map<string, Buffer>;
|
|
270
270
|
@Config('model.memory')
|
|
@@ -274,7 +274,7 @@ export class MemoryModelConfig {
|
|
|
274
274
|
cullRate?: number | TimeSpan;
|
|
275
275
|
}
|
|
276
276
|
function indexName<T extends ModelType>(cls: Class<T>, idx: IndexConfig<T> | string, suffix?: string): string {
|
|
277
|
-
return [cls
|
|
277
|
+
return [cls.Ⲑid, typeof idx === 'string' ? idx : idx.name, suffix].filter(x => !!x).join(':');
|
|
278
278
|
}
|
|
279
279
|
function getFirstId(data: Map<string, unknown> | Set<string>, value?: string | number): string | undefined {
|
|
280
280
|
let id: string | undefined;
|
|
@@ -331,12 +331,12 @@ To enforce that these contracts are honored, the module provides shared test sui
|
|
|
331
331
|
import { Suite } from '@travetto/test';
|
|
332
332
|
|
|
333
333
|
import { MemoryModelConfig, MemoryModelService } from '../src/provider/memory';
|
|
334
|
-
import { ModelCrudSuite } from '../
|
|
335
|
-
import { ModelExpirySuite } from '../
|
|
336
|
-
import { ModelStreamSuite } from '../
|
|
337
|
-
import { ModelIndexedSuite } from '../
|
|
338
|
-
import { ModelBasicSuite } from '../
|
|
339
|
-
import { ModelPolymorphismSuite } from '../
|
|
334
|
+
import { ModelCrudSuite } from '../support/test/crud';
|
|
335
|
+
import { ModelExpirySuite } from '../support/test/expiry';
|
|
336
|
+
import { ModelStreamSuite } from '../support/test/stream';
|
|
337
|
+
import { ModelIndexedSuite } from '../support/test/indexed';
|
|
338
|
+
import { ModelBasicSuite } from '../support/test/basic';
|
|
339
|
+
import { ModelPolymorphismSuite } from '../support/test/polymorphism';
|
|
340
340
|
|
|
341
341
|
@Suite()
|
|
342
342
|
export class MemoryBasicSuite extends ModelBasicSuite {
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/model",
|
|
3
|
-
"
|
|
4
|
-
"version": "3.0.0-rc.2",
|
|
3
|
+
"version": "3.0.0-rc.21",
|
|
5
4
|
"description": "Datastore abstraction for core operations.",
|
|
6
5
|
"keywords": [
|
|
7
6
|
"datastore",
|
|
@@ -17,30 +16,36 @@
|
|
|
17
16
|
"name": "Travetto Framework"
|
|
18
17
|
},
|
|
19
18
|
"files": [
|
|
20
|
-
"
|
|
21
|
-
"bin",
|
|
19
|
+
"__index__.ts",
|
|
22
20
|
"src",
|
|
23
|
-
"
|
|
21
|
+
"support"
|
|
24
22
|
],
|
|
25
|
-
"main": "
|
|
23
|
+
"main": "__index__.ts",
|
|
26
24
|
"repository": {
|
|
27
25
|
"url": "https://github.com/travetto/travetto.git",
|
|
28
26
|
"directory": "module/model"
|
|
29
27
|
},
|
|
30
28
|
"dependencies": {
|
|
31
|
-
"@travetto/
|
|
32
|
-
"@travetto/
|
|
33
|
-
"@travetto/registry": "^3.0.0-rc.
|
|
34
|
-
"@travetto/schema": "^3.0.0-rc.
|
|
29
|
+
"@travetto/config": "^3.0.0-rc.21",
|
|
30
|
+
"@travetto/di": "^3.0.0-rc.20",
|
|
31
|
+
"@travetto/registry": "^3.0.0-rc.20",
|
|
32
|
+
"@travetto/schema": "^3.0.0-rc.21"
|
|
35
33
|
},
|
|
36
34
|
"peerDependencies": {
|
|
37
|
-
"@travetto/cli": "^3.0.0-rc.
|
|
35
|
+
"@travetto/cli": "^3.0.0-rc.20",
|
|
36
|
+
"@travetto/test": "^3.0.0-rc.23"
|
|
38
37
|
},
|
|
39
38
|
"peerDependenciesMeta": {
|
|
40
39
|
"@travetto/cli": {
|
|
41
40
|
"optional": true
|
|
41
|
+
},
|
|
42
|
+
"@travetto/test": {
|
|
43
|
+
"optional": true
|
|
42
44
|
}
|
|
43
45
|
},
|
|
46
|
+
"travetto": {
|
|
47
|
+
"displayName": "Data Modeling Support"
|
|
48
|
+
},
|
|
44
49
|
"publishConfig": {
|
|
45
50
|
"access": "public"
|
|
46
51
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import crypto from 'crypto';
|
|
2
2
|
|
|
3
|
-
import { Class,
|
|
3
|
+
import { Class, ObjectUtil } from '@travetto/base';
|
|
4
4
|
import { SchemaRegistry, SchemaValidator } from '@travetto/schema';
|
|
5
5
|
|
|
6
6
|
import { ModelRegistry } from '../../registry/model';
|
|
@@ -41,7 +41,7 @@ export class ModelCrudUtil {
|
|
|
41
41
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
42
42
|
const result = ModelRegistry.getBaseModel(cls).from(input as object) as T;
|
|
43
43
|
|
|
44
|
-
if (!(result instanceof cls || result.constructor
|
|
44
|
+
if (!(result instanceof cls || result.constructor.Ⲑid === cls.Ⲑid)) {
|
|
45
45
|
if (onTypeMismatch === 'notfound') {
|
|
46
46
|
throw new NotFoundError(cls, result.id);
|
|
47
47
|
} else {
|
|
@@ -66,7 +66,7 @@ export class ModelCrudUtil {
|
|
|
66
66
|
item.id = idSource.uuid();
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
if (
|
|
69
|
+
if (ObjectUtil.isPlainObject(item)) {
|
|
70
70
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
71
71
|
item = cls.from(item as object);
|
|
72
72
|
}
|
|
@@ -95,7 +95,7 @@ export class ModelCrudUtil {
|
|
|
95
95
|
* @param getExisting How to fetch an existing item
|
|
96
96
|
*/
|
|
97
97
|
static async naivePartialUpdate<T extends ModelType>(cls: Class<T>, item: Partial<T>, view: undefined | string, getExisting: () => Promise<T>): Promise<T> {
|
|
98
|
-
if (
|
|
98
|
+
if (ObjectUtil.isPlainObject(item)) {
|
|
99
99
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
100
100
|
item = cls.from(item as object);
|
|
101
101
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ShutdownManager, Class, TimeSpan, TimeUtil } from '@travetto/base';
|
|
2
2
|
|
|
3
3
|
import { ModelRegistry } from '../../registry/model';
|
|
4
4
|
import { ModelExpirySupport } from '../../service/expiry';
|
|
@@ -33,19 +33,18 @@ export class ModelExpiryUtil {
|
|
|
33
33
|
const cullable = ModelRegistry.getClasses().filter(cls => !!ModelRegistry.get(cls).expiresAt);
|
|
34
34
|
if (svc.deleteExpired && cullable.length) {
|
|
35
35
|
let running = true;
|
|
36
|
-
const cullInterval =
|
|
36
|
+
const cullInterval = TimeUtil.timeToMs(svc.config?.cullRate ?? '10m');
|
|
37
37
|
|
|
38
|
-
ShutdownManager.onShutdown({
|
|
38
|
+
ShutdownManager.onShutdown(this, {
|
|
39
39
|
close(cb) {
|
|
40
40
|
running = false;
|
|
41
41
|
cb?.();
|
|
42
|
-
}
|
|
43
|
-
name: 'expiry-culling'
|
|
42
|
+
}
|
|
44
43
|
});
|
|
45
44
|
(async (): Promise<void> => {
|
|
46
|
-
await
|
|
45
|
+
await TimeUtil.wait('1s'); // Wait a second to start culling
|
|
47
46
|
while (running) {
|
|
48
|
-
await
|
|
47
|
+
await TimeUtil.wait(cullInterval);
|
|
49
48
|
await Promise.all(cullable.map(cls => svc.deleteExpired(cls)));
|
|
50
49
|
}
|
|
51
50
|
})();
|
|
@@ -118,7 +118,7 @@ export class ModelIndexedUtil {
|
|
|
118
118
|
opts?: ComputeConfig & { sep?: string }
|
|
119
119
|
): { type: string, key: string, sort?: number | Date } {
|
|
120
120
|
const { fields, sorted } = this.computeIndexParts(cls, idx, item, { ...(opts ?? {}), includeSortInFields: false });
|
|
121
|
-
const key = fields.map(({ value }) => value).map(x => `${x}`).join(opts?.sep ?? '
|
|
121
|
+
const key = fields.map(({ value }) => value).map(x => `${x}`).join(opts?.sep ?? 'Ⲑ');
|
|
122
122
|
const cfg = typeof idx === 'string' ? ModelRegistry.getIndex(cls, idx) : idx;
|
|
123
123
|
return !sorted ? { type: cfg.type, key } : { type: cfg.type, key, sort: sorted.value };
|
|
124
124
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { AppManifest, Class } from '@travetto/base';
|
|
1
|
+
import { Class, GlobalEnv } from '@travetto/base';
|
|
3
2
|
import { SchemaChangeListener } from '@travetto/schema';
|
|
4
3
|
|
|
5
4
|
import { ModelRegistry } from '../../registry/model';
|
|
@@ -14,7 +13,7 @@ export class ModelStorageUtil {
|
|
|
14
13
|
* Register change listener on startup
|
|
15
14
|
*/
|
|
16
15
|
static async registerModelChangeListener(storage: ModelStorageSupport, target?: Class): Promise<void> {
|
|
17
|
-
if (!
|
|
16
|
+
if (!GlobalEnv.dynamic || !(storage?.config?.autoCreate ?? !GlobalEnv.prod)) {
|
|
18
17
|
return;
|
|
19
18
|
}
|
|
20
19
|
|
package/src/provider/file.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
2
|
import { createReadStream } from 'fs';
|
|
3
|
-
|
|
4
|
-
import
|
|
3
|
+
|
|
4
|
+
import os from 'os';
|
|
5
|
+
|
|
5
6
|
import { Readable } from 'stream';
|
|
6
7
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
8
|
+
import { path, RootIndex } from '@travetto/manifest';
|
|
9
|
+
import { StreamUtil, Class, TimeSpan } from '@travetto/base';
|
|
9
10
|
import { Injectable } from '@travetto/di';
|
|
10
11
|
import { Config } from '@travetto/config';
|
|
11
12
|
import { Required } from '@travetto/schema';
|
|
@@ -21,6 +22,7 @@ import { ModelExpiryUtil } from '../internal/service/expiry';
|
|
|
21
22
|
import { NotFoundError } from '../error/not-found';
|
|
22
23
|
import { ExistsError } from '../error/exists';
|
|
23
24
|
import { StreamModel, STREAMS } from '../internal/service/stream';
|
|
25
|
+
import { ModelUtil } from '../internal/util';
|
|
24
26
|
|
|
25
27
|
type Suffix = '.bin' | '.meta' | '.json' | '.expires';
|
|
26
28
|
|
|
@@ -36,12 +38,12 @@ export class FileModelConfig {
|
|
|
36
38
|
cullRate?: number | TimeSpan;
|
|
37
39
|
|
|
38
40
|
async postConstruct(): Promise<void> {
|
|
39
|
-
|
|
40
|
-
this.folder = PathUtil.resolveUnix(os.tmpdir(), Util.uuid().substring(0, 10));
|
|
41
|
-
}
|
|
41
|
+
this.folder ??= path.resolve(os.tmpdir(), `trv_file_${RootIndex.mainModule.name.replace(/[^a-z]/ig, '_')}`);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
const exists = (f: string): Promise<boolean> => fs.stat(f).then(() => true, () => false);
|
|
46
|
+
|
|
45
47
|
/**
|
|
46
48
|
* Standard file support
|
|
47
49
|
*/
|
|
@@ -50,9 +52,9 @@ export class FileModelService implements ModelCrudSupport, ModelStreamSupport, M
|
|
|
50
52
|
|
|
51
53
|
private static async * scanFolder(folder: string, suffix: string): AsyncGenerator<[id: string, field: string]> {
|
|
52
54
|
for (const sub of await fs.readdir(folder)) {
|
|
53
|
-
for (const file of await fs.readdir(
|
|
55
|
+
for (const file of await fs.readdir(path.resolve(folder, sub))) {
|
|
54
56
|
if (file.endsWith(suffix)) {
|
|
55
|
-
yield [file.replace(suffix, ''),
|
|
57
|
+
yield [file.replace(suffix, ''), path.resolve(folder, sub, file)];
|
|
56
58
|
}
|
|
57
59
|
}
|
|
58
60
|
}
|
|
@@ -64,31 +66,28 @@ export class FileModelService implements ModelCrudSupport, ModelStreamSupport, M
|
|
|
64
66
|
|
|
65
67
|
/**
|
|
66
68
|
* The root location for all activity
|
|
67
|
-
*
|
|
68
|
-
* @param folder
|
|
69
69
|
*/
|
|
70
70
|
constructor(public readonly config: FileModelConfig) { }
|
|
71
71
|
|
|
72
72
|
async #resolveName<T extends ModelType>(cls: Class<T> | string, suffix?: Suffix, id?: string): Promise<string> {
|
|
73
73
|
const name = typeof cls === 'string' ? cls : ModelRegistry.getStore(cls);
|
|
74
|
-
let resolved =
|
|
74
|
+
let resolved = path.resolve(this.config.folder, this.config.namespace, name);
|
|
75
75
|
if (id) {
|
|
76
|
-
resolved =
|
|
76
|
+
resolved = path.resolve(resolved, id.replace(/^[/]/, '').substring(0, 3));
|
|
77
77
|
}
|
|
78
78
|
let dir = resolved;
|
|
79
79
|
if (id) {
|
|
80
|
-
resolved =
|
|
80
|
+
resolved = path.resolve(resolved, `${id}${suffix}`);
|
|
81
81
|
dir = path.dirname(resolved);
|
|
82
82
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
83
|
+
|
|
84
|
+
await fs.mkdir(dir, { recursive: true });
|
|
86
85
|
return resolved;
|
|
87
86
|
}
|
|
88
87
|
|
|
89
88
|
async #find<T extends ModelType>(cls: Class<T> | string, suffix: Suffix, id?: string): Promise<string> {
|
|
90
89
|
const file = await this.#resolveName(cls, suffix, id);
|
|
91
|
-
if (id && !(await
|
|
90
|
+
if (id && !(await exists(file))) {
|
|
92
91
|
throw new NotFoundError(cls, id);
|
|
93
92
|
}
|
|
94
93
|
return file;
|
|
@@ -107,7 +106,7 @@ export class FileModelService implements ModelCrudSupport, ModelStreamSupport, M
|
|
|
107
106
|
}
|
|
108
107
|
|
|
109
108
|
uuid(): string {
|
|
110
|
-
return
|
|
109
|
+
return ModelUtil.uuid(32);
|
|
111
110
|
}
|
|
112
111
|
|
|
113
112
|
async get<T extends ModelType>(cls: Class<T>, id: string): Promise<T> {
|
|
@@ -115,7 +114,7 @@ export class FileModelService implements ModelCrudSupport, ModelStreamSupport, M
|
|
|
115
114
|
|
|
116
115
|
const file = await this.#resolveName(cls, '.json', id);
|
|
117
116
|
|
|
118
|
-
if (await
|
|
117
|
+
if (await exists(file)) {
|
|
119
118
|
const content = await StreamUtil.streamToBuffer(createReadStream(file));
|
|
120
119
|
return this.checkExpiry(cls, await ModelCrudUtil.load(cls, content));
|
|
121
120
|
}
|
|
@@ -130,7 +129,7 @@ export class FileModelService implements ModelCrudSupport, ModelStreamSupport, M
|
|
|
130
129
|
|
|
131
130
|
const file = await this.#resolveName(cls, '.json', item.id);
|
|
132
131
|
|
|
133
|
-
if (await
|
|
132
|
+
if (await exists(file)) {
|
|
134
133
|
throw new ExistsError(cls, item.id!);
|
|
135
134
|
}
|
|
136
135
|
|
|
@@ -203,7 +202,7 @@ export class FileModelService implements ModelCrudSupport, ModelStreamSupport, M
|
|
|
203
202
|
|
|
204
203
|
async deleteStream(location: string): Promise<void> {
|
|
205
204
|
const file = await this.#resolveName(STREAMS, BIN, location);
|
|
206
|
-
if (await
|
|
205
|
+
if (await exists(file)) {
|
|
207
206
|
await Promise.all([
|
|
208
207
|
fs.unlink(file),
|
|
209
208
|
fs.unlink(file.replace('.bin', META))
|
|
@@ -226,15 +225,15 @@ export class FileModelService implements ModelCrudSupport, ModelStreamSupport, M
|
|
|
226
225
|
|
|
227
226
|
// Storage management
|
|
228
227
|
async createStorage(): Promise<void> {
|
|
229
|
-
const dir =
|
|
228
|
+
const dir = path.resolve(this.config.folder, this.config.namespace);
|
|
230
229
|
await fs.mkdir(dir, { recursive: true });
|
|
231
230
|
}
|
|
232
231
|
|
|
233
232
|
async deleteStorage(): Promise<void> {
|
|
234
|
-
await
|
|
233
|
+
await fs.rm(path.resolve(this.config.folder, this.config.namespace), { recursive: true, force: true });
|
|
235
234
|
}
|
|
236
235
|
|
|
237
236
|
async truncateModel(cls: Class<ModelType>): Promise<void> {
|
|
238
|
-
await
|
|
237
|
+
await fs.rm(await this.#resolveName(cls === StreamModel ? STREAMS : cls), { recursive: true, force: true });
|
|
239
238
|
}
|
|
240
239
|
}
|
package/src/provider/memory.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Readable } from 'stream';
|
|
2
2
|
|
|
3
|
-
import { StreamUtil } from '@travetto/
|
|
4
|
-
import { Util, Class, TimeSpan } from '@travetto/base';
|
|
3
|
+
import { StreamUtil, Class, TimeSpan } from '@travetto/base';
|
|
5
4
|
import { DeepPartial } from '@travetto/schema';
|
|
6
5
|
import { Injectable } from '@travetto/di';
|
|
7
6
|
import { Config } from '@travetto/config';
|
|
@@ -21,6 +20,7 @@ import { ModelIndexedUtil } from '../internal/service/indexed';
|
|
|
21
20
|
import { ModelStorageUtil } from '../internal/service/storage';
|
|
22
21
|
import { StreamModel, STREAMS } from '../internal/service/stream';
|
|
23
22
|
import { IndexConfig } from '../registry/types';
|
|
23
|
+
import { ModelUtil } from '../internal/util';
|
|
24
24
|
|
|
25
25
|
const STREAM_META = `${STREAMS}_meta`;
|
|
26
26
|
|
|
@@ -34,7 +34,7 @@ export class MemoryModelConfig {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
function indexName<T extends ModelType>(cls: Class<T>, idx: IndexConfig<T> | string, suffix?: string): string {
|
|
37
|
-
return [cls
|
|
37
|
+
return [cls.Ⲑid, typeof idx === 'string' ? idx : idx.name, suffix].filter(x => !!x).join(':');
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
function getFirstId(data: Map<string, unknown> | Set<string>, value?: string | number): string | undefined {
|
|
@@ -119,9 +119,9 @@ export class MemoryModelService implements ModelCrudSupport, ModelStreamSupport,
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
async #
|
|
123
|
-
async #
|
|
124
|
-
async #
|
|
122
|
+
async #persist<T extends ModelType>(cls: Class<T>, item: T, action: 'remove'): Promise<void>;
|
|
123
|
+
async #persist<T extends ModelType>(cls: Class<T>, item: T, action: 'write'): Promise<T>;
|
|
124
|
+
async #persist<T extends ModelType>(cls: Class<T>, item: T, action: 'write' | 'remove'): Promise<T | void> {
|
|
125
125
|
const store = this.#getStore(cls);
|
|
126
126
|
await this.#removeIndices(cls, item.id);
|
|
127
127
|
if (action === 'write') {
|
|
@@ -159,7 +159,7 @@ export class MemoryModelService implements ModelCrudSupport, ModelStreamSupport,
|
|
|
159
159
|
for (const idx of ModelRegistry.get(el).indices ?? []) {
|
|
160
160
|
switch (idx.type) {
|
|
161
161
|
case 'unique': {
|
|
162
|
-
console.error('Unique indices are not supported for', { cls: el
|
|
162
|
+
console.error('Unique indices are not supported for', { cls: el.Ⲑid, idx: idx.name });
|
|
163
163
|
break;
|
|
164
164
|
}
|
|
165
165
|
}
|
|
@@ -169,7 +169,7 @@ export class MemoryModelService implements ModelCrudSupport, ModelStreamSupport,
|
|
|
169
169
|
|
|
170
170
|
// CRUD Support
|
|
171
171
|
uuid(): string {
|
|
172
|
-
return
|
|
172
|
+
return ModelUtil.uuid(32);
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
async get<T extends ModelType>(cls: Class<T>, id: string): Promise<T> {
|
|
@@ -208,13 +208,13 @@ export class MemoryModelService implements ModelCrudSupport, ModelStreamSupport,
|
|
|
208
208
|
await ModelCrudUtil.load(cls, store.get(item.id)!, 'exists');
|
|
209
209
|
}
|
|
210
210
|
const prepped = await ModelCrudUtil.preStore(cls, item, this);
|
|
211
|
-
return await this.#
|
|
211
|
+
return await this.#persist(cls, prepped, 'write');
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
async updatePartial<T extends ModelType>(cls: Class<T>, item: Partial<T> & { id: string }, view?: string): Promise<T> {
|
|
215
215
|
const id = item.id;
|
|
216
216
|
const clean = await ModelCrudUtil.naivePartialUpdate(cls, item, view, () => this.get(cls, id));
|
|
217
|
-
return await this.#
|
|
217
|
+
return await this.#persist(cls, clean, 'write');
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
async delete<T extends ModelType>(cls: Class<T>, id: string): Promise<void> {
|
|
@@ -224,7 +224,7 @@ export class MemoryModelService implements ModelCrudSupport, ModelStreamSupport,
|
|
|
224
224
|
}
|
|
225
225
|
await ModelCrudUtil.load(cls, store.get(id)!);
|
|
226
226
|
const where: ModelType = { id };
|
|
227
|
-
await this.#
|
|
227
|
+
await this.#persist(cls, where, 'remove');
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
async * list<T extends ModelType>(cls: Class<T>): AsyncIterable<T> {
|
|
@@ -7,7 +7,7 @@ import { IndexConfig, ModelOptions } from './types';
|
|
|
7
7
|
/**
|
|
8
8
|
* Model decorator, extends `@Schema`
|
|
9
9
|
*
|
|
10
|
-
* @augments `@
|
|
10
|
+
* @augments `@travetto/schema:Schema`
|
|
11
11
|
*/
|
|
12
12
|
export function Model(conf: Partial<ModelOptions<ModelType>> | string = {}) {
|
|
13
13
|
return function <T extends ModelType, U extends Class<T>>(target: U): U {
|
|
@@ -31,7 +31,7 @@ export function Index<T>(...indices: IndexConfig<any>[]) {
|
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Model field decorator for denoting expiry date/time
|
|
34
|
-
* @augments `@
|
|
34
|
+
* @augments `@travetto/schema:Field`
|
|
35
35
|
*/
|
|
36
36
|
export function ExpiresAt() {
|
|
37
37
|
return <K extends string, T extends Partial<Record<K, Date>>>(tgt: T, prop: K): void => {
|
package/src/registry/model.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RootIndex } from '@travetto/manifest';
|
|
1
2
|
import { SchemaRegistry } from '@travetto/schema';
|
|
2
3
|
import { MetadataRegistry } from '@travetto/registry';
|
|
3
4
|
import { DependencyRegistry } from '@travetto/di';
|
|
@@ -51,12 +52,12 @@ class $ModelRegistry extends MetadataRegistry<ModelOptions<ModelType>> {
|
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
createPending(cls: Class): Partial<ModelOptions<ModelType>> {
|
|
54
|
-
return { class: cls, indices: [], autoCreate: true, baseType: cls
|
|
55
|
+
return { class: cls, indices: [], autoCreate: true, baseType: RootIndex.getFunctionMetadata(cls)?.abstract };
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
onInstallFinalize(cls: Class): ModelOptions<ModelType> {
|
|
58
59
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
59
|
-
const config = this.pending.get(cls
|
|
60
|
+
const config = this.pending.get(cls.Ⲑid)! as ModelOptions<ModelType>;
|
|
60
61
|
|
|
61
62
|
const schema = SchemaRegistry.get(cls);
|
|
62
63
|
const view = schema.views[AllViewⲐ].schema;
|
|
@@ -145,11 +146,11 @@ class $ModelRegistry extends MetadataRegistry<ModelOptions<ModelType>> {
|
|
|
145
146
|
if (candidates.length > 1) {
|
|
146
147
|
if (config.store) {
|
|
147
148
|
throw new AppError('Duplicate models with same store name', 'general', {
|
|
148
|
-
classes: candidates.map(x => x
|
|
149
|
+
classes: candidates.map(x => x.Ⲑid)
|
|
149
150
|
});
|
|
150
151
|
} else {
|
|
151
152
|
throw new AppError('Duplicate models with same class name, but no store name provided', 'general', {
|
|
152
|
-
classes: candidates.map(x => x
|
|
153
|
+
classes: candidates.map(x => x.Ⲑid)
|
|
153
154
|
});
|
|
154
155
|
}
|
|
155
156
|
}
|
package/src/registry/types.ts
CHANGED
package/src/service/bulk.ts
CHANGED
|
@@ -4,10 +4,6 @@ import { ValidationResultError } from '@travetto/schema';
|
|
|
4
4
|
import { ModelCrudSupport } from './crud';
|
|
5
5
|
import { ModelType, OptionalId } from '../types/model';
|
|
6
6
|
|
|
7
|
-
declare global {
|
|
8
|
-
interface Error { toJSON(sub?: unknown): unknown }
|
|
9
|
-
}
|
|
10
|
-
|
|
11
7
|
/**
|
|
12
8
|
* Bulk operation. Each operation has a single action and payload
|
|
13
9
|
*/
|
|
@@ -52,9 +48,8 @@ export class BulkProcessError extends AppError {
|
|
|
52
48
|
/**
|
|
53
49
|
* Provide full results back, with validation errors
|
|
54
50
|
*/
|
|
55
|
-
override toJSON(
|
|
51
|
+
override toJSON(): unknown {
|
|
56
52
|
return {
|
|
57
|
-
...extra,
|
|
58
53
|
at: new Date(),
|
|
59
54
|
message: this.message,
|
|
60
55
|
category: this.category,
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ExecUtil } from '@travetto/
|
|
1
|
+
import { RootIndex } from '@travetto/manifest';
|
|
2
|
+
import { Class, ExecUtil } from '@travetto/base';
|
|
3
|
+
import { GlobalTerminal } from '@travetto/terminal';
|
|
4
|
+
import { ModelRegistry } from '@travetto/model';
|
|
5
|
+
import { InjectableConfig, DependencyRegistry } from '@travetto/di';
|
|
6
|
+
import { RootRegistry } from '@travetto/registry';
|
|
3
7
|
|
|
4
|
-
import
|
|
5
|
-
import type { InjectableConfig } from '@travetto/di';
|
|
8
|
+
import { ModelStorageSupportTarget } from '@travetto/model/src/internal/service/common';
|
|
6
9
|
|
|
7
10
|
import type { ModelStorageSupport } from '../../src/service/storage';
|
|
8
11
|
import type { ModelType } from '../../src/types/model';
|
|
@@ -14,13 +17,16 @@ type CandidateNames = { providers: string[], models: string[] };
|
|
|
14
17
|
*/
|
|
15
18
|
export class ModelCandidateUtil {
|
|
16
19
|
|
|
20
|
+
static async export(op: keyof ModelStorageSupport): Promise<{ models: string[], providers: string[] }> {
|
|
21
|
+
return { models: await this.getModelNames(), providers: await this.getProviderNames(op) };
|
|
22
|
+
}
|
|
23
|
+
|
|
17
24
|
/**
|
|
18
25
|
* Get all models
|
|
19
26
|
*/
|
|
20
27
|
static async #getModels(models?: string[]): Promise<Class<ModelType>[]> {
|
|
21
28
|
const names = new Set(models ?? []);
|
|
22
29
|
const all = names.has('*');
|
|
23
|
-
const { ModelRegistry } = await import('@travetto/model');
|
|
24
30
|
return ModelRegistry.getClasses()
|
|
25
31
|
.map(x => ModelRegistry.getBaseModel(x))
|
|
26
32
|
.filter(x => !models || all || names.has(ModelRegistry.getStore(x)));
|
|
@@ -30,7 +36,6 @@ export class ModelCandidateUtil {
|
|
|
30
36
|
* Get model names
|
|
31
37
|
*/
|
|
32
38
|
static async getModelNames(): Promise<string[]> {
|
|
33
|
-
const { ModelRegistry } = await import('@travetto/model');
|
|
34
39
|
return (await this.#getModels()).map(x => ModelRegistry.getStore(x)).sort();
|
|
35
40
|
}
|
|
36
41
|
|
|
@@ -38,8 +43,6 @@ export class ModelCandidateUtil {
|
|
|
38
43
|
* Get all providers that are viable candidates
|
|
39
44
|
*/
|
|
40
45
|
static async getProviders(op?: keyof ModelStorageSupport): Promise<InjectableConfig[]> {
|
|
41
|
-
const { DependencyRegistry } = await import('@travetto/di');
|
|
42
|
-
const { ModelStorageSupportTarget } = await import('@travetto/model/src/internal/service/common');
|
|
43
46
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
44
47
|
const types = DependencyRegistry.getCandidateTypes<ModelStorageSupport>(ModelStorageSupportTarget as unknown as Class<ModelStorageSupport>);
|
|
45
48
|
return types.filter(x => !op || x.class.prototype[op]);
|
|
@@ -58,7 +61,6 @@ export class ModelCandidateUtil {
|
|
|
58
61
|
* Get a single provider
|
|
59
62
|
*/
|
|
60
63
|
static async getProvider(provider: string): Promise<ModelStorageSupport> {
|
|
61
|
-
const { DependencyRegistry } = await import('@travetto/di');
|
|
62
64
|
const config = (await this.getProviders()).find(x => x.class.name === `${provider}ModelService`)!;
|
|
63
65
|
return DependencyRegistry.getInstance<ModelStorageSupport>(config.class, config.qualifier);
|
|
64
66
|
}
|
|
@@ -68,9 +70,10 @@ export class ModelCandidateUtil {
|
|
|
68
70
|
* @returns
|
|
69
71
|
*/
|
|
70
72
|
static async getCandidates(op: keyof ModelStorageSupport): Promise<CandidateNames> {
|
|
71
|
-
return
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
return GlobalTerminal.withWaiting('Resolving', ExecUtil.worker<CandidateNames>(
|
|
74
|
+
RootIndex.resolveFileImport('@travetto/cli/support/cli.ts'),
|
|
75
|
+
['main', '@travetto/model/support/bin/candidate.ts', op]
|
|
76
|
+
).message);
|
|
74
77
|
}
|
|
75
78
|
|
|
76
79
|
/**
|
|
@@ -85,4 +88,12 @@ export class ModelCandidateUtil {
|
|
|
85
88
|
models: await this.#getModels(models)
|
|
86
89
|
};
|
|
87
90
|
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Handles direct invocation
|
|
95
|
+
*/
|
|
96
|
+
export async function main(op: keyof ModelStorageSupport): Promise<{ models: string[], providers: string[] }> {
|
|
97
|
+
await RootRegistry.init();
|
|
98
|
+
return await ModelCandidateUtil.export(op);
|
|
88
99
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { ShutdownManager, type Class } from '@travetto/base';
|
|
2
2
|
import type { ModelStorageSupport } from '@travetto/model/src/service/storage';
|
|
3
3
|
import type { ModelType } from '@travetto/model/src/types/model';
|
|
4
4
|
|
|
@@ -8,9 +8,9 @@ export class ModelInstallUtil {
|
|
|
8
8
|
throw new Error(`${provider} does not support model installation`);
|
|
9
9
|
}
|
|
10
10
|
for (const m of models) {
|
|
11
|
-
console.log('Installing', { name: m
|
|
11
|
+
console.log('Installing', { name: m.Ⲑid });
|
|
12
12
|
await provider.createModel(m);
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
ShutdownManager.execute(-1); // Release database
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { CliCommand, cliTpl, OptionConfig } from '@travetto/cli';
|
|
2
|
+
import type { ModelStorageSupport } from '@travetto/model/src/service/storage';
|
|
3
|
+
|
|
4
|
+
import { ModelCandidateUtil } from './bin/candidate';
|
|
5
|
+
|
|
6
|
+
type Options = {
|
|
7
|
+
env: OptionConfig<string>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* CLI Entry point for exporting model schemas
|
|
12
|
+
*/
|
|
13
|
+
export abstract class BaseModelCommand extends CliCommand<Options> {
|
|
14
|
+
|
|
15
|
+
restoreEnv?: (err: Error) => unknown;
|
|
16
|
+
|
|
17
|
+
op: keyof ModelStorageSupport;
|
|
18
|
+
|
|
19
|
+
resolve = ModelCandidateUtil.resolve.bind(ModelCandidateUtil);
|
|
20
|
+
|
|
21
|
+
getArgs(): string {
|
|
22
|
+
return '[provider] [models...]';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
getOptions(): Options {
|
|
26
|
+
return { env: this.option({ desc: 'Application environment' }) };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
usage({ providers, models }: { providers: string[], models: string[] }, err = ''): Promise<void> {
|
|
30
|
+
return this.showHelp(err, cliTpl`
|
|
31
|
+
${{ title: 'Providers' }}:
|
|
32
|
+
${providers.map(p => cliTpl` * ${{ type: p }}`).join('\n')}
|
|
33
|
+
|
|
34
|
+
${{ title: 'Models' }}:
|
|
35
|
+
${models.map(p => cliTpl` * ${{ param: p }}`).join('\n')}
|
|
36
|
+
`, false);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async validate(provider: string, models: string[]): Promise<true | void> {
|
|
40
|
+
const candidates = await ModelCandidateUtil.getCandidates(this.op);
|
|
41
|
+
if (!provider) {
|
|
42
|
+
return this.usage(candidates);
|
|
43
|
+
} else {
|
|
44
|
+
if (!candidates.providers.includes(provider)) {
|
|
45
|
+
return this.usage(candidates, cliTpl`${{ param: provider }} is not a valid provider`);
|
|
46
|
+
}
|
|
47
|
+
const badModel = models.find(x => x !== '*' && !candidates.models.includes(x));
|
|
48
|
+
if (badModel) {
|
|
49
|
+
return this.usage(candidates, cliTpl`${{ param: badModel }} is not a valid model`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { ConsoleManager } from '@travetto/base';
|
|
2
|
+
import { RootRegistry } from '@travetto/registry';
|
|
3
|
+
|
|
4
|
+
import { BaseModelCommand } from './cli.base-command';
|
|
5
|
+
import { ModelExportUtil } from './bin/export';
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* CLI Entry point for exporting model schemas
|
|
@@ -10,7 +13,13 @@ export class ModelExportCommand extends BaseModelCommand {
|
|
|
10
13
|
|
|
11
14
|
async action(provider: string, models: string[]): Promise<void> {
|
|
12
15
|
try {
|
|
13
|
-
|
|
16
|
+
ConsoleManager.setDebug(false);
|
|
17
|
+
await RootRegistry.init();
|
|
18
|
+
|
|
19
|
+
if (!await this.validate(provider, models)) {
|
|
20
|
+
return this.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
14
23
|
const resolved = await this.resolve(provider, models);
|
|
15
24
|
await ModelExportUtil.run(resolved.provider, resolved.models);
|
|
16
25
|
} catch (err) {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { cliTpl } from '@travetto/cli';
|
|
2
|
+
import { ConsoleManager } from '@travetto/base';
|
|
3
|
+
import { RootRegistry } from '@travetto/registry';
|
|
4
|
+
|
|
5
|
+
import { BaseModelCommand } from './cli.base-command';
|
|
6
|
+
import { ModelInstallUtil } from './bin/install';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* CLI Entry point for installing models
|
|
10
|
+
*/
|
|
11
|
+
export class ModelInstallCommand extends BaseModelCommand {
|
|
12
|
+
name = 'model:install';
|
|
13
|
+
op = 'createModel' as const;
|
|
14
|
+
|
|
15
|
+
async action(provider: string, models: string[]): Promise<void> {
|
|
16
|
+
try {
|
|
17
|
+
ConsoleManager.setDebug(false);
|
|
18
|
+
await RootRegistry.init();
|
|
19
|
+
|
|
20
|
+
if (!await this.validate(provider, models)) {
|
|
21
|
+
return this.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const resolved = await this.resolve(provider, models);
|
|
25
|
+
await ModelInstallUtil.run(resolved.provider, resolved.models);
|
|
26
|
+
console.log(cliTpl`${{ success: 'Successfully' }} installed ${{ param: models.length.toString() }} model(s)`);
|
|
27
|
+
} catch (err) {
|
|
28
|
+
console.error((err && err instanceof Error) ? err.message : err);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
|
|
3
|
+
import { RootIndex } from '@travetto/manifest';
|
|
4
|
+
import { d, mod } from '@travetto/doc';
|
|
5
|
+
import { Config } from '@travetto/config';
|
|
6
|
+
import { AllType, AllTypeMap } from '@travetto/doc/src/nodes';
|
|
7
|
+
|
|
8
|
+
export const Links = {
|
|
9
|
+
Basic: d.SnippetLink('Basic', '@travetto/model/src/service/basic.ts', /export interface/),
|
|
10
|
+
Crud: d.SnippetLink('CRUD', '@travetto/model/src/service/crud.ts', /export interface/),
|
|
11
|
+
Expiry: d.SnippetLink('Expiry', '@travetto/model/src/service/expiry.ts', /export interface/),
|
|
12
|
+
Indexed: d.SnippetLink('Indexed', '@travetto/model/src/service/indexed.ts', /export interface/),
|
|
13
|
+
Bulk: d.SnippetLink('Bulk', '@travetto/model/src/service/bulk.ts', /export interface/),
|
|
14
|
+
Stream: d.SnippetLink('Streaming', '@travetto/model/src/service/stream.ts', /export interface/),
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const ModelTypes = (file: string | Function): AllTypeMap['SnippetLink'][] => {
|
|
18
|
+
if (typeof file !== 'string') {
|
|
19
|
+
file = RootIndex.getFunctionMetadata(file)!.source;
|
|
20
|
+
}
|
|
21
|
+
const contents = readFileSync(file, 'utf8');
|
|
22
|
+
const found: AllTypeMap['SnippetLink'][] = [];
|
|
23
|
+
const seen = new Set();
|
|
24
|
+
for (const [, key] of contents.matchAll(/Model(Crud|Expiry|Indexed|Bulk|Stream)Support/g)) {
|
|
25
|
+
if (!seen.has(key)) {
|
|
26
|
+
seen.add(key);
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
28
|
+
found.push(Links[key as keyof typeof Links]);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return found;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const ModelCustomConfig = (cfg: Function): AllType => d`
|
|
35
|
+
Out of the box, by installing the module, everything should be wired up by default.If you need to customize any aspect of the source
|
|
36
|
+
or config, you can override and register it with the ${mod.Di} module.
|
|
37
|
+
|
|
38
|
+
${d.Code('Wiring up a custom Model Source', 'doc/custom-service.ts')}
|
|
39
|
+
|
|
40
|
+
where the ${cfg} is defined by:
|
|
41
|
+
|
|
42
|
+
${d.Code(`Structure of ${cfg.name}`, cfg)}
|
|
43
|
+
|
|
44
|
+
Additionally, you can see that the class is registered with the ${Config} annotation, and so these values can be overridden using the
|
|
45
|
+
standard ${mod.Config}resolution paths.
|
|
46
|
+
`;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { DependencyRegistry } from '@travetto/di';
|
|
2
2
|
import { AppError, Class } from '@travetto/base';
|
|
3
3
|
|
|
4
|
-
import { isBulkSupported, isCrudSupported } from '
|
|
5
|
-
import { ModelType } from '
|
|
4
|
+
import { isBulkSupported, isCrudSupported } from '../../src/internal/service/common';
|
|
5
|
+
import { ModelType } from '../../src/types/model';
|
|
6
6
|
import { ModelSuite } from './suite';
|
|
7
7
|
|
|
8
8
|
type ServiceClass = { serviceClass: { new(): unknown } };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import assert from 'assert';
|
|
2
2
|
|
|
3
3
|
import { Suite, Test } from '@travetto/test';
|
|
4
|
+
import { ModelCrudSupport, Model, NotFoundError } from '@travetto/model';
|
|
4
5
|
|
|
5
6
|
import { BaseModelSuite } from './base';
|
|
6
|
-
import { ModelCrudSupport, Model, NotFoundError } from '..';
|
|
7
7
|
|
|
8
8
|
@Model('basic_person')
|
|
9
9
|
class Person {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import assert from 'assert';
|
|
2
2
|
|
|
3
3
|
import { Suite, Test } from '@travetto/test';
|
|
4
4
|
|
|
5
|
-
import { Model } from '
|
|
6
|
-
import { ModelBulkSupport } from '
|
|
5
|
+
import { Model } from '../../src/registry/decorator';
|
|
6
|
+
import { ModelBulkSupport } from '../../src/service/bulk';
|
|
7
7
|
import { BaseModelSuite } from './base';
|
|
8
8
|
|
|
9
9
|
@Model('bulk-user')
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import assert from 'assert';
|
|
2
2
|
|
|
3
3
|
import { Suite, Test } from '@travetto/test';
|
|
4
4
|
import { Schema, Text, Precision, } from '@travetto/schema';
|
|
5
|
+
import { ModelCrudSupport, Model, NotFoundError } from '@travetto/model';
|
|
5
6
|
|
|
6
7
|
import { BaseModelSuite } from './base';
|
|
7
|
-
import { ModelCrudSupport, Model, NotFoundError } from '..';
|
|
8
8
|
|
|
9
9
|
@Schema()
|
|
10
10
|
class Address {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import assert from 'assert';
|
|
2
2
|
|
|
3
3
|
import { Suite, Test } from '@travetto/test';
|
|
4
|
-
import {
|
|
4
|
+
import { TimeSpan, TimeUnit, TimeUtil } from '@travetto/base';
|
|
5
5
|
|
|
6
|
-
import { ExpiresAt, Model } from '
|
|
7
|
-
import { ModelExpirySupport } from '
|
|
8
|
-
import { ModelExpiryUtil } from '
|
|
9
|
-
import { NotFoundError } from '
|
|
6
|
+
import { ExpiresAt, Model } from '../../src/registry/decorator';
|
|
7
|
+
import { ModelExpirySupport } from '../../src/service/expiry';
|
|
8
|
+
import { ModelExpiryUtil } from '../../src/internal/service/expiry';
|
|
9
|
+
import { NotFoundError } from '../../src/error/not-found';
|
|
10
10
|
import { BaseModelSuite } from './base';
|
|
11
11
|
|
|
12
12
|
@Model('expiry-user')
|
|
@@ -22,11 +22,11 @@ export abstract class ModelExpirySuite extends BaseModelSuite<ModelExpirySupport
|
|
|
22
22
|
delayFactor: number = 1;
|
|
23
23
|
|
|
24
24
|
async wait(n: number | TimeSpan) {
|
|
25
|
-
await
|
|
25
|
+
await TimeUtil.wait(TimeUtil.timeToMs(n) * this.delayFactor);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
timeFromNow(v: number | TimeSpan, unit?: TimeUnit) {
|
|
29
|
-
return new Date(Date.now() +
|
|
29
|
+
return new Date(Date.now() + TimeUtil.timeToMs(v, unit) * this.delayFactor);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
@Test()
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import assert from 'assert';
|
|
2
2
|
|
|
3
3
|
import { Suite, Test } from '@travetto/test';
|
|
4
4
|
import { Schema } from '@travetto/schema';
|
|
5
|
-
import {
|
|
5
|
+
import { TimeUtil } from '@travetto/base';
|
|
6
|
+
|
|
7
|
+
import { Index, Model } from '../../src/registry/decorator';
|
|
8
|
+
import { ModelIndexedSupport } from '../../src/service/indexed';
|
|
9
|
+
import { NotFoundError } from '../../src/error/not-found';
|
|
10
|
+
import { IndexNotSupported } from '../../src/error/invalid-index';
|
|
6
11
|
|
|
7
|
-
import { Index, Model } from '../src/registry/decorator';
|
|
8
|
-
import { ModelIndexedSupport } from '../src/service/indexed';
|
|
9
12
|
import { BaseModelSuite } from './base';
|
|
10
|
-
import { NotFoundError } from '../src/error/not-found';
|
|
11
|
-
import { IndexNotSupported } from '../src/error/invalid-index';
|
|
12
13
|
|
|
13
14
|
@Model('index_user')
|
|
14
15
|
@Index({
|
|
@@ -152,9 +153,9 @@ export abstract class ModelIndexedSuite extends BaseModelSuite<ModelIndexedSuppo
|
|
|
152
153
|
async queryComplexDateList() {
|
|
153
154
|
const service = await this.service;
|
|
154
155
|
|
|
155
|
-
await service.create(User4, User4.from({ child: { name: 'bob', age: 40 }, createdDate:
|
|
156
|
-
await service.create(User4, User4.from({ child: { name: 'bob', age: 30 }, createdDate:
|
|
157
|
-
await service.create(User4, User4.from({ child: { name: 'bob', age: 50 }, createdDate:
|
|
156
|
+
await service.create(User4, User4.from({ child: { name: 'bob', age: 40 }, createdDate: TimeUtil.timeFromNow('3d'), color: 'blue' }));
|
|
157
|
+
await service.create(User4, User4.from({ child: { name: 'bob', age: 30 }, createdDate: TimeUtil.timeFromNow('2d'), color: 'red' }));
|
|
158
|
+
await service.create(User4, User4.from({ child: { name: 'bob', age: 50 }, createdDate: TimeUtil.timeFromNow('-1d'), color: 'green' }));
|
|
158
159
|
|
|
159
160
|
const arr = await this.toArray(service.listByIndex(User4, 'nameCreated', User4.from({ child: { name: 'bob' } })));
|
|
160
161
|
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import
|
|
1
|
+
import assert from 'assert';
|
|
2
|
+
import timers from 'timers/promises';
|
|
2
3
|
|
|
3
4
|
import { Suite, Test } from '@travetto/test';
|
|
4
5
|
import { Text, TypeMismatchError } from '@travetto/schema';
|
|
5
|
-
|
|
6
|
-
import { BaseModelSuite } from './base';
|
|
7
6
|
import {
|
|
8
7
|
ModelIndexedSupport, Index, ModelCrudSupport, Model,
|
|
9
8
|
NotFoundError, SubTypeNotSupportedError
|
|
10
|
-
} from '
|
|
11
|
-
|
|
12
|
-
import {
|
|
9
|
+
} from '@travetto/model';
|
|
10
|
+
|
|
11
|
+
import { isIndexedSupported } from '../../src/internal/service/common';
|
|
12
|
+
import { ExistsError } from '../../src/error/exists';
|
|
13
|
+
|
|
14
|
+
import { BaseModelSuite } from './base';
|
|
13
15
|
|
|
14
16
|
@Model({ baseType: true })
|
|
15
17
|
export class Worker {
|
|
@@ -162,6 +164,8 @@ export abstract class ModelPolymorphismSuite extends BaseModelSuite<ModelCrudSup
|
|
|
162
164
|
() => service.update(Engineer, Doctor.from({ ...doc }) as unknown as Engineer),
|
|
163
165
|
(e: Error) => (e instanceof NotFoundError || e instanceof SubTypeNotSupportedError || e instanceof TypeMismatchError) ? undefined : e);
|
|
164
166
|
|
|
167
|
+
await timers.setTimeout(15);
|
|
168
|
+
|
|
165
169
|
try {
|
|
166
170
|
const res = await service.upsert(Doctor, Doctor.from({
|
|
167
171
|
id: doc.id, name: 'gob', specialty: 'eyes'
|
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { createReadStream } from 'fs';
|
|
4
|
-
import * as crypto from 'crypto';
|
|
1
|
+
import assert from 'assert';
|
|
2
|
+
import crypto from 'crypto';
|
|
5
3
|
import { Readable } from 'stream';
|
|
6
4
|
|
|
7
|
-
import {
|
|
8
|
-
import { BeforeAll, Suite, Test } from '@travetto/test';
|
|
9
|
-
import { ResourceManager } from '@travetto/base';
|
|
5
|
+
import { Suite, Test, TestFixtures } from '@travetto/test';
|
|
10
6
|
|
|
11
7
|
import { BaseModelSuite } from './base';
|
|
12
|
-
import { ModelStreamSupport } from '
|
|
8
|
+
import { ModelStreamSupport } from '../../src/service/stream';
|
|
13
9
|
|
|
14
10
|
@Suite()
|
|
15
11
|
export abstract class ModelStreamSuite extends BaseModelSuite<ModelStreamSupport> {
|
|
16
12
|
|
|
17
|
-
|
|
13
|
+
fixture = new TestFixtures(['@travetto/model#support/fixtures']);
|
|
14
|
+
|
|
15
|
+
async getHash(stream: Readable): Promise<string> {
|
|
18
16
|
const hash = crypto.createHash('sha1');
|
|
19
17
|
hash.setEncoding('hex');
|
|
20
18
|
await new Promise((res, rej) => {
|
|
@@ -25,24 +23,18 @@ export abstract class ModelStreamSuite extends BaseModelSuite<ModelStreamSupport
|
|
|
25
23
|
return hash.read() as string;
|
|
26
24
|
}
|
|
27
25
|
|
|
28
|
-
async getStream(resource: string) {
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const hash = await this.getHash(createReadStream(file));
|
|
26
|
+
async getStream(resource: string): Promise<readonly [{ size: number, contentType: string, hash: string, filename: string }, Readable]> {
|
|
27
|
+
const { size } = await this.fixture.describe(resource);
|
|
28
|
+
const hash = await this.getHash(await this.fixture.readStream(resource));
|
|
32
29
|
|
|
33
30
|
return [
|
|
34
|
-
{ size
|
|
35
|
-
|
|
31
|
+
{ size, contentType: '', hash, filename: resource },
|
|
32
|
+
await this.fixture.readStream(resource)
|
|
36
33
|
] as const;
|
|
37
34
|
}
|
|
38
35
|
|
|
39
|
-
@BeforeAll()
|
|
40
|
-
async beforeAll() {
|
|
41
|
-
ResourceManager.addPath(PathUtil.resolveUnix(__dirname, '..', 'resources'));
|
|
42
|
-
}
|
|
43
|
-
|
|
44
36
|
@Test()
|
|
45
|
-
async writeBasic() {
|
|
37
|
+
async writeBasic(): Promise<void> {
|
|
46
38
|
const service = await this.service;
|
|
47
39
|
const [meta, stream] = await this.getStream('/asset.yml');
|
|
48
40
|
|
|
@@ -53,7 +45,7 @@ export abstract class ModelStreamSuite extends BaseModelSuite<ModelStreamSupport
|
|
|
53
45
|
}
|
|
54
46
|
|
|
55
47
|
@Test()
|
|
56
|
-
async writeStream() {
|
|
48
|
+
async writeStream(): Promise<void> {
|
|
57
49
|
const service = await this.service;
|
|
58
50
|
const [meta, stream] = await this.getStream('/asset.yml');
|
|
59
51
|
|
|
@@ -64,7 +56,7 @@ export abstract class ModelStreamSuite extends BaseModelSuite<ModelStreamSupport
|
|
|
64
56
|
}
|
|
65
57
|
|
|
66
58
|
@Test()
|
|
67
|
-
async writeAndDelete() {
|
|
59
|
+
async writeAndDelete(): Promise<void> {
|
|
68
60
|
const service = await this.service;
|
|
69
61
|
const [meta, stream] = await this.getStream('/asset.yml');
|
|
70
62
|
|
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
import { Class
|
|
2
|
-
import { PathUtil } from '@travetto/boot';
|
|
1
|
+
import { Class } from '@travetto/base';
|
|
3
2
|
import { DependencyRegistry } from '@travetto/di';
|
|
4
3
|
import { RootRegistry } from '@travetto/registry';
|
|
5
|
-
import { SuiteRegistry } from '@travetto/test';
|
|
4
|
+
import { SuiteRegistry, TestFixtures } from '@travetto/test';
|
|
6
5
|
|
|
7
|
-
import { isStorageSupported, isStreamSupported } from '
|
|
8
|
-
import { StreamModel } from '
|
|
9
|
-
import { ModelRegistry } from '
|
|
6
|
+
import { isStorageSupported, isStreamSupported } from '../../src/internal/service/common';
|
|
7
|
+
import { StreamModel } from '../../src/internal/service/stream';
|
|
8
|
+
import { ModelRegistry } from '../../src/registry/model';
|
|
10
9
|
|
|
11
10
|
const Loaded = Symbol();
|
|
12
11
|
|
|
13
12
|
export function ModelSuite<T extends { configClass: Class<{ autoCreate?: boolean, namespace?: string }>, serviceClass: Class }>(qualifier?: symbol) {
|
|
13
|
+
const fixtures = new TestFixtures(['@travetto/model']);
|
|
14
14
|
return (target: Class<T>): void => {
|
|
15
|
+
target.prototype.fixtures = fixtures;
|
|
16
|
+
|
|
15
17
|
SuiteRegistry.registerPendingListener(
|
|
16
18
|
target,
|
|
17
19
|
async function (this: T & { [Loaded]?: boolean }) {
|
|
18
|
-
// Track self
|
|
19
|
-
ResourceManager.addPath(PathUtil.resolveUnix(__dirname, 'resources'));
|
|
20
|
-
|
|
21
20
|
await RootRegistry.init();
|
|
22
21
|
|
|
23
22
|
if (!this[Loaded]) {
|
package/bin/candidate.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { EnvInit } from '@travetto/base/bin/init';
|
|
2
|
-
import { ExecUtil } from '@travetto/boot';
|
|
3
|
-
|
|
4
|
-
import type { ModelStorageSupport } from '../src/service/storage';
|
|
5
|
-
import { ModelCandidateUtil } from './lib/candidate';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Handles direct invocation
|
|
9
|
-
*/
|
|
10
|
-
export async function main(op: keyof ModelStorageSupport): Promise<void> {
|
|
11
|
-
try {
|
|
12
|
-
EnvInit.init();
|
|
13
|
-
const { PhaseManager } = await import('@travetto/base');
|
|
14
|
-
await PhaseManager.run('init');
|
|
15
|
-
|
|
16
|
-
ExecUtil.mainResponse({
|
|
17
|
-
models: await ModelCandidateUtil.getModelNames(),
|
|
18
|
-
providers: await ModelCandidateUtil.getProviderNames(op)
|
|
19
|
-
});
|
|
20
|
-
} catch (err) {
|
|
21
|
-
ExecUtil.mainResponse(err);
|
|
22
|
-
}
|
|
23
|
-
}
|
package/bin/cli-model_install.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { color } from '@travetto/cli/src/color';
|
|
2
|
-
|
|
3
|
-
import { BaseModelCommand } from './lib/base-command';
|
|
4
|
-
import { ModelInstallUtil } from './lib/install';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* CLI Entry point for installing models
|
|
8
|
-
*/
|
|
9
|
-
export class ModelInstallCommand extends BaseModelCommand {
|
|
10
|
-
name = 'model:install';
|
|
11
|
-
op = 'createModel' as const;
|
|
12
|
-
|
|
13
|
-
async action(provider: string, models: string[]): Promise<void> {
|
|
14
|
-
try {
|
|
15
|
-
await this.validate(provider, models);
|
|
16
|
-
const resolved = await this.resolve(provider, models);
|
|
17
|
-
await ModelInstallUtil.run(resolved.provider, resolved.models);
|
|
18
|
-
console.log(color`${{ success: 'Successfully' }} installed ${{ param: models.length.toString() }} model(s)`);
|
|
19
|
-
} catch (err) {
|
|
20
|
-
console.error((err && err instanceof Error) ? err.message : err);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
package/bin/lib/base-command.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { CliCommand, OptionConfig } from '@travetto/cli/src/command';
|
|
2
|
-
import { color } from '@travetto/cli/src/color';
|
|
3
|
-
import { EnvInit } from '@travetto/base/bin/init';
|
|
4
|
-
import type { ModelStorageSupport } from '@travetto/model/src/service/storage';
|
|
5
|
-
|
|
6
|
-
import { ModelCandidateUtil } from './candidate';
|
|
7
|
-
|
|
8
|
-
type Options = {
|
|
9
|
-
env: OptionConfig<string>;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* CLI Entry point for exporting model schemas
|
|
14
|
-
*/
|
|
15
|
-
export abstract class BaseModelCommand extends CliCommand<Options> {
|
|
16
|
-
|
|
17
|
-
restoreEnv?: (err: Error) => unknown;
|
|
18
|
-
|
|
19
|
-
op: keyof ModelStorageSupport;
|
|
20
|
-
|
|
21
|
-
resolve = ModelCandidateUtil.resolve.bind(ModelCandidateUtil);
|
|
22
|
-
|
|
23
|
-
envInit(): void {
|
|
24
|
-
EnvInit.init();
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
override async build(): Promise<void> {
|
|
28
|
-
await super.build();
|
|
29
|
-
const { ConsoleManager, PhaseManager } = await import('@travetto/base');
|
|
30
|
-
ConsoleManager.exclude('debug');
|
|
31
|
-
// Init
|
|
32
|
-
await PhaseManager.run('init');
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
getArgs(): string {
|
|
36
|
-
return '[provider] [models...]';
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
getOptions(): Options {
|
|
40
|
-
return { env: this.option({ desc: 'Application environment' }) };
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async usage({ providers, models }: { providers: string[], models: string[] }, err = ''): Promise<void> {
|
|
44
|
-
await this.showHelp(err, color`
|
|
45
|
-
${{ title: 'Providers' }}:
|
|
46
|
-
${providers.map(p => color` * ${{ type: p }}`).join('\n')}
|
|
47
|
-
|
|
48
|
-
${{ title: 'Models' }}:
|
|
49
|
-
${models.map(p => color` * ${{ param: p }}`).join('\n')}
|
|
50
|
-
`);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async validate(provider: string, models: string[]): Promise<void> {
|
|
54
|
-
const candidates = await ModelCandidateUtil.getCandidates(this.op);
|
|
55
|
-
if (!provider) {
|
|
56
|
-
return await this.usage(candidates);
|
|
57
|
-
} else {
|
|
58
|
-
if (!candidates.providers.includes(provider)) {
|
|
59
|
-
await this.usage(candidates, color`${{ param: provider }} is not a valid provider`);
|
|
60
|
-
}
|
|
61
|
-
const badModel = models.find(x => x !== '*' && !candidates.models.includes(x));
|
|
62
|
-
if (badModel) {
|
|
63
|
-
await this.usage(candidates, color`${{ param: badModel }} is not a valid model`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|