@things-factory/dataset 5.0.0-alpha.4 → 5.0.0-alpha.40

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 (97) hide show
  1. package/README.md +13 -0
  2. package/assets/data-samples.jpg +0 -0
  3. package/client/bootstrap.js +21 -1
  4. package/client/pages/{data-entry-form.js → data-entry/data-entry-form.js} +15 -2
  5. package/client/pages/data-entry/data-entry-list-page.js +423 -0
  6. package/client/pages/data-ooc/data-ooc-list-page.js +488 -0
  7. package/client/pages/data-ooc/data-ooc-view.js +182 -0
  8. package/client/pages/data-report/data-report-list-page.js +463 -0
  9. package/client/pages/{data-sample.js → data-sample/data-sample-list-page.js} +151 -76
  10. package/client/pages/data-sample/data-sample-view.js +97 -0
  11. package/client/pages/{data-sensor.js → data-sensor/data-sensor-list-page.js} +7 -12
  12. package/client/pages/{data-item-list.js → data-set/data-item-list.js} +37 -12
  13. package/client/pages/{data-set-importer.js → data-set/data-set-importer.js} +0 -0
  14. package/client/pages/data-set/data-set-list-page.js +727 -0
  15. package/client/route.js +18 -6
  16. package/dist-server/controllers/create-data-sample.js +133 -0
  17. package/dist-server/controllers/create-data-sample.js.map +1 -0
  18. package/dist-server/controllers/data-use-case.js +57 -0
  19. package/dist-server/controllers/data-use-case.js.map +1 -0
  20. package/dist-server/controllers/index.js +17 -0
  21. package/dist-server/controllers/index.js.map +1 -1
  22. package/dist-server/index.js +1 -0
  23. package/dist-server/index.js.map +1 -1
  24. package/dist-server/routes.js +9 -24
  25. package/dist-server/routes.js.map +1 -1
  26. package/dist-server/service/data-item/data-item-mutation.js +5 -1
  27. package/dist-server/service/data-item/data-item-mutation.js.map +1 -1
  28. package/dist-server/service/data-item/data-item-query.js +7 -2
  29. package/dist-server/service/data-item/data-item-query.js.map +1 -1
  30. package/dist-server/service/data-item/data-item-type.js +15 -7
  31. package/dist-server/service/data-item/data-item-type.js.map +1 -1
  32. package/dist-server/service/data-item/data-item.js +17 -3
  33. package/dist-server/service/data-item/data-item.js.map +1 -1
  34. package/dist-server/service/data-ooc/data-ooc-mutation.js +92 -0
  35. package/dist-server/service/data-ooc/data-ooc-mutation.js.map +1 -0
  36. package/dist-server/service/data-ooc/data-ooc-query.js +120 -0
  37. package/dist-server/service/data-ooc/data-ooc-query.js.map +1 -0
  38. package/dist-server/service/data-ooc/data-ooc-subscription.js +65 -0
  39. package/dist-server/service/data-ooc/data-ooc-subscription.js.map +1 -0
  40. package/dist-server/service/data-ooc/data-ooc-type.js +107 -0
  41. package/dist-server/service/data-ooc/data-ooc-type.js.map +1 -0
  42. package/dist-server/service/data-ooc/data-ooc.js +237 -0
  43. package/dist-server/service/data-ooc/data-ooc.js.map +1 -0
  44. package/dist-server/service/data-ooc/index.js +10 -0
  45. package/dist-server/service/data-ooc/index.js.map +1 -0
  46. package/dist-server/service/data-sample/data-sample-mutation.js +2 -138
  47. package/dist-server/service/data-sample/data-sample-mutation.js.map +1 -1
  48. package/dist-server/service/data-sample/data-sample-query.js +7 -2
  49. package/dist-server/service/data-sample/data-sample-query.js.map +1 -1
  50. package/dist-server/service/data-sample/data-sample-type.js +12 -42
  51. package/dist-server/service/data-sample/data-sample-type.js.map +1 -1
  52. package/dist-server/service/data-sample/data-sample.js +34 -3
  53. package/dist-server/service/data-sample/data-sample.js.map +1 -1
  54. package/dist-server/service/data-sensor/data-sensor-query.js +7 -2
  55. package/dist-server/service/data-sensor/data-sensor-query.js.map +1 -1
  56. package/dist-server/service/data-set/data-set-mutation.js +1 -2
  57. package/dist-server/service/data-set/data-set-mutation.js.map +1 -1
  58. package/dist-server/service/data-set/data-set-query.js +162 -3
  59. package/dist-server/service/data-set/data-set-query.js.map +1 -1
  60. package/dist-server/service/data-set/data-set-type.js +75 -3
  61. package/dist-server/service/data-set/data-set-type.js.map +1 -1
  62. package/dist-server/service/data-set/data-set.js +106 -15
  63. package/dist-server/service/data-set/data-set.js.map +1 -1
  64. package/dist-server/service/index.js +6 -2
  65. package/dist-server/service/index.js.map +1 -1
  66. package/package.json +18 -13
  67. package/server/controllers/create-data-sample.ts +177 -0
  68. package/server/controllers/data-use-case.ts +85 -0
  69. package/server/controllers/index.ts +1 -0
  70. package/server/index.ts +1 -0
  71. package/server/routes.ts +17 -31
  72. package/server/service/data-item/data-item-mutation.ts +6 -1
  73. package/server/service/data-item/data-item-query.ts +9 -3
  74. package/server/service/data-item/data-item-type.ts +10 -6
  75. package/server/service/data-item/data-item.ts +15 -4
  76. package/server/service/data-ooc/data-ooc-mutation.ts +150 -0
  77. package/server/service/data-ooc/data-ooc-query.ts +69 -0
  78. package/server/service/data-ooc/data-ooc-subscription.ts +51 -0
  79. package/server/service/data-ooc/data-ooc-type.ts +68 -0
  80. package/server/service/data-ooc/data-ooc.ts +204 -0
  81. package/server/service/data-ooc/index.ts +7 -0
  82. package/server/service/data-sample/data-sample-mutation.ts +3 -172
  83. package/server/service/data-sample/data-sample-query.ts +9 -3
  84. package/server/service/data-sample/data-sample-type.ts +7 -28
  85. package/server/service/data-sample/data-sample.ts +33 -3
  86. package/server/service/data-sensor/data-sensor-query.ts +9 -3
  87. package/server/service/data-set/data-set-mutation.ts +1 -4
  88. package/server/service/data-set/data-set-query.ts +135 -4
  89. package/server/service/data-set/data-set-type.ts +58 -4
  90. package/server/service/data-set/data-set.ts +97 -12
  91. package/server/service/index.ts +6 -2
  92. package/things-factory.config.js +18 -6
  93. package/translations/en.json +45 -3
  94. package/translations/ko.json +44 -3
  95. package/translations/ms.json +44 -3
  96. package/translations/zh.json +44 -3
  97. package/client/pages/data-set.js +0 -457
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/dataset",
3
- "version": "5.0.0-alpha.4",
3
+ "version": "5.0.0-alpha.40",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "client/index.js",
6
6
  "things-factory": true,
