@things-factory/dataset 8.0.0 → 9.0.0-beta.3

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.
Files changed (147) hide show
  1. package/dist-client/activities/activity-data-review-edit.d.ts +5 -1
  2. package/dist-client/activities/activity-data-review-edit.js +143 -5
  3. package/dist-client/activities/activity-data-review-edit.js.map +1 -1
  4. package/dist-client/pages/data-entry/data-entry-list-page.js +2 -2
  5. package/dist-client/pages/data-entry/data-entry-list-page.js.map +1 -1
  6. package/dist-client/tsconfig.tsbuildinfo +1 -1
  7. package/dist-server/activities/activity-data-review.js +18 -5
  8. package/dist-server/activities/activity-data-review.js.map +1 -1
  9. package/dist-server/activities/activity-ooc-review.js +13 -52
  10. package/dist-server/activities/activity-ooc-review.js.map +1 -1
  11. package/dist-server/controllers/create-data-ooc.d.ts +4 -0
  12. package/dist-server/controllers/create-data-ooc.js +65 -0
  13. package/dist-server/controllers/create-data-ooc.js.map +1 -0
  14. package/dist-server/controllers/create-data-sample.js +4 -94
  15. package/dist-server/controllers/create-data-sample.js.map +1 -1
  16. package/dist-server/controllers/index.d.ts +3 -0
  17. package/dist-server/controllers/index.js +3 -0
  18. package/dist-server/controllers/index.js.map +1 -1
  19. package/dist-server/controllers/issue-ooc-resolve.d.ts +3 -0
  20. package/dist-server/controllers/issue-ooc-resolve.js +49 -0
  21. package/dist-server/controllers/issue-ooc-resolve.js.map +1 -0
  22. package/dist-server/controllers/issue-ooc-review.d.ts +3 -0
  23. package/dist-server/controllers/issue-ooc-review.js +47 -0
  24. package/dist-server/controllers/issue-ooc-review.js.map +1 -0
  25. package/dist-server/service/data-sample/data-sample-query.d.ts +1 -1
  26. package/dist-server/service/data-sample/data-sample-query.js +3 -3
  27. package/dist-server/service/data-sample/data-sample-query.js.map +1 -1
  28. package/dist-server/service/index.d.ts +1 -1
  29. package/dist-server/tsconfig.tsbuildinfo +1 -1
  30. package/package.json +26 -26
  31. package/translations/en.json +3 -0
  32. package/translations/ja.json +3 -0
  33. package/translations/ko.json +3 -0
  34. package/translations/ms.json +3 -0
  35. package/translations/zh.json +3 -0
  36. package/client/activities/activity-data-collect-edit.ts +0 -105
  37. package/client/activities/activity-data-collect-view.ts +0 -91
  38. package/client/activities/activity-data-review-edit.ts +0 -133
  39. package/client/activities/activity-data-review-view.ts +0 -145
  40. package/client/activities/activity-ooc-resolve-edit.ts +0 -195
  41. package/client/activities/activity-ooc-resolve-view.ts +0 -143
  42. package/client/activities/activity-ooc-review-edit.ts +0 -173
  43. package/client/activities/activity-ooc-review-view.ts +0 -129
  44. package/client/bootstrap.ts +0 -35
  45. package/client/components/data-entry-form.ts +0 -109
  46. package/client/index.ts +0 -1
  47. package/client/pages/data-archive/data-archive-list-page.ts +0 -277
  48. package/client/pages/data-archive/data-archive-request-popup.ts +0 -177
  49. package/client/pages/data-entry/data-entry-list-page.ts +0 -464
  50. package/client/pages/data-key-set/data-key-item-list.ts +0 -183
  51. package/client/pages/data-key-set/data-key-set-importer.ts +0 -89
  52. package/client/pages/data-key-set/data-key-set-list-page.ts +0 -413
  53. package/client/pages/data-ooc/data-ooc-list-page.ts +0 -549
  54. package/client/pages/data-ooc/data-ooc-page.ts +0 -164
  55. package/client/pages/data-ooc/data-ooc-view.ts +0 -236
  56. package/client/pages/data-ooc/data-oocs-page.ts +0 -200
  57. package/client/pages/data-report/data-report-embed-page.ts +0 -108
  58. package/client/pages/data-report/data-report-list-page.ts +0 -454
  59. package/client/pages/data-report/data-report-samples-page.ts +0 -174
  60. package/client/pages/data-report/jasper-report-oocs-page.ts +0 -110
  61. package/client/pages/data-report/jasper-report-samples-crosstab-page.ts +0 -110
  62. package/client/pages/data-report/jasper-report-samples-page.ts +0 -110
  63. package/client/pages/data-sample/data-sample-list-page.ts +0 -442
  64. package/client/pages/data-sample/data-sample-page.ts +0 -55
  65. package/client/pages/data-sample/data-sample-search-page.ts +0 -424
  66. package/client/pages/data-sample/data-sample-view.ts +0 -292
  67. package/client/pages/data-sample/data-samples-page.ts +0 -249
  68. package/client/pages/data-sensor/data-sensor-list-page.ts +0 -456
  69. package/client/pages/data-set/data-item-list.ts +0 -304
  70. package/client/pages/data-set/data-set-importer.ts +0 -89
  71. package/client/pages/data-set/data-set-list-page.ts +0 -1078
  72. package/client/pages/data-summary/data-summary-list-page.ts +0 -363
  73. package/client/pages/data-summary/data-summary-period-page.ts +0 -439
  74. package/client/pages/data-summary/data-summary-search-page.ts +0 -426
  75. package/client/pages/data-summary/data-summary-view.ts +0 -133
  76. package/client/route.ts +0 -91
  77. package/client/tsconfig.json +0 -13
  78. package/server/activities/activity-data-collect.ts +0 -100
  79. package/server/activities/activity-data-review.ts +0 -82
  80. package/server/activities/activity-ooc-resolve.ts +0 -123
  81. package/server/activities/activity-ooc-review.ts +0 -144
  82. package/server/activities/index.ts +0 -11
  83. package/server/controllers/create-data-sample.ts +0 -426
  84. package/server/controllers/data-use-case.ts +0 -98
  85. package/server/controllers/finalize-data-collection.ts +0 -388
  86. package/server/controllers/index.ts +0 -3
  87. package/server/controllers/issue-data-collection-task.ts +0 -70
  88. package/server/controllers/jasper-report.ts +0 -186
  89. package/server/controllers/query-data-summary-by-period.ts +0 -178
  90. package/server/controllers/shiny-report.ts +0 -54
  91. package/server/engine/index.ts +0 -1
  92. package/server/engine/task/create-data-sample.ts +0 -100
  93. package/server/engine/task/index.ts +0 -2
  94. package/server/engine/task/issue-collect-data.ts +0 -45
  95. package/server/index.ts +0 -8
  96. package/server/routes.ts +0 -188
  97. package/server/service/data-archive/data-archive-mutation.ts +0 -273
  98. package/server/service/data-archive/data-archive-query.ts +0 -58
  99. package/server/service/data-archive/data-archive-type.ts +0 -48
  100. package/server/service/data-archive/data-archive.ts +0 -69
  101. package/server/service/data-archive/index.ts +0 -6
  102. package/server/service/data-key-set/data-key-item-type.ts +0 -31
  103. package/server/service/data-key-set/data-key-set-mutation.ts +0 -201
  104. package/server/service/data-key-set/data-key-set-query.ts +0 -68
  105. package/server/service/data-key-set/data-key-set-type.ts +0 -70
  106. package/server/service/data-key-set/data-key-set.ts +0 -86
  107. package/server/service/data-key-set/index.ts +0 -6
  108. package/server/service/data-ooc/data-ooc-mutation.ts +0 -154
  109. package/server/service/data-ooc/data-ooc-query.ts +0 -106
  110. package/server/service/data-ooc/data-ooc-subscription.ts +0 -48
  111. package/server/service/data-ooc/data-ooc-type.ts +0 -71
  112. package/server/service/data-ooc/data-ooc.ts +0 -259
  113. package/server/service/data-ooc/index.ts +0 -7
  114. package/server/service/data-sample/data-sample-mutation.ts +0 -18
  115. package/server/service/data-sample/data-sample-query.ts +0 -215
  116. package/server/service/data-sample/data-sample-type.ts +0 -47
  117. package/server/service/data-sample/data-sample.ts +0 -193
  118. package/server/service/data-sample/index.ts +0 -6
  119. package/server/service/data-sensor/data-sensor-mutation.ts +0 -116
  120. package/server/service/data-sensor/data-sensor-query.ts +0 -76
  121. package/server/service/data-sensor/data-sensor-type.ts +0 -104
  122. package/server/service/data-sensor/data-sensor.ts +0 -126
  123. package/server/service/data-sensor/index.ts +0 -6
  124. package/server/service/data-set/data-item-type.ts +0 -155
  125. package/server/service/data-set/data-set-mutation.ts +0 -552
  126. package/server/service/data-set/data-set-query.ts +0 -461
  127. package/server/service/data-set/data-set-type.ts +0 -204
  128. package/server/service/data-set/data-set.ts +0 -326
  129. package/server/service/data-set/index.ts +0 -6
  130. package/server/service/data-set-history/data-set-history-query.ts +0 -126
  131. package/server/service/data-set-history/data-set-history-type.ts +0 -12
  132. package/server/service/data-set-history/data-set-history.ts +0 -217
  133. package/server/service/data-set-history/event-subscriber.ts +0 -17
  134. package/server/service/data-set-history/index.ts +0 -7
  135. package/server/service/data-spec/data-spec-manager.ts +0 -21
  136. package/server/service/data-spec/data-spec-query.ts +0 -21
  137. package/server/service/data-spec/data-spec.ts +0 -45
  138. package/server/service/data-spec/index.ts +0 -5
  139. package/server/service/data-summary/data-summary-mutation.ts +0 -45
  140. package/server/service/data-summary/data-summary-query.ts +0 -179
  141. package/server/service/data-summary/data-summary-type.ts +0 -86
  142. package/server/service/data-summary/data-summary.ts +0 -170
  143. package/server/service/data-summary/index.ts +0 -7
  144. package/server/service/index.ts +0 -57
  145. package/server/tsconfig.json +0 -10
  146. package/server/utils/config-resolver.ts +0 -29
  147. package/server/utils/index.ts +0 -1
