@travetto/model 5.0.0 → 5.0.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/model",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.2",
|
|
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": "^5.0.
|
|
30
|
-
"@travetto/di": "^5.0.
|
|
31
|
-
"@travetto/registry": "^5.0.
|
|
32
|
-
"@travetto/schema": "^5.0.
|
|
29
|
+
"@travetto/config": "^5.0.2",
|
|
30
|
+
"@travetto/di": "^5.0.2",
|
|
31
|
+
"@travetto/registry": "^5.0.2",
|
|
32
|
+
"@travetto/schema": "^5.0.2"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@travetto/cli": "^5.0.
|
|
36
|
-
"@travetto/test": "^5.0.
|
|
35
|
+
"@travetto/cli": "^5.0.2",
|
|
36
|
+
"@travetto/test": "^5.0.2"
|
|
37
37
|
},
|
|
38
38
|
"peerDependenciesMeta": {
|
|
39
39
|
"@travetto/cli": {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { hasFunction } from '@travetto/runtime';
|
|
2
|
+
|
|
2
3
|
import type { ModelBulkSupport } from '../../service/bulk';
|
|
3
|
-
import { ModelCrudSupport } from '../../service/crud';
|
|
4
|
+
import type { ModelCrudSupport } from '../../service/crud';
|
|
4
5
|
import type { ModelExpirySupport } from '../../service/expiry';
|
|
5
|
-
import { ModelIndexedSupport } from '../../service/indexed';
|
|
6
|
+
import type { ModelIndexedSupport } from '../../service/indexed';
|
|
6
7
|
import type { ModelStorageSupport } from '../../service/storage';
|
|
7
|
-
import { ModelBlobSupport } from '../../service/blob';
|
|
8
|
+
import type { ModelBlobSupport } from '../../service/blob';
|
|
8
9
|
|
|
9
10
|
export class ModelBasicSupportTarget { }
|
|
10
11
|
export class ModelCrudSupportTarget { }
|
|
@@ -16,57 +17,35 @@ export class ModelIndexedSupportTarget { }
|
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Type guard for determining if service supports basic operations
|
|
19
|
-
* @param o
|
|
20
20
|
*/
|
|
21
|
-
export
|
|
22
|
-
return !!o && 'create' in o;
|
|
23
|
-
}
|
|
21
|
+
export const isBasicSupported = hasFunction<ModelBulkSupport>('create');
|
|
24
22
|
|
|
25
23
|
/**
|
|
26
24
|
* Type guard for determining if service supports crud operations
|
|
27
|
-
* @param o
|
|
28
25
|
*/
|
|
29
|
-
export
|
|
30
|
-
return !!o && 'upsert' in o;
|
|
31
|
-
}
|
|
26
|
+
export const isCrudSupported = hasFunction<ModelCrudSupport>('upsert');
|
|
32
27
|
|
|
33
28
|
/**
|
|
34
29
|
* Type guard for determining if model supports expiry
|
|
35
|
-
* @param o
|
|
36
30
|
*/
|
|
37
|
-
export
|
|
38
|
-
return !!o && 'deleteExpired' in o;
|
|
39
|
-
}
|
|
31
|
+
export const isExpirySupported = hasFunction<ModelExpirySupport>('deleteExpired');
|
|
40
32
|
|
|
41
33
|
/**
|
|
42
34
|
* Type guard for determining if service supports streaming operation
|
|
43
|
-
* @param o
|
|
44
35
|
*/
|
|
45
|
-
export
|
|
46
|
-
return !!o && 'getBlob' in o;
|
|
47
|
-
}
|
|
36
|
+
export const isBlobSupported = hasFunction<ModelBlobSupport>('getBlob');
|
|
48
37
|
|
|
49
38
|
/**
|
|
50
39
|
* Type guard for determining if service supports storage operation
|
|
51
|
-
* @param o
|
|
52
40
|
*/
|
|
53
|
-
export
|
|
54
|
-
return !!o && 'createStorage' in o;
|
|
55
|
-
}
|
|
41
|
+
export const isStorageSupported = hasFunction<ModelStorageSupport>('createStorage');
|
|
56
42
|
|
|
57
43
|
/**
|
|
58
44
|
* Type guard for determining if service supports streaming operation
|
|
59
|
-
* @param o
|
|
60
45
|
*/
|
|
61
|
-
export
|
|
62
|
-
return !!o && 'processBulk' in o;
|
|
63
|
-
}
|
|
46
|
+
export const isBulkSupported = hasFunction<ModelBulkSupport>('processBulk');
|
|
64
47
|
|
|
65
48
|
/**
|
|
66
49
|
* Type guard for determining if service supports indexed operation
|
|
67
|
-
* @param o
|
|
68
50
|
*/
|
|
69
|
-
export
|
|
70
|
-
return !!o && 'getByIndex' in o;
|
|
71
|
-
}
|
|
72
|
-
|
|
51
|
+
export const isIndexedSupported = hasFunction<ModelIndexedSupport>('getByIndex');
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import { castTo, Class, asFull, Util, asConstructable } from '@travetto/runtime';
|
|
1
|
+
import { castTo, Class, Util, asConstructable, AppError } from '@travetto/runtime';
|
|
4
2
|
import { DataUtil, SchemaRegistry, SchemaValidator, ValidationError, ValidationResultError } from '@travetto/schema';
|
|
5
3
|
|
|
6
4
|
import { ModelRegistry } from '../../registry/model';
|
|
@@ -28,18 +26,6 @@ export class ModelCrudUtil {
|
|
|
28
26
|
return { create, valid };
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
/**
|
|
32
|
-
* Provide hash value
|
|
33
|
-
* @param value Input value
|
|
34
|
-
* @param length Number of characters to produce
|
|
35
|
-
*/
|
|
36
|
-
static hashValue(value: string, length = 32): string {
|
|
37
|
-
if (value.length < 32) {
|
|
38
|
-
value = value.padEnd(32, ' ');
|
|
39
|
-
}
|
|
40
|
-
return crypto.createHash('sha1').update(value).digest('hex').substring(0, length);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
29
|
/**
|
|
44
30
|
* Load model
|
|
45
31
|
* @param cls Class to load model for
|
|
@@ -109,36 +95,6 @@ export class ModelCrudUtil {
|
|
|
109
95
|
return castTo(item);
|
|
110
96
|
}
|
|
111
97
|
|
|
112
|
-
/**
|
|
113
|
-
* Performs a naive partial update by fetching, patching, and then storing
|
|
114
|
-
* @param cls Type to store for
|
|
115
|
-
* @param item The object to use for a partial update
|
|
116
|
-
* @param view The schema view to validate against
|
|
117
|
-
* @param getExisting How to fetch an existing item
|
|
118
|
-
*/
|
|
119
|
-
static async naivePartialUpdate<T extends ModelType>(cls: Class<T>, item: Partial<T>, view: undefined | string, getExisting: () => Promise<T>): Promise<T> {
|
|
120
|
-
if (DataUtil.isPlainObject(item)) {
|
|
121
|
-
item = cls.from(castTo(item));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const config = ModelRegistry.get(asConstructable(item).constructor);
|
|
125
|
-
if (config.subType) { // Sub-typing, assign type
|
|
126
|
-
SchemaRegistry.ensureInstanceTypeField(cls, item);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (view) {
|
|
130
|
-
await SchemaValidator.validate(cls, item, view);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const existing = await getExisting();
|
|
134
|
-
|
|
135
|
-
item = Object.assign(existing, item);
|
|
136
|
-
|
|
137
|
-
item = await this.prePersist(cls, item, 'partial');
|
|
138
|
-
|
|
139
|
-
return asFull(item);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
98
|
/**
|
|
143
99
|
* Ensure subtype is not supported
|
|
144
100
|
*/
|
|
@@ -178,4 +134,25 @@ export class ModelCrudUtil {
|
|
|
178
134
|
}
|
|
179
135
|
return item;
|
|
180
136
|
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Ensure everything is correct for a partial update
|
|
140
|
+
*/
|
|
141
|
+
static async prePartialUpdate<T extends ModelType>(cls: Class<T>, item: Partial<T>, view?: string): Promise<Partial<T>> {
|
|
142
|
+
if (!DataUtil.isPlainObject(item)) {
|
|
143
|
+
throw new AppError(`A partial update requires a plain object, not an instance of ${castTo<Function>(item).constructor.name}`, 'data');
|
|
144
|
+
}
|
|
145
|
+
const res = await this.prePersist(cls, castTo(item), 'partial');
|
|
146
|
+
await SchemaValidator.validatePartial(cls, item, view);
|
|
147
|
+
return res;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Ensure everything is correct for a partial update
|
|
152
|
+
*/
|
|
153
|
+
static async naivePartialUpdate<T extends ModelType>(cls: Class<T>, get: () => Promise<T>, item: Partial<T>, view?: string): Promise<T> {
|
|
154
|
+
const prepared = await this.prePartialUpdate(cls, item, view);
|
|
155
|
+
const full = await get();
|
|
156
|
+
return cls.from(castTo({ ...full, ...prepared }));
|
|
157
|
+
}
|
|
181
158
|
}
|
package/support/test/crud.ts
CHANGED
|
@@ -125,22 +125,22 @@ export abstract class ModelCrudSuite extends BaseModelSuite<ModelCrudSupport> {
|
|
|
125
125
|
assert(o.id);
|
|
126
126
|
assert(o.name === 'bob');
|
|
127
127
|
|
|
128
|
-
const o2 = await service.updatePartial(Person,
|
|
128
|
+
const o2 = await service.updatePartial(Person, {
|
|
129
129
|
id: o.id,
|
|
130
130
|
name: 'oscar'
|
|
131
|
-
})
|
|
131
|
+
});
|
|
132
132
|
|
|
133
133
|
assert(o2.name === 'oscar');
|
|
134
134
|
assert(o2.age === 20);
|
|
135
135
|
assert(o2.address.street2 === 'roader');
|
|
136
136
|
|
|
137
|
-
await service.updatePartial(Person,
|
|
137
|
+
await service.updatePartial(Person, {
|
|
138
138
|
id: o2.id,
|
|
139
139
|
gender: 'f',
|
|
140
140
|
address: {
|
|
141
141
|
street1: 'changed\n',
|
|
142
142
|
}
|
|
143
|
-
})
|
|
143
|
+
});
|
|
144
144
|
|
|
145
145
|
const o3 = await service.get(Person, o.id);
|
|
146
146
|
|
|
@@ -175,11 +175,11 @@ export abstract class ModelCrudSuite extends BaseModelSuite<ModelCrudSupport> {
|
|
|
175
175
|
]
|
|
176
176
|
}));
|
|
177
177
|
|
|
178
|
-
const o2 = await service.updatePartial(SimpleList,
|
|
178
|
+
const o2 = await service.updatePartial(SimpleList, {
|
|
179
179
|
id: o.id,
|
|
180
180
|
names: ['a', 'd'],
|
|
181
181
|
simples: [{ name: 'd' }]
|
|
182
|
-
})
|
|
182
|
+
});
|
|
183
183
|
|
|
184
184
|
assert.deepStrictEqual(o2.names, ['a', 'd']);
|
|
185
185
|
assert.deepStrictEqual(o2.simples, [SimpleItem.from({ name: 'd' })]);
|
|
@@ -195,12 +195,12 @@ export abstract class ModelCrudSuite extends BaseModelSuite<ModelCrudSupport> {
|
|
|
195
195
|
assert(o.address === undefined);
|
|
196
196
|
assert(o.name === 'bob-suffix');
|
|
197
197
|
|
|
198
|
-
await service.updatePartial(User2,
|
|
198
|
+
await service.updatePartial(User2, {
|
|
199
199
|
id: o.id,
|
|
200
200
|
address: {
|
|
201
201
|
street1: 'blue'
|
|
202
202
|
}
|
|
203
|
-
})
|
|
203
|
+
});
|
|
204
204
|
|
|
205
205
|
const o3 = await service.get(User2, o.id);
|
|
206
206
|
|
|
@@ -2,6 +2,7 @@ import assert from 'node:assert';
|
|
|
2
2
|
import timers from 'node:timers/promises';
|
|
3
3
|
|
|
4
4
|
import { Suite, Test } from '@travetto/test';
|
|
5
|
+
import { castTo } from '@travetto/runtime';
|
|
5
6
|
import { SubTypeField, Text, TypeMismatchError } from '@travetto/schema';
|
|
6
7
|
import {
|
|
7
8
|
ModelIndexedSupport, Index, ModelCrudSupport, Model,
|
|
@@ -12,7 +13,6 @@ import { isIndexedSupported } from '../../src/internal/service/common';
|
|
|
12
13
|
import { ExistsError } from '../../src/error/exists';
|
|
13
14
|
|
|
14
15
|
import { BaseModelSuite } from './base';
|
|
15
|
-
import { castTo } from '@travetto/runtime';
|
|
16
16
|
|
|
17
17
|
@Model({ baseType: true })
|
|
18
18
|
export class Worker {
|
|
@@ -133,6 +133,9 @@ export abstract class ModelPolymorphismSuite extends BaseModelSuite<ModelCrudSup
|
|
|
133
133
|
name: 'bob2'
|
|
134
134
|
}));
|
|
135
135
|
|
|
136
|
+
const all2 = await collect(service.list(Worker));
|
|
137
|
+
assert(all2.length === 4);
|
|
138
|
+
|
|
136
139
|
const engineers2 = await collect(service.list(Engineer));
|
|
137
140
|
assert(engineers2.length === 2);
|
|
138
141
|
}
|