@travetto/model-query 8.0.4 → 8.0.6
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 +1 -1
- package/package.json +2 -2
- package/src/types/aggregate.ts +22 -9
- package/src/util/aggregate.ts +9 -10
- package/support/test/aggregate.ts +24 -3
- package/support/test/model.ts +7 -0
package/README.md
CHANGED
|
@@ -141,7 +141,7 @@ export interface ModelQueryAggregateSupport extends ModelQuerySupport {
|
|
|
141
141
|
* @param field The field to aggregate on
|
|
142
142
|
* @param query Additional query filtering
|
|
143
143
|
*/
|
|
144
|
-
aggregateFieldByQuery<T extends ModelType, F extends ValidComparableFields<T>>(
|
|
144
|
+
aggregateFieldByQuery<T extends ModelType, const F extends ValidComparableFields<T>>(
|
|
145
145
|
modelClass: Class<T>,
|
|
146
146
|
field: F,
|
|
147
147
|
query?: ModelQuery<T>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/model-query",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.6",
|
|
4
4
|
"description": "Datastore abstraction for advanced query support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"datastore",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@travetto/di": "^8.0.1",
|
|
34
|
-
"@travetto/model": "^8.0.
|
|
34
|
+
"@travetto/model": "^8.0.4",
|
|
35
35
|
"@travetto/schema": "^8.0.2"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
package/src/types/aggregate.ts
CHANGED
|
@@ -16,7 +16,7 @@ export type PathType<T, Path extends string> = Path extends `${infer Head}.${inf
|
|
|
16
16
|
: never;
|
|
17
17
|
|
|
18
18
|
export type AggregateResultType<T, F extends string> = [PathType<T, F>] extends [never]
|
|
19
|
-
? number |
|
|
19
|
+
? number | bigint | undefined
|
|
20
20
|
: PathType<T, F> | undefined;
|
|
21
21
|
|
|
22
22
|
export type DateFieldAggregateResult = {
|
|
@@ -25,16 +25,29 @@ export type DateFieldAggregateResult = {
|
|
|
25
25
|
max?: Date;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
export type
|
|
28
|
+
export type NumberFieldAggregateResult = {
|
|
29
29
|
count: number;
|
|
30
|
-
min?:
|
|
31
|
-
max?:
|
|
32
|
-
avg?:
|
|
33
|
-
sum?:
|
|
30
|
+
min?: number;
|
|
31
|
+
max?: number;
|
|
32
|
+
avg?: number;
|
|
33
|
+
sum?: number;
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
export type
|
|
37
|
-
|
|
36
|
+
export type BigIntFieldAggregateResult = {
|
|
37
|
+
count: number;
|
|
38
|
+
min?: bigint;
|
|
39
|
+
max?: bigint;
|
|
40
|
+
avg?: bigint;
|
|
41
|
+
sum?: bigint;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type FieldAggregateResult<T, F extends string> = F extends any
|
|
45
|
+
? NonNullable<PathType<T, F>> extends Date
|
|
46
|
+
? DateFieldAggregateResult
|
|
47
|
+
: NonNullable<PathType<T, F>> extends bigint
|
|
48
|
+
? BigIntFieldAggregateResult
|
|
49
|
+
: NumberFieldAggregateResult
|
|
50
|
+
: never;
|
|
38
51
|
|
|
39
52
|
/**
|
|
40
53
|
* The contract for a model service with aggregate support
|
|
@@ -49,7 +62,7 @@ export interface ModelQueryAggregateSupport extends ModelQuerySupport {
|
|
|
49
62
|
* @param field The field to aggregate on
|
|
50
63
|
* @param query Additional query filtering
|
|
51
64
|
*/
|
|
52
|
-
aggregateFieldByQuery<T extends ModelType, F extends ValidComparableFields<T>>(
|
|
65
|
+
aggregateFieldByQuery<T extends ModelType, const F extends ValidComparableFields<T>>(
|
|
53
66
|
modelClass: Class<T>,
|
|
54
67
|
field: F,
|
|
55
68
|
query?: ModelQuery<T>
|
package/src/util/aggregate.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { castTo, type Class, hasFunction } from '@travetto/runtime';
|
|
|
3
3
|
import { DataUtil, SchemaRegistryIndex } from '@travetto/schema';
|
|
4
4
|
|
|
5
5
|
import type { ValidComparableFields } from '../model/where-clause.ts';
|
|
6
|
-
import type {
|
|
6
|
+
import type { FieldAggregateResult, ModelQueryAggregateSupport, NumberFieldAggregateResult } from '../types/aggregate.ts';
|
|
7
7
|
|
|
8
8
|
export class ModelQueryAggregateUtil {
|
|
9
9
|
/**
|
|
@@ -17,32 +17,31 @@ export class ModelQueryAggregateUtil {
|
|
|
17
17
|
* @param field The field being aggregated
|
|
18
18
|
* @param rawValues The raw result values from the datastore
|
|
19
19
|
*/
|
|
20
|
-
static resolveAggregate<T extends ModelType, F extends ValidComparableFields<T>>(
|
|
20
|
+
static resolveAggregate<T extends ModelType, const F extends ValidComparableFields<T>>(
|
|
21
21
|
modelClass: Class<T>,
|
|
22
22
|
field: F,
|
|
23
|
-
rawValues:
|
|
23
|
+
rawValues: Partial<Record<keyof NumberFieldAggregateResult, unknown>>
|
|
24
24
|
): FieldAggregateResult<T, F> {
|
|
25
25
|
const count = Number(rawValues.count ?? 0);
|
|
26
26
|
if (count === 0) {
|
|
27
27
|
return castTo({ count: 0 });
|
|
28
28
|
}
|
|
29
29
|
const leafFieldType = SchemaRegistryIndex.getNestedFieldConfig(modelClass, field)!.type;
|
|
30
|
-
const coerce = (value: unknown): AggregateResultType<T, F> => castTo(DataUtil.coerceType(value, leafFieldType, false) ?? undefined);
|
|
31
30
|
|
|
32
31
|
if (leafFieldType === Date) {
|
|
33
32
|
return castTo({
|
|
34
33
|
count,
|
|
35
|
-
min:
|
|
36
|
-
max:
|
|
34
|
+
min: DataUtil.coerceType(rawValues.min, leafFieldType, true),
|
|
35
|
+
max: DataUtil.coerceType(rawValues.max, leafFieldType, true)
|
|
37
36
|
});
|
|
38
37
|
}
|
|
39
38
|
|
|
40
39
|
return castTo({
|
|
41
40
|
count,
|
|
42
|
-
min:
|
|
43
|
-
max:
|
|
44
|
-
avg:
|
|
45
|
-
sum:
|
|
41
|
+
min: DataUtil.coerceType(rawValues.min, leafFieldType, true),
|
|
42
|
+
max: DataUtil.coerceType(rawValues.max, leafFieldType, true),
|
|
43
|
+
avg: DataUtil.coerceType(rawValues.avg, leafFieldType, true),
|
|
44
|
+
sum: DataUtil.coerceType(rawValues.sum, leafFieldType, true)
|
|
46
45
|
});
|
|
47
46
|
}
|
|
48
47
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import assert from 'node:assert';
|
|
2
2
|
|
|
3
|
-
import type { ModelCrudSupport } from '@travetto/model';
|
|
3
|
+
import type { ModelCrudSupport, ModelType } from '@travetto/model';
|
|
4
4
|
import { Suite, Test } from '@travetto/test';
|
|
5
5
|
|
|
6
6
|
import { BaseModelSuite } from '@travetto/model/support/test/base.ts';
|
|
7
7
|
|
|
8
|
-
import type { ModelQueryAggregateSupport } from '../../src/types/aggregate.ts';
|
|
9
|
-
import { Aged, BigIntModel, Person } from './model.ts';
|
|
8
|
+
import type { DateFieldAggregateResult, ModelQueryAggregateSupport, NumberFieldAggregateResult } from '../../src/types/aggregate.ts';
|
|
9
|
+
import { Aged, BigIntModel, MultiFieldModel, Person } from './model.ts';
|
|
10
10
|
|
|
11
11
|
@Suite()
|
|
12
12
|
export abstract class ModelQueryAggregateSuite extends BaseModelSuite<ModelQueryAggregateSupport & ModelCrudSupport> {
|
|
@@ -32,6 +32,27 @@ export abstract class ModelQueryAggregateSuite extends BaseModelSuite<ModelQuery
|
|
|
32
32
|
assert(aggregate.max.getTime() === thirdDate.getTime());
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
@Test('verify model with multiple field types aggregate')
|
|
36
|
+
async testMultiFieldModelAggregate() {
|
|
37
|
+
const service = await this.service;
|
|
38
|
+
const now = new Date();
|
|
39
|
+
await this.saveAll(MultiFieldModel, [
|
|
40
|
+
MultiFieldModel.from({ createdAt: now, score: 10 }),
|
|
41
|
+
MultiFieldModel.from({ createdAt: now, score: 20 })
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
const dateStats = await service.aggregateFieldByQuery(MultiFieldModel, 'createdAt');
|
|
45
|
+
const dateCheck: DateFieldAggregateResult = dateStats;
|
|
46
|
+
assert(dateCheck.count === 2);
|
|
47
|
+
assert(dateCheck.min instanceof Date);
|
|
48
|
+
|
|
49
|
+
const numberStats = await service.aggregateFieldByQuery(MultiFieldModel, 'score');
|
|
50
|
+
const numberCheck: NumberFieldAggregateResult = numberStats;
|
|
51
|
+
assert(numberCheck.count === 2);
|
|
52
|
+
assert(numberCheck.min === 10);
|
|
53
|
+
assert(numberCheck.avg === 15);
|
|
54
|
+
}
|
|
55
|
+
|
|
35
56
|
@Test('verify field aggregate')
|
|
36
57
|
async testFieldAggregate() {
|
|
37
58
|
const people = [
|
package/support/test/model.ts
CHANGED