@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.
- package/package.json +4 -4
- 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.
|
|
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.
|
|
34
|
-
"@travetto/model-indexed": "^8.0.
|
|
35
|
-
"@travetto/model-query": "^8.0.
|
|
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
|
|
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()
|
|
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>(
|
|
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
|
-
.
|
|
733
|
-
|
|
734
|
-
|
|
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,
|
|
750
|
-
|
|
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)
|
|
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: `$${
|
|
762
|
-
max: { $max: `$${
|
|
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:
|
|
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?:
|
|
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
|
|
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?:
|
|
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
|
|
819
|
+
return ModelQuerySuggestUtil.combineSuggestResults(cls, field, prefix, results, (_, b) => b, query);
|
|
800
820
|
}
|
|
801
821
|
|
|
802
822
|
// Other
|