@travetto/model-mongo 8.0.3 → 8.0.5

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
@@ -21,7 +21,7 @@ Supported features:
21
21
  * [CRUD](https://github.com/travetto/travetto/tree/main/module/model/src/types/crud.ts#L10)
22
22
  * [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/types/expiry.ts#L10)
23
23
  * [Indexed](https://github.com/travetto/travetto/tree/main/module/model-indexed/src/types/service.ts#L21)
24
- * [Aggregate](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/aggregate.ts#L30)
24
+ * [Aggregate](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/aggregate.ts#L56)
25
25
  * [Query Crud](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/crud.ts#L11)
26
26
  * [Facet](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/facet.ts#L14)
27
27
  * [Suggest](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/suggest.ts#L12)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-mongo",
3
- "version": "8.0.3",
3
+ "version": "8.0.5",
4
4
  "description": "Mongo backing for the travetto model module.",
5
5
  "keywords": [
6
6
  "database",
@@ -32,7 +32,7 @@
32
32
  "@travetto/config": "^8.0.3",
33
33
  "@travetto/model": "^8.0.3",
34
34
  "@travetto/model-indexed": "^8.0.3",
35
- "@travetto/model-query": "^8.0.3",
35
+ "@travetto/model-query": "^8.0.5",
36
36
  "mongodb": "^7.6.0"
37
37
  },
38
38
  "peerDependencies": {
package/src/service.ts CHANGED
@@ -51,9 +51,7 @@ import {
51
51
  type SortedIndexSelectionType
52
52
  } from '@travetto/model-indexed';
53
53
  import {
54
- type AggregateNumericOperation,
55
- type AggregateOperation,
56
- type AggregateResultType,
54
+ type FieldAggregateResult,
57
55
  type ModelQuery,
58
56
  type ModelQueryAggregateSupport,
59
57
  ModelQueryAggregateUtil,
@@ -65,10 +63,10 @@ import {
65
63
  ModelQuerySuggestUtil,
66
64
  type ModelQuerySupport,
67
65
  ModelQueryUtil,
66
+ type NumberFieldAggregateResult,
68
67
  type PageableModelQuery,
69
68
  QueryVerifier,
70
69
  type ValidComparableFields,
71
- type ValidNumericFields,
72
70
  type ValidStringFields,
73
71
  type WhereClause
74
72
  } from '@travetto/model-query';
@@ -82,10 +80,10 @@ import {
82
80
  type Class,
83
81
  castTo,
84
82
  JSONUtil,
85
- RuntimeError,
86
83
  ShutdownManager,
87
84
  TypedObject
88
85
  } from '@travetto/runtime';
86
+ import { SchemaRegistryIndex } from '@travetto/schema';
89
87
 
90
88
  import type { MongoModelConfig } from './config.ts';
91
89
  import { MongoUtil, type WithId } from './internal/util.ts';
@@ -641,11 +639,19 @@ export class MongoModelService
641
639
  return await Promise.all(items.map(item => this.postLoad(cls, item)));
642
640
  }
643
641
 
644
- async queryOne<T extends ModelType>(cls: Class<T>, query: ModelQuery<T>, failOnMany = true): Promise<T> {
642
+ async getByQuery<T extends ModelType>(cls: Class<T>, query: ModelQuery<T>, failOnMany = true): Promise<T> {
645
643
  const results = await this.query<T>(cls, { ...query, limit: failOnMany ? 2 : 1 });
646
644
  return ModelQueryUtil.verifyGetSingleCounts<T>(cls, failOnMany, results, query.where);
647
645
  }
648
646
 
647
+ async countByQuery<T extends ModelType>(cls: Class<T>, query: ModelQuery<T>): Promise<number> {
648
+ await QueryVerifier.verify(cls, query);
649
+
650
+ const col = await this.getStore(cls);
651
+ const filter = MongoUtil.extractWhereFilter(cls, query.where);
652
+ return col.countDocuments(filter);
653
+ }
654
+
649
655
  // Query Crud
650
656
  async updateByQuery<T extends ModelType>(cls: Class<T>, data: T, query: ModelQuery<T>): Promise<T> {
651
657
  await QueryVerifier.verify(cls, query);
@@ -730,59 +736,42 @@ export class MongoModelService
730
736
  .toSorted((a, b) => b.count - a.count);
731
737
  }
732
738
 
733
- static readonly AGGREGATE_OPERATION_MAPPING: Record<AggregateOperation, '$sum' | '$avg' | '$min' | '$max'> = {
734
- sum: '$sum',
735
- avg: '$avg',
736
- min: '$min',
737
- max: '$max'
738
- };
739
-
740
739
  // Aggregate
741
- async aggregateFieldByQuery<
742
- T extends ModelType,
743
- Op extends AggregateOperation,
744
- F extends (Op extends AggregateNumericOperation ? ValidNumericFields<T> : ValidComparableFields<T>)
745
- >(modelClass: Class<T>, operation: Op, field: F, query?: ModelQuery<T>): Promise<AggregateResultType<T, F>> {
746
- await QueryVerifier.verify(modelClass, query);
740
+ async aggregateFieldByQuery<T extends ModelType, const F extends ValidComparableFields<T>>(
741
+ cls: Class<T>,
742
+ field: F,
743
+ query?: ModelQuery<T>
744
+ ): Promise<FieldAggregateResult<T, F>> {
745
+ await QueryVerifier.verify(cls, query);
747
746
 
748
- const collection = await this.getStore(modelClass);
747
+ const collection = await this.getStore(cls);
749
748
 
750
- const where = ModelQueryUtil.getWhereClause(modelClass, query?.where);
749
+ const where = ModelQueryUtil.getWhereClause(cls, query?.where);
751
750
  let queryObject: Record<string, unknown> = { [field]: { $exists: true, $ne: null } };
752
751
 
753
752
  if (where) {
754
- queryObject = { $and: [queryObject, MongoUtil.extractWhereFilter(modelClass, where)] };
753
+ queryObject = { $and: [queryObject, MongoUtil.extractWhereFilter(cls, where)] };
755
754
  }
756
755
 
757
- const aggregateOperator = MongoModelService.AGGREGATE_OPERATION_MAPPING[operation];
758
- if (!aggregateOperator) {
759
- throw new RuntimeError(`Unsupported aggregate operation: ${operation}`);
760
- }
761
-
762
- const aggregations: object[] = [
763
- { $match: queryObject },
764
- {
765
- $group: {
766
- _id: null,
767
- value: {
768
- [aggregateOperator]: `$${String(field)}`
769
- }
770
- }
771
- }
772
- ];
756
+ const isDate = SchemaRegistryIndex.getNestedFieldConfig(cls, field)!.type === Date;
773
757
 
774
- const result = await collection.aggregate<{ _id: null; value: unknown }>(aggregations).toArray();
775
- const rawValue = result.length ? result[0].value : undefined;
758
+ const groupFields: Record<string, unknown> = {
759
+ _id: null,
760
+ count: { $sum: 1 },
761
+ min: { $min: `$${String(field)}` },
762
+ max: { $max: `$${String(field)}` }
763
+ };
764
+ if (!isDate) {
765
+ groupFields.avg = { $avg: `$${String(field)}` };
766
+ groupFields.sum = { $sum: `$${String(field)}` };
767
+ }
776
768
 
777
- return ModelQueryAggregateUtil.resolveResult(modelClass, operation, field, rawValue);
778
- }
769
+ const aggregations: object[] = [{ $match: queryObject }, { $group: groupFields }];
779
770
 
780
- async countByQuery<T extends ModelType>(cls: Class<T>, query: ModelQuery<T>): Promise<number> {
781
- await QueryVerifier.verify(cls, query);
771
+ const result = await collection.aggregate<NumberFieldAggregateResult>(aggregations).toArray();
782
772
 
783
- const col = await this.getStore(cls);
784
- const filter = MongoUtil.extractWhereFilter(cls, query.where);
785
- return col.countDocuments(filter);
773
+ const row = result.length ? result[0] : { count: 0 };
774
+ return ModelQueryAggregateUtil.resolveAggregate(cls, field, row);
786
775
  }
787
776
 
788
777
  // Suggest