@@ -24,17 +24,22 @@
24
24
  "migration:create": "node ../../node_modules/typeorm/cli.js migration:create -d ./server/migrations"
25
25
  },
26
26
  "dependencies": {
27
- "@operato/data-grist": "1.0.0-alpha.4",
28
- "@operato/dataset": "1.0.0-alpha.4",
29
- "@operato/graphql": "1.0.0-alpha.4",
30
- "@operato/i18n": "1.0.0-alpha.4",
31
- "@operato/layout": "1.0.0-alpha.4",
32
- "@operato/shell": "1.0.0-alpha.4",
33
- "@operato/styles": "1.0.0-alpha.4",
34
- "@operato/utils": "1.0.0-alpha.4",
35
- "@things-factory/auth-base": "^5.0.0-alpha.4",
36
- "@things-factory/env": "^5.0.0-alpha.4",
37
- "@things-factory/shell": "^5.0.0-alpha.4"
27
+ "@operato/app": "1.0.0-beta.7",
28
+ "@operato/data-grist": "1.0.0-beta.7",
29
+ "@operato/dataset": "1.0.0-beta.7",
30
+ "@operato/graphql": "1.0.0-beta.7",
31
+ "@operato/i18n": "1.0.0-beta.7",
32
+ "@operato/layout": "1.0.0-beta.7",
33
+ "@operato/shell": "1.0.0-beta.7",
34
+ "@operato/styles": "1.0.0-beta.7",
35
+ "@operato/utils": "1.0.0-beta.7",
36
+ "@things-factory/auth-base": "^5.0.0-alpha.40",
37
+ "@things-factory/board-service": "^5.0.0-alpha.40",
38
+ "@things-factory/env": "^5.0.0-alpha.40",
39
+ "@things-factory/shell": "^5.0.0-alpha.40",
40
+ "@things-factory/work-shift": "^5.0.0-alpha.40",
41
+ "cron-parser": "^4.3.0",
42
+ "moment-timezone": "^0.5.34"
38
43
  },
