@travetto/model-mongo 3.0.0-rc.2 → 3.0.0-rc.20

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
@@ -1,5 +1,5 @@
1
1
  <!-- This file was generated by @travetto/doc and should not be modified directly -->
2
- <!-- Please modify https://github.com/travetto/travetto/tree/main/module/model-mongo/doc.ts and execute "npx trv doc" to rebuild -->
2
+ <!-- Please modify https://github.com/travetto/travetto/tree/main/module/model-mongo/DOC.ts and execute "npx trv doc" to rebuild -->
3
3
  # MongoDB Model Support
4
4
  ## Mongo backing for the travetto model module.
5
5
 
@@ -15,7 +15,7 @@ Supported features:
15
15
  * [CRUD](https://github.com/travetto/travetto/tree/main/module/model/src/service/crud.ts#L11)
16
16
  * [Streaming](https://github.com/travetto/travetto/tree/main/module/model/src/service/stream.ts#L3)
17
17
  * [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/service/expiry.ts#L11)
18
- * [Bulk](https://github.com/travetto/travetto/tree/main/module/model/src/service/bulk.ts#L23)
18
+ * [Bulk](https://github.com/travetto/travetto/tree/main/module/model/src/service/bulk.ts#L19)
19
19
  * [Indexed](https://github.com/travetto/travetto/tree/main/module/model/src/service/indexed.ts#L12)
20
20
  * [Query Crud](https://github.com/travetto/travetto/tree/main/module/model-query/src/service/crud.ts#L11)
21
21
  * [Facet](https://github.com/travetto/travetto/tree/main/module/model-query/src/service/facet.ts#L12)
@@ -41,15 +41,14 @@ export class Init {
41
41
  }
42
42
  ```
43
43
 
44
- where the [MongoModelConfig](https://github.com/travetto/travetto/tree/main/module/model-mongo/src/config.ts#L12) is defined by:
44
+ where the [MongoModelConfig](https://github.com/travetto/travetto/tree/main/module/model-mongo/src/config.ts#L11) is defined by:
45
45
 
46
46
 
47
47
  **Code: Structure of MongoModelConfig**
48
48
  ```typescript
49
- import * as mongo from 'mongodb';
50
- import { promises as fs } from 'fs';
49
+ import type mongo from 'mongodb';
51
50
 
52
- import { TimeSpan, ResourceManager } from '@travetto/base';
51
+ import { FileResourceProvider, TimeSpan } from '@travetto/base';
53
52
  import { Config } from '@travetto/config';
54
53
  import { Field } from '@travetto/schema';
55
54
 
@@ -104,35 +103,26 @@ export class MongoModelConfig {
104
103
  */
105
104
  cullRate?: number | TimeSpan;
106
105
 
107
- /**
108
- * Load a resource
109
- */
110
- async fetch(val: string): Promise<string> {
111
- return ResourceManager.read(val)
112
- .then(res => typeof res === 'string' ? res : res.toString('utf8'))
113
- .catch(() => fs.readFile(val)
114
- .then(res => typeof res === 'string' ? res : res.toString('utf8'))
115
- )
116
- .catch(() => val);
117
- }
118
-
119
106
  /**
120
107
  * Load all the ssl certs as needed
121
108
  */
122
109
  async postConstruct(): Promise<void> {
110
+ const resources = new FileResourceProvider({ includeCommon: true });
111
+ const resolve = (file: string): Promise<string> => resources.describe(file).then(({ path }) => path, () => file);
112
+
123
113
  const opts = this.options;
124
114
  if (opts.ssl) {
125
115
  if (opts.sslCert) {
126
- opts.tlsCertificateFile = await this.fetch(opts.sslCert);
116
+ opts.tlsCertificateFile = await resolve(opts.sslCert);
127
117
  }
128
118
  if (opts.sslKey) {
129
- opts.sslKey = await this.fetch(opts.sslKey);
119
+ opts.sslKey = await resolve(opts.sslKey);
130
120
  }
131
121
  if (opts.sslCA) {
132
- opts.sslCA = await this.fetch(opts.sslCA);
122
+ opts.sslCA = await resolve(opts.sslCA);
133
123
  }
134
124
  if (opts.sslCRL) {
135
- opts.sslCRL = await this.fetch(opts.sslCRL);
125
+ opts.sslCRL = await resolve(opts.sslCRL);
136
126
  }
137
127
  }
138
128
  }
@@ -155,8 +145,8 @@ export class MongoModelConfig {
155
145
  }
156
146
  ```
157
147
 
158
- Additionally, you can see that the class is registered with the [@Config](https://github.com/travetto/travetto/tree/main/module/config/src/decorator.ts#L9) annotation, and so these values can be overridden using the
159
- standard [Configuration](https://github.com/travetto/travetto/tree/main/module/config#readme "Environment-aware config management using yaml files")resolution paths.
148
+ Additionally, you can see that the class is registered with the [@Config](https://github.com/travetto/travetto/tree/main/module/config/src/decorator.ts#L13) annotation, and so these values can be overridden using the
149
+ standard [Configuration](https://github.com/travetto/travetto/tree/main/module/config#readme "Configuration support")resolution paths.
160
150
 
161
151
 
162
- The SSL file options in `clientOptions` will automatically be resolved to files when given a path. This path can be a [ResourceManager](https://github.com/travetto/travetto/tree/main/module/base/src/resource.ts#L16) path or just a standard file path.
152
+ The SSL file options in `clientOptions` will automatically be resolved to files when given a path. This path can be a [FileResourceProvider](https://github.com/travetto/travetto/tree/main/module/base/src/resource.ts#L46) path or just a standard file path.
File without changes
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-mongo",
3
- "displayName": "MongoDB Model Support",
4
- "version": "3.0.0-rc.2",
3
+ "version": "3.0.0-rc.20",
5
4
  "description": "Mongo backing for the travetto model module.",
6
5
  "keywords": [
7
6
  "mongo",
@@ -16,20 +15,31 @@
16
15
  "name": "Travetto Framework"
17
16
  },
18
17
  "files": [
19
- "index.ts",
18
+ "__index__.ts",
20
19
  "src",
21
20
  "support"
22
21
  ],
23
- "main": "index.ts",
22
+ "main": "__index__.ts",
24
23
  "repository": {
25
24
  "url": "https://github.com/travetto/travetto.git",
26
25
  "directory": "module/model-mongo"
27
26
  },
28
27
  "dependencies": {
29
- "@travetto/config": "^3.0.0-rc.2",
30
- "@travetto/model": "^3.0.0-rc.2",
31
- "@travetto/model-query": "3.0.0-rc.2",
32
- "mongodb": "^4.9.0"
28
+ "@travetto/config": "^3.0.0-rc.20",
29
+ "@travetto/model": "^3.0.0-rc.20",
30
+ "@travetto/model-query": "^3.0.0-rc.20",
31
+ "mongodb": "^5.0.1"
32
+ },
33
+ "peerDependencies": {
34
+ "@travetto/command": "^3.0.0-rc.16"
35
+ },
36
+ "peerDependenciesMeta": {
37
+ "@travetto/command": {
38
+ "optional": true
39
+ }
40
+ },
41
+ "travetto": {
42
+ "displayName": "MongoDB Model Support"
33
43
  },
34
44
  "publishConfig": {
35
45
  "access": "public"
package/src/config.ts CHANGED
@@ -1,7 +1,6 @@
1
- import * as mongo from 'mongodb';
2
- import { promises as fs } from 'fs';
1
+ import type mongo from 'mongodb';
3
2
 
4
- import { TimeSpan, ResourceManager } from '@travetto/base';
3
+ import { FileResourceProvider, TimeSpan } from '@travetto/base';
5
4
  import { Config } from '@travetto/config';
6
5
  import { Field } from '@travetto/schema';
7
6
 
@@ -43,8 +42,7 @@ export class MongoModelConfig {
43
42
  * Mongo client options
44
43
  */
45
44
  @Field(Object)
46
- options: mongo.MongoClientOptions = {
47
- };
45
+ options: mongo.MongoClientOptions = {};
48
46
 
49
47
  /**
50
48
  * Should we auto create the db
@@ -56,35 +54,26 @@ export class MongoModelConfig {
56
54
  */
57
55
  cullRate?: number | TimeSpan;
58
56
 
59
- /**
60
- * Load a resource
61
- */
62
- async fetch(val: string): Promise<string> {
63
- return ResourceManager.read(val)
64
- .then(res => typeof res === 'string' ? res : res.toString('utf8'))
65
- .catch(() => fs.readFile(val)
66
- .then(res => typeof res === 'string' ? res : res.toString('utf8'))
67
- )
68
- .catch(() => val);
69
- }
70
-
71
57
  /**
72
58
  * Load all the ssl certs as needed
73
59
  */
74
60
  async postConstruct(): Promise<void> {
61
+ const resources = new FileResourceProvider({ includeCommon: true });
62
+ const resolve = (file: string): Promise<string> => resources.describe(file).then(({ path }) => path, () => file);
63
+
75
64
  const opts = this.options;
76
65
  if (opts.ssl) {
77
66
  if (opts.sslCert) {
78
- opts.tlsCertificateFile = await this.fetch(opts.sslCert);
67
+ opts.tlsCertificateFile = await resolve(opts.sslCert);
79
68
  }
80
69
  if (opts.sslKey) {
81
- opts.sslKey = await this.fetch(opts.sslKey);
70
+ opts.sslKey = await resolve(opts.sslKey);
82
71
  }
83
72
  if (opts.sslCA) {
84
- opts.sslCA = await this.fetch(opts.sslCA);
73
+ opts.sslCA = await resolve(opts.sslCA);
85
74
  }
86
75
  if (opts.sslCRL) {
87
- opts.sslCRL = await this.fetch(opts.sslCRL);
76
+ opts.sslCRL = await resolve(opts.sslCRL);
88
77
  }
89
78
  }
90
79
  }
@@ -1,10 +1,9 @@
1
1
  import * as mongo from 'mongodb';
2
2
 
3
- import { Class, Util } from '@travetto/base';
3
+ import { Class, DataUtil, ObjectUtil } from '@travetto/base';
4
4
  import { DistanceUnit, ModelQuery, Query, WhereClause } from '@travetto/model-query';
5
- import { ModelType } from '@travetto/model';
5
+ import type { ModelType, IndexField } from '@travetto/model';
6
6
  import { ModelQueryUtil } from '@travetto/model-query/src/internal/service/query';
7
- import { IndexField } from '@travetto/model/src/registry/types';
8
7
 
9
8
  /**
10
9
  * Converting units to various radians
@@ -20,7 +19,6 @@ const RADIANS_TO: Record<DistanceUnit, number> = {
20
19
  export type WithId<T> = T & { _id?: mongo.Binary };
21
20
  const isWithId = <T extends ModelType>(o: T): o is WithId<T> => o && '_id' in o;
22
21
 
23
-
24
22
  /**
25
23
  * Basic mongo utils for conforming to the model module
26
24
  */
@@ -51,7 +49,7 @@ export class MongoUtil {
51
49
  } else if (id instanceof mongo.ObjectId) {
52
50
  return id.toHexString();
53
51
  } else {
54
- return id.buffer.toString('hex');
52
+ return Buffer.from(id.buffer).toString('hex');
55
53
  }
56
54
  }
57
55
 
@@ -119,7 +117,7 @@ export class MongoUtil {
119
117
  return this.uuid(v);
120
118
  } else if (Array.isArray(v)) {
121
119
  return v.map(x => this.replaceId(x));
122
- } else if (Util.isPlainObject(v)) {
120
+ } else if (ObjectUtil.isPlainObject(v)) {
123
121
  const out: Record<string, mongo.Binary> = {};
124
122
  for (const [k, el] of Object.entries(v)) {
125
123
  const found = this.replaceId(el);
@@ -149,9 +147,9 @@ export class MongoUtil {
149
147
  if (subpath === 'id') { // Handle ids directly
150
148
  out._id = this.replaceId(v);
151
149
  } else {
152
- const isPlain = v && Util.isPlainObject(v);
150
+ const isPlain = v && ObjectUtil.isPlainObject(v);
153
151
  const firstKey = isPlain ? Object.keys(v)[0] : '';
154
- if ((isPlain && !firstKey.startsWith('$')) || v?.constructor?.ᚕid) {
152
+ if ((isPlain && !firstKey.startsWith('$')) || v?.constructor?.Ⲑid) {
155
153
  Object.assign(out, this.extractSimple(v, `${subpath}.`));
156
154
  } else {
157
155
  if (firstKey === '$gt' || firstKey === '$lt' || firstKey === '$gte' || firstKey === '$lte') {
@@ -160,7 +158,7 @@ export class MongoUtil {
160
158
  }
161
159
  } else if (firstKey === '$regex') {
162
160
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
163
- v.$regex = Util.toRegex(v.$regex as string | RegExp);
161
+ v.$regex = DataUtil.toRegex(v.$regex as string | RegExp);
164
162
  } else if (firstKey && '$near' in v) {
165
163
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
166
164
  const dist = v.$maxDistance as number;
package/src/service.ts CHANGED
@@ -1,4 +1,4 @@
1
- /* eslint-disable @typescript-eslint/consistent-type-assertions */
1
+ // Wildcard import needed here due to packaging issues
2
2
  import * as mongo from 'mongodb';
3
3
  import { Readable } from 'stream';
4
4
 
@@ -14,7 +14,7 @@ import {
14
14
  PageableModelQuery, ValidStringFields, WhereClause, ModelQuerySuggestSupport
15
15
  } from '@travetto/model-query';
16
16
 
17
- import { ShutdownManager, Util, Class, AppError } from '@travetto/base';
17
+ import { ShutdownManager, type Class, AppError } from '@travetto/base';
18
18
  import { Injectable } from '@travetto/di';
19
19
  import { DeepPartial, FieldConfig, SchemaRegistry, SchemaValidator } from '@travetto/schema';
20
20
 
@@ -29,11 +29,12 @@ import { ModelExpiryUtil } from '@travetto/model/src/internal/service/expiry';
29
29
  import { StreamModel, STREAMS } from '@travetto/model/src/internal/service/stream';
30
30
  import { AllViewⲐ } from '@travetto/schema/src/internal/types';
31
31
  import { ModelBulkUtil } from '@travetto/model/src/internal/service/bulk';
32
+ import { ModelUtil } from '@travetto/model/src/internal/util';
32
33
 
33
34
  import { MongoUtil, WithId } from './internal/util';
34
35
  import { MongoModelConfig } from './config';
35
36
 
36
- const IdxFieldsⲐ = Symbol.for('@trv:model-mongo/idx');
37
+ const IdxFieldsⲐ = Symbol.for('@travetto/model-mongo:idx');
37
38
 
38
39
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
39
40
  const asFielded = <T extends ModelType>(cfg: IndexConfig<T>): { [IdxFieldsⲐ]: mongo.Sort } => (cfg as unknown as { [IdxFieldsⲐ]: mongo.Sort });
@@ -78,7 +79,7 @@ export class MongoModelService implements
78
79
  writeConcern: { w: 1 }
79
80
  });
80
81
  await ModelStorageUtil.registerModelChangeListener(this);
81
- ShutdownManager.onShutdown(this.constructor.ᚕid, () => this.client.close());
82
+ ShutdownManager.onShutdown(this, () => this.client.close());
82
83
  ModelExpiryUtil.registerCull(this);
83
84
  }
84
85
 
@@ -90,7 +91,7 @@ export class MongoModelService implements
90
91
  * Build a mongo identifier
91
92
  */
92
93
  uuid(): string {
93
- return Util.uuid();
94
+ return ModelUtil.uuid();
94
95
  }
95
96
 
96
97
  // Storage
@@ -111,7 +112,7 @@ export class MongoModelService implements
111
112
  out.push(...this.getGeoIndices(field.type, [...path, field], root));
112
113
  } else if (field.type === PointImpl) {
113
114
  const name = [...path, field].map(x => x.name).join('.');
114
- console.debug('Preparing geo-index', { cls: root.ᚕid, name });
115
+ console.debug('Preparing geo-index', { cls: root.Ⲑid, name });
115
116
  out.push({ [name]: '2d' });
116
117
  }
117
118
  }
@@ -193,6 +194,7 @@ export class MongoModelService implements
193
194
  if (!result.insertedId) {
194
195
  throw new ExistsError(cls, cleaned.id);
195
196
  }
197
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
196
198
  delete (cleaned as { _id?: unknown })._id;
197
199
  return cleaned;
198
200
  }
@@ -244,9 +246,11 @@ export class MongoModelService implements
244
246
  .entries(items)
245
247
  .reduce<Record<string, unknown>>((acc, [k, v]) => {
246
248
  if (v === null || v === undefined) {
249
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
247
250
  const o = (acc.$unset ??= {}) as Record<string, unknown>;
248
251
  o[k] = v;
249
252
  } else {
253
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
250
254
  const o = (acc.$set ??= {}) as Record<string, unknown>;
251
255
  o[k] = v;
252
256
  }
@@ -297,9 +301,7 @@ export class MongoModelService implements
297
301
  });
298
302
 
299
303
  await new Promise<unknown>((resolve, reject) => {
300
- input.pipe(writeStream);
301
- input.on('error', reject);
302
- writeStream.once('finish', resolve);
304
+ input.pipe(writeStream).on('finish', resolve).on('error', reject);
303
305
  });
304
306
  }
305
307
 
@@ -348,6 +350,7 @@ export class MongoModelService implements
348
350
 
349
351
  for (const op of operations) {
350
352
  if (op.insert) {
353
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
351
354
  bulk.insert(MongoUtil.preInsertId(op.insert as T));
352
355
  } else if (op.upsert) {
353
356
  bulk.find({ _id: MongoUtil.uuid(op.upsert.id!) }).upsert().updateOne({ $set: op.upsert });
@@ -362,9 +365,11 @@ export class MongoModelService implements
362
365
 
363
366
  for (const op of operations) {
364
367
  if (op.insert) {
368
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
365
369
  MongoUtil.postLoadId(op.insert as T);
366
370
  }
367
371
  }
372
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
368
373
  for (const { index, _id } of res.getUpsertedIds() as { index: number, _id: mongo.ObjectId }[]) {
369
374
  out.insertedIds.set(index, MongoUtil.idToString(_id));
370
375
  }
@@ -380,6 +385,7 @@ export class MongoModelService implements
380
385
  out.errors = res.getWriteErrors();
381
386
  for (const err of out.errors) {
382
387
  const op = operations[err.index];
388
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
383
389
  const k = Object.keys(op)[0] as keyof BulkResponse['counts'];
384
390
  out.counts[k] -= 1;
385
391
  }
@@ -401,6 +407,7 @@ export class MongoModelService implements
401
407
  const result = await store.findOne(
402
408
  this.getWhere(
403
409
  cls,
410
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
404
411
  ModelIndexedUtil.projectIndex(cls, idx, body) as WhereClause<T>
405
412
  )
406
413
  );
@@ -416,6 +423,7 @@ export class MongoModelService implements
416
423
  const result = await store.deleteOne(
417
424
  this.getWhere(
418
425
  cls,
426
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
419
427
  ModelIndexedUtil.projectIndex(cls, idx, body) as WhereClause<T>
420
428
  )
421
429
  );
@@ -437,14 +445,17 @@ export class MongoModelService implements
437
445
  throw new AppError('Cannot list on unique indices', 'data');
438
446
  }
439
447
 
448
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
440
449
  const where = this.getWhere(
441
450
  cls,
451
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
442
452
  ModelIndexedUtil.projectIndex(cls, idx, body, { emptySortValue: { $exists: true } }) as WhereClause<T>
443
- ) as mongo.Filter<T>;
453
+ ) as mongo.Filter<Document>;
444
454
 
445
455
  const cursor = store.find(where, { timeout: true }).batchSize(100).sort(asFielded(idxCfg)[IdxFieldsⲐ]);
446
456
 
447
457
  for await (const el of cursor) {
458
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
448
459
  yield (await MongoUtil.postLoadId(await ModelCrudUtil.load(cls, el))) as T;
449
460
  }
450
461
  }
@@ -506,9 +517,11 @@ export class MongoModelService implements
506
517
  const items = MongoUtil.extractSimple(data);
507
518
  const final = Object.entries(items).reduce<Record<string, unknown>>((acc, [k, v]) => {
508
519
  if (v === null || v === undefined) {
520
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
509
521
  const o = (acc.$unset = acc.$unset ?? {}) as Record<string, unknown>;
510
522
  o[k] = v;
511
523
  } else {
524
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
512
525
  const o = (acc.$set = acc.$set ?? {}) as Record<string, unknown>;
513
526
  o[k] = v;
514
527
  }
@@ -525,6 +538,7 @@ export class MongoModelService implements
525
538
  const col = await this.getStore(cls);
526
539
  const pipeline: object[] = [{
527
540
  $group: {
541
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
528
542
  _id: `$${field as string}`,
529
543
  count: {
530
544
  $sum: 1
@@ -540,6 +554,7 @@ export class MongoModelService implements
540
554
 
541
555
  pipeline.unshift({ $match: q });
542
556
 
557
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
543
558
  const result = (await col.aggregate(pipeline).toArray()) as { _id: mongo.ObjectId, count: number }[];
544
559
 
545
560
  return result.map(val => ({
@@ -1,9 +1,9 @@
1
- import { EnvUtil } from '@travetto/boot';
2
- import type { Service } from '@travetto/command/bin/lib/service';
1
+ import { Env } from '@travetto/base';
2
+ import type { CommandService } from '@travetto/command';
3
3
 
4
- const version = EnvUtil.get('TRV_SERVICE_MONGO', '4.4');
4
+ const version = Env.get('MONGO_VERSION', '6.0');
5
5
 
6
- export const service: Service = {
6
+ export const service: CommandService = {
7
7
  name: 'mongodb',
8
8
  version,
9
9
  port: 27017,