Skip to content

Commit

Permalink
feat(graphql): Add new aggregate groupBy
Browse files Browse the repository at this point in the history
  • Loading branch information
doug-martin committed Mar 31, 2021
1 parent d5eb73b commit 922e696
Show file tree
Hide file tree
Showing 15 changed files with 316 additions and 36 deletions.
200 changes: 200 additions & 0 deletions documentation/docs/migration-guides/v0.24.x-to-v0.25.x.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
---
title: v0.24.x to v0.25.x
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

## Aggregate Queryies Return Arrays

In versions prior to `v0.24.0` aggregate queries returned a single response with just the aggregated values. In `v0.25.0` we have introduced a new `groupBy` option that requires aggregates to return arrays.

When using aggregates without the groupBy the response will always contain a single record with your aggregated
values. If you specify a `groupBy` you will get a response with a distinct group and the corresponding aggregated
values.

Given the following query

```graphql
{
todoItemAggregate {
count {
id
}
sum {
id
}
avg {
id
}
min {
id
title
created
}
max {
id
title
created
}
}
}
```

### Old

The old response would look like

```json
{
"data": {
"todoItemAggregate": {
"count": {
"id": 5
},
"sum": {
"id": 15
},
"avg": {
"id": 3
},
"min": {
"id": "1",
"title": "Add Todo Item Resolver",
"created": "2021-03-29T06:51:26.061Z"
},
"max": {
"id": "5",
"title": "How to create item With Sub Tasks",
"created": "2021-03-29T06:51:26.061Z"
}
}
}
}
```

### New
The new response will look like
```json
{
"data": {
"todoItemAggregate": [
{
"count": {
"id": 5
},
"sum": {
"id": 15
},
"avg": {
"id": 3
},
"min": {
"id": "1",
"title": "Add Todo Item Resolver",
"created": "2021-03-29T06:51:26.061Z"
},
"max": {
"id": "5",
"title": "How to create item With Sub Tasks",
"created": "2021-03-29T06:51:26.061Z"
}
}
]
}
}
```

## New Aggregate GroupBy

The new response format really shines when using the `groupBy` query

Given the following aggregate grouping on `completed`

```graphql {3-5}
{
todoItemAggregate {
groupBy {
completed
}
count {
id
}
sum {
id
}
avg {
id
}
min {
id
title
created
}
max {
id
title
created
}
}
}
```

You'll get the following response with record for each distinct group

```json
{
"data": {
"todoItemAggregate": [
{
"groupBy": {
"completed": false
},
"count": {
"id": 4
},
"sum": {
"id": 14
},
"avg": {
"id": 3.5
},
"min": {
"id": "2",
"title": "Add Todo Item Resolver",
"created": "2021-03-29T06:51:26.061Z"
},
"max": {
"id": "5",
"title": "How to create item With Sub Tasks",
"created": "2021-03-29T06:51:26.061Z"
}
},
{
"groupBy": {
"completed": true
},
"count": {
"id": 1
},
"sum": {
"id": 1
},
"avg": {
"id": 1
},
"min": {
"id": "1",
"title": "Create Nest App",
"created": "2021-03-29T06:51:26.061Z"
},
"max": {
"id": "1",
"title": "Create Nest App",
"created": "2021-03-29T06:51:26.061Z"
}
}
]
}
}
```
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
type FakeTypeAggregateGroupBy {
stringField: String
numberField: Float
boolField: Boolean
dateField: DateTime
}

"""
A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date-time format.
"""
scalar DateTime