@@ -1,388 +0,0 @@
1
- const statistics = require('simple-statistics')
2
- const deepClone = require('lodash/cloneDeep')
3
-
4
- import moment from 'moment-timezone'
5
- import { In } from 'typeorm'
6
-
7
- import { Sorting, getQueryBuilderFromListParams } from '@things-factory/shell'
8
- import { logger } from '@things-factory/env'
9
- import {
10
- getDateRangeForWorkDate,
11
- getDateRangeForWorkShift,
12
- getLatestWorkDateAndShift,
13
- getSummaryScheduleForWorkDate,
14
- getSummaryScheduleForWorkShift
15
- } from '@things-factory/work-shift'
16
-
17
- import { DataSample } from '../service/data-sample/data-sample'
18
- import { DataSet, DataSetSummaryPeriodType } from '../service/data-set/data-set'
19
-
20
- import { DataSummary } from '../service/data-summary/data-summary'
21
- import { DataKeyItem } from '../service/data-key-set/data-key-item-type'
22
-
23
- import { DataItem } from 'service'
24
-
25
- const STAT_FUNCTION_MAP = {
26
- sum: 'sum',
27
- mean: 'mean',
28
- stddev: 'standardDeviation',
29
- variance: 'variance',
30
- min: 'min',
31
- max: 'max',
32
- range: 'range',
33
- median: 'median',
34
- mode: 'mode'
35
- }
36
-
37
- const compareKeys = (dataKeyItems: DataKeyItem[], summary: Partial<DataSummary>, sample: DataSample): boolean => {
38
- return dataKeyItems.every((item, index) => {
39
- const prop = `key0${index + 1}`
40
- return sample[prop] === summary[prop]
41
- })
42
- }
43
-
44
- const buildKeysFromSample = (dataKeyItems: DataKeyItem[], sample: DataSample): Partial<DataSummary> => {
45
- return dataKeyItems.reduce((sum, item, index) => {
46
- const prop = `key0${index + 1}`
47
- sum[prop] = sample[prop]
48
-
49
- return sum
50
- }, {} as Partial<DataSummary>)
51
- }
52
-
53
- const buildKeySortingList = (dataKeyItems: DataKeyItem[]): Sorting[] => {
54
- return dataKeyItems.reduce((sum, item, index) => {
55
- const name = `key0${index + 1}`
56
- sum.push({ name, desc: true })
57
- return sum
58
- }, [])
59
- }
60
-
61
- const calculateSummary = (dataItems: DataItem[], base: { [tag: string]: any[] }) => {
62
- return dataItems.reduce((summary, item) => {
63
- const tag = item.tag
64
-
65
- const data = base[tag]
66
- .flat(Infinity)
67
- .map(Number)
68
- .filter(item => !isNaN(item))
69
-
70
- if (data.length > 0) {
71
- try {
72
- switch (item.stat) {
73
- case 'range':
74
- summary[tag] = statistics.max(data) - statistics.min(data)
75
- break
76
-
77
- default:
78
- const functionName = STAT_FUNCTION_MAP[item.stat]
79
- summary[tag] = (functionName && statistics[functionName](data)) || ''
80
- }
81
- } catch (err) {
82
- summary[tag] = null
83
- console.error(err)
84
- }
85
- } else {
86
- summary[tag] = null
87
- }
88
-
89
- return summary
90
- }, {})
91
- }
92
-
93
- const fillSummaryResult = (dataSummary: Partial<DataSummary>, dataItems: DataItem[], base: { [tag: string]: any[] }): void => {
94
- const summary = calculateSummary(dataItems, base)
95
-
96
- dataSummary.summary = summary
97
- dataItems.slice(0, 4).forEach((dataItem, idx) => {
98
- const value = Number(summary[dataItem.tag])
99
- dataSummary[`data0${idx + 1}`] = isNaN(value) ? null : value
100
- })
101
- }
102
-
103
- async function getLatestTimesForPeriod(periodType: DataSetSummaryPeriodType, context: ResolverContext): Promise<{ date?: string; period?: string; range: Date[] }> {
104
- const { domain } = context.state
105
- const now = moment()
106
-
107
- if (periodType == DataSetSummaryPeriodType.Hour) {
108
- const begin = now.clone().subtract(1, 'hour').startOf('hour')
109
- const end = now.clone().startOf('hour')
110
- const date = begin.clone().tz(domain.timezone)
111
-
112
- return {
113
- date: date.format('YYYY-MM-DD'),
114
- period: date.format('HH'),
115
- range: [begin.toDate(), end.toDate()]
116
- }
117
- } else if (periodType == DataSetSummaryPeriodType.WorkShift) {
118
- const { workDate, workShift, shiftRange } = await getLatestWorkDateAndShift(domain, new Date())
119
-
120
- return { date: workDate, period: workShift, range: shiftRange }
121
- } else if (periodType == DataSetSummaryPeriodType.WorkDate) {
122
- const { workDate, dateRange } = await getLatestWorkDateAndShift(domain, new Date())
123
-
124
- return { date: workDate, range: dateRange }
125
- } else if (periodType == DataSetSummaryPeriodType.Day) {
126
- const begin = now.clone().subtract(1, 'day').startOf('day')
127
- const end = now.clone().startOf('day')
128
- const date = begin.clone().tz(domain.timezone)
129
-
130
- return {
131
- date: date.format('YYYY-MM-DD'),
132
- range: [begin.toDate(), end.toDate()]
133
- }
134
- }
135
- }
136
-
137
- async function getTimesForPeriod(
138
- periodType: DataSetSummaryPeriodType,
139
- date: string,
140
- period: string,
141
- context: ResolverContext
142
- ): Promise<{ date?: string; period?: string; range: Date[] }> {
143
- const { domain } = context.state
144
-
145
- if (periodType == DataSetSummaryPeriodType.Hour) {
146
- const theDate = moment.tz(`${date} ${period}:00:00`, 'YYYY-MM-DD HH:mm:ss', domain.timezone)
147
-
148
- const begin = theDate.clone().startOf('hour').toDate()
149
- const end = theDate.clone().add(+1, 'hour').startOf('hour').toDate()
150
-
151
- return {
152
- date,
153
- period,
154
- range: [begin, end]
155
- }
156
- } else if (periodType == DataSetSummaryPeriodType.WorkShift) {
157
- const range = await getDateRangeForWorkShift(domain, date, period)
158
-
159
- return { date, period, range }
160
- } else if (periodType == DataSetSummaryPeriodType.WorkDate) {
161
- const range = await getDateRangeForWorkDate(domain, date)
162
-
163
- return { date, range }
164
- } else if (periodType == DataSetSummaryPeriodType.Day) {
165
- const theDate = moment.tz(`${date} 00:00:00`, 'YYYY-MM-DD HH:mm:ss', domain.timezone)
166
-
167
- const begin = theDate.clone().startOf('day').toDate()
168
- const end = theDate.clone().add(1, 'day').startOf('day').toDate()
169
-
170
- return {
171
- date: moment(begin).tz(domain.timezone).format('YYYY-MM-DD'),
172
- range: [begin, end]
173
- }
174
- }
175
- }
176
-
177
- export async function getDataFinalizeCrontabSchedule(dataSet: DataSet, context: ResolverContext): Promise<string> {
178
- const { domain, user, tx } = context.state
179
-
180
- try {
181
- const { summaryPeriod } = dataSet
182
-
183
- if (summaryPeriod == DataSetSummaryPeriodType.Hour) {
184
- return '0 5 * * * *'
185
- } else if (summaryPeriod == DataSetSummaryPeriodType.WorkShift) {
186
- return await getSummaryScheduleForWorkShift(domain)
187
- } else if (summaryPeriod == DataSetSummaryPeriodType.WorkDate) {
188
- return await getSummaryScheduleForWorkDate(domain)
189
- } else if (summaryPeriod == DataSetSummaryPeriodType.Day) {
190
- return '0 10 0 * * *'
191
- }
192
- } catch (err) {
193
- console.error(err)
194
- }
195
- }
196
-
197
- export async function finalizeLatestDataCollection(dataSetId: string, context: ResolverContext): Promise<boolean> {
198
- const { domain, user, tx } = context.state
199
-
200
- try {
201
- const dataSet = await tx.getRepository(DataSet).findOne({
202
- where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id: dataSetId },
203
- relations: ['dataKeySet']
204
- })
205
-
206
- const dataKeyItems = dataSet.dataKeySet?.dataKeyItems || []
207
- const dataItems = dataSet.dataItems.filter(item => item.stat)
208
- const initialSummary = dataItems.reduce((sum, item) => {
209
- sum[item.tag] = []
210
- return sum
211
- }, {})
212
-
213
- const { date, period, range } = await getLatestTimesForPeriod(dataSet.summaryPeriod, context)
214
- const limit = 100
215
- var page = 1
216
-
217
- var summaries: Partial<DataSummary>[] = []
218
- var summary: Partial<DataSummary>
219
-
220
- do {
221
- const samples = await getQueryBuilderFromListParams({
222
- repository: tx.getRepository(DataSample),
223
- domain,
224
- params: {
225
- filters: [{ name: 'dataSetId', operator: 'eq', value: dataSetId }],
226
- pagination: { page, limit },
227
- sortings: [...buildKeySortingList(dataKeyItems), { name: 'collectedAt', desc: true }]
228
- },
229
- alias: 'datasample'
230
- })
231
- // The 'Between' operator includes the 'to' time in the filtering, making it unsuitable for the desired use case.
232
- // .andWhere({ collectedAt: Between.apply(null, range) })
233
- .andWhere('datasample.collectedAt >= :from', { from: range[0] })
234
- .andWhere('datasample.collectedAt < :to', { to: range[1] })
235
- .getMany()
236
-
237
- for (const sample of samples) {
238
- if (!summary || !compareKeys(dataKeyItems, summary, sample)) {
239
- if (summary) {
240
- fillSummaryResult(summary, dataItems, summary.summary)
241
- summaries.push(summary)
242
- }
243
-
244
- summary = {
245
- domain,
246
- name: dataSet.name,
247
- description: dataSet.description,
248
- date,
249
- period,
250
- dataSet,
251
- ...buildKeysFromSample(dataKeyItems, sample),
252
- count: 0,
253
- countOoc: 0,
254
- countOos: 0,
255
- summary: deepClone(initialSummary),
256
- updater: user,
257
- creator: user
258
- }
259
- }
260
-
261
- summary.count++
262
- sample.ooc && summary.countOoc++
263
- sample.oos && summary.countOos++
264
-
265
- dataItems.forEach(item => {
266
- summary.summary[item.tag].push(sample.data[item.tag])
267
- })
268
- }
269
-
270
- if (samples.length < limit) {
271
- if (summary) {
272
- fillSummaryResult(summary, dataItems, summary.summary)
273
- summaries.push(summary)
274
- }
275
- break
276
- }
277
-
278
- page++
279
- } while (true)
280
-
281
- tx.getRepository(DataSummary).upsert(summaries, ['domain', 'dataSet', 'key01', 'key02', 'key03', 'key04', 'key05', 'date', 'period'])
282
-
283
- return true
284
- } catch (e) {
285
- logger.error(e)
286
- }
287
-
288
- return false
289
- }
290
-
291
- export async function finalizeDataCollection(dataSetId: string, date: string, period: string, context: ResolverContext): Promise<boolean> {
292
- const { domain, user, tx } = context.state
293
-
294
- try {
295
- const dataSet =
296
- dataSetId &&
297
- (await tx.getRepository(DataSet).findOne({
298
- where: { domain: In([domain.id, domain.parentId].filter(Boolean)), id: dataSetId },
299
- relations: ['dataKeySet']
300
- }))
301
-
302
- const dataKeyItems = dataSet.dataKeySet?.dataKeyItems || []
303
- const dataItems = dataSet.dataItems.filter(item => item.stat)
304
- const initialSummary = dataItems.reduce((sum, item) => {
305
- sum[item.tag] = []
306
- return sum
307
- }, {})
308
-
309
- const times = await getTimesForPeriod(dataSet.summaryPeriod, date, period, context)
310
- const range = times.range
311
- period = times.period
312
-
313
- const limit = 100
314
- var page = 1
315
-
316
- var summaries: Partial<DataSummary>[] = []
317
- var summary: Partial<DataSummary>
318
-
319
- do {
320
- const samples = await getQueryBuilderFromListParams({
321
- repository: tx.getRepository(DataSample),
322
- params: {
323
- filters: [{ name: 'dataSetId', operator: 'eq', value: dataSetId }],
324
- pagination: { page, limit },
325
- sortings: [...buildKeySortingList(dataKeyItems), { name: 'collectedAt', desc: true }]
326
- },
327
- domain,
328
- alias: 'datasample'
329
- })
330
- // The 'Between' operator includes the 'to' time in the filtering, making it unsuitable for the desired use case.
331
- // .andWhere({ collectedAt: Between.apply(null, range) })
332
- .andWhere('datasample.collectedAt >= :from', { from: range[0] })
333
- .andWhere('datasample.collectedAt < :to', { to: range[1] })
334
- .getMany()
335
-
336
- for (const sample of samples) {
337
- if (!summary || !compareKeys(dataKeyItems, summary, sample)) {
338
- if (summary) {
339
- fillSummaryResult(summary, dataItems, summary.summary)
340
- summaries.push(summary)
341
- }
342
-
343
- summary = {
344
- domain,
345
- name: dataSet.name,
346
- description: dataSet.description,
347
- date,
348
- period,
349
- dataSet,
350
- ...buildKeysFromSample(dataKeyItems, sample),
351
- count: 0,
352
- countOoc: 0,
353
- countOos: 0,
354
- summary: deepClone(initialSummary),
355
- updater: user,
356
- creator: user
357
- }
358
- }
359
-
360
- summary.count++
361
- sample.ooc && summary.countOoc++
362
- sample.oos && summary.countOos++
363
-
364
- dataItems.forEach(item => {
365
- summary.summary[item.tag].push(sample.data[item.tag])
366
- })
367
- }
368
-
369
- if (samples.length < limit) {
370
- if (summary) {
371
- fillSummaryResult(summary, dataItems, summary.summary)
372
- summaries.push(summary)
373
- }
374
- break
375
- }
376
-
377
- page++
378
- } while (true)
379
-
380
- tx.getRepository(DataSummary).upsert(summaries, ['domain', 'dataSet', 'key01', 'key02', 'key03', 'key04', 'key05', 'date', 'period'])
381
-
382
- return true
383
- } catch (e) {
384
- logger.error(e)
385
- }
386
-
387
- return false
388
- }
@@ -1,3 +0,0 @@
1
- export * from './create-data-sample'
2
- export * from './data-use-case'
3
- export * from './query-data-summary-by-period'
@@ -1,70 +0,0 @@
1
- import { In } from 'typeorm'
2
-
3
- import { Domain, getDataSource } from '@things-factory/shell'
4
- import { Activity, ActivityInstance, issue } from '@things-factory/worklist'
5
-
6
- import { DataSet } from '../service/data-set/data-set'
7
-
8
- export async function issueDataCollectionTask(
9
- domainId: string,
10
- dataSetId: string,
11
- context: ResolverContext
12
- ): Promise<ActivityInstance | void> {
13
- await getDataSource().transaction(async tx => {
14
- const domain = await tx.getRepository(Domain).findOneBy({ id: domainId })
15
-
16
- if (!domain) {
17
- throw new Error(`domain(${domainId}) not found`)
18
- }
19
-
20
- const dataSet = await tx.getRepository(DataSet).findOne({
21
- where: {
22
- domain: {
23
- id: In([domain.id, domain.parentId].filter(Boolean))
24
- },
25
- id: dataSetId
26
- },
27
- relations: ['entryRole']
28
- })
29
-
30
- const activity = (await tx.getRepository(Activity).findOneBy({
31
- domain: { id: In([domain.id, domain.parentId].filter(Boolean)) },
32
- name: 'Collect Data'
33
- })) as Activity
34
-
35
- if (activity) {
36
- const { entryRole, timeLimit } = dataSet
37
-
38
- /* 해당 dataset에 대한 데이타 수집 태스크를 dataset entryRole에게 할당한다. */
39
- if (entryRole) {
40
- const activityInstance = {
41
- name: `[Data 수집] ${dataSet.name}`,
42
- description: dataSet.description,
43
- activityId: activity.id,
44
- dueAt: new Date(Date.now() + (timeLimit || activity.standardTime || 24 * 60 * 60) * 1000),
45
- input: {
46
- dataSetId: dataSet.id,
47
- dataSetName: dataSet.name
48
- },
49
- assigneeRole: entryRole,
50
- threadsMin: 1,
51
- threadsMax: 1
52
- }
53
-
54
- context.state = {
55
- ...context.state,
56
- domain,
57
- tx
58
- }
59
-
60
- return await issue(activityInstance, context)
61
- } else {
62
- throw new Error(
63
- `Data Entry Role not set. So Data Collect Activity for ${dataSet.name}($dataSet.id) could not be issued.`
64
- )
65
- }
66
- } else {
67
- throw new Error(`Data Collect Activity is not installed.`)
68
- }
69
- })
70
- }
@@ -1,186 +0,0 @@
1
- import FormData from 'form-data'
2
- import fetch from 'node-fetch'
3
-
4
- import { getEndpointUrl } from '../utils/config-resolver'
5
-
6
- import { STORAGE } from '@things-factory/attachment-base'
7
- import { AthenaController } from '@things-factory/aws-base'
8
- import { config } from '@things-factory/env'
9
-
10
- const dataReportConfig = config.get('dataReport')
11
- const {
12
- jasper: {
13
- endpoint: ENDPOINT,
14
- datasource: { database: DATABASE }
15
- }
16
- } = dataReportConfig || {
17
- jasper: {
18
- endpoint: {},
19
- datasource: {}
20
- }
21
- }
22
-
23
- function transformValuesToRows(queryResult) {
24
- var parseData = []
25
- let index = 1
26
- for (let i = 0; i < queryResult.Items.length; i++) {
27
- var j = 0
28
- const data = JSON.parse(queryResult.Items[i].data)
29
- const spec = JSON.parse(queryResult.Items[i].spec)
30
-
31
- for (let key in data) {
32
- if (Array.isArray(data[key])) {
33
- for (j = 0; j < data[key].length; j++) {
34
- for (let specKey in spec) {
35
- if (key === specKey) {
36
- parseData.push({
37
- item: spec[specKey].name,
38
- index: index + j,
39
- value: String(data[key][j])
40
- })
41
- }
42
- }
43
- }
44
- } else {
45
- parseData.push({
46
- item: key,
47
- index,
48
- value: String(data[key])
49
- })
50
- }
51
- }
52
- if (j !== 0) {
53
- index = index + j
54
- } else {
55
- index = index + 1
56
- }
57
- }
58
- }
59
-
60
- /** @todo considering trasformation in lambda, as massive dataset */
61
- function pivotData(rows) {
62
- let parsedData = []
63
- let index = 1
64
- for (let i = 0; i < rows.length; i++) {
65
- let j = 0
66
- const data = JSON.parse(rows[i].data)
67
- const spec = JSON.parse(rows[i].spec)
68
-
69
- for (let key in data) {
70
- /** @todo rule to display or not, about unspecified spec */
71
- const value = data[key]
72
- !spec[key]?.hidden &&
73
- parsedData.push({
74
- item: spec[key]?.name || key,
75
- index,
76
- value: Array.isArray(value) ? value.join(', ') : value
77
- })
78
- }
79
- if (j !== 0) {
80
- index = index + j
81
- } else {
82
- index = index + 1
83
- }
84
- }
85
-
86
- return parsedData
87
- }
88
-
89
- function parseJsonDataField(rows) {
90
- let parsedData = []
91
- for (let i = 0; i < rows.length; i++) {
92
- const row = rows[i]
93
- const data = JSON.parse(row.data)
94
- for (let key in data) {
95
- if (Array.isArray(data[key])) {
96
- data[key] = data[key].toString()
97
- }
98
- }
99
- delete row.data
100
- parsedData.push({ ...row, ...data })
101
- }
102
-
103
- return parsedData
104
- }
105
-
106
- const athenaClient = new AthenaController()
107
-
108
- async function queryAthena(params) {
109
- const { table, domain, datasetId, startDate, endDate, workShift, timezone } = params
110
- const queryData = {
111
- sql: `SELECT ds.name, ds.description, ds.data, dsh.data_items as spec, ds.workdate, ds.workshift,
112
- DATE_FORMAT(
113
- FROM_UNIXTIME(collected_at / 1000 / 1000) AT TIME ZONE '${timezone || 'UTC'}',
114
- '%Y-%m-%d %H:%i:%s'
115
- ) AS dscollected_at
116
- FROM ${table} ds
117
- JOIN data_set_histories dsh
118
- ON (ds.datasetid = dsh.original_id
119
- and ds.data_set_version = dsh.version)
120
- WHERE ds.domain='${domain}'
121
- AND ds.datasetid = '${datasetId}'
122
- AND ds.workdate >= '${startDate}'
123
- AND ds.workdate <= '${endDate}'
124
- ${workShift ? "AND ds.workshift = '" + workShift + "'" : ''}
125
- ORDER BY ds.collected_at`,
126
- db: DATABASE
127
- }
128
- // and json_extract_scalar(data, '$.dauid') = 'A8032AD81730'
129
-
130
- return await athenaClient.query(queryData)
131
- }
132
-
133
- export async function renderJasperReport(context: any) {
134
- const {
135
- state: { domain },
136
- query
137
- } = context
138
-
139
- const template = await STORAGE.readFile(query['reportTemplate'] || 'dynamic_header_sample.jrxml', 'utf-8')
140
- let templateType = query['templateType'] || 'crosstab'
141
- let parsedData = []
142
-
143
- // @todo: get dataset timezone
144
- /**
145
- * const variables = await gql(dataSet(id:${dataSetId}) {
146
- * name, description, partition_keys, timezone
147
- * })
148
- */
149
-
150
- query['domain'] = domain?.subdomain
151
- query['timezone'] = domain?.timezone
152
- const queryResult = await queryAthena(query)
153
- const rows = queryResult.Items
154
-
155
- if (!rows.length) {
156
- return '<h3>Not found result.</h3>'
157
- } else {
158
- const firstRow = rows[0]
159
- // uses the first row values as data-set has no history data.
160
- const parameters = {
161
- name: firstRow.name,
162
- description: firstRow.description,
163
- ...query
164
- }
165
-
166
- if (templateType === 'crosstab') {
167
- parsedData = pivotData(rows)
168
- } else {
169
- parsedData = parseJsonDataField(rows)
170
- }
171
-
172
- const formData = new FormData()
173
- formData.append('template', template)
174
- formData.append('jsonString', JSON.stringify(parsedData))
175
- formData.append('parameters', JSON.stringify(parameters))
176
-
177
- const { reportView } = query
178
- const url = getEndpointUrl(ENDPOINT, reportView)
179
- const response = await fetch(url, {
180
- method: 'POST',
181
- body: formData
182
- })
183
-
184
- return await response.text()
185
- }
186
- }