@things-factory/dataset 5.0.0-alpha.5 → 5.0.0-alpha.50

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 (107) hide show
  1. package/README.md +9 -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 +483 -0
  7. package/client/pages/data-ooc/data-ooc-view.js +183 -0
  8. package/client/pages/data-report/data-report-embed-page.js +113 -0
  9. package/client/pages/data-report/data-report-list-page.js +465 -0
  10. package/client/pages/data-report/jasper-report-oocs-page.js +122 -0
  11. package/client/pages/data-report/jasper-report-samples-crosstab-page.js +122 -0
  12. package/client/pages/data-report/jasper-report-samples-page.js +122 -0
  13. package/client/pages/data-sample/data-sample-list-page.js +386 -0
  14. package/client/pages/data-sample/data-sample-view.js +98 -0
  15. package/client/pages/{data-sensor.js → data-sensor/data-sensor-list-page.js} +43 -64
  16. package/client/pages/{data-item-list.js → data-set/data-item-list.js} +37 -12
  17. package/client/pages/{data-set-importer.js → data-set/data-set-importer.js} +0 -0
  18. package/client/pages/data-set/data-set-list-page.js +746 -0
  19. package/client/route.js +34 -6
  20. package/config/config.development.js +13 -0
  21. package/config/config.production.js +1 -0
  22. package/dist-server/controllers/create-data-sample.js +133 -0
  23. package/dist-server/controllers/create-data-sample.js.map +1 -0
  24. package/dist-server/controllers/data-use-case.js +57 -0
  25. package/dist-server/controllers/data-use-case.js.map +1 -0
  26. package/dist-server/controllers/index.js +18 -0
  27. package/dist-server/controllers/index.js.map +1 -1
  28. package/dist-server/controllers/jasper-report.js +156 -0
  29. package/dist-server/controllers/jasper-report.js.map +1 -0
  30. package/dist-server/index.js +1 -0
  31. package/dist-server/index.js.map +1 -1
  32. package/dist-server/routes.js +13 -24
  33. package/dist-server/routes.js.map +1 -1
  34. package/dist-server/service/data-item/data-item-mutation.js +5 -1
  35. package/dist-server/service/data-item/data-item-mutation.js.map +1 -1
  36. package/dist-server/service/data-item/data-item-query.js +7 -2
  37. package/dist-server/service/data-item/data-item-query.js.map +1 -1
  38. package/dist-server/service/data-item/data-item-type.js +15 -7
  39. package/dist-server/service/data-item/data-item-type.js.map +1 -1
  40. package/dist-server/service/data-item/data-item.js +17 -3
  41. package/dist-server/service/data-item/data-item.js.map +1 -1
  42. package/dist-server/service/data-ooc/data-ooc-mutation.js +92 -0
  43. package/dist-server/service/data-ooc/data-ooc-mutation.js.map +1 -0
  44. package/dist-server/service/data-ooc/data-ooc-query.js +120 -0
  45. package/dist-server/service/data-ooc/data-ooc-query.js.map +1 -0
  46. package/dist-server/service/data-ooc/data-ooc-subscription.js +65 -0
  47. package/dist-server/service/data-ooc/data-ooc-subscription.js.map +1 -0
  48. package/dist-server/service/data-ooc/data-ooc-type.js +107 -0
  49. package/dist-server/service/data-ooc/data-ooc-type.js.map +1 -0
  50. package/dist-server/service/data-ooc/data-ooc.js +237 -0
  51. package/dist-server/service/data-ooc/data-ooc.js.map +1 -0
  52. package/dist-server/service/data-ooc/index.js +10 -0
  53. package/dist-server/service/data-ooc/index.js.map +1 -0
  54. package/dist-server/service/data-sample/data-sample-mutation.js +2 -138
  55. package/dist-server/service/data-sample/data-sample-mutation.js.map +1 -1
  56. package/dist-server/service/data-sample/data-sample-query.js +7 -2
  57. package/dist-server/service/data-sample/data-sample-query.js.map +1 -1
  58. package/dist-server/service/data-sample/data-sample-type.js +12 -42
  59. package/dist-server/service/data-sample/data-sample-type.js.map +1 -1
  60. package/dist-server/service/data-sample/data-sample.js +34 -3
  61. package/dist-server/service/data-sample/data-sample.js.map +1 -1
  62. package/dist-server/service/data-sensor/data-sensor-query.js +7 -2
  63. package/dist-server/service/data-sensor/data-sensor-query.js.map +1 -1
  64. package/dist-server/service/data-set/data-set-mutation.js +40 -14
  65. package/dist-server/service/data-set/data-set-mutation.js.map +1 -1
  66. package/dist-server/service/data-set/data-set-query.js +185 -3
  67. package/dist-server/service/data-set/data-set-query.js.map +1 -1
  68. package/dist-server/service/data-set/data-set-type.js +84 -3
  69. package/dist-server/service/data-set/data-set-type.js.map +1 -1
  70. package/dist-server/service/data-set/data-set.js +110 -15
  71. package/dist-server/service/data-set/data-set.js.map +1 -1
  72. package/dist-server/service/index.js +6 -2
  73. package/dist-server/service/index.js.map +1 -1
  74. package/package.json +19 -13
  75. package/server/controllers/create-data-sample.ts +177 -0
  76. package/server/controllers/data-use-case.ts +85 -0
  77. package/server/controllers/index.ts +2 -0
  78. package/server/controllers/jasper-report.ts +170 -0
  79. package/server/index.ts +1 -0
  80. package/server/routes.ts +21 -31
  81. package/server/service/data-item/data-item-mutation.ts +6 -1
  82. package/server/service/data-item/data-item-query.ts +9 -3
  83. package/server/service/data-item/data-item-type.ts +10 -6
  84. package/server/service/data-item/data-item.ts +15 -4
  85. package/server/service/data-ooc/data-ooc-mutation.ts +150 -0
  86. package/server/service/data-ooc/data-ooc-query.ts +69 -0
  87. package/server/service/data-ooc/data-ooc-subscription.ts +51 -0
  88. package/server/service/data-ooc/data-ooc-type.ts +68 -0
  89. package/server/service/data-ooc/data-ooc.ts +204 -0
  90. package/server/service/data-ooc/index.ts +7 -0
  91. package/server/service/data-sample/data-sample-mutation.ts +3 -172
  92. package/server/service/data-sample/data-sample-query.ts +9 -3
  93. package/server/service/data-sample/data-sample-type.ts +7 -28
  94. package/server/service/data-sample/data-sample.ts +33 -3
  95. package/server/service/data-sensor/data-sensor-query.ts +9 -3
  96. package/server/service/data-set/data-set-mutation.ts +53 -14
  97. package/server/service/data-set/data-set-query.ts +156 -4
  98. package/server/service/data-set/data-set-type.ts +65 -4
  99. package/server/service/data-set/data-set.ts +100 -12
  100. package/server/service/index.ts +6 -2
  101. package/things-factory.config.js +35 -7
  102. package/translations/en.json +46 -3
  103. package/translations/ko.json +45 -3
  104. package/translations/ms.json +44 -3
  105. package/translations/zh.json +44 -3
  106. package/client/pages/data-sample.js +0 -316
  107. package/client/pages/data-set.js +0 -457