39
- "gitHead": "77253f86954dc6f5c14356ea85887c323fd2511a"
44
+ "gitHead": "c64462e85c9b744250f5649d28c0ec4bd56a1b38"
40
45
  }
@@ -0,0 +1,177 @@
1
+ import moment from 'moment-timezone'
2
+ import { EntityManager } from 'typeorm'
3
+
4
+ import { User } from '@things-factory/auth-base'
5
+ import { Domain, getRedirectSubdomainPath, pubsub } from '@things-factory/shell'
6
+
7
+ import { DataItem } from '../service/data-item/data-item'
8
+ import { DataOoc, DataOocStatus } from '../service/data-ooc/data-ooc'
9
+ import { DataSample } from '../service/data-sample/data-sample'
10
+ import { NewDataSample } from '../service/data-sample/data-sample-type'
11
+ import { DataSet } from '../service/data-set/data-set'
12
+ import { DataUseCase } from './data-use-case'
13
+ import { getWorkDateAndShift } from '@things-factory/work-shift'
14
+
15
+
16
+ const debug = require('debug')('things-factory:dataset:controller/save-data-sample')
17
+
18
+ // parse variable javascript string pattern
19
+ const replaceVariables = (keys, dic) => {
20
+ for (const k in keys) {
21
+ const matches = keys[k].match(/\$\{\w*\}/g)
22
+ matches &&
23
+ matches.forEach(m => {
24
+ keys[k] = keys[k].replace(m, dic[m.slice(2, -1)])
25
+ })
26
+ }
27
+ return keys
28
+ }
29
+
30
+ // It is required UTC date for Partitioning File System like AWS S3 from Athena.
31
+ // ex) %YYYY, %MM, %DD
32
+ const formatDate = (keys, _moment) => {
33
+ for (const k in keys) {
34
+ const matches = keys[k].match(/%\w*/g)
35
+ matches &&
36
+ matches.forEach(m => {
37
+ keys[k] = keys[k].replace(m, _moment.format(m.substr(1)))
38
+ })
39
+ }
40
+ return keys
41
+ }
42
+
43
+ export async function createDataSample(
44
+ dataSample: NewDataSample,
45
+ context: {
46
+ state: {
47
+ domain: Domain
48
+ user: User
49
+ tx: EntityManager
50
+ }
51
+ }
52
+ ): Promise<DataSample> {
53
+ const { domain, user, tx } = context.state
54
+
55
+ const dataSet = await tx.getRepository(DataSet).findOne({
56
+ where: { id: dataSample.dataSet.id }
57
+ })
58
+
59
+ const dataItems = await tx.getRepository(DataItem).find({
60
+ where: {
61
+ domain,
62
+ dataSet
63
+ },
64
+ order: {
65
+ sequence: 'DESC'
66
+ }
67
+ })
68
+
69
+ const spec = dataItems.reduce((spec, dataItem) => {
70
+ spec[dataItem.tag] = {
71
+ ...dataItem.spec,
72
+ name: dataItem.name, /* do we need ? */
73
+ hidden: dataItem.hidden
74
+ }
75
+
76
+ return spec
77
+ }, {})
78
+
79
+ const collectedAt = dataSample.collectedAt || new Date()
80
+
81
+ const timezone = dataSet.timezone || domain.timezone || 'UTC'
82
+ const format = 'YYYY-MM-DD'
83
+
84
+ // workDate ex) 2022-04-04
85
+ const { workDate, workShift } = await getWorkDateAndShift(domain, collectedAt, { timezone, format })
86
+
87
+ // local time dataSet timezone or domain timezone or default 'UTC'
88
+
89
+ // const collectedAt = dataSample.collectedAt || new Date()
90
+ const localDateTz = moment(collectedAt).tz(timezone)
91
+ const defaultPartitionKeys = {
92
+ domain: domain.subdomain,
93
+ datasetid: dataSample.dataSet.id, /* It should not be 'data_set_id' as column name duplicated for Glue */
94
+ date: localDateTz.format(format), /* local time date */
95
+ workdate: workDate, /* working date */
96
+ workshift: workShift
97
+ }
98
+
99
+ var partitionKeys = {
100
+ ...defaultPartitionKeys,
101
+ ...dataSet.partitionKeys
102
+ }
103
+
104
+ partitionKeys = formatDate(partitionKeys, localDateTz)
105
+ partitionKeys = replaceVariables(partitionKeys, {
106
+ ...dataSample.data
107
+ })
108
+
109
+ const { ooc, oos } = DataUseCase.evaluate(dataSet, dataItems, dataSample.data) || {}
110
+ const result = await tx.getRepository(DataSample).save({
111
+ name: dataSet.name,
112
+ description: dataSet.description,
113
+ useCase: dataSet.useCase,
114
+ ...dataSample,
115
+ domain,
116
+ partitionKeys,
117
+ spec,
118
+ ooc,
119
+ oos,
120
+ collectedAt,
121
+ workDate,
122
+ workShift,
123
+ creator: user,
124
+ updater: user
125
+ })
126
+
127
+ if (ooc || oos) {
128
+ const dataOoc = await tx.getRepository(DataOoc).save({
129
+ name: dataSet.name,
130
+ description: dataSet.description,
131
+ useCase: dataSet.useCase,
132
+ dataSet,
133
+ dataSample: result,
134
+ data: dataSample.data,
135
+ rawData: dataSample.rawData,
136
+ domain,
137
+ partitionKeys,
138
+ spec,
139
+ ooc,
140
+ oos,
141
+ history: [
142
+ {
143
+ user: {
144
+ id: user.id,
145
+ name: user.name
146
+ },
147
+ state: DataOocStatus.CREATED,
148
+ timestamp: Date.now()
149
+ }
150
+ ],
151
+ state: DataOocStatus.CREATED,
152
+ workDate,
153
+ workShift,
154
+ collectedAt,
155
+ creator: user,
156
+ updater: user
157
+ })
158
+
159
+ pubsub.publish('data-ooc', {
160
+ dataOoc,
161
+ supervisoryRoleId: dataSet.supervisoryRoleId
162
+ })
163
+
164
+ pubsub.publish('notification', {
165
+ notification: {
166
+ domain,
167
+ type: 'error',
168
+ title: `Data OOC occurred on '${dataSet.name}'`,
169
+ body: `Data OOC occurred on '${dataSet.name}'`,
170
+ url: getRedirectSubdomainPath(context, domain.subdomain, `/data-ooc/${dataOoc.id}`),
171
+ timestamp: collectedAt
172
+ }
173
+ })
174
+ }
175
+
176
+ return result
177
+ }
@@ -0,0 +1,85 @@
1
+ import { DataItem, DataSet } from 'server/service'
2
+
3
+ export type DataItemSpec = {
4
+ type: string
5
+ label: string
6
+ name: string
7
+ property: { [option: string]: any }
8
+ }
9
+
10
+ export type DataItemSpecSet = {
11
+ name: string
12
+ description: string
13
+ specs: DataItemSpec[]
14
+ }
15
+
16
+ export type EvaluationResult = { oos: boolean; ooc: boolean }
17
+
18
+ export abstract class DataUseCase {
19
+ static registry: { [name: string]: DataUseCase } = {}
20
+
21
+ public static registerUseCase(name: string, provider: DataUseCase) {
22
+ DataUseCase.registry[name] = provider
23
+ }
24
+
25
+ public static getUseCaseNames() {
26
+ return Object.keys(DataUseCase.registry)
27
+ }
28
+
29
+ public static getUseCase(name: string): DataUseCase | undefined {
30
+ return DataUseCase.registry[name]
31
+ }
32
+
33
+ public static evaluate(dataSet: DataSet, dataItems: DataItem[], data: any): EvaluationResult {
34
+ var ooc = false
35
+ var oos = false
36
+
37
+ if (!dataSet.useCase) {
38
+ return { ooc, oos }
39
+ }
40
+
41
+ const useCaseNames = dataSet.useCase.split(',').map(useCaseName => useCaseName.trim())
42
+ const useCases = useCaseNames.map(useCaseName => DataUseCase.getUseCase(useCaseName)).filter(useCase => !!useCase)
43
+
44
+ for (let i = 0; i < dataItems.length; i++) {
45
+ const dataItem = dataItems[i]
46
+ const { active, tag } = dataItem
47
+ if (!active || !tag) {
48
+ continue
49
+ }
50
+
51
+ let values: any | any[] = data[tag]
52
+ if (typeof values === 'undefined') {
53
+ continue // TODO what if in case no value ?
54
+ }
55
+
56
+ if (!(values instanceof Array)) {
57
+ values = [values]
58
+ }
59
+
60
+ for (let j = 0; j < useCases.length; j++) {
61
+ const useCase = useCases[j]
62
+
63
+ const specs = dataItem.spec?.[dataSet.useCase]
64
+ if (!specs) {
65
+ continue
66
+ }
67
+
68
+ const result = useCase.evaluate(specs, values)
69
+
70
+ if (result) {
71
+ ooc ||= result.ooc
72
+ oos ||= result.oos
73
+ }
74
+
75
+ // if (ooc && oos) {
76
+ // return { ooc, oos }
77
+ // }
78
+ }
79
+ }
80
+
81
+ return { ooc, oos }
82
+ }
83
+
84
+ public abstract evaluate(specs: any, values: any[]): EvaluationResult
85
+ }
@@ -0,0 +1 @@
1
+ export * from './data-use-case'
package/server/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import './routes'
2
2
 
