@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.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.0",
30
- "@travetto/di": "^5.0.0",
31
- "@travetto/registry": "^5.0.0",
32
- "@travetto/schema": "^5.0.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.0",
36
- "@travetto/test": "^5.0.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 { ClassInstance } from '@travetto/runtime';
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 function isBasicSupported(o: ClassInstance): o is ModelBulkSupport {
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 function isCrudSupported(o: ClassInstance): o is ModelCrudSupport {
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 function isExpirySupported(o: ClassInstance): o is ModelExpirySupport {
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 function isBlobSupported(o: ClassInstance): o is ModelBlobSupport {
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 function isStorageSupported(o: ClassInstance): o is ModelStorageSupport {
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 function isBulkSupported(o: ClassInstance): o is ModelBulkSupport {
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 function isIndexedSupported(o: ClassInstance): o is ModelIndexedSupport {
70
- return !!o && 'getByIndex' in o;
71
- }
72
-
51
+ export const isIndexedSupported = hasFunction<ModelIndexedSupport>('getByIndex');
@@ -1,6 +1,4 @@
1
- import crypto from 'node:crypto';
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
  }
@@ -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, Person.from({
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, Person.from({
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, SimpleList.from({
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, User2.from({
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
  }