@travetto/model-mongo 8.0.5 → 8.0.7

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 (2) hide show
  1. package/package.json +4 -4
  2. package/src/service.ts +52 -32
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-mongo",
3
- "version": "8.0.5",
3
+ "version": "8.0.7",
4
4
  "description": "Mongo backing for the travetto model module.",
5
5
  "keywords": [
6
6
  "database",
@@ -30,9 +30,9 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@travetto/config": "^8.0.3",
33
- "@travetto/model": "^8.0.3",
34
- "@travetto/model-indexed": "^8.0.3",
35
- "@travetto/model-query": "^8.0.5",
33
+ "@travetto/model": "^8.0.4",
34
+ "@travetto/model-indexed": "^8.0.4",
35
+ "@travetto/model-query": "^8.0.7",
36
36
  "mongodb": "^7.6.0"
37
37
  },
38
38
  "peerDependencies": {
package/src/service.ts CHANGED
@@ -58,6 +58,7 @@ import {
58
58
  type ModelQueryCrudSupport,
59
59
  ModelQueryCrudUtil,
60
60
  type ModelQueryFacet,
61
+ type FacetModelQuery,
61
62
  type ModelQueryFacetSupport,
62
63
  type ModelQuerySuggestSupport,
63
64
  ModelQuerySuggestUtil,
@@ -66,6 +67,7 @@ import {
66
67
  type NumberFieldAggregateResult,
67
68
  type PageableModelQuery,
68
69
  QueryVerifier,
70
+ type SuggestModelQuery,
69
71
  type ValidComparableFields,
70
72
  type ValidStringFields,
71
73
  type WhereClause
@@ -104,6 +106,13 @@ const handleDuplicateKeyError = (cls: Class, id: string, error: unknown): unknow
104
106
  return error;
105
107
  };
106
108
 
109
+ function isNotFoundError(error: unknown): error is MongoServerError {
110
+ return (
111
+ (error instanceof MongoServerError && (error.code === 26 || error.codeName === 'NamespaceNotFound')) ||
112
+ (error instanceof Error && /ns not found/i.test(error.message))
113
+ );
114
+ }
115
+
107
116
  export const ModelBlobNamespace = '__blobs';
108
117
 
109
118
  /**
@@ -256,13 +265,15 @@ export class MongoModelService
256
265
  async createStorage(): Promise<void> {}
257
266
 
258
267
  async deleteStorage(): Promise<void> {
259
- await this.#db.dropDatabase();
268
+ await ModelStorageUtil.runAndIgnoreNotFound(() => this.#db.dropDatabase(), isNotFoundError);
260
269
  }
261
270
 
262
271
  async upsertModel(cls: Class): Promise<void> {
263
272
  const col = await this.getStore(cls);
264
273
  const indices = [...ModelRegistryIndex.getIndices(cls).map(idx => MongoUtil.getIndex(cls, idx)), ...MongoUtil.getExtraIndices(cls)];
265
- const existingIndices = (await col.indexes().catch(() => [])).filter(idx => idx.name !== '_id_');
274
+ const existingIndices = ((await ModelStorageUtil.runAndIgnoreNotFound(() => col.indexes(), isNotFoundError)) ?? []).filter(
275
+ idx => idx.name !== '_id_'
276
+ );
266
277
 
267
278
  const pendingMap = Object.fromEntries(indices.map(pair => [pair[1].name!, pair]));
268
279
  const existingMap = Object.fromEntries(existingIndices.map(idx => [idx.name!, idx.key]));
@@ -289,13 +300,17 @@ export class MongoModelService
289
300
  }
290
301
  }
291
302
 
303
+ async deleteModel<T extends ModelType>(cls: Class<T>): Promise<void> {
304
+ await ModelStorageUtil.runAndIgnoreNotFound(() => this.#db.collection(ModelRegistryIndex.getStoreName(cls)).drop(), isNotFoundError);
305
+ }
306
+
292
307
  async truncateModel<T extends ModelType>(cls: Class<T>): Promise<void> {
293
308
  const col = await this.getStore(cls);
294
309
  await col.deleteMany({});
295
310
  }
296
311
 
297
312
  async truncateBlob(): Promise<void> {
298
- await this.#bucket.drop().catch(() => {});
313
+ await this.#bucket.drop();
299
314
  }
300
315
 
301
316
  /**
@@ -700,13 +715,14 @@ export class MongoModelService
700
715
  }
701
716
 
702
717
  // Facet
703
- async facetByQuery<T extends ModelType>(cls: Class<T>, field: ValidStringFields<T>, query?: ModelQuery<T>): Promise<ModelQueryFacet[]> {
718
+ async facetByQuery<T extends ModelType>(
719
+ cls: Class<T>,
720
+ field: ValidStringFields<T>,
721
+ query?: FacetModelQuery<T>
722
+ ): Promise<ModelQueryFacet[]> {
704
723
  await QueryVerifier.verify(cls, query);
705
724
 
706
725
  const col = await this.getStore(cls);
707
- if (query) {
708
- await QueryVerifier.verify(cls, query);
709
- }
710
726
 
711
727
  let queryObject: Record<string, unknown> = { [field]: { $exists: true } };
712
728
 
@@ -723,17 +739,22 @@ export class MongoModelService
723
739
  $sum: 1
724
740
  }
725
741
  }
726
- }
742
+ },
743
+ {
744
+ $sort: {
745
+ count: -1
746
+ }
747
+ },
748
+ ...(query?.offset !== undefined ? [{ $skip: query.offset }] : []),
749
+ ...(query?.limit !== undefined ? [{ $limit: query.limit }] : [])
727
750
  ];
728
751
 
729
752
  const result = await col.aggregate<{ _id: ObjectId; count: number }>(aggregations).toArray();
730
753
 
731
- return result
732
- .map(item => ({
733
- key: MongoUtil.idToString(item._id),
734
- count: item.count
735
- }))
736
- .toSorted((a, b) => b.count - a.count);
754
+ return result.map(item => ({
755
+ key: MongoUtil.idToString(item._id),
756
+ count: item.count
757
+ }));
737
758
  }
738
759
 
739
760
  // Aggregate
@@ -746,27 +767,26 @@ export class MongoModelService
746
767
 
747
768
  const collection = await this.getStore(cls);
748
769
 
749
- const where = ModelQueryUtil.getWhereClause(cls, query?.where);
750
- let queryObject: Record<string, unknown> = { [field]: { $exists: true, $ne: null } };
751
-
752
- if (where) {
753
- queryObject = { $and: [queryObject, MongoUtil.extractWhereFilter(cls, where)] };
754
- }
770
+ const where = ModelQueryUtil.getWhereClause(cls, {
771
+ $and: [query?.where ?? {}, { [field]: { $exists: true } }]
772
+ });
755
773
 
756
- const isDate = SchemaRegistryIndex.getNestedFieldConfig(cls, field)!.type === Date;
774
+ const isDate = SchemaRegistryIndex.getNestedFieldConfig(cls, field)?.type === Date;
757
775
 
758
776
  const groupFields: Record<string, unknown> = {
759
777
  _id: null,
760
778
  count: { $sum: 1 },
761
- min: { $min: `$${String(field)}` },
762
- max: { $max: `$${String(field)}` }
779
+ min: { $min: `$${field}` },
780
+ max: { $max: `$${field}` },
781
+ ...(isDate
782
+ ? {}
783
+ : {
784
+ avg: { $avg: `$${field}` },
785
+ sum: { $sum: `$${field}` }
786
+ })
763
787
  };
764
- if (!isDate) {
765
- groupFields.avg = { $avg: `$${String(field)}` };
766
- groupFields.sum = { $sum: `$${String(field)}` };
767
- }
768
788
 
769
- const aggregations: object[] = [{ $match: queryObject }, { $group: groupFields }];
789
+ const aggregations: object[] = [{ $match: MongoUtil.extractWhereFilter(cls, where) }, { $group: groupFields }];
770
790
 
771
791
  const result = await collection.aggregate<NumberFieldAggregateResult>(aggregations).toArray();
772
792
 
@@ -779,24 +799,24 @@ export class MongoModelService
779
799
  cls: Class<T>,
780
800
  field: ValidStringFields<T>,
781
801
  prefix?: string,
782
- query?: PageableModelQuery<T>
802
+ query?: SuggestModelQuery<T>
783
803
  ): Promise<string[]> {
784
804
  await QueryVerifier.verify(cls, query);
785
805
  const resolvedQuery = ModelQuerySuggestUtil.getSuggestFieldQuery<T>(cls, field, prefix, query);
786
806
  const results = await this.query<T>(cls, resolvedQuery);
787
- return ModelQuerySuggestUtil.combineSuggestResults<T, string>(cls, field, prefix, results, a => a, query?.limit);
807
+ return ModelQuerySuggestUtil.combineSuggestResults<T, string>(cls, field, prefix, results, a => a, query);
788
808
  }
789
809
 
790
810
  async suggestByQuery<T extends ModelType>(
791
811
  cls: Class<T>,
792
812
  field: ValidStringFields<T>,
793
813
  prefix?: string,
794
- query?: PageableModelQuery<T>
814
+ query?: SuggestModelQuery<T>
795
815
  ): Promise<T[]> {
796
816
  await QueryVerifier.verify(cls, query);
797
817
  const resolvedQuery = ModelQuerySuggestUtil.getSuggestQuery<T>(cls, field, prefix, query);
798
818
  const results = await this.query<T>(cls, resolvedQuery);
799
- return ModelQuerySuggestUtil.combineSuggestResults(cls, field, prefix, results, (_, b) => b, query?.limit);
819
+ return ModelQuerySuggestUtil.combineSuggestResults(cls, field, prefix, results, (_, b) => b, query);
800
820
  }
801
821
 
802
822
  // Other