3
+ export * from './controllers'
3
4
  export * from './migrations'
4
5
  export * from './middlewares'
5
6
  export * from './service'
package/server/routes.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { getConnection } from 'typeorm'
2
2
 
3
- import { DataSample } from './service'
4
- import { DataItem } from './service/data-item/data-item'
3
+ import { User } from '@things-factory/auth-base'
4
+
5
+ import { createDataSample } from './controllers/create-data-sample'
5
6
  import { DataSensor } from './service/data-sensor/data-sensor'
6
7
 
7
8
  const debug = require('debug')('things-factory:dataset:routes')
@@ -47,41 +48,26 @@ process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRout
47
48
 
48
49
  const domain = sensor.domain
49
50
  const dataSet = sensor.dataSet
50
- const user = sensor.appliance
51
-
52
- const dataItems = await tx.getRepository(DataItem).find({
51
+ const user: User = await tx.getRepository(User).findOne({
53
52
  where: {
54
- domain,
55
- dataSet
56
- },
57
- order: {
58
- sequence: 'DESC'
53
+ reference: sensor.appliance.id,
54
+ userType: 'appliance'
59
55
  }
60
56
  })
61
57
 
62
- var spec = {} as any
63
-
64
- dataItems.forEach(dataItem => {
65
- spec[dataItem.name] = dataItem.spec
66
- })
67
-
68
- await tx.getRepository(DataSample).save({
69
- domain,
70
- name: dataSet.name,
71
- description: dataSet.description,
72
- partitionKeys: dataSet.partitionKeys,
73
- dataSet,
74
- data,
75
- rawData,
76
- spec,
77
- source: deviceId,
78
- collectedAt: new Date(timestamp),
79
- creator: user,
80
- updater: user
81
- })
58
+ return await createDataSample(
59
+ {
60
+ dataSet,
61
+ data,
62
+ rawData,
63
+ source: deviceId,
64
+ collectedAt: new Date(timestamp)
65
+ },
66
+ { state: { domain, user, tx } }
67
+ )
82
68
  })