@@ -0,0 +1,170 @@
1
+ import FormData from 'form-data'
2
+ import fetch from 'node-fetch'
3
+
4
+ import { STORAGE } from '@things-factory/attachment-base'
5
+ import { AthenaController } from '@things-factory/aws-base'
6
+ import { config } from '@things-factory/env'
7
+
8
+ const dataReportConfig = config.get('dataReport')
9
+ const { jasper: {
10
+ endpoint: { protocol: PROTOCOL, host:HOST, port:PORT },
11
+ datasource: { database: DATABASE } }
12
+ } = dataReportConfig
13
+
14
+ /** author: ywnam123 */
15
+ function transformValuesToRows(queryResult) {
16
+ var parseData = []
17
+ let index = 1
18
+ for (let i = 0; i < queryResult.Items.length; i++) {
19
+ var j = 0
20
+ const data = JSON.parse(queryResult.Items[i].data)
21
+ const spec = JSON.parse(queryResult.Items[i].spec)
22
+
23
+ for (let key in data) {
24
+ if (Array.isArray(data[key])) {
25
+ for (j = 0; j < data[key].length; j++) {
26
+ for (let specKey in spec) {
27
+ if (key === specKey) {
28
+ parseData.push({
29
+ item: spec[specKey].name,
30
+ index: index + j,
31
+ value: String(data[key][j])
32
+ })
33
+ }
34
+ }
35
+ }
36
+ } else {
37
+ parseData.push({
38
+ item: key,
39
+ index,
40
+ value: String(data[key])
41
+ })
42
+ }
43
+ }
44
+ if (j !== 0) {
45
+ index = index + j
46
+ } else {
47
+ index = index + 1
48
+ }
49
+ }
50
+ }
51
+
52
+ /** @todo considering trasformation in lambda, as massive dataset */
53
+ function pivotData(rows) {
54
+ let parsedData = []
55
+ let index = 1
56
+ for (let i = 0; i < rows.length; i++) {
57
+ let j = 0
58
+ const data = JSON.parse(rows[i].data)
59
+ const spec = JSON.parse(rows[i].spec)
60
+
61
+ for (let key in data) {
62
+ /** @todo rule to display or not, about unspecified spec */
63
+ const value = data[key]
64
+ !(spec[key]?.hidden) && parsedData.push({
65
+ item: spec[key]?.name || key,
66
+ index,
67
+ value: Array.isArray(value) ? value.join(', ') : value
68
+ })
69
+ }
70
+ if (j !== 0) {
71
+ index = index + j
72
+ } else {
73
+ index = index + 1
74
+ }
75
+ }
76
+
77
+ return parsedData
78
+ }
79
+
80
+ function parseJsonDataField(rows) {
81
+ let parsedData = []
82
+ for (let i = 0; i < rows.length; i++) {
83
+ const row = rows[i]
84
+ const data = JSON.parse(row.data)
85
+ for (let key in data) {
86
+ if (Array.isArray(data[key])) {
87
+ data[key] = data[key].toString()
88
+ }
89
+ }
90
+ delete row.data
91
+ parsedData.push({ ...row, ...data })
92
+ }
93
+
94
+ return parsedData
95
+ }
96
+
97
+ const athenaClient = new AthenaController()
98
+ async function queryAthena(params) {
99
+ const { table, domain, dataSetId, fromWorkDate, toWorkDate, workShift, timezone } = params
100
+ const queryData = {
101
+ sql: `SELECT name, description, data, spec, workdate, workshift,
102
+ DATE_FORMAT(
103
+ FROM_UNIXTIME(collected_at / 1000 / 1000) AT TIME ZONE '${timezone || 'UTC'}',
104
+ '%Y-%m-%d %H:%i:%s'
105
+ ) AS collected_at
106
+ FROM ${table}
107
+ WHERE domain='${domain}'
108
+ AND datasetid = '${dataSetId}'
109
+ AND workdate >= '${fromWorkDate}'
110
+ AND workdate <= '${toWorkDate}'
111
+ ${workShift ? 'AND workshift = \'' + workShift + '\'' : ''}
112
+ ORDER BY collected_at`,
113
+ db: DATABASE
114
+ }
115
+ // and json_extract_scalar(data, '$.dauid') = 'A8032AD81730'
116
+
117
+ return await athenaClient.query(queryData)
118
+ }
119
+ export async function renderJasperReport(context: any) {
120
+ const { state: { domain }, query } = context
121
+
122
+ const template = await STORAGE.readFile(query['template'] || 'dynamic_header_sample.jrxml', 'utf-8')
123
+ let templateType = query['templateType'] || 'crosstab'
124
+ let parsedData = []
125
+
126
+ // @todo: get dataset timezone
127
+ /**
128
+ * const variables = await gql(dataSet(id:${dataSetId}) {
129
+ * name, description, partition_keys, timezone
130
+ * })
131
+ */
132
+
133
+ query['domain'] = domain?.subdomain
134
+ query['timezone'] = domain?.timezone
135
+ const queryResult = await queryAthena(query)
136
+ const rows = queryResult.Items
137
+
138
+ if (!rows.length) {
139
+ return '<h3>Not found result.</h3>'
140
+ }
141
+ else {
142
+ const firstRow = rows[0]
143
+ // uses the first row values as data-set has no history data.
144
+ const parameters = {
145
+ name: firstRow.name,
146
+ description: firstRow.description,
147
+ ...query
148
+ }
149
+
150
+ if (templateType === 'crosstab') {
151
+ parsedData = pivotData(rows)
152
+ } else {
153
+ parsedData = parseJsonDataField(rows)
154
+ }
155
+
156
+ const formData = new FormData()
157
+ formData.append('template', template)
158
+ formData.append('jsonString', JSON.stringify(parsedData))
159
+ formData.append('parameters', JSON.stringify(parameters))
160
+
161
+ const reportUrl = `${PROTOCOL || 'http'}://${HOST}:${PORT}/rest/report/show_html`
162
+ const response = await fetch(reportUrl, {
163
+ method: 'POST',
164
+ body: formData
165
+ })
166
+
167
+ return await response.text()
168
+ }
169
+
170
+ }
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,9 @@
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'
6
+ import { renderJasperReport } from './controllers/jasper-report'
5
7
  import { DataSensor } from './service/data-sensor/data-sensor'