type FakeTypeCountAggregate {
stringField: Int
numberField: Int
Expand All @@ -19,17 +31,19 @@ type FakeTypeMinAggregate {
dateField: DateTime
}

"""
A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date-time format.
"""
scalar DateTime

type FakeTypeMaxAggregate {
stringField: String
numberField: Float
dateField: DateTime
}

type CustomPrefixAggregateGroupBy {
stringField: String
numberField: Float
boolField: Boolean
dateField: DateTime
}

type CustomPrefixCountAggregate {
stringField: Int
numberField: Int
Expand Down Expand Up @@ -58,6 +72,7 @@ type CustomPrefixMaxAggregate {
}

type CustomPrefixAggregateResponse {
groupBy: CustomPrefixAggregateGroupBy
count: CustomPrefixCountAggregate
sum: CustomPrefixSumAggregate
avg: CustomPrefixAvgAggregate
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
type FakeTypeAggregateGroupBy {
stringField: String
numberField: Float
boolField: Boolean
dateField: DateTime
}

"""
A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date-time format.
"""
scalar DateTime

type FakeTypeCountAggregate {
stringField: Int
numberField: Int
Expand All @@ -19,18 +31,14 @@ type FakeTypeMinAggregate {
dateField: DateTime
}

"""
A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date-time format.
"""
scalar DateTime

type FakeTypeMaxAggregate {
stringField: String
numberField: Float
dateField: DateTime
}

type FakeTypeAggregateResponse {
groupBy: FakeTypeAggregateGroupBy
count: FakeTypeCountAggregate
sum: FakeTypeSumAggregate
avg: FakeTypeAvgAggregate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ describe('AggregateRelationsLoader', () => {
const filter = {};
const aggregate: AggregateQuery<RelationDTO> = { count: ['id'] };
const dtos = [{ id: 'dto-1' }, { id: 'dto-2' }];
const dto1Aggregate = { count: { id: 2 } };
const dto2Aggregate = { count: { id: 3 } };
const dto1Aggregate = [{ count: { id: 2 } }];
const dto2Aggregate = [{ count: { id: 3 } }];
when(
service.aggregateRelations(RelationDTO, 'relation', deepEqual(dtos), deepEqual(filter), deepEqual(aggregate)),
).thenResolve(
Expand All @@ -52,7 +52,7 @@ describe('AggregateRelationsLoader', () => {
const filter = {};
const aggregate: AggregateQuery<RelationDTO> = { count: ['id'] };
const dtos = [{ id: 'dto-1' }, { id: 'dto-2' }];
const dto1Aggregate = { count: { id: 2 } };
const dto1Aggregate = [{ count: { id: 2 } }];
when(
service.aggregateRelations(RelationDTO, 'relation', deepEqual(dtos), deepEqual(filter), deepEqual(aggregate)),
).thenResolve(new Map([[dtos[0], dto1Aggregate]]));
Expand All @@ -73,10 +73,10 @@ describe('AggregateRelationsLoader', () => {
const filter2 = {};
const aggregate: AggregateQuery<RelationDTO> = { count: ['id'] };
const dtos = [{ id: 'dto-1' }, { id: 'dto-2' }, { id: 'dto-3' }, { id: 'dto-4' }];
const dto1Aggregate = { count: { id: 2 } };
const dto2Aggregate = { count: { id: 3 } };
const dto3Aggregate = { count: { id: 4 } };
const dto4Aggregate = { count: { id: 5 } };
const dto1Aggregate = [{ count: { id: 2 } }];
const dto2Aggregate = [{ count: { id: 3 } }];
const dto3Aggregate = [{ count: { id: 4 } }];
const dto4Aggregate = [{ count: { id: 5 } }];
when(
service.aggregateRelations(
RelationDTO,
Expand Down Expand Up @@ -124,10 +124,10 @@ describe('AggregateRelationsLoader', () => {
const aggregate1: AggregateQuery<RelationDTO> = { count: ['id'] };
const aggregate2: AggregateQuery<RelationDTO> = { sum: ['id'] };
const dtos = [{ id: 'dto-1' }, { id: 'dto-2' }, { id: 'dto-3' }, { id: 'dto-4' }];
const dto1Aggregate = { count: { id: 2 } };
const dto2Aggregate = { sum: { id: 3 } };
const dto3Aggregate = { count: { id: 4 } };
const dto4Aggregate = { sum: { id: 5 } };
const dto1Aggregate = [{ count: { id: 2 } }];
const dto2Aggregate = [{ sum: { id: 3 } }];
const dto3Aggregate = [{ count: { id: 4 } }];
const dto4Aggregate = [{ sum: { id: 5 } }];
when(
service.aggregateRelations(
RelationDTO,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ type TestResolverDTO {
stringField: String!
}

type TestResolverDTOAggregateGroupBy {
id: ID
stringField: String
}

type TestResolverDTOCountAggregate {
id: Int
stringField: Int
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ type TestResolverDTO {
stringField: String!
}

type TestResolverDTOAggregateGroupBy {
id: ID
stringField: String
}

type TestResolverDTOCountAggregate {
id: Int
stringField: Int
Expand All @@ -19,6 +24,7 @@ type TestResolverDTOMaxAggregate {
}

type TestResolverDTOAggregateResponse {
groupBy: TestResolverDTOAggregateGroupBy
count: TestResolverDTOCountAggregate
min: TestResolverDTOMinAggregate
max: TestResolverDTOMaxAggregate
Expand All @@ -28,7 +34,7 @@ type Query {
testResolverDTOAggregate(
"""Filter to find records to aggregate on"""
filter: TestResolverDTOAggregateFilter
): TestResolverDTOAggregateResponse!
): [TestResolverDTOAggregateResponse!]!
test: TestResolverDTO!
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@ describe('AggregateResolver', () => {
},
};
const aggregateQuery: AggregateQuery<TestResolverDTO> = { count: ['id'] };
const output: AggregateResponse<TestResolverDTO> = {
count: { id: 10 },
};
const output: AggregateResponse<TestResolverDTO>[] = [
{
count: { id: 10 },
},
];
when(mockService.aggregate(objectContaining(input.filter!), deepEqual(aggregateQuery))).thenResolve(output);
const result = await resolver.aggregate(input, aggregateQuery);
return expect(result).toEqual(output);
Expand Down

0 comments on commit 922e696

Please sign in to comment.