@travetto/model 8.0.0-alpha.9 → 8.0.1

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.
Files changed (42) hide show
  1. package/README.md +91 -102
  2. package/__index__.ts +7 -11
  3. package/package.json +18 -18
  4. package/src/error/exists.ts +1 -1
  5. package/src/error/invalid-index.ts +5 -3
  6. package/src/error/invalid-sub-type.ts +1 -1
  7. package/src/error/not-found.ts +1 -1
  8. package/src/error/unique.ts +13 -0
  9. package/src/registry/decorator.ts +38 -32
  10. package/src/registry/registry-adapter.ts +11 -8
  11. package/src/registry/registry-index.ts +12 -33
  12. package/src/registry/types.ts +24 -39
  13. package/src/types/basic.ts +3 -3
  14. package/src/types/blob.ts +6 -6
  15. package/src/types/bulk.ts +5 -9
  16. package/src/types/crud.ts +9 -6
  17. package/src/types/expiry.ts +2 -2
  18. package/src/types/model.ts +11 -2
  19. package/src/types/storage.ts +2 -3
  20. package/src/util/blob.ts +2 -2
  21. package/src/util/bulk.ts +6 -3
  22. package/src/util/crud.ts +105 -22
  23. package/src/util/expiry.ts +4 -5
  24. package/src/util/storage.ts +3 -4
  25. package/support/base-command.ts +3 -5
  26. package/support/bin/candidate.ts +8 -11
  27. package/support/bin/export.ts +2 -2
  28. package/support/bin/install.ts +2 -2
  29. package/support/cli.model_export.ts +9 -5
  30. package/support/cli.model_install.ts +9 -5
  31. package/support/doc.support.tsx +16 -20
  32. package/support/test/base.ts +14 -12
  33. package/support/test/basic.ts +44 -3
  34. package/support/test/blob.ts +8 -9
  35. package/support/test/bulk.ts +16 -5
  36. package/support/test/crud.ts +134 -82
  37. package/support/test/expiry.ts +39 -21
  38. package/support/test/polymorphism.ts +43 -143
  39. package/support/test/suite.ts +15 -12
  40. package/src/types/indexed.ts +0 -43
  41. package/src/util/indexed.ts +0 -144
  42. package/support/test/indexed.ts +0 -190
@@ -1,9 +1,9 @@
1
1
  import assert from 'node:assert';
2
2
  import timers from 'node:timers/promises';
3
3
 
4
+ import { Model, type ModelCrudSupport, NotFoundError, PersistValue, PrePersist } from '@travetto/model';
5
+ import { Precision, Required, Schema, Text } from '@travetto/schema';
4
6
  import { Suite, Test } from '@travetto/test';
5
- import { Schema, Text, Precision, Required, } from '@travetto/schema';
6
- import { type ModelCrudSupport, Model, NotFoundError, PersistValue } from '@travetto/model';
7
7
 
8
8
  import { BaseModelSuite } from './base.ts';
9
9
 
@@ -42,14 +42,13 @@ class SimpleList {
42
42
  }
43
43
 
44
44
  @Model()
45
+ @PrePersist(item => {
46
+ item.name = `${item.name}-suffix`;
47
+ })
45
48
  class User2 {
46
49
  id: string;
47
50
  address?: Address;
48
51
  name: string;
49
-
50
- prePersist() {
51
- this.name = `${this.name}-suffix`;
52
- }
53
52
  }
54
53
 
55
54
  @Model()