83
69
 
84
- return 'OK'
70
+ context.status = 200
85
71
  })
86
72
  })
87
73
 
@@ -24,9 +24,14 @@ export class DataItemMutation {
24
24
  await dataItemRepo.delete({ domain, dataSet: dataSetId })
25
25
 
26
26
  for (let i = 0; i < patches.length; i++) {
27
+ const patch = patches[i]
28
+ if (!patch.options) {
29
+ patch.options = {}
30
+ }
31
+
27
32
  const result = await dataItemRepo.save({
28
33
  quota: 1,
29
- ...patches[i],
34
+ ...patch,
30
35
  sequence: i,
31
36
  dataSet,
32
37
  domain,
@@ -2,7 +2,7 @@ import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from
2
2
  import { getRepository } from 'typeorm'
3
3
 
4
4
  import { User } from '@things-factory/auth-base'
5
- import { convertListParams, Domain, ListParam } from '@things-factory/shell'
5
+ import { Domain, getQueryBuilderFromListParams, ListParam } from '@things-factory/shell'
6
6
 
7
7
  import { DataSet } from '../data-set/data-set'
8
8
  import { DataItem } from './data-item'
@@ -25,8 +25,14 @@ export class DataItemQuery {
25
25
  async dataItems(@Args() params: ListParam, @Ctx() context: any): Promise<DataItemList> {
26
26
  const { domain } = context.state
27
27
 
28
- const convertedParams = convertListParams(params, domain.id)
29
- const [items, total] = await getRepository(DataItem).findAndCount(convertedParams)
28
+ const queryBuilder = getQueryBuilderFromListParams({
29
+ repository: getRepository(DataItem),
30
+ params,
31
+ domain,
32
+ alias: 'dataitem'
33
+ })
34
+
35
+ const [items, total] = await queryBuilder.getManyAndCount()
30
36
 
31
37
  return { items, total }
32
38
  }
@@ -1,16 +1,14 @@
1
- import { Field, ID, InputType, Int, ObjectType } from 'type-graphql'
2
-
3
- import { ScalarObject } from '@things-factory/shell'
4
-
5
1
  import { DataItem, DataItemType } from './data-item'
2
+ import { Field, ID, InputType, Int, ObjectType } from 'type-graphql'
3
+ import { ObjectRef, ScalarObject } from '@things-factory/shell'
6
4
 
7
5
  @InputType()
8
6
  export class DataItemPatch {
9
7
  @Field(type => ID, { nullable: true })
10
8
  id?: string
11
9
 
12
- @Field({ nullable: true })
13
- dataSetId?: string
10
+ @Field(type => ObjectRef, { nullable: true })
11
+ dataSet?: ObjectRef
14
12
 
15
13
  @Field({ nullable: true })
16
14
  name?: string
@@ -30,12 +28,18 @@ export class DataItemPatch {
30
28
  @Field(type => ScalarObject, { nullable: true })
31
29
  options?: ScalarObject
32
30
 
31
+ @Field({ nullable: true })
32
+ unit?: string
33
+
33
34
  @Field(type => Int, { nullable: true })
34
35
  quota?: number
35
36
 
36
37
  @Field({ nullable: true })
37
38
  active?: boolean
38
39
 
40
+ @Field({ nullable: true })
41
+ hidden?: boolean
42
+
39
43
  @Field(type => ScalarObject, { nullable: true })
40
44
  spec?: ScalarObject
41
45
 
@@ -1,4 +1,3 @@
1
- import { Field, ID, Int, ObjectType, registerEnumType } from 'type-graphql'
2
1
  import {
3
2
  Column,
4
3
  CreateDateColumn,
@@ -9,11 +8,11 @@ import {
9
8
  RelationId,
10
9
  UpdateDateColumn
11
10
  } from 'typeorm'
12
-
13
- import { User } from '@things-factory/auth-base'
14
11
  import { Domain, ScalarObject } from '@things-factory/shell'
12
+ import { Field, ID, Int, ObjectType, registerEnumType } from 'type-graphql'
15
13
 
16
14
  import { DataSet } from '../data-set/data-set'
15
+ import { User } from '@things-factory/auth-base'
17
16
 
18
17
  export enum DataItemType {
19
18
  number = 'number',
@@ -54,7 +53,7 @@ export class DataItem {
54
53
  description?: string
55
54
 
56
55
  @ManyToOne(type => DataSet, dataSet => dataSet.dataItems, { onDelete: 'CASCADE' })
57
- @Field(type => DataSet, { nullable: true })
56
+ @Field(type => DataSet, { nullable: false })
58
57
  dataSet?: DataSet
59
58
 
60
59
  @RelationId((dataItem: DataItem) => dataItem.dataSet)
@@ -76,6 +75,12 @@ export class DataItem {
76
75
  @Field({ nullable: true })
77
76
  active?: boolean
78
77
 
78
+ @Column({
79
+ nullable: true
80
+ })
81
+ @Field({ nullable: true })
82
+ hidden?: boolean
83
+
79
84
  @Column({
80
85
  nullable: true
81
86
  })
@@ -86,6 +91,12 @@ export class DataItem {
86
91
  @Field(type => ScalarObject, { nullable: true })
87
92
  options?: ScalarObject
88
93
 
94
+ @Column({
95
+ nullable: true
96
+ })
97
+ @Field({ nullable: true })
98
+ unit?: string
99
+
89
100
  @Column({
90
101
  nullable: true
91
102
  })
@@ -0,0 +1,150 @@
1
+ import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
2
+
3
+ import { DataOoc, DataOocStatus } from './data-ooc'
4
+ import { DataOocPatch, NewDataOoc } from './data-ooc-type'
5
+
6
+ @Resolver(DataOoc)
7
+ export class DataOocMutation {
8
+ @Directive('@privilege(category: "data-ooc", privilege: "mutation", domainOwnerGranted: true)')
9
+ @Directive('@transaction')
10
+ @Mutation(returns => DataOoc, { description: 'To create new DataOoc' })
11
+ async createDataOoc(@Arg('dataOoc') dataOoc: NewDataOoc, @Ctx() context: any): Promise<DataOoc> {
12
+ const { domain, user, tx } = context.state
13
+
14
+ const state = dataOoc.state || DataOocStatus.CREATED
15
+ const history = [
16
+ {
17
+ user: {
18
+ id: user.id,
19
+ name: user.name
20
+ },
21
+ state,
22
+ timestamp: Date.now()
23
+ }
24
+ ]
25
+
26
+ return await tx.getRepository(DataOoc).save({
27
+ ...dataOoc,
28
+ state,
29
+ domain,
30
+ history,
31
+ creator: user,
32
+ updater: user
33
+ })
34
+ }
35
+
36
+ @Directive('@privilege(category: "data-ooc", privilege: "mutation", domainOwnerGranted: true)')
37
+ @Directive('@transaction')
38
+ @Mutation(returns => DataOoc, { description: 'To modify DataOoc information' })
39
+ async updateDataOoc(@Arg('id') id: string, @Arg('patch') patch: DataOocPatch, @Ctx() context: any): Promise<DataOoc> {
40
+ const { domain, user, tx } = context.state
41
+
42
+ const repository = tx.getRepository(DataOoc)
43
+ const dataOoc = await repository.findOne({
44
+ where: { domain, id }
45
+ })
46
+
47
+ const state = patch.state || dataOoc.state
48
+
49
+ const history = dataOoc.history || []
50
+ history.push({
51
+ user: {
52
+ id: user.id,
53
+ name: user.name
54
+ },
55
+ state,
56
+ comment: patch.correctiveAction || '',
57
+ timestamp: Date.now()
58
+ })
59
+
60
+ const more = {} as any
61
+
62
+ if (dataOoc.state !== patch.state) {
63
+ if (patch.state === DataOocStatus.CORRECTED) {
64
+ more.corrector = user
65
+ } else {
66
+ more.corrector = null
67
+ }
68
+ }
69
+
70
+ return await repository.save({
71
+ ...dataOoc,
72
+ ...patch,
73
+ ...more,
74
+ state,
75
+ history,
76
+ updater: user
77
+ })
78
+ }
79
+
80
+ // @Directive('@privilege(category: "data-ooc", privilege: "mutation", domainOwnerGranted: true)')
81
+ // @Directive('@transaction')
82
+ // @Mutation(returns => [DataOoc], { description: "To modify multiple DataOoc' information" })
83
+ // async updateMultipleDataOoc(
84
+ // @Arg('patches', type => [DataOocPatch]) patches: DataOocPatch[],
85
+ // @Ctx() context: any
86
+ // ): Promise<DataOoc[]> {
87
+ // const { domain, user, tx } = context.state
88
+
89
+ // let results = []
90
+ // const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')
91
+ // const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')
92
+ // const dataOocRepo = tx.getRepository(DataOoc)
93
+
94
+ // if (_createRecords.length > 0) {
95
+ // for (let i = 0; i < _createRecords.length; i++) {
96
+ // const newRecord = _createRecords[i]
97
+
98
+ // const result = await dataOocRepo.save({
99
+ // ...newRecord,
100
+ // domain,
101
+ // creator: user,
102
+ // updater: user
103
+ // })
104
+
105
+ // results.push({ ...result, cuFlag: '+' })
106
+ // }
107
+ // }
108
+
109
+ // if (_updateRecords.length > 0) {
110
+ // for (let i = 0; i < _updateRecords.length; i++) {
111
+ // const newRecord = _updateRecords[i]
112
+ // const dataOoc = await dataOocRepo.findOne(newRecord.id)
113
+
114
+ // const result = await dataOocRepo.save({
115
+ // ...dataOoc,
116
+ // ...newRecord,
117
+ // updater: user
118
+ // })
119
+
120
+ // results.push({ ...result, cuFlag: 'M' })
121
+ // }
122
+ // }
123
+
124
+ // return results
125
+ // }
126
+
127
+ // @Directive('@privilege(category: "data-ooc", privilege: "mutation", domainOwnerGranted: true)')
128
+ // @Directive('@transaction')
129
+ // @Mutation(returns => Boolean, { description: 'To delete DataOoc' })
130
+ // async deleteDataOoc(@Arg('id') id: string, @Ctx() context: any): Promise<boolean> {
131
+ // const { domain, tx } = context.state
132
+
133
+ // await tx.getRepository(DataOoc).delete({ domain, id })
134
+ // return true
135
+ // }
136
+
137
+ // @Directive('@privilege(category: "data-ooc", privilege: "mutation", domainOwnerGranted: true)')
138
+ // @Directive('@transaction')
139
+ // @Mutation(returns => Boolean, { description: 'To delete multiple dataOocs' })
140
+ // async deleteDataOocs(@Arg('ids', type => [String]) ids: string[], @Ctx() context: any): Promise<boolean> {
141
+ // const { domain, tx } = context.state
142
+
143
+ // await tx.getRepository(DataOoc).delete({
144
+ // domain,
145
+ // id: In(ids)
146
+ // })
147
+
148
+ // return true
149
+ // }
150
+ }