6
8
 
7
9
  const debug = require('debug')('things-factory:dataset:routes')
@@ -47,41 +49,26 @@ process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRout
47
49
 
48
50
  const domain = sensor.domain
49
51
  const dataSet = sensor.dataSet
50
- const user = sensor.appliance
51
-
52
- const dataItems = await tx.getRepository(DataItem).find({
52
+ const user: User = await tx.getRepository(User).findOne({
53
53
  where: {
54
- domain,
55
- dataSet
56
- },
57
- order: {
58
- sequence: 'DESC'
54
+ reference: sensor.appliance.id,
55
+ userType: 'appliance'
59
56
  }
60
57
  })
61
58
 
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
- })
59
+ return await createDataSample(
60
+ {
61
+ dataSet,
62
+ data,
63
+ rawData,
64
+ source: deviceId,
65
+ collectedAt: new Date(timestamp)
66
+ },
67
+ { state: { domain, user, tx } }
68
+ )
82
69
  })
83
70
 
84
- return 'OK'
71
+ context.status = 200
85
72
  })
86
73
  })
87
74
 
@@ -101,4 +88,7 @@ process.on('bootstrap-module-domain-private-route' as any, (app, domainPrivateRo
101
88
  /*
102
89
  * can add domain private routes to application (auth required, tenancy required)
103
90
  */
91
+ domainPrivateRouter.get('/data-report/jasper', async (context, next) => {
92
+ context.body = await renderJasperReport(context)
93
+ })
104
94
  })
