@travetto/model 5.0.0-rc.8 → 5.0.0

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.
@@ -1,4 +1,4 @@
1
- import { Class, DeepPartial } from '@travetto/runtime';
1
+ import { castTo, Class, DeepPartial, TypedObject } from '@travetto/runtime';
2
2
 
3
3
  import { IndexNotSupported } from '../../error/invalid-index';
4
4
  import { NotFoundError } from '../../error/not-found';
@@ -44,38 +44,30 @@ export class ModelIndexedUtil {
44
44
  const parts = [];
45
45
 
46
46
  while (o !== undefined && o !== null) {
47
- const k = Object.keys(f)[0];
48
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
49
- o = (o[k] as Record<string, unknown>);
47
+ const k = TypedObject.keys(f)[0];
48
+ o = castTo(o[k]);
50
49
  parts.push(k);
51
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
52
- const fk = k as (keyof typeof f);
53
- if (typeof f[fk] === 'boolean' || typeof f[fk] === 'number') {
50
+ if (typeof f[k] === 'boolean' || typeof f[k] === 'number') {
54
51
  if (cfg.type === 'sorted') {
55
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
56
- sortDir = f[fk] === true ? 1 : f[fk] as number;
52
+ sortDir = f[k] === true ? 1 : f[k] === false ? 0 : f[k];
57
53
  }
58
54
  break; // At the bottom
59
55
  } else {
60
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
61
- f = f[fk] as Record<string, unknown>;
56
+ f = castTo(f[k]);
62
57
  }
63
58
  }
64
59
  if (field === sortField) {
65
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
66
- sorted = { path: parts, dir: sortDir, value: o as unknown as number | Date };
60
+ sorted = { path: parts, dir: sortDir, value: castTo(o) };
67
61
  }
68
62
  if (o === undefined || o === null) {
69
63
  const empty = field === sortField ? opts.emptySortValue : opts.emptyValue;
70
64
  if (empty === undefined || empty === Error) {
71
65
  throw new IndexNotSupported(cls, cfg, `Missing field value for ${parts.join('.')}`);
72
66
  }
73
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
74
- o = empty as Record<string, unknown>;
67
+ o = castTo(empty!);
75
68
  } else {
76
69
  if (field !== sortField || (opts.includeSortInFields ?? true)) {
77
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
78
- fields.push({ path: parts, value: o as unknown as string | boolean | Date | number });
70
+ fields.push({ path: parts, value: castTo(o) });
79
71
  }
80
72
  }
81
73
  }
@@ -83,7 +75,6 @@ export class ModelIndexedUtil {
83
75
  return { fields, sorted };
84
76
  }
85
77
 
86
-
87
78
  /**
88
79
  * Project item via index
89
80
  * @param cls Type to get index for
@@ -92,12 +83,11 @@ export class ModelIndexedUtil {
92
83
  static projectIndex<T extends ModelType>(cls: Class<T>, idx: IndexConfig<T> | string, item?: DeepPartial<T>, cfg?: ComputeConfig): Record<string, unknown> {
93
84
  const res: Record<string, unknown> = {};
94
85
  for (const { path, value } of this.computeIndexParts(cls, idx, item ?? {}, cfg).fields) {
95
- let sub = res;
86
+ let sub: Record<string, unknown> = res;
96
87
  const all = path.slice(0);
97
88
  const last = all.pop()!;
98
89
  for (const k of all) {
99
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
100
- sub = (sub[k] ??= {}) as typeof res;
90
+ sub = castTo(sub[k] ??= {});
101
91
  }
102
92
  sub[last] = value;
103
93
  }
@@ -134,11 +124,9 @@ export class ModelIndexedUtil {
134
124
  cls: Class<T>, idx: string, body: OptionalId<T>
135
125
  ): Promise<T> {
136
126
  try {
137
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
138
- const { id } = await service.getByIndex(cls, idx, body as DeepPartial<T>);
127
+ const { id } = await service.getByIndex(cls, idx, castTo(body));
139
128
  body.id = id;
140
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
141
- return await service.update(cls, body as T);
129
+ return await service.update(cls, castTo(body));
142
130
  } catch (err) {
143
131
  if (err instanceof NotFoundError) {
144
132
  return await service.create(cls, body);
@@ -12,14 +12,11 @@ export class ModelStorageUtil {
12
12
  /**
13
13
  * Register change listener on startup
14
14
  */
15
- static async registerModelChangeListener(storage: ModelStorageSupport, target?: Class): Promise<void> {
15
+ static async registerModelChangeListener(storage: ModelStorageSupport): Promise<void> {
16
16
  if (!Runtime.dynamic || !(storage?.config?.autoCreate ?? !Runtime.production)) {
17
17
  return;
18
18
  }
19
19
 
20
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
21
- target = target ?? storage.constructor as Class<ModelStorageSupport>;
22
-
23
20
  const checkType = (cls: Class, enforceBase = true): boolean => {
24
21
  if (enforceBase && ModelRegistry.getBaseModel(cls) !== cls) {
25
22
  return false;
@@ -1,4 +1,4 @@
1
- import { Class } from '@travetto/runtime';
1
+ import { asConstructable, castTo, Class } from '@travetto/runtime';
2
2
  import { SchemaRegistry } from '@travetto/schema';
3
3
 
4
4
  import { ModelType } from '../types/model';
@@ -25,7 +25,7 @@ export function Model(conf: Partial<ModelOptions<ModelType>> | string = {}) {
25
25
  * Defines an index on a model
26
26
  */
27
27
  export function Index<T extends ModelType>(...indices: IndexConfig<T>[]) {
28
- return function (target: Class<T>) {
28
+ return function (target: Class<T>): void {
29
29
  ModelRegistry.getOrCreatePending(target).indices!.push(...indices);
30
30
  };
31
31
  }
@@ -36,8 +36,7 @@ export function Index<T extends ModelType>(...indices: IndexConfig<T>[]) {
36
36
  */
37
37
  export function ExpiresAt() {
38
38
  return <K extends string, T extends Partial<Record<K, Date>>>(tgt: T, prop: K): void => {
39
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
40
- ModelRegistry.register(tgt.constructor as Class<T>, { expiresAt: prop });
39
+ ModelRegistry.register(asConstructable(tgt).constructor, { expiresAt: prop });
41
40
  };
42
41
  }
43
42
 
@@ -49,8 +48,7 @@ export function PrePersist<T>(handler: DataHandler<T>, scope: PrePersistScope =
49
48
  ModelRegistry.registerDataHandlers(tgt, {
50
49
  prePersist: [{
51
50
  scope,
52
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
53
- handler: handler as DataHandler
51
+ handler: castTo(handler)
54
52
  }]
55
53
  });
56
54
  };
@@ -61,13 +59,11 @@ export function PrePersist<T>(handler: DataHandler<T>, scope: PrePersistScope =
61
59
  */
62
60
  export function PersistValue<T>(handler: (curr: T | undefined) => T, scope: PrePersistScope = 'all') {
63
61
  return function <K extends string, C extends Partial<Record<K, T>>>(tgt: C, prop: K): void {
64
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
65
- ModelRegistry.registerDataHandlers(tgt.constructor as Class<C>, {
62
+ ModelRegistry.registerDataHandlers(asConstructable(tgt).constructor, {
66
63
  prePersist: [{
67
64
  scope,
68
65
  handler: (inst): void => {
69
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
70
- const cInst = (inst as unknown as Record<K, T>);
66
+ const cInst: Record<K, T> = castTo(inst);
71
67
  cInst[prop] = handler(cInst[prop]);
72
68
  }
73
69
  }]
@@ -81,7 +77,6 @@ export function PersistValue<T>(handler: (curr: T | undefined) => T, scope: PreP
81
77
  */
82
78
  export function PostLoad<T>(handler: DataHandler<T>) {
83
79
  return function (tgt: Class<T>): void {
84
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
85
- ModelRegistry.registerDataHandlers(tgt, { postLoad: [handler as DataHandler] });
80
+ ModelRegistry.registerDataHandlers(tgt, { postLoad: [castTo(handler)] });
86
81
  };
87
82
  }
@@ -1,7 +1,7 @@
1
1
  import { SchemaRegistry } from '@travetto/schema';
2
2
  import { MetadataRegistry } from '@travetto/registry';
3
3
  import { DependencyRegistry } from '@travetto/di';
4
- import { AppError, Class, describeFunction } from '@travetto/runtime';
4
+ import { AppError, castTo, Class, describeFunction, asFull } from '@travetto/runtime';
5
5
  import { AllViewⲐ } from '@travetto/schema/src/internal/types';
6
6
 
7
7
  import { IndexConfig, IndexType, ModelOptions } from './types';
@@ -71,8 +71,7 @@ class $ModelRegistry extends MetadataRegistry<ModelOptions<ModelType>> {
71
71
  }
72
72
 
73
73
  onInstallFinalize(cls: Class): ModelOptions<ModelType> {
74
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
75
- const config = this.pending.get(cls.Ⲑid)! as ModelOptions<ModelType>;
74
+ const config = asFull(this.pending.get(cls.Ⲑid)!);
76
75
 
77
76
  const schema = SchemaRegistry.get(cls);
78
77
  const view = schema.views[AllViewⲐ].schema;
@@ -103,7 +102,7 @@ class $ModelRegistry extends MetadataRegistry<ModelOptions<ModelType>> {
103
102
  /**
104
103
  * Find base class for a given model
105
104
  */
106
- getBaseModel(cls: Class): Class<ModelType> {
105
+ getBaseModel<T extends ModelType>(cls: Class<T>): Class<T> {
107
106
  if (!this.baseModels.has(cls)) {
108
107
  let conf = this.get(cls) ?? this.getOrCreatePending(cls);
109
108
  let parent = cls;
@@ -208,12 +207,12 @@ class $ModelRegistry extends MetadataRegistry<ModelOptions<ModelType>> {
208
207
  * Get expiry field
209
208
  * @param cls
210
209
  */
211
- getExpiry(cls: Class): string {
210
+ getExpiry<T extends ModelType>(cls: Class<T>): keyof T {
212
211
  const expiry = this.get(cls).expiresAt;
213
212
  if (!expiry) {
214
213
  throw new AppError(`${cls.name} is not configured with expiry support, please use @ExpiresAt to declare expiration behavior`, 'general');
215
214
  }
216
- return expiry;
215
+ return castTo(expiry);
217
216
  }
218
217
  }
219
218
 
@@ -0,0 +1,36 @@
1
+ import { BinaryInput, BlobMeta, ByteRange } from '@travetto/runtime';
2
+
3
+ /**
4
+ * Support for Blobs CRUD.
5
+ *
6
+ * @concrete ../internal/service/common#ModelBlobSupportTarget
7
+ */
8
+ export interface ModelBlobSupport {
9
+
10
+ /**
11
+ * Upsert blob to storage
12
+ * @param location The location of the blob
13
+ * @param input The actual blob to write
14
+ * @param meta Additional metadata to store with the blob
15
+ * @param overwrite Should we replace content if already found, defaults to true
16
+ */
17
+ upsertBlob(location: string, input: BinaryInput, meta?: BlobMeta, overwrite?: boolean): Promise<void>;
18
+
19
+ /**
20
+ * Get blob from storage
21
+ * @param location The location of the blob
22
+ */
23
+ getBlob(location: string, range?: ByteRange): Promise<Blob>;
24
+
25
+ /**
26
+ * Get metadata for blob
27
+ * @param location The location of the blob
28
+ */
29
+ describeBlob(location: string): Promise<BlobMeta>;
30
+
31
+ /**
32
+ * Delete blob by location
33
+ * @param location The location of the blob
34
+ */
35
+ deleteBlob(location: string): Promise<void>;
36
+ }
@@ -1,4 +1,4 @@
1
- import { Class } from '@travetto/runtime';
1
+ import { castTo, Class } from '@travetto/runtime';
2
2
  import { ModelRegistry } from '@travetto/model/src/registry/model';
3
3
  import { InjectableConfig, DependencyRegistry } from '@travetto/di';
4
4
  import { ModelStorageSupportTarget } from '@travetto/model/src/internal/service/common';
@@ -40,8 +40,7 @@ export class ModelCandidateUtil {
40
40
  * Get all providers that are viable candidates
41
41
  */
42
42
  static async getProviders(op?: keyof ModelStorageSupport): Promise<InjectableConfig[]> {
43
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
44
- const types = DependencyRegistry.getCandidateTypes<ModelStorageSupport>(ModelStorageSupportTarget as unknown as Class<ModelStorageSupport>);
43
+ const types = DependencyRegistry.getCandidateTypes<ModelStorageSupport>(castTo(ModelStorageSupportTarget));
45
44
  return types.filter(x => !op || x.class.prototype?.[op]);
46
45
  }
47
46
 
@@ -8,14 +8,14 @@ export const Links = {
8
8
  Expiry: d.codeLink('Expiry', '@travetto/model/src/service/expiry.ts', /export interface/),
9
9
  Indexed: d.codeLink('Indexed', '@travetto/model/src/service/indexed.ts', /export interface/),
10
10
  Bulk: d.codeLink('Bulk', '@travetto/model/src/service/bulk.ts', /export interface/),
11
- Stream: d.codeLink('Streaming', '@travetto/model/src/service/stream.ts', /export interface/),
11
+ Blob: d.codeLink('Blob', '@travetto/model/src/service/blob.ts', /export interface/),
12
12
  };
13
13
 
14
14
  export const ModelTypes = (fn: | Function): DocJSXElement[] => {
15
15
  const { content } = DocFileUtil.readSource(fn);
16
16
  const found: DocJSXElementByFn<'CodeLink'>[] = [];
17
17
  const seen = new Set();
18
- for (const [, key] of content.matchAll(/Model(Crud|Expiry|Indexed|Bulk|Stream)Support/g)) {
18
+ for (const [, key] of content.matchAll(/Model(Crud|Expiry|Indexed|Bulk|Blob)Support/g)) {
19
19
  if (!seen.has(key)) {
20
20
  seen.add(key);
21
21
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
@@ -0,0 +1 @@
1
+ abcdefghijklmnopqrstuvwxyz
File without changes
File without changes
Binary file
Binary file
Binary file
Binary file
@@ -1,5 +1,5 @@
1
1
  import { DependencyRegistry } from '@travetto/di';
2
- import { AppError, Class } from '@travetto/runtime';
2
+ import { AppError, castTo, Class, classConstruct } from '@travetto/runtime';
3
3
 
4
4
  import { isBulkSupported, isCrudSupported } from '../../src/internal/service/common';
5
5
  import { ModelType } from '../../src/types/model';
@@ -11,7 +11,7 @@ type ServiceClass = { serviceClass: { new(): unknown } };
11
11
  export abstract class BaseModelSuite<T> {
12
12
 
13
13
  static ifNot(pred: (svc: unknown) => boolean): (x: unknown) => Promise<boolean> {
14
- return async (x: unknown) => !pred(new (x as ServiceClass).serviceClass());
14
+ return async (x: unknown) => !pred(classConstruct(castTo<ServiceClass>(x).serviceClass));
15
15
  }
16
16
 
17
17
  serviceClass: Class<T>;
@@ -36,7 +36,7 @@ export abstract class BaseModelSuite<T> {
36
36
  const res = await svc.processBulk(cls, items.map(x => ({ insert: x })));
37
37
  return res.counts.insert;
38
38
  } else if (isCrudSupported(svc)) {
39
- const out = [] as Promise<M>[];
39
+ const out: Promise<M>[] = [];
40
40
  for (const el of items) {
41
41
  out.push(svc.create(cls, el));
42
42
  }
@@ -0,0 +1,136 @@
1
+ import assert from 'node:assert';
2
+
3
+ import { Suite, Test, TestFixtures } from '@travetto/test';
4
+ import { BaseModelSuite } from '@travetto/model/support/test/base';
5
+ import { BinaryUtil, Util } from '@travetto/runtime';
6
+
7
+ import { ModelBlobSupport } from '../../src/service/blob';
8
+ import { ModelBlobUtil } from '../../src/internal/service/blob';
9
+
10
+ const meta = BinaryUtil.getBlobMeta;
11
+
12
+ @Suite()
13
+ export abstract class ModelBlobSuite extends BaseModelSuite<ModelBlobSupport> {
14
+
15
+ fixture = new TestFixtures(['@travetto/model']);
16
+
17
+ @Test()
18
+ async writeBasic(): Promise<void> {
19
+ const service = await this.service;
20
+ const buffer = await this.fixture.read('/asset.yml', true);
21
+
22
+ const id = Util.uuid();
23
+
24
+ await service.upsertBlob(id, buffer);
25
+ const m = await service.describeBlob(id);
26
+ const retrieved = await service.describeBlob(id);
27
+ assert.deepStrictEqual(m, retrieved);
28
+ }
29
+
30
+ @Test()
31
+ async upsert(): Promise<void> {
32
+ const service = await this.service;
33
+ const buffer = await this.fixture.read('/asset.yml', true);
34
+
35
+ const id = Util.uuid();
36
+
37
+ await service.upsertBlob(id, buffer, { hash: '10' });
38
+ assert((await service.describeBlob(id)).hash === '10');
39
+
40
+ await service.upsertBlob(id, buffer, { hash: '20' });
41
+ assert((await service.describeBlob(id)).hash === '20');
42
+
43
+ await service.upsertBlob(id, buffer, { hash: '30' }, false);
44
+ assert((await service.describeBlob(id)).hash === '20');
45
+ }
46
+
47
+ @Test()
48
+ async writeStream(): Promise<void> {
49
+ const service = await this.service;
50
+ const buffer = await this.fixture.read('/asset.yml', true);
51
+
52
+ const id = Util.uuid();
53
+ await service.upsertBlob(id, buffer);
54
+ const { hash } = await service.describeBlob(id);
55
+
56
+ const retrieved = await service.getBlob(id);
57
+ const { hash: received } = meta(retrieved)!;
58
+ assert(hash === received);
59
+ }
60
+
61
+ @Test()
62
+ async writeAndDelete(): Promise<void> {
63
+ const service = await this.service;
64
+ const buffer = await this.fixture.read('/asset.yml', true);
65
+
66
+ const id = Util.uuid();
67
+ await service.upsertBlob(id, buffer);
68
+
69
+ await service.deleteBlob(id);
70
+
71
+ await assert.rejects(async () => {
72
+ await service.getBlob(id);
73
+ });
74
+ }
75
+
76
+ @Test()
77
+ async partialStream(): Promise<void> {
78
+ const service = await this.service;
79
+ const buffer = await this.fixture.read('/text.txt', true);
80
+
81
+ const id = Util.uuid();
82
+ await service.upsertBlob(id, buffer);
83
+
84
+ const retrieved = await service.getBlob(id);
85
+ const content = await retrieved.text();
86
+ assert(content.startsWith('abc'));
87
+ assert(content.endsWith('xyz'));
88
+
89
+ const partial = await service.getBlob(id, { start: 10, end: 20 });
90
+ assert(partial.size === 11);
91
+ const partialMeta = meta(partial)!;
92
+ const subContent = await partial.text();
93
+ const range = await ModelBlobUtil.enforceRange({ start: 10, end: 20 }, partialMeta.size!);
94
+ assert(subContent.length === (range.end - range.start) + 1);
95
+
96
+ const og = await this.fixture.read('/text.txt');
97
+
98
+ assert(subContent === og.substring(10, 21));
99
+
100
+ const partialUnbounded = await service.getBlob(id, { start: 10 });
101
+ const partialUnboundedMeta = meta(partial)!;
102
+ const subContent2 = await partialUnbounded.text();
103
+ const range2 = await ModelBlobUtil.enforceRange({ start: 10 }, partialUnboundedMeta.size!);
104
+ assert(subContent2.length === (range2.end - range2.start) + 1);
105
+ assert(subContent2.startsWith('klm'));
106
+ assert(subContent2.endsWith('xyz'));
107
+
108
+ const partialSingle = await service.getBlob(id, { start: 10, end: 10 });
109
+ const subContent3 = await partialSingle.text();
110
+ assert(subContent3.length === 1);
111
+ assert(subContent3 === 'k');
112
+
113
+ const partialOverBounded = await service.getBlob(id, { start: 20, end: 40 });
114
+ const subContent4 = await partialOverBounded.text();
115
+ assert(subContent4.length === 6);
116
+ assert(subContent4.endsWith('xyz'));
117
+
118
+ await assert.rejects(() => service.getBlob(id, { start: -10, end: 10 }));
119
+ await assert.rejects(() => service.getBlob(id, { start: 30, end: 37 }));
120
+ }
121
+
122
+
123
+ @Test()
124
+ async writeAndGet() {
125
+ const service = await this.service;
126
+ const buffer = await this.fixture.read('/asset.yml', true);
127
+ await service.upsertBlob('orange', buffer, { contentType: 'text/yaml', filename: 'asset.yml' });
128
+ const saved = await service.getBlob('orange');
129
+ const savedMeta = meta(saved)!;
130
+
131
+ assert('text/yaml' === savedMeta.contentType);
132
+ assert(buffer.length === savedMeta.size);
133
+ assert('asset.yml' === savedMeta.filename);
134
+ assert(undefined === savedMeta.hash);
135
+ }
136
+ }
@@ -49,7 +49,7 @@ class User2 {
49
49
  name: string;
50
50
 
51
51
  prePersist() {
52
- this.name = `${this.name}-suff`;
52
+ this.name = `${this.name}-suffix`;
53
53
  }
54
54
  }
55
55
 
@@ -193,7 +193,7 @@ export abstract class ModelCrudSuite extends BaseModelSuite<ModelCrudSupport> {
193
193
  }));
194
194
 
195
195
  assert(o.address === undefined);
196
- assert(o.name === 'bob-suff');
196
+ assert(o.name === 'bob-suffix');
197
197
 
198
198
  await service.updatePartial(User2, User2.from({
199
199
  id: o.id,
@@ -217,7 +217,7 @@ export abstract class ModelCrudSuite extends BaseModelSuite<ModelCrudSupport> {
217
217
  assert(res.createdDate instanceof Date);
218
218
  }
219
219
 
220
- @Test('verify prepersist on create/update')
220
+ @Test('verify pre-persist on create/update')
221
221
  async testPrePersist() {
222
222
  const service = await this.service;
223
223
  const res = await service.create(Dated, Dated.from({}));
@@ -12,6 +12,7 @@ import { isIndexedSupported } from '../../src/internal/service/common';
12
12
  import { ExistsError } from '../../src/error/exists';
13
13
 
14
14
  import { BaseModelSuite } from './base';
15
+ import { castTo } from '@travetto/runtime';
15
16
 
16
17
  @Model({ baseType: true })
17
18
  export class Worker {
@@ -70,7 +71,7 @@ export class IndexedEngineer extends IndexedWorker {
70
71
  }
71
72
 
72
73
  async function collect<T>(iterable: AsyncIterable<T>): Promise<T[]> {
73
- const out = [] as T[];
74
+ const out: T[] = [];
74
75
  for await (const el of iterable) {
75
76
  out.push(el);
76
77
  }
@@ -116,12 +117,12 @@ export abstract class ModelPolymorphismSuite extends BaseModelSuite<ModelCrudSup
116
117
 
117
118
  const fire3 = all.find(x => x instanceof Firefighter);
118
119
  assert(fire3 instanceof Firefighter);
119
- assert((fire3 as Firefighter).firehouse === 20);
120
+ assert(fire3.firehouse === 20);
120
121
  assert(fire3.name === 'rob');
121
122
 
122
123
  const eng3 = all.find(x => x instanceof Engineer);
123
124
  assert(eng3 instanceof Engineer);
124
- assert((eng3 as Engineer).major === 'oranges');
125
+ assert(eng3.major === 'oranges');
125
126
  assert(eng3.name === 'cob');
126
127
 
127
128
  const engineers = await collect(service.list(Engineer));
@@ -161,7 +162,7 @@ export abstract class ModelPolymorphismSuite extends BaseModelSuite<ModelCrudSup
161
162
  );
162
163
 
163
164
  await assert.rejects(
164
- () => service.update(Engineer, Doctor.from({ ...doc }) as unknown as Engineer),
165
+ () => service.update(Engineer, castTo(Doctor.from({ ...doc }))),
165
166
  (e: Error) => (e instanceof NotFoundError || e instanceof SubTypeNotSupportedError || e instanceof TypeMismatchError) ? undefined : e);
166
167
 
167
168
  await timers.setTimeout(15);
@@ -205,7 +206,7 @@ export abstract class ModelPolymorphismSuite extends BaseModelSuite<ModelCrudSup
205
206
 
206
207
  @Test('Polymorphic index', { skip: BaseModelSuite.ifNot(isIndexedSupported) })
207
208
  async polymorphicIndexGet() {
208
- const service = (await this.service) as unknown as ModelIndexedSupport;
209
+ const service: ModelIndexedSupport = castTo(await this.service);
209
210
  const now = 30;
210
211
  const [doc, fire, eng] = [
211
212
  IndexedDoctor.from({ name: 'bob', specialty: 'feet', age: now }),
@@ -235,7 +236,7 @@ export abstract class ModelPolymorphismSuite extends BaseModelSuite<ModelCrudSup
235
236
 
236
237
  @Test('Polymorphic index', { skip: BaseModelSuite.ifNot(isIndexedSupported) })
237
238
  async polymorphicIndexDelete() {
238
- const service = (await this.service) as unknown as ModelIndexedSupport;
239
+ const service: ModelIndexedSupport = castTo(await this.service);
239
240
  const now = 30;
240
241
  const [doc, fire, eng] = [
241
242
  IndexedDoctor.from({ name: 'bob', specialty: 'feet', age: now }),
@@ -3,8 +3,8 @@ import { DependencyRegistry } from '@travetto/di';
3
3
  import { RootRegistry } from '@travetto/registry';
4
4
  import { SuiteRegistry, TestFixtures } from '@travetto/test';
5
5
 
6
- import { isStorageSupported, isStreamSupported } from '../../src/internal/service/common';
7
- import { StreamModel } from '../../src/internal/service/stream';
6
+ import { isBlobSupported, isStorageSupported } from '../../src/internal/service/common';
7
+ import { MODEL_BLOB } from '../../src/internal/service/blob';
8
8
  import { ModelRegistry } from '../../src/registry/model';
9
9
 
10
10
  const Loaded = Symbol();
@@ -61,11 +61,11 @@ export function ModelSuite<T extends { configClass: Class<{ autoCreate?: boolean
61
61
  }
62
62
  }
63
63
  }
64
- if (isStreamSupported(service)) {
64
+ if (isBlobSupported(service)) {
65
65
  if (service.truncateModel) {
66
- await service.truncateModel(StreamModel);
66
+ await service.truncateModel(MODEL_BLOB);
67
67
  } else if (service.deleteModel) {
68
- await service.deleteModel(StreamModel);
68
+ await service.deleteModel(MODEL_BLOB);
69
69
  }
70
70
  }
71
71
  } else {
@@ -1,22 +0,0 @@
1
- import { AppError, Class } from '@travetto/runtime';
2
-
3
- import { ModelType } from '../../types/model';
4
- import { StreamRange } from '../../service/stream';
5
-
6
- class Cls { id: string; }
7
- export const StreamModel: Class<ModelType> = Cls;
8
- export const STREAMS = '_streams';
9
-
10
-
11
- /**
12
- * Enforce byte range for stream stream/file of a certain size
13
- */
14
- export function enforceRange({ start, end }: StreamRange, size: number): Required<StreamRange> {
15
- end = Math.min(end ?? size - 1, size - 1);
16
-
17
- if (Number.isNaN(start) || Number.isNaN(end) || !Number.isFinite(start) || start >= size || start < 0 || start > end) {
18
- throw new AppError('Invalid position, out of range', 'data');
19
- }
20
-
21
- return { start, end };
22
- }