@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/dataset",
3
- "version": "6.2.87",
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": "^1.0.1",
31
- "@operato/data-grist": "^1.3.5",
32
- "@operato/dataset": "^1.0.0",
33
- "@operato/graphql": "^1.0.0",
34
- "@operato/grist-editor": "^1.0.0",
35
- "@operato/i18n": "^1.0.0",
36
- "@operato/layout": "^1.0.1",
37
- "@operato/shell": "^1.0.1",
38
- "@operato/styles": "^1.0.0",
39
- "@operato/utils": "^1.0.1",
40
- "@things-factory/auth-base": "^6.2.84",
41
- "@things-factory/aws-base": "^6.2.86",
42
- "@things-factory/board-service": "^6.2.86",
43
- "@things-factory/env": "^6.2.33",
44
- "@things-factory/integration-base": "^6.2.86",
45
- "@things-factory/organization": "^6.2.84",
46
- "@things-factory/scheduler-client": "^6.2.84",
47
- "@things-factory/shell": "^6.2.84",
48
- "@things-factory/work-shift": "^6.2.84",
49
- "@things-factory/worklist": "^6.2.86",
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": "66920c55f3f7822378644fd0623e78744e73ebe4"
55
+ "gitHead": "778315d165d7f15e147583a45d5079c3d7cbce38"
56
56
  }
@@ -1,4 +1,4 @@
1
- import { withFilter } from 'graphql-subscriptions'
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: (_, args, context, info) => {
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 withFilter(
25
- () => pubsub.asyncIterator('data-ooc'),
26
- async (payload, variables, context, info) => {
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
- )(_, args, context, info)
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"]}