Skip to content

Commit 814a806

Browse files
authored
Add ProgressReportFilters.cumulativeSummary.scheduleStatus (#3310)
1 parent 396bcb4 commit 814a806

File tree

6 files changed

+87
-2
lines changed

6 files changed

+87
-2
lines changed

src/components/progress-report/dto/progress-report-list.dto.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
} from '~/common';
99
import { EngagementFilters } from '../../engagement/dto';
1010
import { PeriodicReportListInput } from '../../periodic-report/dto';
11+
import { ProgressSummaryFilters } from '../../progress-summary/dto';
1112
import { ProgressReportStatus } from './progress-report-status.enum';
1213
import { ProgressReport } from './progress-report.entity';
1314

@@ -21,6 +22,9 @@ export abstract class ProgressReportFilters extends PickType(
2122
})
2223
readonly status?: readonly ProgressReportStatus[];
2324

25+
@FilterField(() => ProgressSummaryFilters)
26+
readonly cumulativeSummary?: ProgressSummaryFilters & {};
27+
2428
@FilterField(() => EngagementFilters)
2529
readonly engagement?: EngagementFilters & {};
2630
}

src/components/progress-report/progress-report.repository.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@ import {
1111
paginate,
1212
requestingUser,
1313
sortWith,
14+
variable,
1415
} from '~/core/database/query';
1516
import { engagementFilters } from '../engagement/engagement.repository';
1617
import { progressReportSorters } from '../periodic-report/periodic-report.repository';
18+
import { SummaryPeriod } from '../progress-summary/dto';
19+
import { progressSummaryFilters } from '../progress-summary/progress-summary.repository';
1720
import {
1821
ProgressReport,
1922
ProgressReportFilters,
@@ -84,6 +87,18 @@ export const progressReportFilters = filter.define(
8487
start: filter.dateTimeProp(),
8588
end: filter.dateTimeProp(),
8689
status: filter.stringListProp(),
90+
cumulativeSummary: filter.sub(() => progressSummaryFilters)((sub) =>
91+
sub
92+
.optionalMatch([
93+
node('outer'),
94+
relation('out', '', 'summary', ACTIVE),
95+
node('node', 'ProgressSummary', {
96+
period: variable(`"${SummaryPeriod.Cumulative}"`),
97+
}),
98+
])
99+
// needed in conjunction with `optionalMatch`
100+
.with('outer, node'),
101+
),
87102
engagement: filter.sub(
88103
() => engagementFilters,
89104
'requestingUser',
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './progress-summary.dto';
22
export * from './schedule-status.enum';
3+
export * from './progress-summary-filters.dto';
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Field, InputType } from '@nestjs/graphql';
2+
import { stripIndent } from 'common-tags';
3+
import { ScheduleStatus } from './schedule-status.enum';
4+
5+
@InputType()
6+
export abstract class ProgressSummaryFilters {
7+
@Field(() => [ScheduleStatus], {
8+
nullable: 'itemsAndList',
9+
description: stripIndent`
10+
Filter by schedule status.
11+
- \`[X, Y]\` will allow summaries with either X or Y status.
12+
- \`[null, X]\` will allow missing summaries or summaries with X status.
13+
- \`[null]\` will filter to only missing summaries.
14+
- \`null\` and \`[]\` will be ignored.
15+
`,
16+
})
17+
readonly scheduleStatus?: ReadonlyArray<ScheduleStatus | null>;
18+
}

src/components/progress-summary/progress-summary.repository.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
import { Injectable } from '@nestjs/common';
2-
import { mapValues } from '@seedcompany/common';
2+
import { cleanJoin, isNotFalsy, mapValues, setOf } from '@seedcompany/common';
33
import { inArray, node, Query, relation } from 'cypher-query-builder';
44
import { ID } from '~/common';
55
import { CommonRepository } from '~/core/database';
66
import {
77
ACTIVE,
88
defineSorters,
9+
filter,
910
listConcat,
1011
merge,
1112
SortCol,
1213
} from '~/core/database/query';
14+
import { WhereExp } from '~/core/database/query/where-and-list';
1315
import { ProgressReport } from '../progress-report/dto';
14-
import { FetchedSummaries, ProgressSummary, SummaryPeriod } from './dto';
16+
import {
17+
FetchedSummaries,
18+
ProgressSummary,
19+
ProgressSummaryFilters,
20+
SummaryPeriod,
21+
} from './dto';
1522

1623
@Injectable()
1724
export class ProgressSummaryRepository extends CommonRepository {
@@ -95,3 +102,32 @@ export const progressSummarySorters = defineSorters(ProgressSummary, {
95102
query.return<SortCol>('(node.actual - node.planned) as sortValue'),
96103
).asRecord,
97104
});
105+
106+
export const progressSummaryFilters = filter.define(
107+
() => ProgressSummaryFilters,
108+
{
109+
scheduleStatus: ({ value, query }) => {
110+
const status = setOf(value);
111+
if (status.size === 0) {
112+
return undefined;
113+
}
114+
if (status.size === 1 && status.has(null)) {
115+
return query.where(new WhereExp('node IS NULL'));
116+
}
117+
118+
const conditions = cleanJoin(' OR ', [
119+
status.has(null) && `node IS NULL`,
120+
status.has('Ahead') && `node.actual - node.planned > 0.1`,
121+
status.has('Behind') && `node.actual - node.planned < -0.1`,
122+
status.has('OnTime') &&
123+
`node.actual - node.planned <= 0.1 and node.actual - node.planned >= -0.1`,
124+
]);
125+
const required = status.has(null) ? undefined : `node IS NOT NULL`;
126+
const str = [required, conditions]
127+
.filter(isNotFalsy)
128+
.map((s) => `(${s})`)
129+
.join(' AND ');
130+
return str ? query.where(new WhereExp(str)) : query;
131+
},
132+
},
133+
);

src/core/database/query/where-and-list.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
WhereOp,
66
} from 'cypher-query-builder';
77
import { AnyConditions } from 'cypher-query-builder/dist/typings/clauses/where-utils';
8+
import { exp, ExpressionInput } from './cypher-expression';
89

910
export class WhereAndList extends WhereOp {
1011
constructor(public conditions: AnyConditions[]) {
@@ -24,3 +25,13 @@ export class WhereAndList extends WhereOp {
2425
return braces ? `(${string})` : string;
2526
}
2627
}
28+
29+
export class WhereExp extends WhereOp {
30+
constructor(public exp: ExpressionInput) {
31+
super();
32+
}
33+
34+
evaluate() {
35+
return exp(this.exp);
36+
}
37+
}

0 commit comments

Comments
 (0)