@@ -76,26 +75,27 @@ class BigIntModel {
76
75
 
77
76
  @Suite()
78
77
  export abstract class ModelCrudSuite extends BaseModelSuite<ModelCrudSupport> {
78
+ indexLimitSkew = 0;
79
79
 
80
80
  @Test('save it')
81
81
  async save() {
82
82
  const service = await this.service;
83
83
 
84
- const people = [1, 2, 3, 8].map(x => Person.from({
85
- id: service.idSource.create(),
86
- name: 'Bob',
87
- age: 20 + x,
88
- gender: 'm',
89
- address: {
90
- street1: 'a',
91
- ...(x === 1 ? { street2: 'b' } : {})
92
- }
93
- }));
94
-
95
- await Promise.all(
96
- people.map(el => service.upsert(Person, el))
84
+ const people = [1, 2, 3, 8].map(x =>
85
+ Person.from({
86
+ id: service.idSource.create(),
87
+ name: 'Bob',
88
+ age: 20 + x,
89
+ gender: 'm',
90
+ address: {
91
+ street1: 'a',
92
+ ...(x === 1 ? { street2: 'b' } : {})
93
+ }
94
+ })
97
95
  );
98
96
 
97
+ await Promise.all(people.map(el => service.upsert(Person, el)));
98
+
99
99
  const single = await service.get(Person, people[2].id);
100
100
  assert(single !== undefined);
101
101
  assert(single.age === 23);
@@ -121,15 +121,18 @@ export abstract class ModelCrudSuite extends BaseModelSuite<ModelCrudSupport> {
121
121
  @Test('Verify partial update with field removal')
122
122
  async testPartialUpdate() {
123
123
  const service = await this.service;
124
- const o = await service.create(Person, Person.from({
125
- name: 'bob',
126
- age: 20,
127
- gender: 'm',
128
- address: {
129
- street1: 'road',
130
- street2: 'roader'
131
- }
132
- }));
124
+ const o = await service.create(
125
+ Person,
126
+ Person.from({
127
+ name: 'bob',
128
+ age: 20,
129
+ gender: 'm',
130
+ address: {
131
+ street1: 'road',
132
+ street2: 'roader'
133
+ }
134
+ })
135
+ );
133
136
  assert(o.id);
134
137
  assert(o.name === 'bob');
135
138
 
@@ -146,7 +149,7 @@ export abstract class ModelCrudSuite extends BaseModelSuite<ModelCrudSupport> {
146
149
  id: o2.id,
147
150
  gender: 'f',
148
151
  address: {
149
- street1: 'changed\n',
152
+ street1: 'changed\n'
150
153
  }
151
154
  });
152
155
 
@@ -168,20 +171,23 @@ export abstract class ModelCrudSuite extends BaseModelSuite<ModelCrudSupport> {
168
171
  @Test('Verify partial update with field removal and lists')
169
172
  async testPartialUpdateList() {
170
173
  const service = await this.service;
171
- const o = await service.create(SimpleList, SimpleList.from({
172
- names: ['a', 'b', 'c'],
173
- simples: [
174
- {
175
- name: 'a',
176
- },
177
- {
178
- name: 'b',
179
- },
180
- {
181
- name: 'c',
182
- }
183
- ]
184
- }));
174
+ const o = await service.create(
175
+ SimpleList,
176
+ SimpleList.from({
177
+ names: ['a', 'b', 'c'],
178
+ simples: [
179
+ {
180
+ name: 'a'
181
+ },
182
+ {
183
+ name: 'b'
184
+ },
185
+ {
186
+ name: 'c'
187
+ }
188
+ ]
189
+ })
190
+ );
185
191
 
186
192
  const o2 = await service.updatePartial(SimpleList, {
187
193
  id: o.id,
@@ -196,9 +202,12 @@ export abstract class ModelCrudSuite extends BaseModelSuite<ModelCrudSupport> {
196
202
  @Test('Verify partial update with field removal and lists')
197
203
  async testBlankPartialUpdate() {
198
204
  const service = await this.service;
199
- const o = await service.create(User2, User2.from({
200
- name: 'bob',
201
- }));
205
+ const o = await service.create(
206
+ User2,
207
+ User2.from({
208
+ name: 'bob'
209
+ })
210
+ );
202
211
 
203
212
  assert(o.address === undefined);
204
213
  assert(o.name === 'bob-suffix');
@@ -246,21 +255,21 @@ export abstract class ModelCrudSuite extends BaseModelSuite<ModelCrudSupport> {
246
255
  async list() {
247
256
  const service = await this.service;
248
257
 
249
- const people = [1, 2, 3].map(x => Person.from({
250
- id: service.idSource.create(),
251
- name: 'Bob',
252
- age: 20 + x,
253
- gender: 'm',
254
- address: {
255
- street1: 'a',
256
- ...(x === 1 ? { street2: 'b' } : {})
257
- }
258
- }));
259
-
260
- await Promise.all(
261
- people.map(el => service.upsert(Person, el))
258
+ const people = [1, 2, 3].map(x =>
259
+ Person.from({
260
+ id: service.idSource.create(),
261
+ name: 'Bob',
262
+ age: 20 + x,
263
+ gender: 'm',
264
+ address: {
265
+ street1: 'a',
266
+ ...(x === 1 ? { street2: 'b' } : {})
267
+ }
268
+ })
262
269
  );
263
270
 
271
+ await Promise.all(people.map(el => service.upsert(Person, el)));
272
+
264
273
  const found = (await this.toArray(service.list(Person))).toSorted((a, b) => a.age - b.age);
265
274
 
266
275
  assert(found[0].age === people[0].age);
@@ -268,20 +277,60 @@ export abstract class ModelCrudSuite extends BaseModelSuite<ModelCrudSupport> {
268
277
  assert(found[2].age === people[2].age);
269
278
  }
270
279
 
280
+ @Test('verify list abort signal')
281
+ async listAbortSignal() {
282
+ const service = await this.service;
283
+
284
+ await Promise.all(
285
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(x =>
286
+ service.upsert(
287
+ Person,
288
+ Person.from({
289
+ id: service.idSource.create(),
290
+ name: 'Bob',
291
+ age: 20 + x,
292
+ gender: 'm',
293
+ address: {
294
+ street1: 'a',
295
+ ...(x === 1 ? { street2: 'b' } : {})
296
+ }
297
+ })
298
+ )
299
+ )
300
+ );
301
+
302
+ const controller = new AbortController();
303
+ const found: Person[] = [];
304
+
305
+ for await (const items of service.list(Person, { abort: controller.signal, batchSizeHint: 1 })) {
306
+ found.push(...items);
307
+ controller.abort();
308
+ await timers.setTimeout(10);
309
+ }
310
+
311
+ if (this.indexLimitSkew) {
312
+ assert(found.length > 0 && found.length < this.indexLimitSkew);
313
+ } else {
314
+ assert(found.length === 1);
315
+ }
316
+ }
317
+
271
318
  @Test('save it')
272
319
  async verifyRaw() {
273
320
  const service = await this.service;
274
321
 
275
322
  const people = await Promise.all(
276
- [1, 2, 3, 8].map((x, i) => service[i % 2 === 0 ? 'upsert' : 'create'](Person, {
277
- name: 'Bob',
278
- age: 20 + x,
279
- gender: 'm',
280
- address: {
281
- street1: 'a',
282
- ...(x === 1 ? { street2: 'b' } : {})
283
- }
284
- }))
323
+ [1, 2, 3, 8].map((x, i) =>
324
+ service[i % 2 === 0 ? 'upsert' : 'create'](Person, {
325
+ name: 'Bob',
326
+ age: 20 + x,
327
+ gender: 'm',
328
+ address: {
329
+ street1: 'a',
330
+ ...(x === 1 ? { street2: 'b' } : {})
331
+ }
332
+ })
333
+ )
285
334
  );
286
335
 
287
336
  const single = await service.get(Person, people[2].id);
@@ -331,10 +380,7 @@ export abstract class ModelCrudSuite extends BaseModelSuite<ModelCrudSupport> {
331
380
  const service = await this.service;
332
381
  const o = await service.create(SimpleList, {
333
382
  names: ['rob', 'tom'],
334
- simples: [
335
- { name: 'roger' },
336
- { name: 'dodger' }
337
- ]
383
+ simples: [{ name: 'roger' }, { name: 'dodger' }]
338
384
  });
339
385
  assert(o.names.length === 2);
340
386
  assert(o.simples);
@@ -356,10 +402,13 @@ export abstract class ModelCrudSuite extends BaseModelSuite<ModelCrudSupport> {
356
402
  const service = await this.service;
357
403
 
358
404
  // Create with bigint values
359
- const created = await service.create(BigIntModel, BigIntModel.from({
360
- largeNumber: 9007199254740991n, // Number.MAX_SAFE_INTEGER as bigint
361
- optionalBigInt: 1234567890123456789n
362
- }));
405
+ const created = await service.create(
406
+ BigIntModel,
407
+ BigIntModel.from({
408
+ largeNumber: 9007199254740991n, // Number.MAX_SAFE_INTEGER as bigint
409
+ optionalBigInt: 1234567890123456789n
410
+ })
411
+ );
363
412
 
364
413
  assert(created.id);
365
414
  assert.strictEqual(created.largeNumber, 9007199254740991n);
@@ -371,11 +420,14 @@ export abstract class ModelCrudSuite extends BaseModelSuite<ModelCrudSupport> {
371
420
  assert.strictEqual(retrieved.optionalBigInt, 1234567890123456789n);
372
421
 
373
422
  // Update with new bigint value
374
- const updated = await service.update(BigIntModel, BigIntModel.from({
375
- id: created.id,
376
- largeNumber: 18014398509481982n,
377
- optionalBigInt: undefined
378
- }));
423
+ const updated = await service.update(
424
+ BigIntModel,
425
+ BigIntModel.from({
426
+ id: created.id,
427
+ largeNumber: 18014398509481982n,
428
+ optionalBigInt: undefined
429
+ })
430
+ );
379
431
 
380
432
  assert.strictEqual(updated.largeNumber, 18014398509481982n);
381
433
  assert.strictEqual(updated.optionalBigInt, undefined);
@@ -385,4 +437,4 @@ export abstract class ModelCrudSuite extends BaseModelSuite<ModelCrudSupport> {
385
437
  assert.strictEqual(final.largeNumber, 18014398509481982n);
386
438
  assert(!final.optionalBigInt);
387
439
  }
388
- }
440
+ }
@@ -1,13 +1,13 @@
1
1
  import assert from 'node:assert';
2
2
  import timers from 'node:timers/promises';
3
3
 
4
- import { Suite, Test } from '@travetto/test';
5
4
  import { type TimeSpan, TimeUtil } from '@travetto/runtime';
5
+ import { Suite, Test } from '@travetto/test';
6
6
 
7
+ import { NotFoundError } from '../../src/error/not-found.ts';
7
8
  import { ExpiresAt, Model } from '../../src/registry/decorator.ts';
8
9
  import type { ModelExpirySupport } from '../../src/types/expiry.ts';
9
10
  import { ModelExpiryUtil } from '../../src/util/expiry.ts';
10
- import { NotFoundError } from '../../src/error/not-found.ts';
11
11
  import { BaseModelSuite } from './base.ts';
12
12
 
13
13
  @Model('expiry-user')
@@ -20,7 +20,6 @@ export class ExpiryUser {
20
20
 
21
21
  @Suite()
22
22
  export abstract class ModelExpirySuite extends BaseModelSuite<ModelExpirySupport> {
23
-
24
23
  delayFactor: number = 1;
25
24
 
26
25
  async wait(input: TimeSpan | number | string) {
@@ -34,9 +33,12 @@ export abstract class ModelExpirySuite extends BaseModelSuite<ModelExpirySupport
34
33
  @Test()
35
34
  async basic() {
36
35
  const service = await this.service;
37
- const result = await service.upsert(ExpiryUser, ExpiryUser.from({
38
- expiresAt: this.timeFromNow('2s')
39
- }));
36
+ const result = await service.upsert(
37
+ ExpiryUser,
38
+ ExpiryUser.from({
39
+ expiresAt: this.timeFromNow('2s')
40
+ })
41
+ );
40
42
  assert(result instanceof ExpiryUser);
41
43
 
42
44
  const expiry = ModelExpiryUtil.getExpiryState(ExpiryUser, await service.get(ExpiryUser, result.id));
@@ -46,9 +48,12 @@ export abstract class ModelExpirySuite extends BaseModelSuite<ModelExpirySupport
46
48
  @Test()
47
49
  async aging() {
48
50
  const service = await this.service;
49
- const result = await service.upsert(ExpiryUser, ExpiryUser.from({
50
- expiresAt: this.timeFromNow(100)
51
- }));
51
+ const result = await service.upsert(
52
+ ExpiryUser,
53
+ ExpiryUser.from({
54
+ expiresAt: this.timeFromNow(100)
55
+ })
56
+ );
52
57
 
53
58
  assert(result instanceof ExpiryUser);
54
59
 
@@ -60,9 +65,12 @@ export abstract class ModelExpirySuite extends BaseModelSuite<ModelExpirySupport
60
65
  @Test()
61
66
  async updateExpired() {
62
67
  const service = await this.service;
63
- const result = await service.upsert(ExpiryUser, ExpiryUser.from({
64
- expiresAt: this.timeFromNow(100)
65
- }));
68
+ const result = await service.upsert(
69
+ ExpiryUser,
70
+ ExpiryUser.from({
71
+ expiresAt: this.timeFromNow(100)
72
+ })
73
+ );
66
74
 
67
75
  assert(result instanceof ExpiryUser);
68
76
 
@@ -74,14 +82,17 @@ export abstract class ModelExpirySuite extends BaseModelSuite<ModelExpirySupport
74
82
  @Test()
75
83
  async ageWithExtension() {
76
84
  const service = await this.service;
77
- const result = await service.upsert(ExpiryUser, ExpiryUser.from({
78
- expiresAt: this.timeFromNow('2s')
79
- }));
85
+ const result = await service.upsert(
86
+ ExpiryUser,
87
+ ExpiryUser.from({
88
+ expiresAt: this.timeFromNow('2s')
89
+ })
90
+ );
80
91
  assert(result instanceof ExpiryUser);
81
92
 
82
93
  await this.wait(50);
83
94
 
84
- assert(!ModelExpiryUtil.getExpiryState(ExpiryUser, (await service.get(ExpiryUser, result.id))).expired);
95
+ assert(!ModelExpiryUtil.getExpiryState(ExpiryUser, await service.get(ExpiryUser, result.id)).expired);
85
96
 
86
97
  await service.updatePartial(ExpiryUser, {
87
98
  id: result.id,
@@ -97,16 +108,23 @@ export abstract class ModelExpirySuite extends BaseModelSuite<ModelExpirySupport
97
108
  async culling() {
98
109
  const service = await this.service;
99
110
 
100
- let total;
111
+ let total: number;
101
112
 
102
113
  total = await this.getSize(ExpiryUser);
103
114
  assert(total === 0);
104
115
 
105
116
  // Create
106
117
  await Promise.all(
107
- Array(10).fill(0).map((x, i) => service.upsert(ExpiryUser, ExpiryUser.from({
108
- expiresAt: this.timeFromNow(300 + i * this.delayFactor)
109
- })))
118
+ Array(10)
119
+ .fill(0)
120
+ .map((x, i) =>
121
+ service.upsert(
122
+ ExpiryUser,
123
+ ExpiryUser.from({
124
+ expiresAt: this.timeFromNow(300 + i * this.delayFactor)
125
+ })
126
+ )
127
+ )
110
128
  );
111
129
 
112
130
  // Let expire
@@ -124,4 +142,4 @@ export abstract class ModelExpirySuite extends BaseModelSuite<ModelExpirySupport
124
142
  total = await this.getSize(ExpiryUser);
125
143
  assert(total === 0);
126
144
  }
127
- }
145
+ }