@things-factory/ops-master 10.0.18

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 (181) hide show
  1. package/.dockerignore +31 -0
  2. package/dist-client/index.d.ts +1 -0
  3. package/dist-client/index.js +2 -0
  4. package/dist-client/index.js.map +1 -0
  5. package/dist-client/pages/master-axes.d.ts +33 -0
  6. package/dist-client/pages/master-axes.js +176 -0
  7. package/dist-client/pages/master-axes.js.map +1 -0
  8. package/dist-client/pages/master-list.d.ts +68 -0
  9. package/dist-client/pages/master-list.js +267 -0
  10. package/dist-client/pages/master-list.js.map +1 -0
  11. package/dist-client/route.d.ts +1 -0
  12. package/dist-client/route.js +8 -0
  13. package/dist-client/route.js.map +1 -0
  14. package/dist-client/tsconfig.tsbuildinfo +1 -0
  15. package/dist-server/index.d.ts +1 -0
  16. package/dist-server/index.js +5 -0
  17. package/dist-server/index.js.map +1 -0
  18. package/dist-server/service/asset/asset-lifecycle.d.ts +83 -0
  19. package/dist-server/service/asset/asset-lifecycle.js +99 -0
  20. package/dist-server/service/asset/asset-lifecycle.js.map +1 -0
  21. package/dist-server/service/asset/asset-master-resolver.d.ts +44 -0
  22. package/dist-server/service/asset/asset-master-resolver.js +140 -0
  23. package/dist-server/service/asset/asset-master-resolver.js.map +1 -0
  24. package/dist-server/service/asset/asset-master.d.ts +21 -0
  25. package/dist-server/service/asset/asset-master.js +25 -0
  26. package/dist-server/service/asset/asset-master.js.map +1 -0
  27. package/dist-server/service/asset/asset-query.d.ts +8 -0
  28. package/dist-server/service/asset/asset-query.js +50 -0
  29. package/dist-server/service/asset/asset-query.js.map +1 -0
  30. package/dist-server/service/asset/index.d.ts +6 -0
  31. package/dist-server/service/asset/index.js +10 -0
  32. package/dist-server/service/asset/index.js.map +1 -0
  33. package/dist-server/service/asset/physical-asset-class.d.ts +34 -0
  34. package/dist-server/service/asset/physical-asset-class.js +104 -0
  35. package/dist-server/service/asset/physical-asset-class.js.map +1 -0
  36. package/dist-server/service/asset/physical-asset.d.ts +53 -0
  37. package/dist-server/service/asset/physical-asset.js +123 -0
  38. package/dist-server/service/asset/physical-asset.js.map +1 -0
  39. package/dist-server/service/equipment/equipment-class.d.ts +34 -0
  40. package/dist-server/service/equipment/equipment-class.js +104 -0
  41. package/dist-server/service/equipment/equipment-class.js.map +1 -0
  42. package/dist-server/service/equipment/equipment-master-resolver.d.ts +60 -0
  43. package/dist-server/service/equipment/equipment-master-resolver.js +200 -0
  44. package/dist-server/service/equipment/equipment-master-resolver.js.map +1 -0
  45. package/dist-server/service/equipment/equipment-master.d.ts +29 -0
  46. package/dist-server/service/equipment/equipment-master.js +36 -0
  47. package/dist-server/service/equipment/equipment-master.js.map +1 -0
  48. package/dist-server/service/equipment/equipment-query.d.ts +8 -0
  49. package/dist-server/service/equipment/equipment-query.js +50 -0
  50. package/dist-server/service/equipment/equipment-query.js.map +1 -0
  51. package/dist-server/service/equipment/equipment.d.ts +45 -0
  52. package/dist-server/service/equipment/equipment.js +133 -0
  53. package/dist-server/service/equipment/equipment.js.map +1 -0
  54. package/dist-server/service/equipment/index.d.ts +8 -0
  55. package/dist-server/service/equipment/index.js +12 -0
  56. package/dist-server/service/equipment/index.js.map +1 -0
  57. package/dist-server/service/equipment/state-period-rules.d.ts +76 -0
  58. package/dist-server/service/equipment/state-period-rules.js +88 -0
  59. package/dist-server/service/equipment/state-period-rules.js.map +1 -0
  60. package/dist-server/service/equipment/stop-reason-query.d.ts +11 -0
  61. package/dist-server/service/equipment/stop-reason-query.js +39 -0
  62. package/dist-server/service/equipment/stop-reason-query.js.map +1 -0
  63. package/dist-server/service/equipment/stop-reason.d.ts +58 -0
  64. package/dist-server/service/equipment/stop-reason.js +114 -0
  65. package/dist-server/service/equipment/stop-reason.js.map +1 -0
  66. package/dist-server/service/index.d.ts +46 -0
  67. package/dist-server/service/index.js +80 -0
  68. package/dist-server/service/index.js.map +1 -0
  69. package/dist-server/service/location/index.d.ts +5 -0
  70. package/dist-server/service/location/index.js +9 -0
  71. package/dist-server/service/location/index.js.map +1 -0
  72. package/dist-server/service/location/location-master-resolver.d.ts +28 -0
  73. package/dist-server/service/location/location-master-resolver.js +80 -0
  74. package/dist-server/service/location/location-master-resolver.js.map +1 -0
  75. package/dist-server/service/location/location-master.d.ts +24 -0
  76. package/dist-server/service/location/location-master.js +27 -0
  77. package/dist-server/service/location/location-master.js.map +1 -0
  78. package/dist-server/service/location/location-query.d.ts +7 -0
  79. package/dist-server/service/location/location-query.js +41 -0
  80. package/dist-server/service/location/location-query.js.map +1 -0
  81. package/dist-server/service/location/operational-location.d.ts +52 -0
  82. package/dist-server/service/location/operational-location.js +132 -0
  83. package/dist-server/service/location/operational-location.js.map +1 -0
  84. package/dist-server/service/master-axis.d.ts +29 -0
  85. package/dist-server/service/master-axis.js +39 -0
  86. package/dist-server/service/master-axis.js.map +1 -0
  87. package/dist-server/service/master-crud.d.ts +44 -0
  88. package/dist-server/service/master-crud.js +73 -0
  89. package/dist-server/service/master-crud.js.map +1 -0
  90. package/dist-server/service/master-list.d.ts +12 -0
  91. package/dist-server/service/master-list.js +24 -0
  92. package/dist-server/service/master-list.js.map +1 -0
  93. package/dist-server/service/material/index.d.ts +6 -0
  94. package/dist-server/service/material/index.js +10 -0
  95. package/dist-server/service/material/index.js.map +1 -0
  96. package/dist-server/service/material/material-class.d.ts +34 -0
  97. package/dist-server/service/material/material-class.js +104 -0
  98. package/dist-server/service/material/material-class.js.map +1 -0
  99. package/dist-server/service/material/material-definition.d.ts +42 -0
  100. package/dist-server/service/material/material-definition.js +112 -0
  101. package/dist-server/service/material/material-definition.js.map +1 -0
  102. package/dist-server/service/material/material-master-resolver.d.ts +44 -0
  103. package/dist-server/service/material/material-master-resolver.js +140 -0
  104. package/dist-server/service/material/material-master-resolver.js.map +1 -0
  105. package/dist-server/service/material/material-master.d.ts +9 -0
  106. package/dist-server/service/material/material-master.js +24 -0
  107. package/dist-server/service/material/material-master.js.map +1 -0
  108. package/dist-server/service/material/material-query.d.ts +8 -0
  109. package/dist-server/service/material/material-query.js +50 -0
  110. package/dist-server/service/material/material-query.js.map +1 -0
  111. package/dist-server/service/operation/index.d.ts +5 -0
  112. package/dist-server/service/operation/index.js +9 -0
  113. package/dist-server/service/operation/index.js.map +1 -0
  114. package/dist-server/service/operation/operation-definition.d.ts +52 -0
  115. package/dist-server/service/operation/operation-definition.js +142 -0
  116. package/dist-server/service/operation/operation-definition.js.map +1 -0
  117. package/dist-server/service/operation/operation-master-resolver.d.ts +28 -0
  118. package/dist-server/service/operation/operation-master-resolver.js +80 -0
  119. package/dist-server/service/operation/operation-master-resolver.js.map +1 -0
  120. package/dist-server/service/operation/operation-master.d.ts +21 -0
  121. package/dist-server/service/operation/operation-master.js +28 -0
  122. package/dist-server/service/operation/operation-master.js.map +1 -0
  123. package/dist-server/service/operation/operation-query.d.ts +7 -0
  124. package/dist-server/service/operation/operation-query.js +41 -0
  125. package/dist-server/service/operation/operation-query.js.map +1 -0
  126. package/dist-server/service/personnel/index.d.ts +6 -0
  127. package/dist-server/service/personnel/index.js +10 -0
  128. package/dist-server/service/personnel/index.js.map +1 -0
  129. package/dist-server/service/personnel/person.d.ts +51 -0
  130. package/dist-server/service/personnel/person.js +119 -0
  131. package/dist-server/service/personnel/person.js.map +1 -0
  132. package/dist-server/service/personnel/personnel-class.d.ts +54 -0
  133. package/dist-server/service/personnel/personnel-class.js +114 -0
  134. package/dist-server/service/personnel/personnel-class.js.map +1 -0
  135. package/dist-server/service/personnel/personnel-master-resolver.d.ts +44 -0
  136. package/dist-server/service/personnel/personnel-master-resolver.js +140 -0
  137. package/dist-server/service/personnel/personnel-master-resolver.js.map +1 -0
  138. package/dist-server/service/personnel/personnel-master.d.ts +39 -0
  139. package/dist-server/service/personnel/personnel-master.js +34 -0
  140. package/dist-server/service/personnel/personnel-master.js.map +1 -0
  141. package/dist-server/service/personnel/personnel-query.d.ts +21 -0
  142. package/dist-server/service/personnel/personnel-query.js +57 -0
  143. package/dist-server/service/personnel/personnel-query.js.map +1 -0
  144. package/dist-server/service/personnel/qualification.d.ts +97 -0
  145. package/dist-server/service/personnel/qualification.js +122 -0
  146. package/dist-server/service/personnel/qualification.js.map +1 -0
  147. package/dist-server/service/resource/resource-class.d.ts +25 -0
  148. package/dist-server/service/resource/resource-class.js +29 -0
  149. package/dist-server/service/resource/resource-class.js.map +1 -0
  150. package/dist-server/service/status/axis-stamp.d.ts +16 -0
  151. package/dist-server/service/status/axis-stamp.js +22 -0
  152. package/dist-server/service/status/axis-stamp.js.map +1 -0
  153. package/dist-server/service/status/index.d.ts +3 -0
  154. package/dist-server/service/status/index.js +7 -0
  155. package/dist-server/service/status/index.js.map +1 -0
  156. package/dist-server/service/status/master-status.d.ts +45 -0
  157. package/dist-server/service/status/master-status.js +129 -0
  158. package/dist-server/service/status/master-status.js.map +1 -0
  159. package/dist-server/service/test-spec/index.d.ts +5 -0
  160. package/dist-server/service/test-spec/index.js +9 -0
  161. package/dist-server/service/test-spec/index.js.map +1 -0
  162. package/dist-server/service/test-spec/test-spec-master-resolver.d.ts +28 -0
  163. package/dist-server/service/test-spec/test-spec-master-resolver.js +80 -0
  164. package/dist-server/service/test-spec/test-spec-master-resolver.js.map +1 -0
  165. package/dist-server/service/test-spec/test-spec-master.d.ts +6 -0
  166. package/dist-server/service/test-spec/test-spec-master.js +18 -0
  167. package/dist-server/service/test-spec/test-spec-master.js.map +1 -0
  168. package/dist-server/service/test-spec/test-spec-query.d.ts +7 -0
  169. package/dist-server/service/test-spec/test-spec-query.js +41 -0
  170. package/dist-server/service/test-spec/test-spec-query.js.map +1 -0
  171. package/dist-server/service/test-spec/test-specification.d.ts +41 -0
  172. package/dist-server/service/test-spec/test-specification.js +106 -0
  173. package/dist-server/service/test-spec/test-specification.js.map +1 -0
  174. package/dist-server/tsconfig.tsbuildinfo +1 -0
  175. package/package.json +50 -0
  176. package/things-factory.config.js +12 -0
  177. package/translations/en.json +53 -0
  178. package/translations/ja.json +1 -0
  179. package/translations/ko.json +53 -0
  180. package/translations/ms.json +1 -0
  181. package/translations/zh.json +1 -0
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.calibrationBaselineOf = calibrationBaselineOf;
4
+ exports.assetLifecycleOf = assetLifecycleOf;
5
+ const ops_contract_1 = require("@operato/ops-contract");
6
+ /**
7
+ * **언제부터 세나** — 마지막으로 통과한 교정 시각.
8
+ *
9
+ * 사용 횟수는 교정 이후로 센다. 교정은 자산을 처음 상태로 되돌리는 일이고, 되돌린 뒤에도 예전 횟수를
10
+ * 계속 세면 멀쩡한 지그가 정격 초과로 잠긴다.
11
+ *
12
+ * 교정 기록이 없으면 비운다 — 부르는 쪽이 **처음부터** 센다.
13
+ */
14
+ function calibrationBaselineOf(asset) {
15
+ let latest;
16
+ for (const result of asset.testResults ?? []) {
17
+ if (result.result !== 'pass' || !result.at) {
18
+ continue;
19
+ }
20
+ if (!latest || Date.parse(result.at) > Date.parse(latest)) {
21
+ latest = result.at;
22
+ }
23
+ }
24
+ return latest;
25
+ }
26
+ /**
27
+ * 이 자산을 지금 써도 되나.
28
+ *
29
+ * `usedSinceCalibration` 은 부르는 쪽이 센다 — 사용 기록은 실적에 있고 여기는 마스터이기 때문이다.
30
+ */
31
+ function assetLifecycleOf(asset, classDefs, usedSinceCalibration, at) {
32
+ const gaps = [];
33
+ const calibratedAt = calibrationBaselineOf(asset);
34
+ const period = { effectiveStart: isoOf(asset.effectiveStart), effectiveEnd: isoOf(asset.effectiveEnd) };
35
+ if ((0, ops_contract_1.effectivityAt)(period, at) !== undefined) {
36
+ gaps.push({ assetName: asset.name, lack: 'not-effective' });
37
+ }
38
+ gaps.push(...calibrationGaps(asset, classDefs, at));
39
+ /* 정격을 선언하지 않았으면 횟수로 막지 않는다 — 선언한 것만 걸린다. */
40
+ const limit = asset.cycleLimit;
41
+ if (typeof limit === 'number' && limit > 0 && usedSinceCalibration >= limit) {
42
+ gaps.push({ assetName: asset.name, lack: 'cycle-exceeded', used: usedSinceCalibration, limit });
43
+ }
44
+ return {
45
+ assetName: asset.name,
46
+ used: usedSinceCalibration,
47
+ limit,
48
+ remaining: typeof limit === 'number' && limit > 0 ? Math.max(0, limit - usedSinceCalibration) : undefined,
49
+ calibratedAt,
50
+ calibrationExpiresAt: nearestExpiry(asset, classDefs, at),
51
+ gaps
52
+ };
53
+ }
54
+ function calibrationGaps(asset, classDefs, at) {
55
+ const closure = (0, ops_contract_1.classClosure)(asset.assetClassIds, classDefs, at);
56
+ const required = (0, ops_contract_1.requiredTestsFor)([...closure], classDefs, at);
57
+ if (!required.length) {
58
+ return [];
59
+ }
60
+ const bySpec = new Map((asset.testResults ?? []).map(result => [result.specId, result]));
61
+ const gaps = [];
62
+ for (const specId of required) {
63
+ const result = bySpec.get(specId);
64
+ if (!result || (result.result !== 'pass' && result.result !== 'fail')) {
65
+ gaps.push({ assetName: asset.name, lack: 'calibration-missing', specId });
66
+ continue;
67
+ }
68
+ if (result.result === 'fail') {
69
+ gaps.push({ assetName: asset.name, lack: 'calibration-failed', specId });
70
+ continue;
71
+ }
72
+ if (!(0, ops_contract_1.testPassedAt)(result, at)) {
73
+ gaps.push({ assetName: asset.name, lack: 'calibration-expired', specId, expiredAt: result.expiresAt });
74
+ }
75
+ }
76
+ return gaps;
77
+ }
78
+ /** 가장 먼저 만료되는 교정 시각. 화면이 「언제까지 쓸 수 있나」를 보이는 데 쓴다. */
79
+ function nearestExpiry(asset, classDefs, at) {
80
+ const closure = (0, ops_contract_1.classClosure)(asset.assetClassIds, classDefs, at);
81
+ const required = new Set((0, ops_contract_1.requiredTestsFor)([...closure], classDefs, at));
82
+ let nearest;
83
+ for (const result of asset.testResults ?? []) {
84
+ if (!required.has(result.specId) || result.result !== 'pass' || !result.expiresAt) {
85
+ continue;
86
+ }
87
+ if (!nearest || Date.parse(result.expiresAt) < Date.parse(nearest)) {
88
+ nearest = result.expiresAt;
89
+ }
90
+ }
91
+ return nearest;
92
+ }
93
+ function isoOf(at) {
94
+ if (!at) {
95
+ return undefined;
96
+ }
97
+ return typeof at === 'string' ? at : at.toISOString();
98
+ }
99
+ //# sourceMappingURL=asset-lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-lifecycle.js","sourceRoot":"","sources":["../../../server/service/asset/asset-lifecycle.ts"],"names":[],"mappings":"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","sourcesContent":["import { classClosure, effectivityAt, requiredTestsFor, testPassedAt } from '@operato/ops-contract'\nimport type { ResourceClassDef, TestResult } from '@operato/ops-contract'\n\n/**\n * 이 자산을 지금 써도 되나 — **반복해서 쓰는 물건의 수명을 거는 자리.**\n *\n * 자산은 설비와 달리 **돌아온다.** 그래서 「고장인가」가 아니라 「몇 번 더 쓸 수 있나 · 교정이 살아\n * 있나」를 묻는다. 정격을 넘긴 지그로 계속 찍으면 치수가 벌어지고, 그 사실은 며칠 뒤 검사에서야\n * 드러난다. 그때는 이미 만든 것이 다 나가 있다.\n *\n * ── 교정에 새 칸을 만들지 않았다 ────────────────────────────────────────────\n * 자산은 이미 `testSpecificationIds` 와 `testResults` 를 든다. 교정은 검사이고, 교정 기한이 지난 것은\n * **검사 결과가 만료된 것**이다. 자격에서 쓴 판단이 그대로 붙는다 — `calibrationDue` 같은 칸을 새로\n * 만들면 같은 사실이 두 곳에 살고, 둘이 어긋나는 날이 온다.\n *\n * 새로 필요한 것은 **사용 횟수** 하나뿐이다. 그것만 정격(`cycleLimit`)과 견준다.\n *\n * ── 기록이 없을 때 (인원과 같은 규율) ──────────────────────────────────────\n * 교정 기록이 없으면 막는다. 「교정한 적이 없다」는 「교정이 살아 있다」가 아니다.\n */\n\nexport type AssetLack =\n /** 그 이름이 자산 마스터에 없다 — 등록하거나 이름을 고친다. */\n | 'not-registered'\n /** 폐기했거나 아직 들여오지 않았다. */\n | 'not-effective'\n /** 요구된 교정의 기록이 없다. */\n | 'calibration-missing'\n /** 교정에 불합격했다. */\n | 'calibration-failed'\n /** 교정 기한이 지났다 — 교정하면 된다. */\n | 'calibration-expired'\n /** 정격 사용 횟수를 넘겼다 — 교체하거나 정격을 다시 정한다. */\n | 'cycle-exceeded'\n\nexport interface AssetGap {\n assetName: string\n lack: AssetLack\n /** 교정 때문이면 어느 검사인가. */\n specId?: string\n /** 만료된 것이면 언제 만료됐나(ISO). */\n expiredAt?: string\n /** 정격을 넘긴 것이면 몇 번 썼고 정격이 몇 번인가. */\n used?: number\n /** 정격. */\n limit?: number\n}\n\n/** 화면이 보여 줄 수명. 남은 횟수를 **모르면 비운다** — 0 으로 두면 「다 썼다」로 읽힌다. */\nexport interface AssetLifecycle {\n assetName: string\n /** 교정 이후 몇 번 썼나. */\n used: number\n /** 정격 — 선언하지 않았으면 없다. */\n limit?: number\n /** 남은 횟수 — 정격을 선언했을 때만 있다. */\n remaining?: number\n /** 언제 교정했나(ISO) — 그 시점부터 센다. */\n calibratedAt?: string\n /** 교정이 언제 만료되나(ISO). */\n calibrationExpiresAt?: string\n gaps: AssetGap[]\n}\n\n/** 판단에 필요한 자산의 사실만. 엔티티를 통째로 받지 않는다. */\nexport interface JudgeableAsset {\n name: string\n assetClassIds?: string[]\n /** 정격 사용 횟수. 선언하지 않았으면 횟수로 막지 않는다. */\n cycleLimit?: number\n testResults?: TestResult[]\n effectiveStart?: Date | string\n effectiveEnd?: Date | string\n}\n\n/**\n * **언제부터 세나** — 마지막으로 통과한 교정 시각.\n *\n * 사용 횟수는 교정 이후로 센다. 교정은 자산을 처음 상태로 되돌리는 일이고, 되돌린 뒤에도 예전 횟수를\n * 계속 세면 멀쩡한 지그가 정격 초과로 잠긴다.\n *\n * 교정 기록이 없으면 비운다 — 부르는 쪽이 **처음부터** 센다.\n */\nexport function calibrationBaselineOf(asset: JudgeableAsset): string | undefined {\n let latest: string | undefined\n\n for (const result of asset.testResults ?? []) {\n if (result.result !== 'pass' || !result.at) {\n continue\n }\n if (!latest || Date.parse(result.at) > Date.parse(latest)) {\n latest = result.at\n }\n }\n\n return latest\n}\n\n/**\n * 이 자산을 지금 써도 되나.\n *\n * `usedSinceCalibration` 은 부르는 쪽이 센다 — 사용 기록은 실적에 있고 여기는 마스터이기 때문이다.\n */\nexport function assetLifecycleOf(\n asset: JudgeableAsset,\n classDefs: readonly ResourceClassDef[],\n usedSinceCalibration: number,\n at: string\n): AssetLifecycle {\n const gaps: AssetGap[] = []\n const calibratedAt = calibrationBaselineOf(asset)\n\n const period = { effectiveStart: isoOf(asset.effectiveStart), effectiveEnd: isoOf(asset.effectiveEnd) }\n if (effectivityAt(period, at) !== undefined) {\n gaps.push({ assetName: asset.name, lack: 'not-effective' })\n }\n\n gaps.push(...calibrationGaps(asset, classDefs, at))\n\n /* 정격을 선언하지 않았으면 횟수로 막지 않는다 — 선언한 것만 걸린다. */\n const limit = asset.cycleLimit\n if (typeof limit === 'number' && limit > 0 && usedSinceCalibration >= limit) {\n gaps.push({ assetName: asset.name, lack: 'cycle-exceeded', used: usedSinceCalibration, limit })\n }\n\n return {\n assetName: asset.name,\n used: usedSinceCalibration,\n limit,\n remaining: typeof limit === 'number' && limit > 0 ? Math.max(0, limit - usedSinceCalibration) : undefined,\n calibratedAt,\n calibrationExpiresAt: nearestExpiry(asset, classDefs, at),\n gaps\n }\n}\n\nfunction calibrationGaps(asset: JudgeableAsset, classDefs: readonly ResourceClassDef[], at: string): AssetGap[] {\n const closure = classClosure(asset.assetClassIds, classDefs, at)\n const required = requiredTestsFor([...closure], classDefs, at)\n if (!required.length) {\n return []\n }\n\n const bySpec = new Map((asset.testResults ?? []).map(result => [result.specId, result]))\n const gaps: AssetGap[] = []\n\n for (const specId of required) {\n const result = bySpec.get(specId)\n\n if (!result || (result.result !== 'pass' && result.result !== 'fail')) {\n gaps.push({ assetName: asset.name, lack: 'calibration-missing', specId })\n continue\n }\n\n if (result.result === 'fail') {\n gaps.push({ assetName: asset.name, lack: 'calibration-failed', specId })\n continue\n }\n\n if (!testPassedAt(result, at)) {\n gaps.push({ assetName: asset.name, lack: 'calibration-expired', specId, expiredAt: result.expiresAt })\n }\n }\n\n return gaps\n}\n\n/** 가장 먼저 만료되는 교정 시각. 화면이 「언제까지 쓸 수 있나」를 보이는 데 쓴다. */\nfunction nearestExpiry(\n asset: JudgeableAsset,\n classDefs: readonly ResourceClassDef[],\n at: string\n): string | undefined {\n const closure = classClosure(asset.assetClassIds, classDefs, at)\n const required = new Set(requiredTestsFor([...closure], classDefs, at))\n let nearest: string | undefined\n\n for (const result of asset.testResults ?? []) {\n if (!required.has(result.specId) || result.result !== 'pass' || !result.expiresAt) {\n continue\n }\n if (!nearest || Date.parse(result.expiresAt) < Date.parse(nearest)) {\n nearest = result.expiresAt\n }\n }\n\n return nearest\n}\n\nfunction isoOf(at: Date | string | undefined): string | undefined {\n if (!at) {\n return undefined\n }\n\n return typeof at === 'string' ? at : at.toISOString()\n}\n"]}
@@ -0,0 +1,44 @@
1
+ import { ListParam } from '@things-factory/shell';
2
+ import { MasterPatch } from '../master-crud';
3
+ import { PhysicalAssetClass } from './physical-asset-class';
4
+ import { PhysicalAsset } from './physical-asset';
5
+ /**
6
+ * 물리 자산 축을 채우고 고친다.
7
+ *
8
+ * ── 왜 마스터는 그리드에서 고칠 수 있나 ────────────────────────────────────
9
+ * 업무 기록과 달리 마스터는 **선언**이다. 「이 사람이 용접 자격을 갖는다」는 일어난 일이 아니라 지금의
10
+ * 규정이고, 규정은 바뀐다. 없앨 때 행을 지우지 않고 유효 기간의 끝을 채우는 것이 그래서다 —
11
+ * 지우면 그것을 가리키는 지난 기록이 가리킬 것을 잃는다.
12
+ *
13
+ * 규칙은 `master-crud.ts` 한 곳에 있다. 여기는 축의 이름만 붙인다.
14
+ */
15
+ export declare class PhysicalAssetClassList {
16
+ items: PhysicalAssetClass[];
17
+ total: number;
18
+ }
19
+ export declare class PhysicalAssetClassResolver {
20
+ physicalAssetClasses(params: ListParam, context: ResolverContext): Promise<PhysicalAssetClassList>;
21
+ /**
22
+ * 그리드가 보낸 변경을 한 번에 적용한다.
23
+ *
24
+ * 패치를 `ScalarObject` 로 받는다 — 축마다 입력 타입을 따로 만들면 칸을 하나 더할 때마다 두 곳을
25
+ * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는
26
+ * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.
27
+ */
28
+ updateMultiplePhysicalAssetClass(patches: MasterPatch[], context: ResolverContext): Promise<PhysicalAssetClass[]>;
29
+ }
30
+ export declare class PhysicalAssetList {
31
+ items: PhysicalAsset[];
32
+ total: number;
33
+ }
34
+ export declare class PhysicalAssetResolver {
35
+ physicalAssets(params: ListParam, context: ResolverContext): Promise<PhysicalAssetList>;
36
+ /**
37
+ * 그리드가 보낸 변경을 한 번에 적용한다.
38
+ *
39
+ * 패치를 `ScalarObject` 로 받는다 — 축마다 입력 타입을 따로 만들면 칸을 하나 더할 때마다 두 곳을
40
+ * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는
41
+ * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.
42
+ */
43
+ updateMultiplePhysicalAsset(patches: MasterPatch[], context: ResolverContext): Promise<PhysicalAsset[]>;
44
+ }
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PhysicalAssetResolver = exports.PhysicalAssetList = exports.PhysicalAssetClassResolver = exports.PhysicalAssetClassList = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const type_graphql_1 = require("type-graphql");
6
+ const shell_1 = require("@things-factory/shell");
7
+ const master_crud_1 = require("../master-crud");
8
+ const master_axis_1 = require("../master-axis");
9
+ const master_list_1 = require("../master-list");
10
+ const physical_asset_class_1 = require("./physical-asset-class");
11
+ const physical_asset_1 = require("./physical-asset");
12
+ /**
13
+ * 물리 자산 축을 채우고 고친다.
14
+ *
15
+ * ── 왜 마스터는 그리드에서 고칠 수 있나 ────────────────────────────────────
16
+ * 업무 기록과 달리 마스터는 **선언**이다. 「이 사람이 용접 자격을 갖는다」는 일어난 일이 아니라 지금의
17
+ * 규정이고, 규정은 바뀐다. 없앨 때 행을 지우지 않고 유효 기간의 끝을 채우는 것이 그래서다 —
18
+ * 지우면 그것을 가리키는 지난 기록이 가리킬 것을 잃는다.
19
+ *
20
+ * 규칙은 `master-crud.ts` 한 곳에 있다. 여기는 축의 이름만 붙인다.
21
+ */
22
+ let PhysicalAssetClassList = class PhysicalAssetClassList {
23
+ };
24
+ exports.PhysicalAssetClassList = PhysicalAssetClassList;
25
+ tslib_1.__decorate([
26
+ (0, type_graphql_1.Field)(type => [physical_asset_class_1.PhysicalAssetClass]),
27
+ tslib_1.__metadata("design:type", Array)
28
+ ], PhysicalAssetClassList.prototype, "items", void 0);
29
+ tslib_1.__decorate([
30
+ (0, type_graphql_1.Field)(type => type_graphql_1.Int),
31
+ tslib_1.__metadata("design:type", Number)
32
+ ], PhysicalAssetClassList.prototype, "total", void 0);
33
+ exports.PhysicalAssetClassList = PhysicalAssetClassList = tslib_1.__decorate([
34
+ (0, type_graphql_1.ObjectType)({ description: 'A page of physical asset classes' })
35
+ ], PhysicalAssetClassList);
36
+ let PhysicalAssetClassResolver = class PhysicalAssetClassResolver {
37
+ async physicalAssetClasses(params, context) {
38
+ const { domain } = context.state;
39
+ const { items, total } = await (0, master_list_1.listMaster)('physicalAssetClass', params, domain);
40
+ return { items: items, total };
41
+ }
42
+ /**
43
+ * 그리드가 보낸 변경을 한 번에 적용한다.
44
+ *
45
+ * 패치를 `ScalarObject` 로 받는다 — 축마다 입력 타입을 따로 만들면 칸을 하나 더할 때마다 두 곳을
46
+ * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는
47
+ * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.
48
+ */
49
+ async updateMultiplePhysicalAssetClass(patches, context) {
50
+ const { domain, user, tx } = context.state;
51
+ const axis = (0, master_axis_1.masterAxisOf)('physicalAssetClass');
52
+ const saved = await (0, master_crud_1.saveMasterPatches)(tx, domain, axis.entity, patches, user, {
53
+ hasEffectivePeriod: axis.hasEffectivePeriod
54
+ });
55
+ return saved;
56
+ }
57
+ };
58
+ exports.PhysicalAssetClassResolver = PhysicalAssetClassResolver;
59
+ tslib_1.__decorate([
60
+ (0, type_graphql_1.Directive)('@privilege(category: "ops-master", privilege: "query", domainOwnerGranted: true)'),
61
+ (0, type_graphql_1.Query)(returns => PhysicalAssetClassList, { description: 'To fetch physical asset classes' }),
62
+ tslib_1.__param(0, (0, type_graphql_1.Args)(type => shell_1.ListParam)),
63
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
64
+ tslib_1.__metadata("design:type", Function),
65
+ tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
66
+ tslib_1.__metadata("design:returntype", Promise)
67
+ ], PhysicalAssetClassResolver.prototype, "physicalAssetClasses", null);
68
+ tslib_1.__decorate([
69
+ (0, type_graphql_1.Directive)('@privilege(category: "ops-master", privilege: "mutation", domainOwnerGranted: true)'),
70
+ (0, type_graphql_1.Directive)('@transaction'),
71
+ (0, type_graphql_1.Mutation)(returns => [physical_asset_class_1.PhysicalAssetClass], { description: 'To create, change or retire physical asset classes' }),
72
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('patches', type => [shell_1.ScalarObject])),
73
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
74
+ tslib_1.__metadata("design:type", Function),
75
+ tslib_1.__metadata("design:paramtypes", [Array, Object]),
76
+ tslib_1.__metadata("design:returntype", Promise)
77
+ ], PhysicalAssetClassResolver.prototype, "updateMultiplePhysicalAssetClass", null);
78
+ exports.PhysicalAssetClassResolver = PhysicalAssetClassResolver = tslib_1.__decorate([
79
+ (0, type_graphql_1.Resolver)(physical_asset_class_1.PhysicalAssetClass)
80
+ ], PhysicalAssetClassResolver);
81
+ let PhysicalAssetList = class PhysicalAssetList {
82
+ };
83
+ exports.PhysicalAssetList = PhysicalAssetList;
84
+ tslib_1.__decorate([
85
+ (0, type_graphql_1.Field)(type => [physical_asset_1.PhysicalAsset]),
86
+ tslib_1.__metadata("design:type", Array)
87
+ ], PhysicalAssetList.prototype, "items", void 0);
88
+ tslib_1.__decorate([
89
+ (0, type_graphql_1.Field)(type => type_graphql_1.Int),
90
+ tslib_1.__metadata("design:type", Number)
91
+ ], PhysicalAssetList.prototype, "total", void 0);
92
+ exports.PhysicalAssetList = PhysicalAssetList = tslib_1.__decorate([
93
+ (0, type_graphql_1.ObjectType)({ description: 'A page of physical assets' })
94
+ ], PhysicalAssetList);
95
+ let PhysicalAssetResolver = class PhysicalAssetResolver {
96
+ async physicalAssets(params, context) {
97
+ const { domain } = context.state;
98
+ const { items, total } = await (0, master_list_1.listMaster)('physicalAsset', params, domain);
99
+ return { items: items, total };
100
+ }
101
+ /**
102
+ * 그리드가 보낸 변경을 한 번에 적용한다.
103
+ *
104
+ * 패치를 `ScalarObject` 로 받는다 — 축마다 입력 타입을 따로 만들면 칸을 하나 더할 때마다 두 곳을
105
+ * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는
106
+ * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.
107
+ */
108
+ async updateMultiplePhysicalAsset(patches, context) {
109
+ const { domain, user, tx } = context.state;
110
+ const axis = (0, master_axis_1.masterAxisOf)('physicalAsset');
111
+ const saved = await (0, master_crud_1.saveMasterPatches)(tx, domain, axis.entity, patches, user, {
112
+ hasEffectivePeriod: axis.hasEffectivePeriod
113
+ });
114
+ return saved;
115
+ }
116
+ };
117
+ exports.PhysicalAssetResolver = PhysicalAssetResolver;
118
+ tslib_1.__decorate([
119
+ (0, type_graphql_1.Directive)('@privilege(category: "ops-master", privilege: "query", domainOwnerGranted: true)'),
120
+ (0, type_graphql_1.Query)(returns => PhysicalAssetList, { description: 'To fetch physical assets' }),
121
+ tslib_1.__param(0, (0, type_graphql_1.Args)(type => shell_1.ListParam)),
122
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
123
+ tslib_1.__metadata("design:type", Function),
124
+ tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
125
+ tslib_1.__metadata("design:returntype", Promise)
126
+ ], PhysicalAssetResolver.prototype, "physicalAssets", null);
127
+ tslib_1.__decorate([
128
+ (0, type_graphql_1.Directive)('@privilege(category: "ops-master", privilege: "mutation", domainOwnerGranted: true)'),
129
+ (0, type_graphql_1.Directive)('@transaction'),
130
+ (0, type_graphql_1.Mutation)(returns => [physical_asset_1.PhysicalAsset], { description: 'To create, change or retire physical assets' }),
131
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('patches', type => [shell_1.ScalarObject])),
132
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
133
+ tslib_1.__metadata("design:type", Function),
134
+ tslib_1.__metadata("design:paramtypes", [Array, Object]),
135
+ tslib_1.__metadata("design:returntype", Promise)
136
+ ], PhysicalAssetResolver.prototype, "updateMultiplePhysicalAsset", null);
137
+ exports.PhysicalAssetResolver = PhysicalAssetResolver = tslib_1.__decorate([
138
+ (0, type_graphql_1.Resolver)(physical_asset_1.PhysicalAsset)
139
+ ], PhysicalAssetResolver);
140
+ //# sourceMappingURL=asset-master-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-master-resolver.js","sourceRoot":"","sources":["../../../server/service/asset/asset-master-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Args, Arg, Ctx, Directive, Int, Mutation, ObjectType, Field, Query, Resolver } from 'type-graphql'\n\nimport { ListParam, ScalarObject } from '@things-factory/shell'\n\nimport { MasterPatch, saveMasterPatches } from '../master-crud'\nimport { masterAxisOf } from '../master-axis'\nimport { listMaster } from '../master-list'\nimport { PhysicalAssetClass } from './physical-asset-class'\nimport { PhysicalAsset } from './physical-asset'\n\n/**\n * 물리 자산 축을 채우고 고친다.\n *\n * ── 왜 마스터는 그리드에서 고칠 수 있나 ────────────────────────────────────\n * 업무 기록과 달리 마스터는 **선언**이다. 「이 사람이 용접 자격을 갖는다」는 일어난 일이 아니라 지금의\n * 규정이고, 규정은 바뀐다. 없앨 때 행을 지우지 않고 유효 기간의 끝을 채우는 것이 그래서다 —\n * 지우면 그것을 가리키는 지난 기록이 가리킬 것을 잃는다.\n *\n * 규칙은 `master-crud.ts` 한 곳에 있다. 여기는 축의 이름만 붙인다.\n */\n\n@ObjectType({ description: 'A page of physical asset classes' })\nexport class PhysicalAssetClassList {\n @Field(type => [PhysicalAssetClass])\n items: PhysicalAssetClass[]\n\n @Field(type => Int)\n total: number\n}\n\n@Resolver(PhysicalAssetClass)\nexport class PhysicalAssetClassResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => PhysicalAssetClassList, { description: 'To fetch physical asset classes' })\n async physicalAssetClasses(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<PhysicalAssetClassList> {\n const { domain } = context.state\n const { items, total } = await listMaster('physicalAssetClass', params, domain)\n\n return { items: items as PhysicalAssetClass[], total }\n }\n\n /**\n * 그리드가 보낸 변경을 한 번에 적용한다.\n *\n * 패치를 `ScalarObject` 로 받는다 — 축마다 입력 타입을 따로 만들면 칸을 하나 더할 때마다 두 곳을\n * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는\n * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.\n */\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [PhysicalAssetClass], { description: 'To create, change or retire physical asset classes' })\n async updateMultiplePhysicalAssetClass(\n @Arg('patches', type => [ScalarObject]) patches: MasterPatch[],\n @Ctx() context: ResolverContext\n ): Promise<PhysicalAssetClass[]> {\n const { domain, user, tx } = context.state\n const axis = masterAxisOf('physicalAssetClass')\n\n const saved = await saveMasterPatches(tx, domain, axis.entity, patches, user, {\n hasEffectivePeriod: axis.hasEffectivePeriod\n })\n\n return saved as PhysicalAssetClass[]\n }\n}\n\n@ObjectType({ description: 'A page of physical assets' })\nexport class PhysicalAssetList {\n @Field(type => [PhysicalAsset])\n items: PhysicalAsset[]\n\n @Field(type => Int)\n total: number\n}\n\n@Resolver(PhysicalAsset)\nexport class PhysicalAssetResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => PhysicalAssetList, { description: 'To fetch physical assets' })\n async physicalAssets(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<PhysicalAssetList> {\n const { domain } = context.state\n const { items, total } = await listMaster('physicalAsset', params, domain)\n\n return { items: items as PhysicalAsset[], total }\n }\n\n /**\n * 그리드가 보낸 변경을 한 번에 적용한다.\n *\n * 패치를 `ScalarObject` 로 받는다 — 축마다 입력 타입을 따로 만들면 칸을 하나 더할 때마다 두 곳을\n * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는\n * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.\n */\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [PhysicalAsset], { description: 'To create, change or retire physical assets' })\n async updateMultiplePhysicalAsset(\n @Arg('patches', type => [ScalarObject]) patches: MasterPatch[],\n @Ctx() context: ResolverContext\n ): Promise<PhysicalAsset[]> {\n const { domain, user, tx } = context.state\n const axis = masterAxisOf('physicalAsset')\n\n const saved = await saveMasterPatches(tx, domain, axis.entity, patches, user, {\n hasEffectivePeriod: axis.hasEffectivePeriod\n })\n\n return saved as PhysicalAsset[]\n }\n}\n"]}
@@ -0,0 +1,21 @@
1
+ import type { ResourceClassDef } from '@operato/ops-contract';
2
+ import type { PhysicalAsset } from './physical-asset';
3
+ import type { PhysicalAssetClass } from './physical-asset-class';
4
+ /** 트윈 `ReferenceMaster.assets` 의 한 항목. */
5
+ export interface AssetEntry {
6
+ id: string;
7
+ assetClassIds?: string[];
8
+ homeLocation?: string;
9
+ identity?: string;
10
+ properties?: unknown[];
11
+ testSpecificationIds?: string[];
12
+ testResults?: unknown[];
13
+ effectiveStart?: string;
14
+ effectiveEnd?: string;
15
+ }
16
+ export declare function toAssetEntry(asset: PhysicalAsset): AssetEntry;
17
+ /** 자산 축 전체 — 등급과 개체가 함께 나간다. */
18
+ export declare function assetMaster(classes: PhysicalAssetClass[], assets: PhysicalAsset[]): {
19
+ assetClasses: ResourceClassDef[];
20
+ assets: AssetEntry[];
21
+ };
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toAssetEntry = toAssetEntry;
4
+ exports.assetMaster = assetMaster;
5
+ const resource_class_1 = require("../resource/resource-class");
6
+ function toAssetEntry(asset) {
7
+ const out = { id: asset.name };
8
+ (0, resource_class_1.put)(out, 'assetClassIds', asset.assetClassIds);
9
+ (0, resource_class_1.put)(out, 'homeLocation', asset.homeLocation);
10
+ (0, resource_class_1.put)(out, 'identity', asset.identity);
11
+ (0, resource_class_1.put)(out, 'properties', asset.properties);
12
+ (0, resource_class_1.put)(out, 'testSpecificationIds', asset.testSpecificationIds);
13
+ (0, resource_class_1.put)(out, 'testResults', asset.testResults);
14
+ (0, resource_class_1.put)(out, 'effectiveStart', (0, resource_class_1.iso)(asset.effectiveStart));
15
+ (0, resource_class_1.put)(out, 'effectiveEnd', (0, resource_class_1.iso)(asset.effectiveEnd));
16
+ return out;
17
+ }
18
+ /** 자산 축 전체 — 등급과 개체가 함께 나간다. */
19
+ function assetMaster(classes, assets) {
20
+ return {
21
+ assetClasses: classes.map(resource_class_1.toResourceClassDef),
22
+ assets: assets.map(toAssetEntry)
23
+ };
24
+ }
25
+ //# sourceMappingURL=asset-master.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-master.js","sourceRoot":"","sources":["../../../server/service/asset/asset-master.ts"],"names":[],"mappings":";;AAmBA,oCAaC;AAGD,kCAQC;AAzCD,+DAAyE;AAiBzE,SAAgB,YAAY,CAAC,KAAoB;IAC/C,MAAM,GAAG,GAA4B,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,CAAA;IAEvD,IAAA,oBAAG,EAAC,GAAG,EAAE,eAAe,EAAE,KAAK,CAAC,aAAa,CAAC,CAAA;IAC9C,IAAA,oBAAG,EAAC,GAAG,EAAE,cAAc,EAAE,KAAK,CAAC,YAAY,CAAC,CAAA;IAC5C,IAAA,oBAAG,EAAC,GAAG,EAAE,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;IACpC,IAAA,oBAAG,EAAC,GAAG,EAAE,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC,CAAA;IACxC,IAAA,oBAAG,EAAC,GAAG,EAAE,sBAAsB,EAAE,KAAK,CAAC,oBAAoB,CAAC,CAAA;IAC5D,IAAA,oBAAG,EAAC,GAAG,EAAE,aAAa,EAAE,KAAK,CAAC,WAAW,CAAC,CAAA;IAC1C,IAAA,oBAAG,EAAC,GAAG,EAAE,gBAAgB,EAAE,IAAA,oBAAG,EAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAA;IACrD,IAAA,oBAAG,EAAC,GAAG,EAAE,cAAc,EAAE,IAAA,oBAAG,EAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAA;IAEjD,OAAO,GAA4B,CAAA;AACrC,CAAC;AAED,gCAAgC;AAChC,SAAgB,WAAW,CACzB,OAA6B,EAC7B,MAAuB;IAEvB,OAAO;QACL,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,mCAAkB,CAAC;QAC7C,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC;KACjC,CAAA;AACH,CAAC","sourcesContent":["import type { ResourceClassDef } from '@operato/ops-contract'\n\nimport { iso, put, toResourceClassDef } from '../resource/resource-class'\nimport type { PhysicalAsset } from './physical-asset'\nimport type { PhysicalAssetClass } from './physical-asset-class'\n\n/** 트윈 `ReferenceMaster.assets` 의 한 항목. */\nexport interface AssetEntry {\n id: string\n assetClassIds?: string[]\n homeLocation?: string\n identity?: string\n properties?: unknown[]\n testSpecificationIds?: string[]\n testResults?: unknown[]\n effectiveStart?: string\n effectiveEnd?: string\n}\n\nexport function toAssetEntry(asset: PhysicalAsset): AssetEntry {\n const out: Record<string, unknown> = { id: asset.name }\n\n put(out, 'assetClassIds', asset.assetClassIds)\n put(out, 'homeLocation', asset.homeLocation)\n put(out, 'identity', asset.identity)\n put(out, 'properties', asset.properties)\n put(out, 'testSpecificationIds', asset.testSpecificationIds)\n put(out, 'testResults', asset.testResults)\n put(out, 'effectiveStart', iso(asset.effectiveStart))\n put(out, 'effectiveEnd', iso(asset.effectiveEnd))\n\n return out as unknown as AssetEntry\n}\n\n/** 자산 축 전체 — 등급과 개체가 함께 나간다. */\nexport function assetMaster(\n classes: PhysicalAssetClass[],\n assets: PhysicalAsset[]\n): { assetClasses: ResourceClassDef[]; assets: AssetEntry[] } {\n return {\n assetClasses: classes.map(toResourceClassDef),\n assets: assets.map(toAssetEntry)\n }\n}\n"]}
@@ -0,0 +1,8 @@
1
+ export declare class AssetMaster {
2
+ assetClasses: string;
3
+ assets: string;
4
+ }
5
+ export declare class AssetQuery {
6
+ /** 자산 축 전체를 한 번에 낸다. */
7
+ assetMaster(context: ResolverContext): Promise<AssetMaster>;
8
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AssetQuery = exports.AssetMaster = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const type_graphql_1 = require("type-graphql");
6
+ const shell_1 = require("@things-factory/shell");
7
+ const asset_master_1 = require("./asset-master");
8
+ const physical_asset_1 = require("./physical-asset");
9
+ const physical_asset_class_1 = require("./physical-asset-class");
10
+ let AssetMaster = class AssetMaster {
11
+ };
12
+ exports.AssetMaster = AssetMaster;
13
+ tslib_1.__decorate([
14
+ (0, type_graphql_1.Field)(type => String, { description: 'ResourceClassDef[] as JSON text' }),
15
+ tslib_1.__metadata("design:type", String)
16
+ ], AssetMaster.prototype, "assetClasses", void 0);
17
+ tslib_1.__decorate([
18
+ (0, type_graphql_1.Field)(type => String, { description: 'ReferenceMaster assets[] as JSON text' }),
19
+ tslib_1.__metadata("design:type", String)
20
+ ], AssetMaster.prototype, "assets", void 0);
21
+ exports.AssetMaster = AssetMaster = tslib_1.__decorate([
22
+ (0, type_graphql_1.ObjectType)({ description: 'Physical asset master as the twin receives it' })
23
+ ], AssetMaster);
24
+ let AssetQuery = class AssetQuery {
25
+ /** 자산 축 전체를 한 번에 낸다. */
26
+ async assetMaster(context) {
27
+ const { domain } = context.state;
28
+ const [classes, assets] = await Promise.all([
29
+ (0, shell_1.getRepository)(physical_asset_class_1.PhysicalAssetClass).find({ where: { domain: { id: domain.id } }, order: { name: 'ASC' } }),
30
+ (0, shell_1.getRepository)(physical_asset_1.PhysicalAsset).find({ where: { domain: { id: domain.id } }, order: { name: 'ASC' } })
31
+ ]);
32
+ const master = (0, asset_master_1.assetMaster)(classes, assets);
33
+ return {
34
+ assetClasses: JSON.stringify(master.assetClasses),
35
+ assets: JSON.stringify(master.assets)
36
+ };
37
+ }
38
+ };
39
+ exports.AssetQuery = AssetQuery;
40
+ tslib_1.__decorate([
41
+ (0, type_graphql_1.Query)(returns => AssetMaster, { description: 'Physical asset master for the twin to pull' }),
42
+ tslib_1.__param(0, (0, type_graphql_1.Ctx)()),
43
+ tslib_1.__metadata("design:type", Function),
44
+ tslib_1.__metadata("design:paramtypes", [Object]),
45
+ tslib_1.__metadata("design:returntype", Promise)
46
+ ], AssetQuery.prototype, "assetMaster", null);
47
+ exports.AssetQuery = AssetQuery = tslib_1.__decorate([
48
+ (0, type_graphql_1.Resolver)(physical_asset_1.PhysicalAsset)
49
+ ], AssetQuery);
50
+ //# sourceMappingURL=asset-query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-query.js","sourceRoot":"","sources":["../../../server/service/asset/asset-query.ts"],"names":[],"mappings":";;;;AAAA,+CAAsE;AAEtE,iDAAqD;AAErD,iDAAgE;AAChE,qDAAgD;AAChD,iEAA2D;AAGpD,IAAM,WAAW,GAAjB,MAAM,WAAW;CAMvB,CAAA;AANY,kCAAW;AAEtB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,iCAAiC,EAAE,CAAC;;iDACtD;AAGpB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,uCAAuC,EAAE,CAAC;;2CAClE;sBALH,WAAW;IADvB,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,+CAA+C,EAAE,CAAC;GAChE,WAAW,CAMvB;AAGM,IAAM,UAAU,GAAhB,MAAM,UAAU;IACrB,wBAAwB;IAElB,AAAN,KAAK,CAAC,WAAW,CAAQ,OAAwB;QAC/C,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAEhC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC1C,IAAA,qBAAa,EAAC,yCAAkB,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACxG,IAAA,qBAAa,EAAC,8BAAa,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;SACpG,CAAC,CAAA;QAEF,MAAM,MAAM,GAAG,IAAA,0BAAgB,EAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAEhD,OAAO;YACL,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,YAAY,CAAC;YACjD,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC;SACtC,CAAA;IACH,CAAC;CACF,CAAA;AAlBY,gCAAU;AAGf;IADL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,WAAW,EAAE,4CAA4C,EAAE,CAAC;IAC1E,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;6CAcvB;qBAjBU,UAAU;IADtB,IAAA,uBAAQ,EAAC,8BAAa,CAAC;GACX,UAAU,CAkBtB","sourcesContent":["import { Ctx, Field, ObjectType, Query, Resolver } from 'type-graphql'\n\nimport { getRepository } from '@things-factory/shell'\n\nimport { assetMaster as buildAssetMaster } from './asset-master'\nimport { PhysicalAsset } from './physical-asset'\nimport { PhysicalAssetClass } from './physical-asset-class'\n\n@ObjectType({ description: 'Physical asset master as the twin receives it' })\nexport class AssetMaster {\n @Field(type => String, { description: 'ResourceClassDef[] as JSON text' })\n assetClasses: string\n\n @Field(type => String, { description: 'ReferenceMaster assets[] as JSON text' })\n assets: string\n}\n\n@Resolver(PhysicalAsset)\nexport class AssetQuery {\n /** 자산 축 전체를 한 번에 낸다. */\n @Query(returns => AssetMaster, { description: 'Physical asset master for the twin to pull' })\n async assetMaster(@Ctx() context: ResolverContext): Promise<AssetMaster> {\n const { domain } = context.state\n\n const [classes, assets] = await Promise.all([\n getRepository(PhysicalAssetClass).find({ where: { domain: { id: domain.id } }, order: { name: 'ASC' } }),\n getRepository(PhysicalAsset).find({ where: { domain: { id: domain.id } }, order: { name: 'ASC' } })\n ])\n\n const master = buildAssetMaster(classes, assets)\n\n return {\n assetClasses: JSON.stringify(master.assetClasses),\n assets: JSON.stringify(master.assets)\n }\n }\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import { AssetQuery } from './asset-query';
2
+ import { PhysicalAsset } from './physical-asset';
3
+ import { PhysicalAssetClass } from './physical-asset-class';
4
+ import { PhysicalAssetClassResolver, PhysicalAssetResolver } from './asset-master-resolver';
5
+ export declare const entities: (typeof PhysicalAsset | typeof PhysicalAssetClass)[];
6
+ export declare const resolvers: (typeof PhysicalAssetClassResolver | typeof PhysicalAssetResolver | typeof AssetQuery)[];
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolvers = exports.entities = void 0;
4
+ const asset_query_1 = require("./asset-query");
5
+ const physical_asset_1 = require("./physical-asset");
6
+ const physical_asset_class_1 = require("./physical-asset-class");
7
+ const asset_master_resolver_1 = require("./asset-master-resolver");
8
+ exports.entities = [physical_asset_class_1.PhysicalAssetClass, physical_asset_1.PhysicalAsset];
9
+ exports.resolvers = [asset_query_1.AssetQuery, asset_master_resolver_1.PhysicalAssetClassResolver, asset_master_resolver_1.PhysicalAssetResolver];
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/asset/index.ts"],"names":[],"mappings":";;;AAAA,+CAA0C;AAC1C,qDAAgD;AAChD,iEAA2D;AAC3D,mEAA2F;AAE9E,QAAA,QAAQ,GAAG,CAAC,yCAAkB,EAAE,8BAAa,CAAC,CAAA;AAC9C,QAAA,SAAS,GAAG,CAAC,wBAAU,EAAE,kDAA0B,EAAE,6CAAqB,CAAC,CAAA","sourcesContent":["import { AssetQuery } from './asset-query'\nimport { PhysicalAsset } from './physical-asset'\nimport { PhysicalAssetClass } from './physical-asset-class'\nimport { PhysicalAssetClassResolver, PhysicalAssetResolver } from './asset-master-resolver'\n\nexport const entities = [PhysicalAssetClass, PhysicalAsset]\nexport const resolvers = [AssetQuery, PhysicalAssetClassResolver, PhysicalAssetResolver]\n"]}
@@ -0,0 +1,34 @@
1
+ import { Domain } from '@things-factory/shell';
2
+ import { User } from '@things-factory/auth-base';
3
+ /**
4
+ * 자산 등급 — **ISA-95 `PhysicalAssetClass`**.
5
+ *
6
+ * 물리 자산은 반복해서 쓰는 물건이다 — 팔레트 · 랙 · 지그. 설비와 다른 점은 **돌아온다**는 것이다.
7
+ * 공정이 「팔레트 1개」를 요구하고, 그것이 모자라면 출고가 못 나간다.
8
+ *
9
+ * 구조는 인원 등급 · 설비 등급과 같다(표준이 셋을 같은 모양으로 정의한다).
10
+ */
11
+ export declare class PhysicalAssetClass {
12
+ readonly id: string;
13
+ domain?: Domain;
14
+ domainId?: string;
15
+ /** 표준 `PhysicalAssetClassID`. */
16
+ name: string;
17
+ description?: string;
18
+ /** 상위 등급들 — 표준 `PhysicalAssetClassBaseID`(복수). 「6축 용접기」가 「용접기」를 상속한다. */
19
+ baseIds?: string[];
20
+ /** 이 등급의 적격을 정하는 `TestSpecification` 참조들 — 표준 `TestSpecificationID`. */
21
+ testSpecificationIds?: string[];
22
+ /** 등급 속성 — 표준 `PhysicalAssetClassProperty`. */
23
+ properties?: Record<string, unknown>[];
24
+ /** 언제부터 유효한가 — 표준 `EffectiveStartDate`. */
25
+ effectiveStart?: Date;
26
+ /** 언제까지 유효한가 — 표준 `EffectiveEndDate`. */
27
+ effectiveEnd?: Date;
28
+ createdAt?: Date;
29
+ updatedAt?: Date;
30
+ creator?: User;
31
+ creatorId?: string;
32
+ updater?: User;
33
+ updaterId?: string;
34
+ }
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PhysicalAssetClass = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const typeorm_1 = require("typeorm");
6
+ const type_graphql_1 = require("type-graphql");
7
+ const shell_1 = require("@things-factory/shell");
8
+ const auth_base_1 = require("@things-factory/auth-base");
9
+ /**
10
+ * 자산 등급 — **ISA-95 `PhysicalAssetClass`**.
11
+ *
12
+ * 물리 자산은 반복해서 쓰는 물건이다 — 팔레트 · 랙 · 지그. 설비와 다른 점은 **돌아온다**는 것이다.
13
+ * 공정이 「팔레트 1개」를 요구하고, 그것이 모자라면 출고가 못 나간다.
14
+ *
15
+ * 구조는 인원 등급 · 설비 등급과 같다(표준이 셋을 같은 모양으로 정의한다).
16
+ */
17
+ let PhysicalAssetClass = class PhysicalAssetClass {
18
+ };
19
+ exports.PhysicalAssetClass = PhysicalAssetClass;
20
+ tslib_1.__decorate([
21
+ (0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
22
+ (0, type_graphql_1.Field)(type => type_graphql_1.ID),
23
+ tslib_1.__metadata("design:type", String)
24
+ ], PhysicalAssetClass.prototype, "id", void 0);
25
+ tslib_1.__decorate([
26
+ (0, typeorm_1.ManyToOne)(type => shell_1.Domain),
27
+ (0, type_graphql_1.Field)(type => shell_1.Domain),
28
+ tslib_1.__metadata("design:type", shell_1.Domain)
29
+ ], PhysicalAssetClass.prototype, "domain", void 0);
30
+ tslib_1.__decorate([
31
+ (0, typeorm_1.RelationId)((klass) => klass.domain),
32
+ tslib_1.__metadata("design:type", String)
33
+ ], PhysicalAssetClass.prototype, "domainId", void 0);
34
+ tslib_1.__decorate([
35
+ (0, typeorm_1.Column)(),
36
+ (0, type_graphql_1.Field)(),
37
+ tslib_1.__metadata("design:type", String)
38
+ ], PhysicalAssetClass.prototype, "name", void 0);
39
+ tslib_1.__decorate([
40
+ (0, typeorm_1.Column)({ nullable: true }),
41
+ (0, type_graphql_1.Field)({ nullable: true }),
42
+ tslib_1.__metadata("design:type", String)
43
+ ], PhysicalAssetClass.prototype, "description", void 0);
44
+ tslib_1.__decorate([
45
+ (0, typeorm_1.Column)({ type: 'simple-json', nullable: true }),
46
+ (0, type_graphql_1.Field)(type => [String], { nullable: true }),
47
+ tslib_1.__metadata("design:type", Array)
48
+ ], PhysicalAssetClass.prototype, "baseIds", void 0);
49
+ tslib_1.__decorate([
50
+ (0, typeorm_1.Column)({ type: 'simple-json', nullable: true }),
51
+ (0, type_graphql_1.Field)(type => [String], { nullable: true }),
52
+ tslib_1.__metadata("design:type", Array)
53
+ ], PhysicalAssetClass.prototype, "testSpecificationIds", void 0);
54
+ tslib_1.__decorate([
55
+ (0, typeorm_1.Column)({ type: 'simple-json', nullable: true }),
56
+ (0, type_graphql_1.Field)(type => String, { nullable: true, description: 'ResourceProperty[] as JSON text' }),
57
+ tslib_1.__metadata("design:type", Array)
58
+ ], PhysicalAssetClass.prototype, "properties", void 0);
59
+ tslib_1.__decorate([
60
+ (0, typeorm_1.Column)({ nullable: true }),
61
+ (0, type_graphql_1.Field)({ nullable: true }),
62
+ tslib_1.__metadata("design:type", Date
63
+ /** 언제까지 유효한가 — 표준 `EffectiveEndDate`. */
64
+ )
65
+ ], PhysicalAssetClass.prototype, "effectiveStart", void 0);
66
+ tslib_1.__decorate([
67
+ (0, typeorm_1.Column)({ nullable: true }),
68
+ (0, type_graphql_1.Field)({ nullable: true }),
69
+ tslib_1.__metadata("design:type", Date)
70
+ ], PhysicalAssetClass.prototype, "effectiveEnd", void 0);
71
+ tslib_1.__decorate([
72
+ (0, typeorm_1.CreateDateColumn)(),
73
+ (0, type_graphql_1.Field)({ nullable: true }),
74
+ tslib_1.__metadata("design:type", Date)
75
+ ], PhysicalAssetClass.prototype, "createdAt", void 0);
76
+ tslib_1.__decorate([
77
+ (0, typeorm_1.UpdateDateColumn)(),
78
+ (0, type_graphql_1.Field)({ nullable: true }),
79
+ tslib_1.__metadata("design:type", Date)
80
+ ], PhysicalAssetClass.prototype, "updatedAt", void 0);
81
+ tslib_1.__decorate([
82
+ (0, typeorm_1.ManyToOne)(type => auth_base_1.User, { nullable: true }),
83
+ (0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true }),
84
+ tslib_1.__metadata("design:type", auth_base_1.User)
85
+ ], PhysicalAssetClass.prototype, "creator", void 0);
86
+ tslib_1.__decorate([
87
+ (0, typeorm_1.RelationId)((klass) => klass.creator),
88
+ tslib_1.__metadata("design:type", String)
89
+ ], PhysicalAssetClass.prototype, "creatorId", void 0);
90
+ tslib_1.__decorate([
91
+ (0, typeorm_1.ManyToOne)(type => auth_base_1.User, { nullable: true }),
92
+ (0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true }),
93
+ tslib_1.__metadata("design:type", auth_base_1.User)
94
+ ], PhysicalAssetClass.prototype, "updater", void 0);
95
+ tslib_1.__decorate([
96
+ (0, typeorm_1.RelationId)((klass) => klass.updater),
97
+ tslib_1.__metadata("design:type", String)
98
+ ], PhysicalAssetClass.prototype, "updaterId", void 0);
99
+ exports.PhysicalAssetClass = PhysicalAssetClass = tslib_1.__decorate([
100
+ (0, typeorm_1.Entity)({ name: 'ops_physical_asset_class' }),
101
+ (0, typeorm_1.Index)('ix_ops_physical_asset_class_0', (klass) => [klass.domain, klass.name], { unique: true }),
102
+ (0, type_graphql_1.ObjectType)({ description: 'ISA-95 PhysicalAssetClass — a kind of equipment that operations require' })
103
+ ], PhysicalAssetClass);
104
+ //# sourceMappingURL=physical-asset-class.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"physical-asset-class.js","sourceRoot":"","sources":["../../../server/service/asset/physical-asset-class.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Column,\n CreateDateColumn,\n Entity,\n Index,\n ManyToOne,\n PrimaryGeneratedColumn,\n RelationId,\n UpdateDateColumn\n} from 'typeorm'\nimport { Field, ID, ObjectType } from 'type-graphql'\n\nimport { Domain } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\n\n/**\n * 자산 등급 — **ISA-95 `PhysicalAssetClass`**.\n *\n * 물리 자산은 반복해서 쓰는 물건이다 — 팔레트 · 랙 · 지그. 설비와 다른 점은 **돌아온다**는 것이다.\n * 공정이 「팔레트 1개」를 요구하고, 그것이 모자라면 출고가 못 나간다.\n *\n * 구조는 인원 등급 · 설비 등급과 같다(표준이 셋을 같은 모양으로 정의한다).\n */\n@Entity({ name: 'ops_physical_asset_class' })\n@Index('ix_ops_physical_asset_class_0', (klass: PhysicalAssetClass) => [klass.domain, klass.name], { unique: true })\n@ObjectType({ description: 'ISA-95 PhysicalAssetClass — a kind of equipment that operations require' })\nexport class PhysicalAssetClass {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain)\n domain?: Domain\n\n @RelationId((klass: PhysicalAssetClass) => klass.domain)\n domainId?: string\n\n /** 표준 `PhysicalAssetClassID`. */\n @Column()\n @Field()\n name: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n description?: string\n\n /** 상위 등급들 — 표준 `PhysicalAssetClassBaseID`(복수). 「6축 용접기」가 「용접기」를 상속한다. */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => [String], { nullable: true })\n baseIds?: string[]\n\n /** 이 등급의 적격을 정하는 `TestSpecification` 참조들 — 표준 `TestSpecificationID`. */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => [String], { nullable: true })\n testSpecificationIds?: string[]\n\n /** 등급 속성 — 표준 `PhysicalAssetClassProperty`. */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => String, { nullable: true, description: 'ResourceProperty[] as JSON text' })\n properties?: Record<string, unknown>[]\n\n /** 언제부터 유효한가 — 표준 `EffectiveStartDate`. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n effectiveStart?: Date\n\n /** 언제까지 유효한가 — 표준 `EffectiveEndDate`. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n effectiveEnd?: Date\n\n @CreateDateColumn()\n @Field({ nullable: true })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true })\n updatedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n creator?: User\n\n @RelationId((klass: PhysicalAssetClass) => klass.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n updater?: User\n\n @RelationId((klass: PhysicalAssetClass) => klass.updater)\n updaterId?: string\n}\n"]}