@things-factory/dataset 6.2.87 → 7.0.0-alpha.1
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/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/data-ooc/data-ooc-subscription.js +4 -4
- package/dist-server/service/data-ooc/data-ooc-subscription.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +22 -22
- package/server/service/data-ooc/data-ooc-subscription.ts +7 -7
- package/dist-server/controllers/generate-data-summary.js +0 -329
- package/dist-server/controllers/generate-data-summary.js.map +0 -1
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@things-factory/dataset",
|
3
|
-
"version": "
|
3
|
+
"version": "7.0.0-alpha.1",
|
4
4
|
"main": "dist-server/index.js",
|
5
5
|
"browser": "dist-client/index.js",
|
6
6
|
"things-factory": true,
|
@@ -27,30 +27,30 @@
|
|
27
27
|
"migration:create": "node ../../node_modules/typeorm/cli.js migration:create -d ./server/migrations"
|
28
28
|
},
|
29
29
|
"dependencies": {
|
30
|
-
"@operato/app": "^
|
31
|
-
"@operato/data-grist": "^
|
32
|
-
"@operato/dataset": "^
|
33
|
-
"@operato/graphql": "^
|
34
|
-
"@operato/grist-editor": "^
|
35
|
-
"@operato/i18n": "^
|
36
|
-
"@operato/layout": "^
|
37
|
-
"@operato/shell": "^
|
38
|
-
"@operato/styles": "^
|
39
|
-
"@operato/utils": "^
|
40
|
-
"@things-factory/auth-base": "^
|
41
|
-
"@things-factory/aws-base": "^
|
42
|
-
"@things-factory/board-service": "^
|
43
|
-
"@things-factory/env": "^
|
44
|
-
"@things-factory/integration-base": "^
|
45
|
-
"@things-factory/organization": "^
|
46
|
-
"@things-factory/scheduler-client": "^
|
47
|
-
"@things-factory/shell": "^
|
48
|
-
"@things-factory/work-shift": "^
|
49
|
-
"@things-factory/worklist": "^
|
30
|
+
"@operato/app": "^2.0.0-alpha.0",
|
31
|
+
"@operato/data-grist": "^2.0.0-alpha.0",
|
32
|
+
"@operato/dataset": "^2.0.0-alpha.0",
|
33
|
+
"@operato/graphql": "^2.0.0-alpha.0",
|
34
|
+
"@operato/grist-editor": "^2.0.0-alpha.0",
|
35
|
+
"@operato/i18n": "^2.0.0-alpha.0",
|
36
|
+
"@operato/layout": "^2.0.0-alpha.0",
|
37
|
+
"@operato/shell": "^2.0.0-alpha.0",
|
38
|
+
"@operato/styles": "^2.0.0-alpha.0",
|
39
|
+
"@operato/utils": "^2.0.0-alpha.0",
|
40
|
+
"@things-factory/auth-base": "^7.0.0-alpha.1",
|
41
|
+
"@things-factory/aws-base": "^7.0.0-alpha.1",
|
42
|
+
"@things-factory/board-service": "^7.0.0-alpha.1",
|
43
|
+
"@things-factory/env": "^7.0.0-alpha.0",
|
44
|
+
"@things-factory/integration-base": "^7.0.0-alpha.1",
|
45
|
+
"@things-factory/organization": "^7.0.0-alpha.1",
|
46
|
+
"@things-factory/scheduler-client": "^7.0.0-alpha.1",
|
47
|
+
"@things-factory/shell": "^7.0.0-alpha.1",
|
48
|
+
"@things-factory/work-shift": "^7.0.0-alpha.1",
|
49
|
+
"@things-factory/worklist": "^7.0.0-alpha.1",
|
50
50
|
"cron-parser": "^4.3.0",
|
51
51
|
"moment-timezone": "^0.5.40",
|
52
52
|
"simple-statistics": "^7.8.3",
|
53
53
|
"statistics": "^3.3.0"
|
54
54
|
},
|
55
|
-
"gitHead": "
|
55
|
+
"gitHead": "778315d165d7f15e147583a45d5079c3d7cbce38"
|
56
56
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import {
|
1
|
+
import { filter, pipe } from 'graphql-yoga'
|
2
2
|
import { Resolver, Root, Subscription } from 'type-graphql'
|
3
3
|
|
4
4
|
import { User } from '@things-factory/auth-base'
|
@@ -9,7 +9,7 @@ import { DataOoc } from './data-ooc'
|
|
9
9
|
@Resolver(DataOoc)
|
10
10
|
export class DataOocSubscription {
|
11
11
|
@Subscription({
|
12
|
-
subscribe: (
|
12
|
+
subscribe: ({ args, context, info }) => {
|
13
13
|
const { domain, user } = context.state
|
14
14
|
const subdomain = domain?.subdomain
|
15
15
|
|
@@ -21,9 +21,9 @@ export class DataOocSubscription {
|
|
21
21
|
throw new Error(`domain(${subdomain}) is not working for user(${user.email}).`)
|
22
22
|
}
|
23
23
|
|
24
|
-
return
|
25
|
-
|
26
|
-
async (payload
|
24
|
+
return pipe(
|
25
|
+
pubsub.subscribe('data-ooc'),
|
26
|
+
filter(async (payload: { dataOoc: DataOoc; supervisoryRoleId: string }) => {
|
27
27
|
const { dataOoc, supervisoryRoleId } = payload
|
28
28
|
const { domain } = dataOoc
|
29
29
|
|
@@ -38,8 +38,8 @@ export class DataOocSubscription {
|
|
38
38
|
})
|
39
39
|
|
40
40
|
return !!userWithRoles.roles.find(role => role.id === supervisoryRoleId)
|
41
|
-
}
|
42
|
-
)
|
41
|
+
})
|
42
|
+
)
|
43
43
|
}
|
44
44
|
})
|
45
45
|
dataOoc(@Root() payload: { dataOoc: DataOoc; supervisoryRoleId: string }): DataOoc {
|
@@ -1,329 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.generateDataSummary = exports.generateLatestDataSummaries = exports.getDataSummaryCrontabSchedule = void 0;
|
4
|
-
const tslib_1 = require("tslib");
|
5
|
-
const statistics = require('simple-statistics');
|
6
|
-
const deepClone = require('lodash/cloneDeep');
|
7
|
-
const moment_timezone_1 = tslib_1.__importDefault(require("moment-timezone"));
|
8
|
-
const typeorm_1 = require("typeorm");
|
9
|
-
const shell_1 = require("@things-factory/shell");
|
10
|
-
const env_1 = require("@things-factory/env");
|
11
|
-
const work_shift_1 = require("@things-factory/work-shift");
|
12
|
-
const data_sample_1 = require("../service/data-sample/data-sample");
|
13
|
-
const data_set_1 = require("../service/data-set/data-set");
|
14
|
-
const data_summary_1 = require("../service/data-summary/data-summary");
|
15
|
-
const STAT_FUNCTION_MAP = {
|
16
|
-
sum: 'sum',
|
17
|
-
mean: 'mean',
|
18
|
-
stddev: 'standardDeviation',
|
19
|
-
variance: 'variance',
|
20
|
-
min: 'min',
|
21
|
-
max: 'max',
|
22
|
-
range: 'range',
|
23
|
-
median: 'median',
|
24
|
-
mode: 'mode'
|
25
|
-
};
|
26
|
-
const compareKeys = (dataKeyItems, summary, sample) => {
|
27
|
-
return dataKeyItems.every((item, index) => {
|
28
|
-
const prop = `key0${index + 1}`;
|
29
|
-
return sample[prop] === summary[prop];
|
30
|
-
});
|
31
|
-
};
|
32
|
-
const buildKeysFromSample = (dataKeyItems, sample) => {
|
33
|
-
return dataKeyItems.reduce((sum, item, index) => {
|
34
|
-
const prop = `key0${index + 1}`;
|
35
|
-
sum[prop] = sample[prop];
|
36
|
-
return sum;
|
37
|
-
}, {});
|
38
|
-
};
|
39
|
-
const buildKeySortingList = (dataKeyItems) => {
|
40
|
-
return dataKeyItems.reduce((sum, item, index) => {
|
41
|
-
const name = `key0${index + 1}`;
|
42
|
-
sum.push({ name, desc: true });
|
43
|
-
return sum;
|
44
|
-
}, []);
|
45
|
-
};
|
46
|
-
const calculateSummary = (dataItems, base) => {
|
47
|
-
return dataItems.reduce((summary, item) => {
|
48
|
-
const tag = item.tag;
|
49
|
-
const data = base[tag]
|
50
|
-
.flat(Infinity)
|
51
|
-
.map(Number)
|
52
|
-
.filter(item => !isNaN(item));
|
53
|
-
if (data.length > 0) {
|
54
|
-
try {
|
55
|
-
switch (item.stat) {
|
56
|
-
case 'range':
|
57
|
-
summary[tag] = statistics.max(data) - statistics.min(data);
|
58
|
-
break;
|
59
|
-
default:
|
60
|
-
const functionName = STAT_FUNCTION_MAP[item.stat];
|
61
|
-
summary[tag] = (functionName && statistics[functionName](data)) || '';
|
62
|
-
}
|
63
|
-
}
|
64
|
-
catch (err) {
|
65
|
-
summary[tag] = null;
|
66
|
-
console.error(err);
|
67
|
-
}
|
68
|
-
}
|
69
|
-
else {
|
70
|
-
summary[tag] = null;
|
71
|
-
}
|
72
|
-
return summary;
|
73
|
-
}, {});
|
74
|
-
};
|
75
|
-
const fillSummaryResult = (dataSummary, dataItems, base) => {
|
76
|
-
const summary = calculateSummary(dataItems, base);
|
77
|
-
dataSummary.summary = summary;
|
78
|
-
dataItems.slice(0, 4).forEach((dataItem, idx) => {
|
79
|
-
const value = Number(summary[dataItem.tag]);
|
80
|
-
dataSummary[`data0${idx + 1}`] = isNaN(value) ? null : value;
|
81
|
-
});
|
82
|
-
};
|
83
|
-
async function getLatestTimesForPeriod(periodType, context) {
|
84
|
-
const { domain } = context.state;
|
85
|
-
const now = (0, moment_timezone_1.default)();
|
86
|
-
if (periodType == data_set_1.DataSetSummaryPeriodType.Hour) {
|
87
|
-
const begin = now.clone().subtract(1, 'hour').startOf('hour');
|
88
|
-
const end = now.clone().startOf('hour');
|
89
|
-
const date = begin.clone().tz(domain.timezone);
|
90
|
-
return {
|
91
|
-
date: date.format('YYYY-MM-DD'),
|
92
|
-
period: date.format('HH'),
|
93
|
-
range: [begin.toDate(), end.toDate()]
|
94
|
-
};
|
95
|
-
}
|
96
|
-
else if (periodType == data_set_1.DataSetSummaryPeriodType.WorkShift) {
|
97
|
-
const { workDate, workShift, shiftRange } = await (0, work_shift_1.getLatestWorkDateAndShift)(domain, new Date());
|
98
|
-
return { date: workDate, period: workShift, range: shiftRange };
|
99
|
-
}
|
100
|
-
else if (periodType == data_set_1.DataSetSummaryPeriodType.WorkDate) {
|
101
|
-
const { workDate, dateRange } = await (0, work_shift_1.getLatestWorkDateAndShift)(domain, new Date());
|
102
|
-
return { date: workDate, range: dateRange };
|
103
|
-
}
|
104
|
-
else if (periodType == data_set_1.DataSetSummaryPeriodType.Day) {
|
105
|
-
const begin = now.clone().subtract(1, 'day').startOf('day');
|
106
|
-
const end = now.clone().startOf('day');
|
107
|
-
const date = begin.clone().tz(domain.timezone);
|
108
|
-
return {
|
109
|
-
date: date.format('YYYY-MM-DD'),
|
110
|
-
range: [begin.toDate(), end.toDate()]
|
111
|
-
};
|
112
|
-
}
|
113
|
-
}
|
114
|
-
async function getTimesForPeriod(periodType, date, period, context) {
|
115
|
-
const { domain } = context.state;
|
116
|
-
if (periodType == data_set_1.DataSetSummaryPeriodType.Hour) {
|
117
|
-
const theDate = moment_timezone_1.default.tz(`${date} ${period}:00:00`, 'YYYY-MM-DD HH:mm:ss', domain.timezone);
|
118
|
-
const begin = theDate.clone().startOf('hour').toDate();
|
119
|
-
const end = theDate.clone().add(+1, 'hour').startOf('hour').toDate();
|
120
|
-
return {
|
121
|
-
date,
|
122
|
-
period,
|
123
|
-
range: [begin, end]
|
124
|
-
};
|
125
|
-
}
|
126
|
-
else if (periodType == data_set_1.DataSetSummaryPeriodType.WorkShift) {
|
127
|
-
const range = await (0, work_shift_1.getDateRangeForWorkShift)(domain, date, period);
|
128
|
-
return { date, period, range };
|
129
|
-
}
|
130
|
-
else if (periodType == data_set_1.DataSetSummaryPeriodType.WorkDate) {
|
131
|
-
const range = await (0, work_shift_1.getDateRangeForWorkDate)(domain, date);
|
132
|
-
return { date, range };
|
133
|
-
}
|
134
|
-
else if (periodType == data_set_1.DataSetSummaryPeriodType.Day) {
|
135
|
-
const theDate = moment_timezone_1.default.tz(`${date} 00:00:00`, 'YYYY-MM-DD HH:mm:ss', domain.timezone);
|
136
|
-
const begin = theDate.clone().startOf('day').toDate();
|
137
|
-
const end = theDate.clone().add(1, 'day').startOf('day').toDate();
|
138
|
-
return {
|
139
|
-
date: (0, moment_timezone_1.default)(begin).tz(domain.timezone).format('YYYY-MM-DD'),
|
140
|
-
range: [begin, end]
|
141
|
-
};
|
142
|
-
}
|
143
|
-
}
|
144
|
-
async function getDataSummaryCrontabSchedule(dataSet, context) {
|
145
|
-
const { domain, user, tx } = context.state;
|
146
|
-
try {
|
147
|
-
const { summaryPeriod } = dataSet;
|
148
|
-
if (summaryPeriod == data_set_1.DataSetSummaryPeriodType.Hour) {
|
149
|
-
return '0 5 * * * *';
|
150
|
-
}
|
151
|
-
else if (summaryPeriod == data_set_1.DataSetSummaryPeriodType.WorkShift) {
|
152
|
-
return await (0, work_shift_1.getSummaryScheduleForWorkShift)(domain);
|
153
|
-
}
|
154
|
-
else if (summaryPeriod == data_set_1.DataSetSummaryPeriodType.WorkDate) {
|
155
|
-
return await (0, work_shift_1.getSummaryScheduleForWorkDate)(domain);
|
156
|
-
}
|
157
|
-
else if (summaryPeriod == data_set_1.DataSetSummaryPeriodType.Day) {
|
158
|
-
return '0 10 0 * * *';
|
159
|
-
}
|
160
|
-
}
|
161
|
-
catch (err) {
|
162
|
-
console.error(err);
|
163
|
-
}
|
164
|
-
}
|
165
|
-
exports.getDataSummaryCrontabSchedule = getDataSummaryCrontabSchedule;
|
166
|
-
async function generateLatestDataSummaries(dataSetId, context) {
|
167
|
-
var _a;
|
168
|
-
const { domain, user, tx } = context.state;
|
169
|
-
try {
|
170
|
-
const dataSet = await tx.getRepository(data_set_1.DataSet).findOne({
|
171
|
-
where: { domain: { id: (0, typeorm_1.In)([domain.id, domain.parentId].filter(Boolean)) }, id: dataSetId },
|
172
|
-
relations: ['dataKeySet']
|
173
|
-
});
|
174
|
-
const dataKeyItems = ((_a = dataSet.dataKeySet) === null || _a === void 0 ? void 0 : _a.dataKeyItems) || [];
|
175
|
-
const dataItems = dataSet.dataItems.filter(item => item.stat);
|
176
|
-
const initialSummary = dataItems.reduce((sum, item) => {
|
177
|
-
sum[item.tag] = [];
|
178
|
-
return sum;
|
179
|
-
}, {});
|
180
|
-
const { date, period, range } = await getLatestTimesForPeriod(dataSet.summaryPeriod, context);
|
181
|
-
const limit = 100;
|
182
|
-
var page = 1;
|
183
|
-
var summaries = [];
|
184
|
-
var summary;
|
185
|
-
do {
|
186
|
-
const samples = await (0, shell_1.getQueryBuilderFromListParams)({
|
187
|
-
repository: tx.getRepository(data_sample_1.DataSample),
|
188
|
-
domain,
|
189
|
-
params: {
|
190
|
-
filters: [{ name: 'dataSetId', operator: 'eq', value: dataSetId }],
|
191
|
-
pagination: { page, limit },
|
192
|
-
sortings: [...buildKeySortingList(dataKeyItems), { name: 'collectedAt', desc: true }]
|
193
|
-
},
|
194
|
-
alias: 'datasample'
|
195
|
-
})
|
196
|
-
// The 'Between' operator includes the 'to' time in the filtering, making it unsuitable for the desired use case.
|
197
|
-
// .andWhere({ collectedAt: Between.apply(null, range) })
|
198
|
-
.andWhere('datasample.collectedAt >= :from', { from: range[0] })
|
199
|
-
.andWhere('datasample.collectedAt < :to', { to: range[1] })
|
200
|
-
.getMany();
|
201
|
-
for (const sample of samples) {
|
202
|
-
if (!summary || !compareKeys(dataKeyItems, summary, sample)) {
|
203
|
-
if (summary) {
|
204
|
-
fillSummaryResult(summary, dataItems, summary.summary);
|
205
|
-
summaries.push(summary);
|
206
|
-
}
|
207
|
-
summary = Object.assign(Object.assign({ domain, name: dataSet.name, description: dataSet.description, date,
|
208
|
-
period,
|
209
|
-
dataSet }, buildKeysFromSample(dataKeyItems, sample)), { count: 0, countOoc: 0, countOos: 0, summary: deepClone(initialSummary), updater: user, creator: user });
|
210
|
-
}
|
211
|
-
summary.count++;
|
212
|
-
sample.ooc && summary.countOoc++;
|
213
|
-
sample.oos && summary.countOos++;
|
214
|
-
dataItems.forEach(item => {
|
215
|
-
summary.summary[item.tag].push(sample.data[item.tag]);
|
216
|
-
});
|
217
|
-
}
|
218
|
-
if (samples.length < limit) {
|
219
|
-
if (summary) {
|
220
|
-
fillSummaryResult(summary, dataItems, summary.summary);
|
221
|
-
summaries.push(summary);
|
222
|
-
}
|
223
|
-
break;
|
224
|
-
}
|
225
|
-
page++;
|
226
|
-
} while (true);
|
227
|
-
tx.getRepository(data_summary_1.DataSummary).upsert(summaries, [
|
228
|
-
'domain',
|
229
|
-
'dataSet',
|
230
|
-
'key01',
|
231
|
-
'key02',
|
232
|
-
'key03',
|
233
|
-
'key04',
|
234
|
-
'key05',
|
235
|
-
'date',
|
236
|
-
'period'
|
237
|
-
]);
|
238
|
-
return true;
|
239
|
-
}
|
240
|
-
catch (e) {
|
241
|
-
env_1.logger.error(e);
|
242
|
-
}
|
243
|
-
return false;
|
244
|
-
}
|
245
|
-
exports.generateLatestDataSummaries = generateLatestDataSummaries;
|
246
|
-
async function generateDataSummary(dataSetId, date, period, context) {
|
247
|
-
var _a;
|
248
|
-
const { domain, user, tx } = context.state;
|
249
|
-
try {
|
250
|
-
const dataSet = dataSetId &&
|
251
|
-
(await tx.getRepository(data_set_1.DataSet).findOne({
|
252
|
-
where: { domain: (0, typeorm_1.In)([domain.id, domain.parentId].filter(Boolean)), id: dataSetId },
|
253
|
-
relations: ['dataKeySet']
|
254
|
-
}));
|
255
|
-
const dataKeyItems = ((_a = dataSet.dataKeySet) === null || _a === void 0 ? void 0 : _a.dataKeyItems) || [];
|
256
|
-
const dataItems = dataSet.dataItems.filter(item => item.stat);
|
257
|
-
const initialSummary = dataItems.reduce((sum, item) => {
|
258
|
-
sum[item.tag] = [];
|
259
|
-
return sum;
|
260
|
-
}, {});
|
261
|
-
const times = await getTimesForPeriod(dataSet.summaryPeriod, date, period, context);
|
262
|
-
const range = times.range;
|
263
|
-
period = times.period;
|
264
|
-
const limit = 100;
|
265
|
-
var page = 1;
|
266
|
-
var summaries = [];
|
267
|
-
var summary;
|
268
|
-
do {
|
269
|
-
const samples = await (0, shell_1.getQueryBuilderFromListParams)({
|
270
|
-
repository: tx.getRepository(data_sample_1.DataSample),
|
271
|
-
params: {
|
272
|
-
filters: [{ name: 'dataSetId', operator: 'eq', value: dataSetId }],
|
273
|
-
pagination: { page, limit },
|
274
|
-
sortings: [...buildKeySortingList(dataKeyItems), { name: 'collectedAt', desc: true }]
|
275
|
-
},
|
276
|
-
domain,
|
277
|
-
alias: 'datasample'
|
278
|
-
})
|
279
|
-
// The 'Between' operator includes the 'to' time in the filtering, making it unsuitable for the desired use case.
|
280
|
-
// .andWhere({ collectedAt: Between.apply(null, range) })
|
281
|
-
.andWhere('datasample.collectedAt >= :from', { from: range[0] })
|
282
|
-
.andWhere('datasample.collectedAt < :to', { to: range[1] })
|
283
|
-
.getMany();
|
284
|
-
for (const sample of samples) {
|
285
|
-
if (!summary || !compareKeys(dataKeyItems, summary, sample)) {
|
286
|
-
if (summary) {
|
287
|
-
fillSummaryResult(summary, dataItems, summary.summary);
|
288
|
-
summaries.push(summary);
|
289
|
-
}
|
290
|
-
summary = Object.assign(Object.assign({ domain, name: dataSet.name, description: dataSet.description, date,
|
291
|
-
period,
|
292
|
-
dataSet }, buildKeysFromSample(dataKeyItems, sample)), { count: 0, countOoc: 0, countOos: 0, summary: deepClone(initialSummary), updater: user, creator: user });
|
293
|
-
}
|
294
|
-
summary.count++;
|
295
|
-
sample.ooc && summary.countOoc++;
|
296
|
-
sample.oos && summary.countOos++;
|
297
|
-
dataItems.forEach(item => {
|
298
|
-
summary.summary[item.tag].push(sample.data[item.tag]);
|
299
|
-
});
|
300
|
-
}
|
301
|
-
if (samples.length < limit) {
|
302
|
-
if (summary) {
|
303
|
-
fillSummaryResult(summary, dataItems, summary.summary);
|
304
|
-
summaries.push(summary);
|
305
|
-
}
|
306
|
-
break;
|
307
|
-
}
|
308
|
-
page++;
|
309
|
-
} while (true);
|
310
|
-
tx.getRepository(data_summary_1.DataSummary).upsert(summaries, [
|
311
|
-
'domain',
|
312
|
-
'dataSet',
|
313
|
-
'key01',
|
314
|
-
'key02',
|
315
|
-
'key03',
|
316
|
-
'key04',
|
317
|
-
'key05',
|
318
|
-
'date',
|
319
|
-
'period'
|
320
|
-
]);
|
321
|
-
return true;
|
322
|
-
}
|
323
|
-
catch (e) {
|
324
|
-
env_1.logger.error(e);
|
325
|
-
}
|
326
|
-
return false;
|
327
|
-
}
|
328
|
-
exports.generateDataSummary = generateDataSummary;
|
329
|
-
//# sourceMappingURL=generate-data-summary.js.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"generate-data-summary.js","sourceRoot":"","sources":["../../server/controllers/generate-data-summary.ts"],"names":[],"mappings":"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","sourcesContent":["const statistics = require('simple-statistics')\nconst deepClone = require('lodash/cloneDeep')\n\nimport moment from 'moment-timezone'\nimport { In } from 'typeorm'\n\nimport { Sorting, getQueryBuilderFromListParams } from '@things-factory/shell'\nimport { logger } from '@things-factory/env'\nimport {\n getDateRangeForWorkDate,\n getDateRangeForWorkShift,\n getLatestWorkDateAndShift,\n getSummaryScheduleForWorkDate,\n getSummaryScheduleForWorkShift\n} from '@things-factory/work-shift'\n\nimport { DataSample } from '../service/data-sample/data-sample'\nimport { DataSet, DataSetSummaryPeriodType } from '../service/data-set/data-set'\n\nimport { DataSummary } from '../service/data-summary/data-summary'\nimport { DataKeyItem } from '../service/data-key-set/data-key-item-type'\n\nimport { DataItem } from 'service'\n\nconst STAT_FUNCTION_MAP = {\n sum: 'sum',\n mean: 'mean',\n stddev: 'standardDeviation',\n variance: 'variance',\n min: 'min',\n max: 'max',\n range: 'range',\n median: 'median',\n mode: 'mode'\n}\n\nconst compareKeys = (dataKeyItems: DataKeyItem[], summary: Partial<DataSummary>, sample: DataSample): boolean => {\n return dataKeyItems.every((item, index) => {\n const prop = `key0${index + 1}`\n return sample[prop] === summary[prop]\n })\n}\n\nconst buildKeysFromSample = (dataKeyItems: DataKeyItem[], sample: DataSample): Partial<DataSummary> => {\n return dataKeyItems.reduce((sum, item, index) => {\n const prop = `key0${index + 1}`\n sum[prop] = sample[prop]\n\n return sum\n }, {} as Partial<DataSummary>)\n}\n\nconst buildKeySortingList = (dataKeyItems: DataKeyItem[]): Sorting[] => {\n return dataKeyItems.reduce((sum, item, index) => {\n const name = `key0${index + 1}`\n sum.push({ name, desc: true })\n return sum\n }, [])\n}\n\nconst calculateSummary = (dataItems: DataItem[], base: { [tag: string]: any[] }) => {\n return dataItems.reduce((summary, item) => {\n const tag = item.tag\n\n const data = base[tag]\n .flat(Infinity)\n .map(Number)\n .filter(item => !isNaN(item))\n\n if (data.length > 0) {\n try {\n switch (item.stat) {\n case 'range':\n summary[tag] = statistics.max(data) - statistics.min(data)\n break\n\n default:\n const functionName = STAT_FUNCTION_MAP[item.stat]\n summary[tag] = (functionName && statistics[functionName](data)) || ''\n }\n } catch (err) {\n summary[tag] = null\n console.error(err)\n }\n } else {\n summary[tag] = null\n }\n\n return summary\n }, {})\n}\n\nconst fillSummaryResult = (\n dataSummary: Partial<DataSummary>,\n dataItems: DataItem[],\n base: { [tag: string]: any[] }\n): void => {\n const summary = calculateSummary(dataItems, base)\n\n dataSummary.summary = summary\n dataItems.slice(0, 4).forEach((dataItem, idx) => {\n const value = Number(summary[dataItem.tag])\n dataSummary[`data0${idx + 1}`] = isNaN(value) ? null : value\n })\n}\n\nasync function getLatestTimesForPeriod(\n periodType: DataSetSummaryPeriodType,\n context: ResolverContext\n): Promise<{ date?: string; period?: string; range: Date[] }> {\n const { domain } = context.state\n const now = moment()\n\n if (periodType == DataSetSummaryPeriodType.Hour) {\n const begin = now.clone().subtract(1, 'hour').startOf('hour')\n const end = now.clone().startOf('hour')\n const date = begin.clone().tz(domain.timezone)\n\n return {\n date: date.format('YYYY-MM-DD'),\n period: date.format('HH'),\n range: [begin.toDate(), end.toDate()]\n }\n } else if (periodType == DataSetSummaryPeriodType.WorkShift) {\n const { workDate, workShift, shiftRange } = await getLatestWorkDateAndShift(domain, new Date())\n\n return { date: workDate, period: workShift, range: shiftRange }\n } else if (periodType == DataSetSummaryPeriodType.WorkDate) {\n const { workDate, dateRange } = await getLatestWorkDateAndShift(domain, new Date())\n\n return { date: workDate, range: dateRange }\n } else if (periodType == DataSetSummaryPeriodType.Day) {\n const begin = now.clone().subtract(1, 'day').startOf('day')\n const end = now.clone().startOf('day')\n const date = begin.clone().tz(domain.timezone)\n\n return {\n date: date.format('YYYY-MM-DD'),\n range: [begin.toDate(), end.toDate()]\n }\n }\n}\n\nasync function getTimesForPeriod(\n periodType: DataSetSummaryPeriodType,\n date: string,\n period: string,\n context: ResolverContext\n): Promise<{ date?: string; period?: string; range: Date[] }> {\n const { domain } = context.state\n\n if (periodType == DataSetSummaryPeriodType.Hour) {\n const theDate = moment.tz(`${date} ${period}:00:00`, 'YYYY-MM-DD HH:mm:ss', domain.timezone)\n\n const begin = theDate.clone().startOf('hour').toDate()\n const end = theDate.clone().add(+1, 'hour').startOf('hour').toDate()\n\n return {\n date,\n period,\n range: [begin, end]\n }\n } else if (periodType == DataSetSummaryPeriodType.WorkShift) {\n const range = await getDateRangeForWorkShift(domain, date, period)\n\n return { date, period, range }\n } else if (periodType == DataSetSummaryPeriodType.WorkDate) {\n const range = await getDateRangeForWorkDate(domain, date)\n\n return { date, range }\n } else if (periodType == DataSetSummaryPeriodType.Day) {\n const theDate = moment.tz(`${date} 00:00:00`, 'YYYY-MM-DD HH:mm:ss', domain.timezone)\n\n const begin = theDate.clone().startOf('day').toDate()\n const end = theDate.clone().add(1, 'day').startOf('day').toDate()\n\n return {\n date: moment(begin).tz(domain.timezone).format('YYYY-MM-DD'),\n range: [begin, end]\n }\n }\n}\n\nexport async function getDataSummaryCrontabSchedule(dataSet: DataSet, context: ResolverContext): Promise<string> {\n const { domain, user, tx } = context.state\n\n try {\n const { summaryPeriod } = dataSet\n\n if (summaryPeriod == DataSetSummaryPeriodType.Hour) {\n return '0 5 * * * *'\n } else if (summaryPeriod == DataSetSummaryPeriodType.WorkShift) {\n return await getSummaryScheduleForWorkShift(domain)\n } else if (summaryPeriod == DataSetSummaryPeriodType.WorkDate) {\n return await getSummaryScheduleForWorkDate(domain)\n } else if (summaryPeriod == DataSetSummaryPeriodType.Day) {\n return '0 10 0 * * *'\n }\n } catch (err) {\n console.error(err)\n }\n}\n\nexport async function generateLatestDataSummaries(dataSetId: string, context: ResolverContext): Promise<boolean> {\n const { domain, user, tx } = context.state\n\n try {\n const dataSet = await tx.getRepository(DataSet).findOne({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id: dataSetId },\n relations: ['dataKeySet']\n })\n\n const dataKeyItems = dataSet.dataKeySet?.dataKeyItems || []\n const dataItems = dataSet.dataItems.filter(item => item.stat)\n const initialSummary = dataItems.reduce((sum, item) => {\n sum[item.tag] = []\n return sum\n }, {})\n\n const { date, period, range } = await getLatestTimesForPeriod(dataSet.summaryPeriod, context)\n const limit = 100\n var page = 1\n\n var summaries: Partial<DataSummary>[] = []\n var summary: Partial<DataSummary>\n\n do {\n const samples = await getQueryBuilderFromListParams({\n repository: tx.getRepository(DataSample),\n domain,\n params: {\n filters: [{ name: 'dataSetId', operator: 'eq', value: dataSetId }],\n pagination: { page, limit },\n sortings: [...buildKeySortingList(dataKeyItems), { name: 'collectedAt', desc: true }]\n },\n alias: 'datasample'\n })\n // The 'Between' operator includes the 'to' time in the filtering, making it unsuitable for the desired use case.\n // .andWhere({ collectedAt: Between.apply(null, range) })\n .andWhere('datasample.collectedAt >= :from', { from: range[0] })\n .andWhere('datasample.collectedAt < :to', { to: range[1] })\n .getMany()\n\n for (const sample of samples) {\n if (!summary || !compareKeys(dataKeyItems, summary, sample)) {\n if (summary) {\n fillSummaryResult(summary, dataItems, summary.summary)\n summaries.push(summary)\n }\n\n summary = {\n domain,\n name: dataSet.name,\n description: dataSet.description,\n date,\n period,\n dataSet,\n ...buildKeysFromSample(dataKeyItems, sample),\n count: 0,\n countOoc: 0,\n countOos: 0,\n summary: deepClone(initialSummary),\n updater: user,\n creator: user\n }\n }\n\n summary.count++\n sample.ooc && summary.countOoc++\n sample.oos && summary.countOos++\n\n dataItems.forEach(item => {\n summary.summary[item.tag].push(sample.data[item.tag])\n })\n }\n\n if (samples.length < limit) {\n if (summary) {\n fillSummaryResult(summary, dataItems, summary.summary)\n summaries.push(summary)\n }\n break\n }\n\n page++\n } while (true)\n\n tx.getRepository(DataSummary).upsert(summaries, [\n 'domain',\n 'dataSet',\n 'key01',\n 'key02',\n 'key03',\n 'key04',\n 'key05',\n 'date',\n 'period'\n ])\n\n return true\n } catch (e) {\n logger.error(e)\n }\n\n return false\n}\n\nexport async function generateDataSummary(\n dataSetId: string,\n date: string,\n period: string,\n context: ResolverContext\n): Promise<boolean> {\n const { domain, user, tx } = context.state\n\n try {\n const dataSet =\n dataSetId &&\n (await tx.getRepository(DataSet).findOne({\n where: { domain: In([domain.id, domain.parentId].filter(Boolean)), id: dataSetId },\n relations: ['dataKeySet']\n }))\n\n const dataKeyItems = dataSet.dataKeySet?.dataKeyItems || []\n const dataItems = dataSet.dataItems.filter(item => item.stat)\n const initialSummary = dataItems.reduce((sum, item) => {\n sum[item.tag] = []\n return sum\n }, {})\n\n const times = await getTimesForPeriod(dataSet.summaryPeriod, date, period, context)\n const range = times.range\n period = times.period\n\n const limit = 100\n var page = 1\n\n var summaries: Partial<DataSummary>[] = []\n var summary: Partial<DataSummary>\n\n do {\n const samples = await getQueryBuilderFromListParams({\n repository: tx.getRepository(DataSample),\n params: {\n filters: [{ name: 'dataSetId', operator: 'eq', value: dataSetId }],\n pagination: { page, limit },\n sortings: [...buildKeySortingList(dataKeyItems), { name: 'collectedAt', desc: true }]\n },\n domain,\n alias: 'datasample'\n })\n // The 'Between' operator includes the 'to' time in the filtering, making it unsuitable for the desired use case.\n // .andWhere({ collectedAt: Between.apply(null, range) })\n .andWhere('datasample.collectedAt >= :from', { from: range[0] })\n .andWhere('datasample.collectedAt < :to', { to: range[1] })\n .getMany()\n\n for (const sample of samples) {\n if (!summary || !compareKeys(dataKeyItems, summary, sample)) {\n if (summary) {\n fillSummaryResult(summary, dataItems, summary.summary)\n summaries.push(summary)\n }\n\n summary = {\n domain,\n name: dataSet.name,\n description: dataSet.description,\n date,\n period,\n dataSet,\n ...buildKeysFromSample(dataKeyItems, sample),\n count: 0,\n countOoc: 0,\n countOos: 0,\n summary: deepClone(initialSummary),\n updater: user,\n creator: user\n }\n }\n\n summary.count++\n sample.ooc && summary.countOoc++\n sample.oos && summary.countOos++\n\n dataItems.forEach(item => {\n summary.summary[item.tag].push(sample.data[item.tag])\n })\n }\n\n if (samples.length < limit) {\n if (summary) {\n fillSummaryResult(summary, dataItems, summary.summary)\n summaries.push(summary)\n }\n break\n }\n\n page++\n } while (true)\n\n tx.getRepository(DataSummary).upsert(summaries, [\n 'domain',\n 'dataSet',\n 'key01',\n 'key02',\n 'key03',\n 'key04',\n 'key05',\n 'date',\n 'period'\n ])\n\n return true\n } catch (e) {\n logger.error(e)\n }\n\n return false\n}\n"]}
|