@travetto/model-mongo 5.0.0-rc.10 → 5.0.0-rc.11

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 CHANGED
@@ -17,10 +17,10 @@ This module provides an [mongodb](https://mongodb.com)-based implementation for
17
17
 
18
18
  Supported features:
19
19
  * [CRUD](https://github.com/travetto/travetto/tree/main/module/model/src/service/crud.ts#L11)
20
- * [Streaming](https://github.com/travetto/travetto/tree/main/module/model/src/service/stream.ts#L3)
21
20
  * [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/service/expiry.ts#L11)
22
21
  * [Bulk](https://github.com/travetto/travetto/tree/main/module/model/src/service/bulk.ts#L19)
23
22
  * [Indexed](https://github.com/travetto/travetto/tree/main/module/model/src/service/indexed.ts#L12)
23
+ * [Blob](https://github.com/travetto/travetto/tree/main/module/model/src/service/blob.ts#L8)
24
24
  * [Query Crud](https://github.com/travetto/travetto/tree/main/module/model-query/src/service/crud.ts#L11)
25
25
  * [Facet](https://github.com/travetto/travetto/tree/main/module/model-query/src/service/facet.ts#L12)
26
26
  * [Query](https://github.com/travetto/travetto/tree/main/module/model-query/src/service/query.ts#L10)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-mongo",
3
- "version": "5.0.0-rc.10",
3
+ "version": "5.0.0-rc.11",
4
4
  "description": "Mongo backing for the travetto model module.",
5
5
  "keywords": [
6
6
  "mongo",
@@ -25,13 +25,13 @@
25
25
  "directory": "module/model-mongo"
26
26
  },
27
27
  "dependencies": {
28
- "@travetto/config": "^5.0.0-rc.10",
29
- "@travetto/model": "^5.0.0-rc.10",
30
- "@travetto/model-query": "^5.0.0-rc.10",
28
+ "@travetto/config": "^5.0.0-rc.11",
29
+ "@travetto/model": "^5.0.0-rc.11",
30
+ "@travetto/model-query": "^5.0.0-rc.11",
31
31
  "mongodb": "^6.8.0"
32
32
  },
33
33
  "peerDependencies": {
34
- "@travetto/command": "^5.0.0-rc.9"
34
+ "@travetto/command": "^5.0.0-rc.10"
35
35
  },
36
36
  "peerDependenciesMeta": {
37
37
  "@travetto/command": {
package/src/service.ts CHANGED
@@ -1,19 +1,15 @@
1
- // Wildcard import needed here due to packaging issues
2
1
  import {
3
2
  type Db, GridFSBucket, MongoClient, type Sort, type CreateIndexesOptions,
4
3
  type GridFSFile, type IndexSpecification, type Collection, ObjectId,
5
4
  Binary
6
5
  } from 'mongodb';
7
- import { Readable } from 'node:stream';
8
6
  import { pipeline } from 'node:stream/promises';
7
+ import { Readable } from 'node:stream';
9
8
 
10
9
  import {
11
- ModelRegistry, ModelType, OptionalId,
12
- ModelCrudSupport, ModelStorageSupport, ModelStreamSupport,
13
- ModelExpirySupport, ModelBulkSupport, ModelIndexedSupport,
14
- StreamMeta, BulkOp, BulkResponse,
15
- NotFoundError, ExistsError, IndexConfig,
16
- StreamRange
10
+ ModelRegistry, ModelType, OptionalId, ModelCrudSupport, ModelStorageSupport,
11
+ ModelExpirySupport, ModelBulkSupport, ModelIndexedSupport, BulkOp, BulkResponse,
12
+ NotFoundError, ExistsError, IndexConfig, ModelBlobSupport, ModelBlobUtil
17
13
  } from '@travetto/model';
18
14
  import {
19
15
  ModelQuery, ModelQueryCrudSupport, ModelQueryFacetSupport, ModelQuerySupport,
@@ -21,7 +17,10 @@ import {
21
17
  QueryVerifier
22
18
  } from '@travetto/model-query';
23
19
 
24
- import { ShutdownManager, type Class, type DeepPartial, AppError, TypedObject, castTo, asFull } from '@travetto/runtime';
20
+ import {
21
+ ShutdownManager, type Class, type DeepPartial, AppError, TypedObject,
22
+ castTo, asFull, BlobMeta, ByteRange, BinaryInput, BinaryUtil
23
+ } from '@travetto/runtime';
25
24
  import { Injectable } from '@travetto/di';
26
25
  import { FieldConfig, SchemaRegistry, SchemaValidator } from '@travetto/schema';
27
26
 
@@ -33,9 +32,9 @@ import { ModelQuerySuggestUtil } from '@travetto/model-query/src/internal/servic
33
32
  import { PointImpl } from '@travetto/model-query/src/internal/model/point';
34
33
  import { ModelQueryExpiryUtil } from '@travetto/model-query/src/internal/service/expiry';
35
34
  import { ModelExpiryUtil } from '@travetto/model/src/internal/service/expiry';
36
- import { enforceRange, StreamModel, STREAMS } from '@travetto/model/src/internal/service/stream';
37
35
  import { AllViewⲐ } from '@travetto/schema/src/internal/types';
38
36
  import { ModelBulkUtil } from '@travetto/model/src/internal/service/bulk';
37
+ import { MODEL_BLOB, ModelBlobNamespace } from '@travetto/model/src/internal/service/blob';
39
38
 
40
39
  import { MongoUtil, WithId } from './internal/util';
41
40
  import { MongoModelConfig } from './config';
@@ -46,7 +45,7 @@ const asFielded = (cfg: IndexConfig<ModelType>): { [IdxFieldsⲐ]: Sort } => cas
46
45
 
47
46
  type IdxCfg = CreateIndexesOptions;
48
47
 
49
- type StreamRaw = GridFSFile & { metadata: StreamMeta };
48
+ type BlobRaw = GridFSFile & { metadata?: BlobMeta };
50
49
 
51
50
  /**
52
51
  * Mongo-based model source
@@ -54,7 +53,7 @@ type StreamRaw = GridFSFile & { metadata: StreamMeta };
54
53
  @Injectable()
55
54
  export class MongoModelService implements
56
55
  ModelCrudSupport, ModelStorageSupport,
57
- ModelBulkSupport, ModelStreamSupport,
56
+ ModelBulkSupport, ModelBlobSupport,
58
57
  ModelIndexedSupport, ModelQuerySupport,
59
58
  ModelQueryCrudSupport, ModelQueryFacetSupport,
60
59
  ModelQuerySuggestSupport, ModelExpirySupport {
@@ -66,11 +65,11 @@ export class MongoModelService implements
66
65
 
67
66
  constructor(public readonly config: MongoModelConfig) { }
68
67
 
69
- async #describeStreamRaw(location: string): Promise<StreamRaw> {
70
- const files: StreamRaw[] = castTo(await this.#bucket.find({ filename: location }, { limit: 1 }).toArray());
68
+ async #describeBlobRaw(location: string): Promise<BlobRaw> {
69
+ const files: BlobRaw[] = await this.#bucket.find({ filename: location }, { limit: 1 }).toArray();
71
70
 
72
71
  if (!files?.length) {
73
- throw new NotFoundError(STREAMS, location);
72
+ throw new NotFoundError(ModelBlobNamespace, location);
74
73
  }
75
74
 
76
75
  return files[0];
@@ -80,7 +79,7 @@ export class MongoModelService implements
80
79
  this.client = await MongoClient.connect(this.config.url, this.config.options);
81
80
  this.#db = this.client.db(this.config.namespace);
82
81
  this.#bucket = new GridFSBucket(this.#db, {
83
- bucketName: STREAMS,
82
+ bucketName: ModelBlobNamespace,
84
83
  writeConcern: { w: 1 }
85
84
  });
86
85
  await ModelStorageUtil.registerModelChangeListener(this);
@@ -151,10 +150,8 @@ export class MongoModelService implements
151
150
  }
152
151
 
153
152
  async truncateModel<T extends ModelType>(cls: Class<T>): Promise<void> {
154
- if (cls === StreamModel) {
155
- try {
156
- await this.#bucket.drop();
157
- } catch { }
153
+ if (cls === MODEL_BLOB) {
154
+ await this.#bucket.drop().catch(() => { });
158
155
  } else {
159
156
  const col = await this.getStore(cls);
160
157
  await col.deleteMany({});
@@ -283,37 +280,39 @@ export class MongoModelService implements
283
280
  }
284
281
  }
285
282
 
286
- // Stream
287
- async upsertStream(location: string, input: Readable, meta: StreamMeta): Promise<void> {
283
+ // Blob
284
+ async insertBlob(location: string, input: BinaryInput, meta?: BlobMeta, errorIfExisting = false): Promise<void> {
285
+ await this.describeBlob(location);
286
+ if (errorIfExisting) {
287
+ throw new ExistsError(ModelBlobNamespace, location);
288
+ }
289
+ return this.upsertBlob(location, input, meta);
290
+ }
291
+
292
+ async upsertBlob(location: string, input: BinaryInput, meta?: BlobMeta): Promise<void> {
293
+ const [stream, blobMeta] = await ModelBlobUtil.getInput(input, meta);
288
294
  const writeStream = this.#bucket.openUploadStream(location, {
289
- contentType: meta.contentType,
290
- metadata: meta
295
+ contentType: blobMeta.contentType,
296
+ metadata: blobMeta
291
297
  });
292
298
 
293
- await pipeline(input, writeStream);
299
+ await pipeline(stream, writeStream);
294
300
  }
295
301
 
296
- async getStream(location: string, range?: StreamRange): Promise<Readable> {
297
- const meta = await this.describeStream(location);
298
-
299
- if (range) {
300
- range = enforceRange(range, meta.size);
301
- range.end! += 1; // range is exclusive
302
- }
303
-
304
- const res = await this.#bucket.openDownloadStreamByName(location, range);
305
- if (!res) {
306
- throw new NotFoundError(STREAMS, location);
307
- }
308
- return res;
302
+ async getBlob(location: string, range?: ByteRange): Promise<Blob> {
303
+ const meta = await this.describeBlob(location);
304
+ const final = range ? ModelBlobUtil.enforceRange(range, meta.size!) : undefined;
305
+ const mongoRange = final ? { start: final.start, end: final.end + 1 } : undefined;
306
+ const res = (): Readable => this.#bucket.openDownloadStreamByName(location, mongoRange);
307
+ return BinaryUtil.readableBlob(res, { ...meta, range: final });
309
308
  }
310
309
 
311
- async describeStream(location: string): Promise<StreamMeta> {
312
- return (await this.#describeStreamRaw(location)).metadata;
310
+ async describeBlob(location: string): Promise<BlobMeta> {
311
+ return (await this.#describeBlobRaw(location)).metadata ?? {};
313
312
  }
314
313
 
315
- async deleteStream(location: string): Promise<void> {
316
- const fileId = (await this.#describeStreamRaw(location))._id;
314
+ async deleteBlob(location: string): Promise<void> {
315
+ const fileId = (await this.#describeBlobRaw(location))._id;
317
316
  await this.#bucket.delete(fileId);
318
317
  }
319
318