-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgetTaskOverview.js
More file actions
102 lines (93 loc) · 3.17 KB
/
getTaskOverview.js
File metadata and controls
102 lines (93 loc) · 3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
'use strict';
const Archetype = require('archetype');
const escape = require('regexp.escape');
const GetTaskOverviewParams = new Archetype({
start: { $type: Date },
end: { $type: Date },
status: { $type: 'string' },
name: { $type: 'string' }
}).compile('GetTaskOverviewParams');
/** Statuses shown on the Task overview page. */
const OVERVIEW_STATUSES = ['pending', 'succeeded', 'failed', 'cancelled'];
function buildMatch(params) {
const { start, end, status, name } = params;
const match = {};
if (start != null && end != null) {
match.scheduledAt = { $gte: start, $lt: end };
} else if (start != null) {
match.scheduledAt = { $gte: start };
}
const statusVal = typeof status === 'string' ? status.trim() : status;
if (statusVal != null && statusVal !== '') {
match.status = statusVal;
} else {
match.status = { $in: ['pending', 'in_progress', 'succeeded', 'failed', 'cancelled', 'unknown'] };
}
if (name != null && name !== '') {
const nameStr = typeof name === 'string' ? name.trim() : String(name);
match.name = { $regex: escape(nameStr), $options: 'i' };
}
return match;
}
module.exports = ({ db }) => async function getTaskOverview(params) {
params = new GetTaskOverviewParams(params);
if (typeof params.status === 'string') params.status = params.status.trim();
if (typeof params.name === 'string') params.name = params.name.trim();
const { Task } = db.models;
const match = buildMatch(params);
const defaultCounts = OVERVIEW_STATUSES.map(s => ({ k: s, v: 0 }));
const pipeline = [
{ $match: match },
{
$facet: {
statusCounts: [
{ $group: { _id: { $ifNull: ['$status', 'unknown'] }, count: { $sum: 1 } } },
{ $group: { _id: null, counts: { $push: { k: '$_id', v: '$count' } } } },
{
$project: {
statusCounts: {
$arrayToObject: {
$concatArrays: [{ $literal: defaultCounts }, '$counts']
}
}
}
},
{ $replaceRoot: { newRoot: '$statusCounts' } }
],
tasksByName: [
{
$group: {
_id: '$name',
totalCount: { $sum: 1 },
lastRun: { $max: '$scheduledAt' },
pending: { $sum: { $cond: [{ $eq: ['$status', 'pending'] }, 1, 0] } },
succeeded: { $sum: { $cond: [{ $eq: ['$status', 'succeeded'] }, 1, 0] } },
failed: { $sum: { $cond: [{ $eq: ['$status', 'failed'] }, 1, 0] } },
cancelled: { $sum: { $cond: [{ $eq: ['$status', 'cancelled'] }, 1, 0] } }
}
},
{
$project: {
_id: 0,
name: '$_id',
totalCount: 1,
lastRun: 1,
statusCounts: {
pending: '$pending',
succeeded: '$succeeded',
failed: '$failed',
cancelled: '$cancelled'
}
}
},
{ $sort: { name: 1 } }
]
}
}
];
const [result] = await Task.aggregate(pipeline);
return {
statusCounts: result.statusCounts?.[0] ?? {},
tasksByName: result.tasksByName || []
};
};