@@ -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
+ }
@@ -0,0 +1,69 @@
1
+ import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'
2
+ import { getRepository } from 'typeorm'
3
+
4
+ import { User } from '@things-factory/auth-base'
5
+ import { Domain, getQueryBuilderFromListParams, ListParam } from '@things-factory/shell'
6
+
7
+ import { DataSample } from '../data-sample/data-sample'
8
+ import { DataSet } from '../data-set/data-set'
9
+ import { DataOoc } from './data-ooc'
10
+ import { DataOocList } from './data-ooc-type'
11
+
12
+ @Resolver(DataOoc)
13
+ export class DataOocQuery {
14
+ @Directive('@privilege(category: "data-ooc", privilege: "query", domainOwnerGranted: true)')
15
+ @Query(returns => DataOoc, { description: 'To fetch a DataOoc' })
16
+ async dataOoc(@Arg('id') id: string, @Ctx() context: any): Promise<DataOoc> {
17
+ const { domain } = context.state
18
+
19
+ return await getRepository(DataOoc).findOne({
20
+ where: { domain, id }
21
+ })
22
+ }
23
+
24
+ @Directive('@privilege(category: "data-ooc", privilege: "query", domainOwnerGranted: true)')
25
+ @Query(returns => DataOocList, { description: 'To fetch multiple DataOoc' })
26
+ async dataOocs(@Args() params: ListParam, @Ctx() context: any): Promise<DataOocList> {
27
+ const { domain } = context.state
28
+
29
+ const queryBuilder = getQueryBuilderFromListParams({
30
+ repository: getRepository(DataOoc),
31
+ params,
32
+ domain,
33
+ alias: 'dataooc'
34
+ })
35
+
36
+ const [items, total] = await queryBuilder.getManyAndCount()
37
+
38
+ return { items, total }
39
+ }
40
+
41
+ @FieldResolver(type => DataSet)
42
+ async dataSet(@Root() dataOoc: DataOoc): Promise<DataSet> {
43
+ return await getRepository(DataSet).findOne({
44
+ id: dataOoc.dataSetId
45
+ })
46
+ }
47
+
48
+ @FieldResolver(type => DataSample)
49
+ async dataSample(@Root() dataOoc: DataOoc): Promise<DataSample> {
50
+ return await getRepository(DataSample).findOne({
51
+ id: dataOoc.dataSampleId
52
+ })
53
+ }
54
+
55
+ @FieldResolver(type => Domain)
56
+ async domain(@Root() dataOoc: DataOoc): Promise<Domain> {
57
+ return await getRepository(Domain).findOne(dataOoc.domainId)
58
+ }
59
+
60
+ @FieldResolver(type => User)
61
+ async updater(@Root() dataOoc: DataOoc): Promise<User> {
62
+ return await getRepository(User).findOne(dataOoc.updaterId)
63
+ }
64
+
65
+ @FieldResolver(type => User)
66
+ async creator(@Root() dataOoc: DataOoc): Promise<User> {
67
+ return await getRepository(User).findOne(dataOoc.creatorId)
68
+ }
69
+ }
@@ -0,0 +1,51 @@
1
+ import { Resolver, Subscription, Root } from 'type-graphql'
2
+ import { withFilter } from 'graphql-subscriptions'
3
+ import { pubsub } from '@things-factory/shell'
4
+ import { User } from '@things-factory/auth-base'
5
+ import { DataOoc } from './data-ooc'
6
+ import { getRepository } from 'typeorm'
7
+
8
+ const debug = require('debug')('things-factory:dataset:data-ooc-subscription')
9
+
10
+ @Resolver(DataOoc)
11
+ export class DataOocSubscription {
12
+ @Subscription({
13
+ subscribe: (_, args, context, info) => {
14
+ const { domain, user } = context.state
15
+ const subdomain = domain?.subdomain
16
+
17
+ debug('subscribe', subdomain)
18
+
19
+ if (!domain) {
20
+ throw new Error('domain required')
21
+ }
22
+
23
+ if (!user.domains?.find(d => d.subdomain === subdomain)) {
24
+ throw new Error(`domain(${subdomain}) is not working for user(${user.email}).`)
25
+ }
26
+
27
+ return withFilter(
28
+ () => pubsub.asyncIterator('data-ooc'),
29
+ async (payload, variables, context, info) => {
30
+ const { dataOoc, supervisoryRoleId } = payload
31
+ const { domain } = dataOoc
32
+
33
+ if (subdomain !== domain?.subdomain) {
34
+ return false
35
+ }
36
+
37
+ // check if the user has that role
38
+ const userWithRoles: User = await getRepository(User).findOne({
39
+ where: { id: user.id },
40
+ relations: ['roles']
41
+ })
42
+
43
+ return userWithRoles.roles.find(role => role.id === supervisoryRoleId)
44
+ }
45
+ )(_, args, context, info)
46
+ }
47
+ })
48
+ dataOoc(@Root() payload: { dataOoc: DataOoc; supervisoryRoleId: string }): DataOoc {
49
+ return payload.dataOoc
50
+ }
51
+ }