@things-factory/ops-master 10.0.19 → 10.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/bootstrap.d.ts +18 -0
- package/dist-client/bootstrap.js +36 -0
- package/dist-client/bootstrap.js.map +1 -0
- package/dist-client/index.d.ts +15 -1
- package/dist-client/index.js +18 -1
- package/dist-client/index.js.map +1 -1
- package/dist-client/pages/master/equipment-class.d.ts +12 -0
- package/dist-client/pages/master/equipment-class.js +42 -0
- package/dist-client/pages/master/equipment-class.js.map +1 -0
- package/dist-client/pages/master/equipment.d.ts +12 -0
- package/dist-client/pages/master/equipment.js +57 -0
- package/dist-client/pages/master/equipment.js.map +1 -0
- package/dist-client/pages/master/grist-iso-duration.d.ts +20 -0
- package/dist-client/pages/master/grist-iso-duration.js +70 -0
- package/dist-client/pages/master/grist-iso-duration.js.map +1 -0
- package/dist-client/pages/master/grist-reference.d.ts +91 -0
- package/dist-client/pages/master/grist-reference.js +419 -0
- package/dist-client/pages/master/grist-reference.js.map +1 -0
- package/dist-client/pages/master/import-rows.d.ts +35 -0
- package/dist-client/pages/master/import-rows.js +66 -0
- package/dist-client/pages/master/import-rows.js.map +1 -0
- package/dist-client/pages/master/iso-duration.d.ts +34 -0
- package/dist-client/pages/master/iso-duration.js +76 -0
- package/dist-client/pages/master/iso-duration.js.map +1 -0
- package/dist-client/pages/master/master-options.d.ts +33 -0
- package/dist-client/pages/master/master-options.js +47 -0
- package/dist-client/pages/master/master-options.js.map +1 -0
- package/dist-client/pages/master/master-page-base.d.ts +357 -0
- package/dist-client/pages/master/master-page-base.js +626 -0
- package/dist-client/pages/master/master-page-base.js.map +1 -0
- package/dist-client/pages/master/material-class.d.ts +12 -0
- package/dist-client/pages/master/material-class.js +42 -0
- package/dist-client/pages/master/material-class.js.map +1 -0
- package/dist-client/pages/master/material-definition.d.ts +12 -0
- package/dist-client/pages/master/material-definition.js +62 -0
- package/dist-client/pages/master/material-definition.js.map +1 -0
- package/dist-client/pages/master/operation-definition.d.ts +12 -0
- package/dist-client/pages/master/operation-definition.js +49 -0
- package/dist-client/pages/master/operation-definition.js.map +1 -0
- package/dist-client/pages/master/operational-location.d.ts +84 -0
- package/dist-client/pages/master/operational-location.js +426 -0
- package/dist-client/pages/master/operational-location.js.map +1 -0
- package/dist-client/pages/master/person.d.ts +12 -0
- package/dist-client/pages/master/person.js +41 -0
- package/dist-client/pages/master/person.js.map +1 -0
- package/dist-client/pages/master/personnel-class.d.ts +12 -0
- package/dist-client/pages/master/personnel-class.js +43 -0
- package/dist-client/pages/master/personnel-class.js.map +1 -0
- package/dist-client/pages/master/physical-asset-class.d.ts +12 -0
- package/dist-client/pages/master/physical-asset-class.js +40 -0
- package/dist-client/pages/master/physical-asset-class.js.map +1 -0
- package/dist-client/pages/master/physical-asset.d.ts +12 -0
- package/dist-client/pages/master/physical-asset.js +41 -0
- package/dist-client/pages/master/physical-asset.js.map +1 -0
- package/dist-client/pages/master/recipe-definition.d.ts +136 -0
- package/dist-client/pages/master/recipe-definition.js +404 -0
- package/dist-client/pages/master/recipe-definition.js.map +1 -0
- package/dist-client/pages/master/reference-targets.d.ts +42 -0
- package/dist-client/pages/master/reference-targets.js +82 -0
- package/dist-client/pages/master/reference-targets.js.map +1 -0
- package/dist-client/pages/master/route-definition.d.ts +19 -0
- package/dist-client/pages/master/route-definition.js +40 -0
- package/dist-client/pages/master/route-definition.js.map +1 -0
- package/dist-client/pages/master/stop-reason.d.ts +12 -0
- package/dist-client/pages/master/stop-reason.js +48 -0
- package/dist-client/pages/master/stop-reason.js.map +1 -0
- package/dist-client/pages/master/test-specification.d.ts +93 -0
- package/dist-client/pages/master/test-specification.js +449 -0
- package/dist-client/pages/master/test-specification.js.map +1 -0
- package/dist-client/pages/master-axes.d.ts +20 -29
- package/dist-client/pages/master-axes.js +32 -182
- package/dist-client/pages/master-axes.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +76 -3
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/asset/asset-lifecycle.d.ts +30 -7
- package/dist-server/service/asset/asset-lifecycle.js +33 -6
- package/dist-server/service/asset/asset-lifecycle.js.map +1 -1
- package/dist-server/service/asset/asset-master-resolver.d.ts +9 -0
- package/dist-server/service/asset/asset-master-resolver.js +41 -0
- package/dist-server/service/asset/asset-master-resolver.js.map +1 -1
- package/dist-server/service/asset/asset-master.js +1 -1
- package/dist-server/service/asset/asset-master.js.map +1 -1
- package/dist-server/service/asset/asset-query.d.ts +9 -1
- package/dist-server/service/asset/asset-query.js +28 -6
- package/dist-server/service/asset/asset-query.js.map +1 -1
- package/dist-server/service/asset/physical-asset-class.js +1 -1
- package/dist-server/service/asset/physical-asset-class.js.map +1 -1
- package/dist-server/service/asset/physical-asset.d.ts +17 -4
- package/dist-server/service/asset/physical-asset.js +6 -6
- package/dist-server/service/asset/physical-asset.js.map +1 -1
- package/dist-server/service/equipment/equipment-class.js +1 -1
- package/dist-server/service/equipment/equipment-class.js.map +1 -1
- package/dist-server/service/equipment/equipment-master-resolver.d.ts +9 -0
- package/dist-server/service/equipment/equipment-master-resolver.js +58 -0
- package/dist-server/service/equipment/equipment-master-resolver.js.map +1 -1
- package/dist-server/service/equipment/equipment-master.d.ts +3 -2
- package/dist-server/service/equipment/equipment-master.js +21 -4
- package/dist-server/service/equipment/equipment-master.js.map +1 -1
- package/dist-server/service/equipment/equipment-query.d.ts +9 -1
- package/dist-server/service/equipment/equipment-query.js +28 -6
- package/dist-server/service/equipment/equipment-query.js.map +1 -1
- package/dist-server/service/equipment/equipment.d.ts +27 -1
- package/dist-server/service/equipment/equipment.js +8 -3
- package/dist-server/service/equipment/equipment.js.map +1 -1
- package/dist-server/service/equipment/state-period-rules.d.ts +19 -0
- package/dist-server/service/equipment/state-period-rules.js +35 -1
- package/dist-server/service/equipment/state-period-rules.js.map +1 -1
- package/dist-server/service/index.d.ts +4 -1
- package/dist-server/service/index.js +11 -2
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/location/location-master-resolver.d.ts +29 -0
- package/dist-server/service/location/location-master-resolver.js +228 -1
- package/dist-server/service/location/location-master-resolver.js.map +1 -1
- package/dist-server/service/location/location-query.d.ts +9 -1
- package/dist-server/service/location/location-query.js +24 -9
- package/dist-server/service/location/location-query.js.map +1 -1
- package/dist-server/service/location/operational-location.d.ts +37 -0
- package/dist-server/service/location/operational-location.js +22 -2
- package/dist-server/service/location/operational-location.js.map +1 -1
- package/dist-server/service/master-axis.js +2 -2
- package/dist-server/service/master-axis.js.map +1 -1
- package/dist-server/service/master-conformance-resolver.d.ts +34 -0
- package/dist-server/service/master-conformance-resolver.js +143 -0
- package/dist-server/service/master-conformance-resolver.js.map +1 -0
- package/dist-server/service/master-conformance.d.ts +80 -0
- package/dist-server/service/master-conformance.js +266 -0
- package/dist-server/service/master-conformance.js.map +1 -0
- package/dist-server/service/master-page-query.d.ts +33 -0
- package/dist-server/service/master-page-query.js +55 -0
- package/dist-server/service/master-page-query.js.map +1 -0
- package/dist-server/service/master-page.d.ts +85 -0
- package/dist-server/service/master-page.js +104 -0
- package/dist-server/service/master-page.js.map +1 -0
- package/dist-server/service/material/material-class.js +1 -1
- package/dist-server/service/material/material-class.js.map +1 -1
- package/dist-server/service/material/material-definition.js +2 -2
- package/dist-server/service/material/material-definition.js.map +1 -1
- package/dist-server/service/material/material-master-resolver.d.ts +62 -0
- package/dist-server/service/material/material-master-resolver.js +213 -0
- package/dist-server/service/material/material-master-resolver.js.map +1 -1
- package/dist-server/service/material/material-query.d.ts +9 -1
- package/dist-server/service/material/material-query.js +28 -6
- package/dist-server/service/material/material-query.js.map +1 -1
- package/dist-server/service/material/recipe-index.d.ts +23 -0
- package/dist-server/service/material/recipe-index.js +44 -0
- package/dist-server/service/material/recipe-index.js.map +1 -0
- package/dist-server/service/operation/operation-definition.d.ts +1 -1
- package/dist-server/service/operation/operation-definition.js +4 -4
- package/dist-server/service/operation/operation-definition.js.map +1 -1
- package/dist-server/service/operation/operation-master-resolver.d.ts +24 -0
- package/dist-server/service/operation/operation-master-resolver.js +107 -0
- package/dist-server/service/operation/operation-master-resolver.js.map +1 -1
- package/dist-server/service/operation/operation-query.d.ts +10 -2
- package/dist-server/service/operation/operation-query.js +25 -10
- package/dist-server/service/operation/operation-query.js.map +1 -1
- package/dist-server/service/personnel/person.js +3 -3
- package/dist-server/service/personnel/person.js.map +1 -1
- package/dist-server/service/personnel/personnel-class.d.ts +1 -1
- package/dist-server/service/personnel/personnel-class.js +2 -2
- package/dist-server/service/personnel/personnel-class.js.map +1 -1
- package/dist-server/service/personnel/personnel-master-resolver.d.ts +9 -0
- package/dist-server/service/personnel/personnel-master-resolver.js +43 -0
- package/dist-server/service/personnel/personnel-master-resolver.js.map +1 -1
- package/dist-server/service/personnel/personnel-master.js +1 -1
- package/dist-server/service/personnel/personnel-master.js.map +1 -1
- package/dist-server/service/personnel/personnel-query.d.ts +9 -1
- package/dist-server/service/personnel/personnel-query.js +28 -6
- package/dist-server/service/personnel/personnel-query.js.map +1 -1
- package/dist-server/service/recipe/recipe-definition.d.ts +3 -3
- package/dist-server/service/recipe/recipe-definition.js +3 -3
- package/dist-server/service/recipe/recipe-definition.js.map +1 -1
- package/dist-server/service/recipe/recipe-master-resolver.d.ts +1 -1
- package/dist-server/service/recipe/recipe-master-resolver.js +1 -1
- package/dist-server/service/recipe/recipe-master-resolver.js.map +1 -1
- package/dist-server/service/recipe/recipe-master.d.ts +1 -1
- package/dist-server/service/recipe/recipe-master.js +2 -2
- package/dist-server/service/recipe/recipe-master.js.map +1 -1
- package/dist-server/service/recipe/recipe-query.d.ts +11 -3
- package/dist-server/service/recipe/recipe-query.js +30 -9
- package/dist-server/service/recipe/recipe-query.js.map +1 -1
- package/dist-server/service/recipe/route-definition.d.ts +6 -6
- package/dist-server/service/recipe/route-definition.js +6 -6
- package/dist-server/service/recipe/route-definition.js.map +1 -1
- package/dist-server/service/resource/class-lineage.d.ts +46 -0
- package/dist-server/service/resource/class-lineage.js +80 -0
- package/dist-server/service/resource/class-lineage.js.map +1 -0
- package/dist-server/service/resource/class-members.d.ts +36 -0
- package/dist-server/service/resource/class-members.js +50 -0
- package/dist-server/service/resource/class-members.js.map +1 -0
- package/dist-server/service/resource/referrers.d.ts +54 -0
- package/dist-server/service/resource/referrers.js +99 -0
- package/dist-server/service/resource/referrers.js.map +1 -0
- package/dist-server/service/test-spec/criteria-check.d.ts +53 -0
- package/dist-server/service/test-spec/criteria-check.js +142 -0
- package/dist-server/service/test-spec/criteria-check.js.map +1 -0
- package/dist-server/service/test-spec/criteria-rows.d.ts +89 -0
- package/dist-server/service/test-spec/criteria-rows.js +139 -0
- package/dist-server/service/test-spec/criteria-rows.js.map +1 -0
- package/dist-server/service/test-spec/test-spec-master-resolver.d.ts +33 -7
- package/dist-server/service/test-spec/test-spec-master-resolver.js +137 -2
- package/dist-server/service/test-spec/test-spec-master-resolver.js.map +1 -1
- package/dist-server/service/test-spec/test-spec-query.d.ts +9 -1
- package/dist-server/service/test-spec/test-spec-query.js +23 -9
- package/dist-server/service/test-spec/test-spec-query.js.map +1 -1
- package/dist-server/service/test-spec/test-specification.js +1 -1
- package/dist-server/service/test-spec/test-specification.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/helps/ops-master/equipment-class.ko.md +11 -0
- package/helps/ops-master/equipment-class.md +11 -0
- package/helps/ops-master/equipment.ko.md +11 -0
- package/helps/ops-master/equipment.md +11 -0
- package/helps/ops-master/material-class.ko.md +11 -0
- package/helps/ops-master/material-class.md +11 -0
- package/helps/ops-master/material-definition.ko.md +11 -0
- package/helps/ops-master/material-definition.md +11 -0
- package/helps/ops-master/operation-definition.ko.md +11 -0
- package/helps/ops-master/operation-definition.md +11 -0
- package/helps/ops-master/operational-location.ko.md +11 -0
- package/helps/ops-master/operational-location.md +11 -0
- package/helps/ops-master/person.ko.md +11 -0
- package/helps/ops-master/person.md +11 -0
- package/helps/ops-master/personnel-class.ko.md +11 -0
- package/helps/ops-master/personnel-class.md +11 -0
- package/helps/ops-master/physical-asset-class.ko.md +11 -0
- package/helps/ops-master/physical-asset-class.md +11 -0
- package/helps/ops-master/physical-asset.ko.md +11 -0
- package/helps/ops-master/physical-asset.md +11 -0
- package/helps/ops-master/recipe-definition.ko.md +11 -0
- package/helps/ops-master/recipe-definition.md +11 -0
- package/helps/ops-master/route-definition.ko.md +11 -0
- package/helps/ops-master/route-definition.md +11 -0
- package/helps/ops-master/stop-reason.ko.md +11 -0
- package/helps/ops-master/stop-reason.md +11 -0
- package/helps/ops-master/test-specification.ko.md +11 -0
- package/helps/ops-master/test-specification.md +11 -0
- package/package.json +6 -6
- package/things-factory.config.js +22 -2
- package/translations/en.json +86 -3
- package/translations/ja.json +92 -1
- package/translations/ko.json +93 -10
- package/translations/ms.json +92 -1
- package/translations/zh.json +92 -1
- package/dist-client/pages/master-list.d.ts +0 -68
- package/dist-client/pages/master-list.js +0 -239
- package/dist-client/pages/master-list.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-period-rules.js","sourceRoot":"","sources":["../../../server/service/equipment/state-period-rules.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;
|
|
1
|
+
{"version":3,"file":"state-period-rules.js","sourceRoot":"","sources":["../../../server/service/equipment/state-period-rules.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 상태 구간을 받아도 되나 — **순수 판단.**\n *\n * ── 왜 규칙이 필요한가 ──────────────────────────────────────────────────────\n * 구간은 사람이 되돌아가 적는다. 그래서 겹치고, 거꾸로 되고, 미래로 간다. 그대로 받으면 가동률의\n * 분자가 분모보다 커지는 날이 온다. 그때는 이미 잘못된 구간이 수백 개 쌓여 있다.\n *\n * ── 왜 사유와 상태를 맞춰 보나 ──────────────────────────────────────────────\n * ISO 22400 에서 가동률을 깎느냐 마느냐는 **상태**가 정한다. 「점심시간」을 `down` 으로 적으면 가동률이\n * 오류 보고 없이 낮아지고, 「고장」을 `planned-stop` 으로 적으면 오류 보고 없이 높아진다. 둘 다 조용한\n * 거짓이라 나중에 찾을 방법이 없다.\n */\n\n/** 계약의 `EQUIPMENT_STATUS` 와 같은 어휘. 여기서 새로 만들지 않는다. */\nexport const EQUIPMENT_PERIOD_STATUS = ['idle', 'busy', 'down', 'setup', 'planned-stop'] as const\n\nexport type EquipmentPeriodStatus = (typeof EQUIPMENT_PERIOD_STATUS)[number]\n\n/**\n * 정지 사유가 붙을 수 있는 상태 — **`busy` 는 빠진다.**\n *\n * 돌고 있는 것에는 사유가 없다(§`StopReason.status` 주석). 그래서 구간이 가질 수 있는 상태는 다섯인데\n * 사유가 가질 수 있는 상태는 넷이다.\n */\nexport const STOP_REASON_STATUS = EQUIPMENT_PERIOD_STATUS.filter(status => status !== 'busy')\n\n/**\n * 이 사유를 마스터에 적을 수 있나 — **적을 수 없으면 왜인지, 그리고 무엇이 되는지.**\n *\n * ── 왜 마스터에서 막나 (2026-09-03) ────────────────────────────────────────\n * 사유의 `status` 가 자유 문자열이라 `broken` 이 그대로 저장됐다. 그러면 **그 사유를 쓴 모든 구간이**\n * 「사유와 상태가 어긋난다」로 걸린다(§`reasonIssues`). 잘못은 마스터 한 줄에서 났는데 불은 구간\n * 수백 개에서 켜지고, 그 문장은 마스터를 가리키지 않는다.\n *\n * 그래서 틀린 자리에서 막는다. 구간 쪽 검사는 그대로 둔다 — 마스터를 채우기 전에 쓰인 지난 줄과,\n * 사유를 나중에 고친 경우가 거기서 걸린다.\n */\nexport function stopReasonStatusGap(status: unknown): string | undefined {\n const said = typeof status === 'string' ? status.trim() : ''\n\n if (!said) {\n return (\n '정지 사유에는 어느 상태에 쓰이는지가 있어야 합니다 — 가동률을 깎느냐 마느냐를 그 값이 정합니다 ' +\n `(쓸 수 있는 것: ${STOP_REASON_STATUS.join(' · ')})`\n )\n }\n\n if (said === 'busy') {\n return '돌고 있는 상태에는 정지 사유가 없습니다 — busy 는 정지가 아닙니다'\n }\n\n if (!(STOP_REASON_STATUS as readonly string[]).includes(said)) {\n return (\n `모르는 상태입니다: \"${said}\" — 이 값으로 저장하면 그 사유를 쓴 모든 구간이 어긋남으로 걸립니다 ` +\n `(쓸 수 있는 것: ${STOP_REASON_STATUS.join(' · ')})`\n )\n }\n\n return undefined\n}\n\nexport type PeriodProblem =\n /** 끝이 시작보다 앞이거나 같다 — 길이가 없는 구간은 셀 것이 없다. */\n | 'not-a-period'\n /** 아직 오지 않은 시각이다. */\n | 'in-the-future'\n /** 같은 설비의 다른 구간과 겹친다 — 한 설비가 같은 시각에 두 상태일 수 없다. */\n | 'overlaps'\n /** 계약이 모르는 상태다. */\n | 'unknown-status'\n /** 사유가 사유 마스터에 없다. */\n | 'unknown-reason'\n /** 사유가 이 상태의 사유가 아니다 — 가동률이 오류 보고 없이 틀어진다. */\n | 'reason-status-mismatch'\n /** 이 사유는 상세를 함께 적어야 한다. */\n | 'detail-required'\n\nexport interface PeriodIssue {\n problem: PeriodProblem\n /** 겹치는 것이면 어느 구간과 겹치나(시작 시각, ISO). */\n conflictsWith?: string\n /** 사유 문제이면 어느 사유인가. */\n reasonCode?: string\n /** 사유가 속한 상태와 적힌 상태. */\n reasonStatus?: string\n status?: string\n}\n\nexport interface JudgeablePeriod {\n status: string\n startTime: Date | string\n endTime: Date | string\n reasonCode?: string\n reasonDetail?: string\n}\n\n/** 사유 마스터에서 필요한 것만. */\nexport interface StopReasonFact {\n name: string\n status: string\n detailRequired?: boolean\n}\n\n/** 이미 적혀 있는 구간 — 겹침을 볼 때만 쓴다. */\nexport interface ExistingPeriod {\n startTime: Date | string\n endTime: Date | string\n}\n\n/**\n * 이 구간을 받아도 되나.\n *\n * `now` 를 부르는 쪽이 준다 — 이 함수가 시계를 읽으면 테스트가 시각에 흔들린다.\n */\nexport function judgePeriod(\n period: JudgeablePeriod,\n context: {\n now: Date | string\n /** 같은 설비의 이미 적힌 구간들. 부르는 쪽이 시각으로 좁혀서 준다. */\n existing?: readonly ExistingPeriod[]\n /**\n * 사유 마스터에서 읽은 것.\n *\n * **`undefined` 와 빈 배열의 뜻이 다르다.** `undefined` 는 「마스터를 아직 채우지 않았다」이고\n * 확인하지 않는다. 빈 배열은 「채웠는데 이 사유가 없다」이고 막는다. 둘을 섞으면 오타로 적은\n * 사유가 오류 보고 없이 통과한다.\n */\n reasons?: readonly StopReasonFact[]\n }\n): PeriodIssue[] {\n const issues: PeriodIssue[] = []\n\n const start = ms(period.startTime)\n const end = ms(period.endTime)\n\n if (!(end > start)) {\n issues.push({ problem: 'not-a-period' })\n }\n\n if (end > ms(context.now)) {\n issues.push({ problem: 'in-the-future' })\n }\n\n if (!(EQUIPMENT_PERIOD_STATUS as readonly string[]).includes(period.status)) {\n issues.push({ problem: 'unknown-status', status: period.status })\n }\n\n for (const other of context.existing ?? []) {\n const otherStart = ms(other.startTime)\n const otherEnd = ms(other.endTime)\n\n /* 끝과 시작이 맞닿는 것은 겹침이 아니다 — 한 구간이 끝나는 순간 다음이 시작한다. */\n if (start < otherEnd && otherStart < end) {\n issues.push({ problem: 'overlaps', conflictsWith: isoOf(other.startTime) })\n }\n }\n\n issues.push(...reasonIssues(period, context.reasons))\n\n return issues\n}\n\nfunction reasonIssues(period: JudgeablePeriod, reasons: readonly StopReasonFact[] | undefined): PeriodIssue[] {\n /*\n * 사유를 적지 않은 것은 흠이 아니다. 정지는 일단 적고 사유는 나중에 정하는 것이 현장의 순서이고,\n * 사유를 요구하면 그 순서를 막게 된다.\n */\n if (!period.reasonCode) {\n return []\n }\n\n /*\n * 마스터를 아직 채우지 않은 현장은 확인하지 않는다 — 선언한 것만 걸린다.\n *\n * 빈 배열은 여기서 걸러지지 않는다. 채웠는데 이 사유가 없는 것이고, 아래에서 「모르는 사유」가 된다.\n */\n if (!reasons) {\n return []\n }\n\n const found = reasons.find(reason => reason.name === period.reasonCode)\n\n if (!found) {\n return [{ problem: 'unknown-reason', reasonCode: period.reasonCode }]\n }\n\n const issues: PeriodIssue[] = []\n\n if (found.status !== period.status) {\n issues.push({\n problem: 'reason-status-mismatch',\n reasonCode: found.name,\n reasonStatus: found.status,\n status: period.status\n })\n }\n\n if (found.detailRequired && !period.reasonDetail) {\n issues.push({ problem: 'detail-required', reasonCode: found.name })\n }\n\n return issues\n}\n\nfunction ms(at: Date | string): number {\n return typeof at === 'string' ? Date.parse(at) : at.getTime()\n}\n\nfunction isoOf(at: Date | string): string {\n return typeof at === 'string' ? at : at.toISOString()\n}\n"]}
|
|
@@ -9,6 +9,8 @@ export * from './recipe/recipe-master-resolver';
|
|
|
9
9
|
export * from './test-spec/test-spec-master-resolver';
|
|
10
10
|
export * from './master-crud';
|
|
11
11
|
export * from './master-axis';
|
|
12
|
+
export * from './master-conformance';
|
|
13
|
+
export * from './master-conformance-resolver';
|
|
12
14
|
export * from './master-list';
|
|
13
15
|
export * from './personnel/person';
|
|
14
16
|
export * from './personnel/personnel-class';
|
|
@@ -47,7 +49,8 @@ export * from './test-spec/test-spec-master';
|
|
|
47
49
|
export * from './test-spec/test-spec-query';
|
|
48
50
|
export * from './status/axis-stamp';
|
|
49
51
|
export * from './status/master-status';
|
|
52
|
+
import { MasterConformanceResolver } from './master-conformance-resolver';
|
|
50
53
|
export declare const entities: (typeof import("./equipment/equipment").Equipment | typeof import("./equipment/equipment-class").EquipmentClass | typeof import("./equipment/stop-reason").StopReason | typeof import("./material/material-definition").MaterialDefinition | typeof import("./operation/operation-definition").OperationDefinition | typeof import("./location/operational-location").OperationalLocation | typeof import("./personnel/person").Person | typeof import("./asset/physical-asset").PhysicalAsset | typeof import("./recipe").RecipeDefinition | typeof import("./recipe").RouteDefinition | typeof import("./test-spec/test-specification").TestSpecification)[];
|
|
51
54
|
export declare const schema: {
|
|
52
|
-
resolverClasses: (typeof import("./personnel/personnel-master-resolver").PersonnelClassResolver | typeof import("./personnel/personnel-master-resolver").PersonResolver | typeof import("./equipment/equipment-master-resolver").EquipmentClassResolver | typeof import("./equipment/equipment-master-resolver").EquipmentResolver | typeof import("./equipment/equipment-master-resolver").StopReasonResolver | typeof import("./asset/asset-master-resolver").PhysicalAssetClassResolver | typeof import("./asset/asset-master-resolver").PhysicalAssetResolver | typeof import("./material/material-master-resolver").MaterialClassResolver | typeof import("./material/material-master-resolver").MaterialDefinitionResolver | typeof import("./location/location-master-resolver").OperationalLocationResolver | typeof import("./operation/operation-master-resolver").OperationDefinitionResolver | typeof import("./recipe/recipe-master-resolver").RecipeDefinitionResolver | typeof import("./recipe/recipe-master-resolver").RouteDefinitionResolver | typeof import("./test-spec/test-spec-master-resolver").TestSpecificationResolver | typeof import("./personnel/personnel-query").PersonnelQuery | typeof import("./equipment/equipment-query").EquipmentQuery | typeof import("./asset/asset-query").AssetQuery | typeof import("./location/location-query").LocationQuery | typeof import("./material/material-query").MaterialQuery | typeof import("./operation/operation-query").OperationQuery | typeof import("./operation/operation-readiness-resolver").OperationReadinessResolver | typeof import("./recipe/recipe-query").RecipeQuery | typeof import("./test-spec/test-spec-query").TestSpecificationQuery | typeof import("./status/master-status").OpsMasterStatusQuery | typeof import("./equipment/stop-reason-query").StopReasonQuery)[];
|
|
55
|
+
resolverClasses: (typeof import("./personnel/personnel-master-resolver").PersonnelClassResolver | typeof import("./personnel/personnel-master-resolver").PersonResolver | typeof import("./equipment/equipment-master-resolver").EquipmentClassResolver | typeof import("./equipment/equipment-master-resolver").EquipmentResolver | typeof import("./equipment/equipment-master-resolver").StopReasonResolver | typeof import("./asset/asset-master-resolver").PhysicalAssetClassResolver | typeof import("./asset/asset-master-resolver").PhysicalAssetResolver | typeof import("./material/material-master-resolver").MaterialClassResolver | typeof import("./material/material-master-resolver").MaterialDefinitionResolver | typeof import("./location/location-master-resolver").OperationalLocationResolver | typeof import("./operation/operation-master-resolver").OperationDefinitionResolver | typeof import("./recipe/recipe-master-resolver").RecipeDefinitionResolver | typeof import("./recipe/recipe-master-resolver").RouteDefinitionResolver | typeof import("./test-spec/test-spec-master-resolver").TestSpecificationResolver | typeof MasterConformanceResolver | typeof import("./personnel/personnel-query").PersonnelQuery | typeof import("./equipment/equipment-query").EquipmentQuery | typeof import("./asset/asset-query").AssetQuery | typeof import("./location/location-query").LocationQuery | typeof import("./material/material-query").MaterialQuery | typeof import("./operation/operation-query").OperationQuery | typeof import("./operation/operation-readiness-resolver").OperationReadinessResolver | typeof import("./recipe/recipe-query").RecipeQuery | typeof import("./test-spec/test-spec-query").TestSpecificationQuery | typeof import("./status/master-status").OpsMasterStatusQuery | typeof import("./equipment/stop-reason-query").StopReasonQuery)[];
|
|
53
56
|
};
|
|
@@ -14,6 +14,8 @@ tslib_1.__exportStar(require("./recipe/recipe-master-resolver"), exports);
|
|
|
14
14
|
tslib_1.__exportStar(require("./test-spec/test-spec-master-resolver"), exports);
|
|
15
15
|
tslib_1.__exportStar(require("./master-crud"), exports);
|
|
16
16
|
tslib_1.__exportStar(require("./master-axis"), exports);
|
|
17
|
+
tslib_1.__exportStar(require("./master-conformance"), exports);
|
|
18
|
+
tslib_1.__exportStar(require("./master-conformance-resolver"), exports);
|
|
17
19
|
tslib_1.__exportStar(require("./master-list"), exports);
|
|
18
20
|
tslib_1.__exportStar(require("./personnel/person"), exports);
|
|
19
21
|
tslib_1.__exportStar(require("./personnel/personnel-class"), exports);
|
|
@@ -59,9 +61,11 @@ const location_1 = require("./location");
|
|
|
59
61
|
const material_1 = require("./material");
|
|
60
62
|
const operation_1 = require("./operation");
|
|
61
63
|
const personnel_1 = require("./personnel");
|
|
62
|
-
/*
|
|
64
|
+
/* 라우팅·레시피 — 품목→지시서를 이으려면 그 사이에 이 둘이 있어야 한다(§`recipe-definition.ts`). */
|
|
63
65
|
const recipe_1 = require("./recipe");
|
|
64
66
|
const status_1 = require("./status");
|
|
67
|
+
/* 마스터 정합성 — 축을 가로지르므로 어느 축에도 안 속한다. */
|
|
68
|
+
const master_conformance_resolver_1 = require("./master-conformance-resolver");
|
|
65
69
|
const test_spec_1 = require("./test-spec");
|
|
66
70
|
exports.entities = [
|
|
67
71
|
/* ENTITIES */
|
|
@@ -85,7 +89,12 @@ exports.schema = {
|
|
|
85
89
|
...operation_1.resolvers,
|
|
86
90
|
...recipe_1.resolvers,
|
|
87
91
|
...test_spec_1.resolvers,
|
|
88
|
-
...status_1.resolvers
|
|
92
|
+
...status_1.resolvers,
|
|
93
|
+
/*
|
|
94
|
+
* **파일을 export 하는 것만으로는 스키마에 안 올라온다.** 여기 적어야 한다 — 처음에 그것을
|
|
95
|
+
* 빠뜨려 `masterConformance` 가 「Cannot query field」로 나왔다. [확인함] 2026-09-04
|
|
96
|
+
*/
|
|
97
|
+
master_conformance_resolver_1.MasterConformanceResolver
|
|
89
98
|
]
|
|
90
99
|
};
|
|
91
100
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,yBAAyB;AACzB,oEAAyC;AACzC,gFAAqD;AACrD,gFAAqD;AACrD,wEAA6C;AAC7C,8EAAmD;AACnD,8EAAmD;AACnD,gFAAqD;AACrD,0EAA+C;AAC/C,gFAAqD;AACrD,wDAA6B;AAC7B,wDAA6B;AAC7B,wDAA6B;AAC7B,6DAAkC;AAClC,sEAA2C;AAC3C,uEAA4C;AAC5C,sEAA2C;AAC3C,oEAAyC;AACzC,gEAAqC;AACrC,sEAA2C;AAC3C,yEAA8C;AAC9C,kEAAuC;AACvC,uEAA4C;AAC5C,sEAA2C;AAC3C,kEAAuC;AACvC,iEAAsC;AACtC,uEAA4C;AAC5C,+DAAoC;AACpC,8DAAmC;AACnC,0EAA+C;AAC/C,qEAA0C;AAC1C,oEAAyC;AACzC,oEAAyC;AACzC,yEAA8C;AAC9C,qEAA0C;AAC1C,oEAAyC;AACzC,2EAAgD;AAChD,uEAA4C;AAC5C,sEAA2C;AAC3C,0EAA+C;AAC/C,mFAAwD;AACxD,qEAA0C;AAC1C,oEAAyC;AACzC,iEAAsC;AACtC,gEAAqC;AACrC,yEAA8C;AAC9C,uEAA4C;AAC5C,sEAA2C;AAC3C,8DAAmC;AACnC,iEAAsC;AAEtC,mCAAmC;AACnC,mCAAgF;AAChF,2CAA4F;AAC5F,yCAAyF;AACzF,yCAAyF;AACzF,2CAA4F;AAC5F,2CAA4F;AAC5F,wEAAwE;AACxE,qCAAmF;AACnF,qCAAuD;AACvD,2CAA0F;AAE7E,QAAA,QAAQ,GAAG;IACtB,cAAc;IACd,GAAG,oBAAiB;IACpB,GAAG,oBAAiB;IACpB,GAAG,gBAAa;IAChB,GAAG,mBAAgB;IACnB,GAAG,mBAAgB;IACnB,GAAG,oBAAiB;IACpB,GAAG,iBAAc;IACjB,GAAG,oBAAgB;CACpB,CAAA;AAEY,QAAA,MAAM,GAAG;IACpB,eAAe,EAAE;QACf,sBAAsB;QACtB,GAAG,qBAAkB;QACrB,GAAG,qBAAkB;QACrB,GAAG,iBAAc;QACjB,GAAG,oBAAiB;QACpB,GAAG,oBAAiB;QACpB,GAAG,qBAAkB;QACrB,GAAG,kBAAe;QAClB,GAAG,qBAAiB;QACpB,GAAG,kBAAe;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,yBAAyB;AACzB,oEAAyC;AACzC,gFAAqD;AACrD,gFAAqD;AACrD,wEAA6C;AAC7C,8EAAmD;AACnD,8EAAmD;AACnD,gFAAqD;AACrD,0EAA+C;AAC/C,gFAAqD;AACrD,wDAA6B;AAC7B,wDAA6B;AAC7B,+DAAoC;AACpC,wEAA6C;AAC7C,wDAA6B;AAC7B,6DAAkC;AAClC,sEAA2C;AAC3C,uEAA4C;AAC5C,sEAA2C;AAC3C,oEAAyC;AACzC,gEAAqC;AACrC,sEAA2C;AAC3C,yEAA8C;AAC9C,kEAAuC;AACvC,uEAA4C;AAC5C,sEAA2C;AAC3C,kEAAuC;AACvC,iEAAsC;AACtC,uEAA4C;AAC5C,+DAAoC;AACpC,8DAAmC;AACnC,0EAA+C;AAC/C,qEAA0C;AAC1C,oEAAyC;AACzC,oEAAyC;AACzC,yEAA8C;AAC9C,qEAA0C;AAC1C,oEAAyC;AACzC,2EAAgD;AAChD,uEAA4C;AAC5C,sEAA2C;AAC3C,0EAA+C;AAC/C,mFAAwD;AACxD,qEAA0C;AAC1C,oEAAyC;AACzC,iEAAsC;AACtC,gEAAqC;AACrC,yEAA8C;AAC9C,uEAA4C;AAC5C,sEAA2C;AAC3C,8DAAmC;AACnC,iEAAsC;AAEtC,mCAAmC;AACnC,mCAAgF;AAChF,2CAA4F;AAC5F,yCAAyF;AACzF,yCAAyF;AACzF,2CAA4F;AAC5F,2CAA4F;AAC5F,wEAAwE;AACxE,qCAAmF;AACnF,qCAAuD;AACvD,uCAAuC;AACvC,+EAAyE;AACzE,2CAA0F;AAE7E,QAAA,QAAQ,GAAG;IACtB,cAAc;IACd,GAAG,oBAAiB;IACpB,GAAG,oBAAiB;IACpB,GAAG,gBAAa;IAChB,GAAG,mBAAgB;IACnB,GAAG,mBAAgB;IACnB,GAAG,oBAAiB;IACpB,GAAG,iBAAc;IACjB,GAAG,oBAAgB;CACpB,CAAA;AAEY,QAAA,MAAM,GAAG;IACpB,eAAe,EAAE;QACf,sBAAsB;QACtB,GAAG,qBAAkB;QACrB,GAAG,qBAAkB;QACrB,GAAG,iBAAc;QACjB,GAAG,oBAAiB;QACpB,GAAG,oBAAiB;QACpB,GAAG,qBAAkB;QACrB,GAAG,kBAAe;QAClB,GAAG,qBAAiB;QACpB,GAAG,kBAAe;QAElB;;;WAGG;QACH,uDAAyB;KAC1B;CACF,CAAA","sourcesContent":["/* EXPORT ENTITY TYPES */\nexport * from './resource/resource-class'\nexport * from './personnel/personnel-master-resolver'\nexport * from './equipment/equipment-master-resolver'\nexport * from './asset/asset-master-resolver'\nexport * from './material/material-master-resolver'\nexport * from './location/location-master-resolver'\nexport * from './operation/operation-master-resolver'\nexport * from './recipe/recipe-master-resolver'\nexport * from './test-spec/test-spec-master-resolver'\nexport * from './master-crud'\nexport * from './master-axis'\nexport * from './master-conformance'\nexport * from './master-conformance-resolver'\nexport * from './master-list'\nexport * from './personnel/person'\nexport * from './personnel/personnel-class'\nexport * from './personnel/personnel-master'\nexport * from './personnel/personnel-query'\nexport * from './personnel/qualification'\nexport * from './equipment/equipment'\nexport * from './equipment/equipment-class'\nexport * from './equipment/state-period-rules'\nexport * from './equipment/stop-reason'\nexport * from './equipment/equipment-master'\nexport * from './equipment/equipment-query'\nexport * from './asset/asset-lifecycle'\nexport * from './asset/physical-asset'\nexport * from './asset/physical-asset-class'\nexport * from './asset/asset-master'\nexport * from './asset/asset-query'\nexport * from './location/operational-location'\nexport * from './location/location-master'\nexport * from './location/location-query'\nexport * from './material/material-class'\nexport * from './material/material-definition'\nexport * from './material/material-master'\nexport * from './material/material-query'\nexport * from './operation/operation-definition'\nexport * from './operation/operation-master'\nexport * from './operation/operation-query'\nexport * from './operation/operation-readiness'\nexport * from './operation/operation-readiness-resolver'\nexport * from './recipe/recipe-definition'\nexport * from './recipe/route-definition'\nexport * from './recipe/recipe-master'\nexport * from './recipe/recipe-query'\nexport * from './test-spec/test-specification'\nexport * from './test-spec/test-spec-master'\nexport * from './test-spec/test-spec-query'\nexport * from './status/axis-stamp'\nexport * from './status/master-status'\n\n/* IMPORT ENTITIES AND RESOLVERS */\nimport { entities as AssetEntities, resolvers as AssetResolvers } from './asset'\nimport { entities as EquipmentEntities, resolvers as EquipmentResolvers } from './equipment'\nimport { entities as LocationEntities, resolvers as LocationResolvers } from './location'\nimport { entities as MaterialEntities, resolvers as MaterialResolvers } from './material'\nimport { entities as OperationEntities, resolvers as OperationResolvers } from './operation'\nimport { entities as PersonnelEntities, resolvers as PersonnelResolvers } from './personnel'\n/* 라우팅·레시피 — 품목→지시서를 이으려면 그 사이에 이 둘이 있어야 한다(§`recipe-definition.ts`). */\nimport { entities as RecipeEntities, resolvers as RecipeResolvers } from './recipe'\nimport { resolvers as StatusResolvers } from './status'\n/* 마스터 정합성 — 축을 가로지르므로 어느 축에도 안 속한다. */\nimport { MasterConformanceResolver } from './master-conformance-resolver'\nimport { entities as TestSpecEntities, resolvers as TestSpecResolvers } from './test-spec'\n\nexport const entities = [\n /* ENTITIES */\n ...PersonnelEntities,\n ...EquipmentEntities,\n ...AssetEntities,\n ...LocationEntities,\n ...MaterialEntities,\n ...OperationEntities,\n ...RecipeEntities,\n ...TestSpecEntities\n]\n\nexport const schema = {\n resolverClasses: [\n /* RESOLVER CLASSES */\n ...PersonnelResolvers,\n ...EquipmentResolvers,\n ...AssetResolvers,\n ...LocationResolvers,\n ...MaterialResolvers,\n ...OperationResolvers,\n ...RecipeResolvers,\n ...TestSpecResolvers,\n ...StatusResolvers,\n\n /*\n * **파일을 export 하는 것만으로는 스키마에 안 올라온다.** 여기 적어야 한다 — 처음에 그것을\n * 빠뜨려 `masterConformance` 가 「Cannot query field」로 나왔다. [확인함] 2026-09-04\n */\n MasterConformanceResolver\n ]\n}\n"]}
|
|
@@ -17,6 +17,35 @@ export declare class OperationalLocationList {
|
|
|
17
17
|
}
|
|
18
18
|
export declare class OperationalLocationResolver {
|
|
19
19
|
operationalLocations(params: ListParam, context: ResolverContext): Promise<OperationalLocationList>;
|
|
20
|
+
/**
|
|
21
|
+
* 이 자리 바로 아래에 몇이 있나.
|
|
22
|
+
*
|
|
23
|
+
* 계층을 한 단씩 걷는 화면이 이 값으로 「그 줄에 들어갈 것이 있나」를 말한다. 아이콘만으로는 그것을
|
|
24
|
+
* 말하지 못한다 — 눌러 보기 전에는 안에 무엇이 있는지, 있기는 한지 알 수 없다.
|
|
25
|
+
*
|
|
26
|
+
* 세는 방식과 값은 `countChildren` 머리말에 적었다.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* 여기서 일하는 사람들.
|
|
30
|
+
*
|
|
31
|
+
* **넘치면 몇이 남았는지 말한다**(`occupantOverflow`). 조용히 자르면 「셋이 있다」와 「서른이
|
|
32
|
+
* 있는데 셋만 보인다」가 같아 보이고, 그 칸을 보고 사람이 판단을 내린다.
|
|
33
|
+
*
|
|
34
|
+
* 아무도 없으면 빈 목록이다 — 없는 것은 없다고 낸다.
|
|
35
|
+
*/
|
|
36
|
+
staff(location: OperationalLocation, context: ResolverContext): Promise<string[]>;
|
|
37
|
+
/** 여기 있는 설비들. */
|
|
38
|
+
equipmentHere(location: OperationalLocation, context: ResolverContext): Promise<string[]>;
|
|
39
|
+
/** 여기 있는 자산들 — 공구 · 지그처럼 옮겨 다니는 것. */
|
|
40
|
+
assetsHere(location: OperationalLocation, context: ResolverContext): Promise<string[]>;
|
|
41
|
+
/**
|
|
42
|
+
* 위 세 칸에서 **안 보인 것이 몇인가.**
|
|
43
|
+
*
|
|
44
|
+
* 셋을 합쳐 하나로 낸다. 칸마다 따로 두면 화면이 숫자 셋을 더 들고 있어야 하는데, 사람이 알고
|
|
45
|
+
* 싶은 것은 「이 자리에 더 있나」 하나다.
|
|
46
|
+
*/
|
|
47
|
+
occupantOverflow(location: OperationalLocation, context: ResolverContext): Promise<number>;
|
|
48
|
+
childCount(location: OperationalLocation, context: ResolverContext): Promise<number>;
|
|
20
49
|
/**
|
|
21
50
|
* 그리드가 보낸 변경을 한 번에 적용한다.
|
|
22
51
|
*
|
|
@@ -8,6 +8,10 @@ const master_crud_1 = require("../master-crud");
|
|
|
8
8
|
const master_axis_1 = require("../master-axis");
|
|
9
9
|
const master_list_1 = require("../master-list");
|
|
10
10
|
const operational_location_1 = require("./operational-location");
|
|
11
|
+
const person_1 = require("../personnel/person");
|
|
12
|
+
const equipment_1 = require("../equipment/equipment");
|
|
13
|
+
const physical_asset_1 = require("../asset/physical-asset");
|
|
14
|
+
const referrers_1 = require("../resource/referrers");
|
|
11
15
|
/**
|
|
12
16
|
* 자리 축을 채우고 고친다.
|
|
13
17
|
*
|
|
@@ -32,11 +36,194 @@ tslib_1.__decorate([
|
|
|
32
36
|
exports.OperationalLocationList = OperationalLocationList = tslib_1.__decorate([
|
|
33
37
|
(0, type_graphql_1.ObjectType)({ description: 'A page of operational locations' })
|
|
34
38
|
], OperationalLocationList);
|
|
39
|
+
/**
|
|
40
|
+
* 「바로 아래에 몇이 있나」를 세는 곳.
|
|
41
|
+
*
|
|
42
|
+
* ── 물어본 요청만 센다 ──────────────────────────────────────────────────────
|
|
43
|
+
* 처음에는 목록 리졸버가 늘 세게 했다. 그러면 **개수를 쓰지 않는 조회도 값을 치른다** — 고르기 팝업,
|
|
44
|
+
* 자동완성, 다른 화면의 목록까지 전부. 로케이션 목록은 여러 곳에서 부른다.
|
|
45
|
+
*
|
|
46
|
+
* 그래서 `childCount` 를 필드 리졸버로 둔다. GraphQL 이 **물어본 요청에만** 이것을 부르므로, 안 묻는
|
|
47
|
+
* 조회는 질의가 한 번뿐이다. 「이 목록은 개수가 필요하다/아니다」를 서버 쪽에 플래그로 두지 않아도
|
|
48
|
+
* 된다 — 묻는 것이 곧 그 표시다.
|
|
49
|
+
*
|
|
50
|
+
* ── 물었으면 한 번에 센다 ───────────────────────────────────────────────────
|
|
51
|
+
* 필드 리졸버는 줄마다 불린다. 거기서 그때그때 세면 `limit 20` 에 카운트 20회, 100 이면 100회다 —
|
|
52
|
+
* N+1 이다.
|
|
53
|
+
*
|
|
54
|
+
* 그래서 목록 리졸버가 그 페이지를 요청에 남겨 두고(`locationPage`), 첫 줄이 물을 때 **페이지 전체를
|
|
55
|
+
* 한 번에** 세어 요청 안에 담아 둔다. 담는 것은 **결과가 아니라 약속(Promise)** 이다 — 줄들이 거의
|
|
56
|
+
* 동시에 묻기 때문에, 결과를 담으면 스무 개가 각자 질의를 띄운 뒤에야 채워진다.
|
|
57
|
+
*
|
|
58
|
+
* SELECT parent_id, COUNT(1) … WHERE domain = ? AND parent_id IN (…) GROUP BY parent_id
|
|
59
|
+
*
|
|
60
|
+
* `IN` 에 들어가는 것은 그 페이지의 아이디와 이름뿐이라 표 전체 크기와 무관하다.
|
|
61
|
+
* `ix_ops_operational_location_1`(도메인 · 상위)이 이 질의를 받는다.
|
|
62
|
+
*
|
|
63
|
+
* ── 상위를 두 가지로 찾는다 ──────────────────────────────────────────────────
|
|
64
|
+
* `parentId` 는 외래 키가 아니라 문자열이라 쓰는 쪽이 정한다. 지금 데이터는 아이디가 아니라 **이름**을
|
|
65
|
+
* 담고 있다(`LINE-1` 의 상위가 `PLANT-1`). 한쪽만 보면 개수가 오류 보고 없이 0 이 된다.
|
|
66
|
+
*/
|
|
67
|
+
async function countChildren(locations, domain) {
|
|
68
|
+
const keys = [...new Set(locations.flatMap(location => [location.id, location.name]).filter(Boolean))];
|
|
69
|
+
if (!keys.length)
|
|
70
|
+
return new Map();
|
|
71
|
+
const counted = await (0, shell_1.getRepository)(operational_location_1.OperationalLocation)
|
|
72
|
+
.createQueryBuilder('location')
|
|
73
|
+
.select('location.parentId', 'parentId')
|
|
74
|
+
.addSelect('COUNT(1)', 'count')
|
|
75
|
+
.where('location.domain = :domain', { domain: domain.id })
|
|
76
|
+
.andWhere('location.parentId IN (:...keys)', { keys })
|
|
77
|
+
.groupBy('location.parentId')
|
|
78
|
+
.getRawMany();
|
|
79
|
+
return new Map(counted.map(row => [row.parentId, Number(row.count)]));
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 아이디로 적힌 자식과 이름으로 적힌 자식을 **더한다.**
|
|
83
|
+
*
|
|
84
|
+
* 같은 자식이 두 규약으로 중복 등록돼 있으면 개수가 부풀 수 있다. 그런 데이터는 이미 결함이지만, 여기서
|
|
85
|
+
* 한쪽을 조용히 버리지는 않는다 — 버리면 어느 쪽이 빠졌는지 아무도 모른다.
|
|
86
|
+
*/
|
|
87
|
+
function sumFor(location, counted) {
|
|
88
|
+
return (counted.get(location.id) || 0) + (location.name ? counted.get(location.name) || 0 : 0);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* **이 자리에 무엇이 있나** — 들어오는 관계.
|
|
92
|
+
*
|
|
93
|
+
* ── 왜 필요한가 ────────────────────────────────────────────────────────────
|
|
94
|
+
* 자리 하나를 열어도 「여기서 누가 일하나 · 무슨 설비가 있나」를 알 수 없었다. 사람 화면을 열어
|
|
95
|
+
* 근무 자리로 걸러야 했고, 설비는 또 설비 화면에서 같은 일을 해야 했다. 다른 화면의 참조 칸을
|
|
96
|
+
* 눌러 자리로 걸어 들어와도 그 자리가 무엇인지는 이름뿐이었다.
|
|
97
|
+
*
|
|
98
|
+
* ── 줄마다 세지 않는다 ─────────────────────────────────────────────────────
|
|
99
|
+
* `childCount` 와 같은 방식이다. 목록 리졸버가 그 페이지를 요청에 남겨 두고, 첫 줄이 물을 때
|
|
100
|
+
* **페이지 전체를 한 번에** 묻는다. 담는 것은 결과가 아니라 **약속**이다 — 줄들이 거의 동시에
|
|
101
|
+
* 물으므로 결과를 담으면 스무 개가 각자 질의를 띄운다.
|
|
102
|
+
*
|
|
103
|
+
* ── 자리를 두 가지로 찾는다 ────────────────────────────────────────────────
|
|
104
|
+
* `homeLocation` 은 외래 키가 아니라 문자열이라 쓰는 쪽이 정한다. 지금 자료는 **이름**을 담는다
|
|
105
|
+
* (`P-ECU-S-0001` 의 근무 자리가 `ECU-SUB-01`). 아이디도 함께 넣어 묻는다 — 한쪽만 보면 목록이
|
|
106
|
+
* 오류 보고 없이 빈다. `childCount` 가 같은 이유로 그렇게 한다.
|
|
107
|
+
*/
|
|
108
|
+
/** 한 자리에 보일 이름 수. 넘치면 몇이 남았는지 함께 낸다. */
|
|
109
|
+
const OCCUPANT_SHOWN = 8;
|
|
110
|
+
async function scanOccupants(locations, domain) {
|
|
111
|
+
const keys = [...new Set(locations.flatMap(one => [one.id, one.name]).filter(Boolean))];
|
|
112
|
+
if (keys.length === 0) {
|
|
113
|
+
return { staff: new Map(), equipment: new Map(), assets: new Map() };
|
|
114
|
+
}
|
|
115
|
+
const of = async (Entity) => {
|
|
116
|
+
const rows = await (0, shell_1.getRepository)(Entity)
|
|
117
|
+
.createQueryBuilder('row')
|
|
118
|
+
.select(['row.id', 'row.name', 'row.homeLocation'])
|
|
119
|
+
.where('row.domain_id = :domain', { domain: domain.id })
|
|
120
|
+
.andWhere('row.home_location IN (:...keys)', { keys })
|
|
121
|
+
.getMany();
|
|
122
|
+
return (0, referrers_1.indexReferrers)(rows.map(one => ({ points: one.homeLocation, name: one.name })));
|
|
123
|
+
};
|
|
124
|
+
const [staff, equipment, assets] = await Promise.all([of(person_1.Person), of(equipment_1.Equipment), of(physical_asset_1.PhysicalAsset)]);
|
|
125
|
+
return { staff, equipment, assets };
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* 이 줄의 답을 낸다.
|
|
129
|
+
*
|
|
130
|
+
* **페이지에 없으면 그 줄만 따로 묻는다.** 한 요청에 목록 조회가 둘 있으면 뒤엣것이 앞엣것의
|
|
131
|
+
* 페이지를 덮어쓰고, 그때 남는 줄들이 「아무도 없다」로 나온다 — 자리가 비어 있는 것과 못 본 것이
|
|
132
|
+
* 같아 보인다. 들어오는 관계는 **비어 있는 것이 기본**이라 이 거짓말이 특히 안 띈다.
|
|
133
|
+
* 틀린 목록보다 질의 한 번이 낫다. `childCount` 가 같은 이유로 같은 자리를 둔다.
|
|
134
|
+
*/
|
|
135
|
+
async function occupantsOf(location, context) {
|
|
136
|
+
const state = context.state;
|
|
137
|
+
const page = state.locationPage;
|
|
138
|
+
const inPage = !!page?.some(one => one.id === location.id);
|
|
139
|
+
if (!inPage) {
|
|
140
|
+
return scanOccupants([location], state.domain);
|
|
141
|
+
}
|
|
142
|
+
/* 요청 안에서 한 번만 훑는다. 약속을 담는다. */
|
|
143
|
+
state.occupantScan = state.occupantScan || scanOccupants(page, state.domain);
|
|
144
|
+
return state.occupantScan;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* 한 자리의 이름들을 낸다 — 아이디로도 이름으로도 걸린 것을 합친다.
|
|
148
|
+
*
|
|
149
|
+
* 자료가 어느 쪽으로 적혔는지 자리마다 다를 수 있어 둘 다 본다. 합칠 때 겹치는 것은 한 번만 센다.
|
|
150
|
+
*/
|
|
151
|
+
function namesAt(index, location) {
|
|
152
|
+
const found = [...(index.get(location.id) ?? []), ...(index.get(location.name) ?? [])];
|
|
153
|
+
return [...new Set(found)].sort();
|
|
154
|
+
}
|
|
35
155
|
let OperationalLocationResolver = class OperationalLocationResolver {
|
|
36
156
|
async operationalLocations(params, context) {
|
|
37
157
|
const { domain } = context.state;
|
|
38
158
|
const { items, total } = await (0, master_list_1.listMaster)('operationalLocation', params, domain);
|
|
39
|
-
|
|
159
|
+
const locations = items;
|
|
160
|
+
/*
|
|
161
|
+
* 여기서 개수를 세지 않는다. 이 페이지만 요청에 남겨 둔다 — `childCount` 를 **물어본 요청**이
|
|
162
|
+
* 있으면 그 리졸버가 이것을 보고 한 번에 센다(위 머리말).
|
|
163
|
+
*/
|
|
164
|
+
context.state.locationPage = locations;
|
|
165
|
+
return { items: locations, total };
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* 이 자리 바로 아래에 몇이 있나.
|
|
169
|
+
*
|
|
170
|
+
* 계층을 한 단씩 걷는 화면이 이 값으로 「그 줄에 들어갈 것이 있나」를 말한다. 아이콘만으로는 그것을
|
|
171
|
+
* 말하지 못한다 — 눌러 보기 전에는 안에 무엇이 있는지, 있기는 한지 알 수 없다.
|
|
172
|
+
*
|
|
173
|
+
* 세는 방식과 값은 `countChildren` 머리말에 적었다.
|
|
174
|
+
*/
|
|
175
|
+
/**
|
|
176
|
+
* 여기서 일하는 사람들.
|
|
177
|
+
*
|
|
178
|
+
* **넘치면 몇이 남았는지 말한다**(`occupantOverflow`). 조용히 자르면 「셋이 있다」와 「서른이
|
|
179
|
+
* 있는데 셋만 보인다」가 같아 보이고, 그 칸을 보고 사람이 판단을 내린다.
|
|
180
|
+
*
|
|
181
|
+
* 아무도 없으면 빈 목록이다 — 없는 것은 없다고 낸다.
|
|
182
|
+
*/
|
|
183
|
+
async staff(location, context) {
|
|
184
|
+
return (0, referrers_1.cappedList)(namesAt((await occupantsOf(location, context)).staff, location), OCCUPANT_SHOWN).shown;
|
|
185
|
+
}
|
|
186
|
+
/** 여기 있는 설비들. */
|
|
187
|
+
async equipmentHere(location, context) {
|
|
188
|
+
return (0, referrers_1.cappedList)(namesAt((await occupantsOf(location, context)).equipment, location), OCCUPANT_SHOWN).shown;
|
|
189
|
+
}
|
|
190
|
+
/** 여기 있는 자산들 — 공구 · 지그처럼 옮겨 다니는 것. */
|
|
191
|
+
async assetsHere(location, context) {
|
|
192
|
+
return (0, referrers_1.cappedList)(namesAt((await occupantsOf(location, context)).assets, location), OCCUPANT_SHOWN).shown;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* 위 세 칸에서 **안 보인 것이 몇인가.**
|
|
196
|
+
*
|
|
197
|
+
* 셋을 합쳐 하나로 낸다. 칸마다 따로 두면 화면이 숫자 셋을 더 들고 있어야 하는데, 사람이 알고
|
|
198
|
+
* 싶은 것은 「이 자리에 더 있나」 하나다.
|
|
199
|
+
*/
|
|
200
|
+
async occupantOverflow(location, context) {
|
|
201
|
+
const scan = await occupantsOf(location, context);
|
|
202
|
+
return ((0, referrers_1.cappedList)(namesAt(scan.staff, location), OCCUPANT_SHOWN).hidden +
|
|
203
|
+
(0, referrers_1.cappedList)(namesAt(scan.equipment, location), OCCUPANT_SHOWN).hidden +
|
|
204
|
+
(0, referrers_1.cappedList)(namesAt(scan.assets, location), OCCUPANT_SHOWN).hidden);
|
|
205
|
+
}
|
|
206
|
+
async childCount(location, context) {
|
|
207
|
+
const { domain, locationPage } = context.state;
|
|
208
|
+
const page = locationPage;
|
|
209
|
+
const inPage = !!page?.some(one => one.id === location.id);
|
|
210
|
+
/*
|
|
211
|
+
* 목록 조회가 남긴 페이지에 없으면 그 줄만 센다.
|
|
212
|
+
*
|
|
213
|
+
* 한 요청에 목록 조회가 둘 있으면 뒤엣것이 앞엣것의 페이지를 덮어쓴다. 그때 남는 줄들을 조용히 0 으로
|
|
214
|
+
* 두지 않는다 — 틀린 개수보다 질의 한 번이 낫다.
|
|
215
|
+
*/
|
|
216
|
+
if (!inPage) {
|
|
217
|
+
const counted = await countChildren([location], domain);
|
|
218
|
+
return sumFor(location, counted);
|
|
219
|
+
}
|
|
220
|
+
/*
|
|
221
|
+
* 요청 안에서 한 번만 센다. **약속을 담는다** — 줄들이 거의 동시에 묻기 때문에 결과를 담으면
|
|
222
|
+
* 스무 개가 각자 질의를 띄운다.
|
|
223
|
+
*/
|
|
224
|
+
const state = context.state;
|
|
225
|
+
state.locationChildCounts = state.locationChildCounts || countChildren(page, domain);
|
|
226
|
+
return sumFor(location, await state.locationChildCounts);
|
|
40
227
|
}
|
|
41
228
|
/**
|
|
42
229
|
* 그리드가 보낸 변경을 한 번에 적용한다.
|
|
@@ -64,6 +251,46 @@ tslib_1.__decorate([
|
|
|
64
251
|
tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
|
|
65
252
|
tslib_1.__metadata("design:returntype", Promise)
|
|
66
253
|
], OperationalLocationResolver.prototype, "operationalLocations", null);
|
|
254
|
+
tslib_1.__decorate([
|
|
255
|
+
(0, type_graphql_1.FieldResolver)(type => [String], { description: 'People whose home location is here' }),
|
|
256
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
257
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
258
|
+
tslib_1.__metadata("design:type", Function),
|
|
259
|
+
tslib_1.__metadata("design:paramtypes", [operational_location_1.OperationalLocation, Object]),
|
|
260
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
261
|
+
], OperationalLocationResolver.prototype, "staff", null);
|
|
262
|
+
tslib_1.__decorate([
|
|
263
|
+
(0, type_graphql_1.FieldResolver)(type => [String], { description: 'Equipment stationed here' }),
|
|
264
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
265
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
266
|
+
tslib_1.__metadata("design:type", Function),
|
|
267
|
+
tslib_1.__metadata("design:paramtypes", [operational_location_1.OperationalLocation, Object]),
|
|
268
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
269
|
+
], OperationalLocationResolver.prototype, "equipmentHere", null);
|
|
270
|
+
tslib_1.__decorate([
|
|
271
|
+
(0, type_graphql_1.FieldResolver)(type => [String], { description: 'Physical assets kept here' }),
|
|
272
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
273
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
274
|
+
tslib_1.__metadata("design:type", Function),
|
|
275
|
+
tslib_1.__metadata("design:paramtypes", [operational_location_1.OperationalLocation, Object]),
|
|
276
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
277
|
+
], OperationalLocationResolver.prototype, "assetsHere", null);
|
|
278
|
+
tslib_1.__decorate([
|
|
279
|
+
(0, type_graphql_1.FieldResolver)(type => type_graphql_1.Int, { description: 'How many occupants are not shown in the lists above' }),
|
|
280
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
281
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
282
|
+
tslib_1.__metadata("design:type", Function),
|
|
283
|
+
tslib_1.__metadata("design:paramtypes", [operational_location_1.OperationalLocation, Object]),
|
|
284
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
285
|
+
], OperationalLocationResolver.prototype, "occupantOverflow", null);
|
|
286
|
+
tslib_1.__decorate([
|
|
287
|
+
(0, type_graphql_1.FieldResolver)(type => type_graphql_1.Int, { description: 'How many locations sit directly under this one' }),
|
|
288
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
289
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
290
|
+
tslib_1.__metadata("design:type", Function),
|
|
291
|
+
tslib_1.__metadata("design:paramtypes", [operational_location_1.OperationalLocation, Object]),
|
|
292
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
293
|
+
], OperationalLocationResolver.prototype, "childCount", null);
|
|
67
294
|
tslib_1.__decorate([
|
|
68
295
|
(0, type_graphql_1.Directive)('@privilege(category: "ops-master", privilege: "mutation", domainOwnerGranted: true)'),
|
|
69
296
|
(0, type_graphql_1.Directive)('@transaction'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"location-master-resolver.js","sourceRoot":"","sources":["../../../server/service/location/location-master-resolver.ts"],"names":[],"mappings":";;;;AAAA,+CAA2G;AAE3G,iDAA+D;AAE/D,gDAA+D;AAC/D,gDAA6C;AAC7C,gDAA2C;AAC3C,iEAA4D;AAE5D;;;;;;;;;GASG;AAGI,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;CAMnC,CAAA;AANY,0DAAuB;AAElC;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,0CAAmB,CAAC,CAAC;;sDACT;AAG5B;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,CAAC;;sDACN;kCALF,uBAAuB;IADnC,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,iCAAiC,EAAE,CAAC;GAClD,uBAAuB,CAMnC;AAGM,IAAM,2BAA2B,GAAjC,MAAM,2BAA2B;IAGhC,AAAN,KAAK,CAAC,oBAAoB,CAA0B,MAAiB,EAAS,OAAwB;QACpG,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAChC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,IAAA,wBAAU,EAAC,qBAAqB,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;QAEhF,OAAO,EAAE,KAAK,EAAE,KAA8B,EAAE,KAAK,EAAE,CAAA;IACzD,CAAC;IAED;;;;;;OAMG;IAIG,AAAN,KAAK,CAAC,iCAAiC,CACG,OAAsB,EACvD,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAC1C,MAAM,IAAI,GAAG,IAAA,0BAAY,EAAC,qBAAqB,CAAC,CAAA;QAEhD,MAAM,KAAK,GAAG,MAAM,IAAA,+BAAiB,EAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;YAC5E,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;SAC5C,CAAC,CAAA;QAEF,OAAO,KAA8B,CAAA;IACvC,CAAC;CACF,CAAA;AAjCY,kEAA2B;AAGhC;IAFL,IAAA,wBAAS,EAAC,kFAAkF,CAAC;IAC7F,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,uBAAuB,EAAE,EAAE,WAAW,EAAE,gCAAgC,EAAE,CAAC;IACjE,mBAAA,IAAA,mBAAI,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAS,CAAC,CAAA;IAAqB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAAjB,iBAAS;;uEAKpE;AAYK;IAHL,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,0CAAmB,CAAC,EAAE,EAAE,WAAW,EAAE,mDAAmD,EAAE,CAAC;IAE9G,mBAAA,IAAA,kBAAG,EAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,oBAAY,CAAC,CAAC,CAAA;IACtC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;oFAUP;sCAhCU,2BAA2B;IADvC,IAAA,uBAAQ,EAAC,0CAAmB,CAAC;GACjB,2BAA2B,CAiCvC","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 { OperationalLocation } from './operational-location'\n\n/**\n * 자리 축을 채우고 고친다.\n *\n * ── 왜 마스터는 그리드에서 고칠 수 있나 ────────────────────────────────────\n * 업무 기록과 달리 마스터는 **선언**이다. 「이 사람이 용접 자격을 갖는다」는 일어난 일이 아니라 지금의\n * 규정이고, 규정은 바뀐다. 없앨 때 행을 지우지 않고 유효 기간의 끝을 채우는 것이 그래서다 —\n * 지우면 그것을 가리키는 지난 기록이 가리킬 것을 잃는다.\n *\n * 규칙은 `master-crud.ts` 한 곳에 있다. 여기는 축의 이름만 붙인다.\n */\n\n@ObjectType({ description: 'A page of operational locations' })\nexport class OperationalLocationList {\n @Field(type => [OperationalLocation])\n items: OperationalLocation[]\n\n @Field(type => Int)\n total: number\n}\n\n@Resolver(OperationalLocation)\nexport class OperationalLocationResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => OperationalLocationList, { description: 'To fetch operational locations' })\n async operationalLocations(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<OperationalLocationList> {\n const { domain } = context.state\n const { items, total } = await listMaster('operationalLocation', params, domain)\n\n return { items: items as OperationalLocation[], 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 => [OperationalLocation], { description: 'To create, change or retire operational locations' })\n async updateMultipleOperationalLocation(\n @Arg('patches', type => [ScalarObject]) patches: MasterPatch[],\n @Ctx() context: ResolverContext\n ): Promise<OperationalLocation[]> {\n const { domain, user, tx } = context.state\n const axis = masterAxisOf('operationalLocation')\n\n const saved = await saveMasterPatches(tx, domain, axis.entity, patches, user, {\n hasEffectivePeriod: axis.hasEffectivePeriod\n })\n\n return saved as OperationalLocation[]\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"location-master-resolver.js","sourceRoot":"","sources":["../../../server/service/location/location-master-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Args, Arg, Ctx, Directive, FieldResolver, Int, Mutation, ObjectType, Field, Query, Resolver, Root } from 'type-graphql'\n\nimport { Domain, ListParam, ScalarObject, getRepository } from '@things-factory/shell'\n\nimport { MasterPatch, saveMasterPatches } from '../master-crud'\nimport { masterAxisOf } from '../master-axis'\nimport { listMaster } from '../master-list'\nimport { OperationalLocation } from './operational-location'\nimport { Person } from '../personnel/person'\nimport { Equipment } from '../equipment/equipment'\nimport { PhysicalAsset } from '../asset/physical-asset'\nimport { cappedList, indexReferrers } from '../resource/referrers'\n\n/**\n * 자리 축을 채우고 고친다.\n *\n * ── 왜 마스터는 그리드에서 고칠 수 있나 ────────────────────────────────────\n * 업무 기록과 달리 마스터는 **선언**이다. 「이 사람이 용접 자격을 갖는다」는 일어난 일이 아니라 지금의\n * 규정이고, 규정은 바뀐다. 없앨 때 행을 지우지 않고 유효 기간의 끝을 채우는 것이 그래서다 —\n * 지우면 그것을 가리키는 지난 기록이 가리킬 것을 잃는다.\n *\n * 규칙은 `master-crud.ts` 한 곳에 있다. 여기는 축의 이름만 붙인다.\n */\n\n@ObjectType({ description: 'A page of operational locations' })\nexport class OperationalLocationList {\n @Field(type => [OperationalLocation])\n items: OperationalLocation[]\n\n @Field(type => Int)\n total: number\n}\n\n/**\n * 「바로 아래에 몇이 있나」를 세는 곳.\n *\n * ── 물어본 요청만 센다 ──────────────────────────────────────────────────────\n * 처음에는 목록 리졸버가 늘 세게 했다. 그러면 **개수를 쓰지 않는 조회도 값을 치른다** — 고르기 팝업,\n * 자동완성, 다른 화면의 목록까지 전부. 로케이션 목록은 여러 곳에서 부른다.\n *\n * 그래서 `childCount` 를 필드 리졸버로 둔다. GraphQL 이 **물어본 요청에만** 이것을 부르므로, 안 묻는\n * 조회는 질의가 한 번뿐이다. 「이 목록은 개수가 필요하다/아니다」를 서버 쪽에 플래그로 두지 않아도\n * 된다 — 묻는 것이 곧 그 표시다.\n *\n * ── 물었으면 한 번에 센다 ───────────────────────────────────────────────────\n * 필드 리졸버는 줄마다 불린다. 거기서 그때그때 세면 `limit 20` 에 카운트 20회, 100 이면 100회다 —\n * N+1 이다.\n *\n * 그래서 목록 리졸버가 그 페이지를 요청에 남겨 두고(`locationPage`), 첫 줄이 물을 때 **페이지 전체를\n * 한 번에** 세어 요청 안에 담아 둔다. 담는 것은 **결과가 아니라 약속(Promise)** 이다 — 줄들이 거의\n * 동시에 묻기 때문에, 결과를 담으면 스무 개가 각자 질의를 띄운 뒤에야 채워진다.\n *\n * SELECT parent_id, COUNT(1) … WHERE domain = ? AND parent_id IN (…) GROUP BY parent_id\n *\n * `IN` 에 들어가는 것은 그 페이지의 아이디와 이름뿐이라 표 전체 크기와 무관하다.\n * `ix_ops_operational_location_1`(도메인 · 상위)이 이 질의를 받는다.\n *\n * ── 상위를 두 가지로 찾는다 ──────────────────────────────────────────────────\n * `parentId` 는 외래 키가 아니라 문자열이라 쓰는 쪽이 정한다. 지금 데이터는 아이디가 아니라 **이름**을\n * 담고 있다(`LINE-1` 의 상위가 `PLANT-1`). 한쪽만 보면 개수가 오류 보고 없이 0 이 된다.\n */\nasync function countChildren(locations: OperationalLocation[], domain: Domain): Promise<Map<string, number>> {\n const keys = [...new Set(locations.flatMap(location => [location.id, location.name]).filter(Boolean))]\n\n if (!keys.length) return new Map()\n\n const counted = await getRepository(OperationalLocation)\n .createQueryBuilder('location')\n .select('location.parentId', 'parentId')\n .addSelect('COUNT(1)', 'count')\n .where('location.domain = :domain', { domain: domain.id })\n .andWhere('location.parentId IN (:...keys)', { keys })\n .groupBy('location.parentId')\n .getRawMany()\n\n return new Map<string, number>(counted.map(row => [row.parentId, Number(row.count)]))\n}\n\n/**\n * 아이디로 적힌 자식과 이름으로 적힌 자식을 **더한다.**\n *\n * 같은 자식이 두 규약으로 중복 등록돼 있으면 개수가 부풀 수 있다. 그런 데이터는 이미 결함이지만, 여기서\n * 한쪽을 조용히 버리지는 않는다 — 버리면 어느 쪽이 빠졌는지 아무도 모른다.\n */\nfunction sumFor(location: OperationalLocation, counted: Map<string, number>): number {\n return (counted.get(location.id) || 0) + (location.name ? counted.get(location.name) || 0 : 0)\n}\n\n/**\n * **이 자리에 무엇이 있나** — 들어오는 관계.\n *\n * ── 왜 필요한가 ────────────────────────────────────────────────────────────\n * 자리 하나를 열어도 「여기서 누가 일하나 · 무슨 설비가 있나」를 알 수 없었다. 사람 화면을 열어\n * 근무 자리로 걸러야 했고, 설비는 또 설비 화면에서 같은 일을 해야 했다. 다른 화면의 참조 칸을\n * 눌러 자리로 걸어 들어와도 그 자리가 무엇인지는 이름뿐이었다.\n *\n * ── 줄마다 세지 않는다 ─────────────────────────────────────────────────────\n * `childCount` 와 같은 방식이다. 목록 리졸버가 그 페이지를 요청에 남겨 두고, 첫 줄이 물을 때\n * **페이지 전체를 한 번에** 묻는다. 담는 것은 결과가 아니라 **약속**이다 — 줄들이 거의 동시에\n * 물으므로 결과를 담으면 스무 개가 각자 질의를 띄운다.\n *\n * ── 자리를 두 가지로 찾는다 ────────────────────────────────────────────────\n * `homeLocation` 은 외래 키가 아니라 문자열이라 쓰는 쪽이 정한다. 지금 자료는 **이름**을 담는다\n * (`P-ECU-S-0001` 의 근무 자리가 `ECU-SUB-01`). 아이디도 함께 넣어 묻는다 — 한쪽만 보면 목록이\n * 오류 보고 없이 빈다. `childCount` 가 같은 이유로 그렇게 한다.\n */\n\n/** 한 자리에 보일 이름 수. 넘치면 몇이 남았는지 함께 낸다. */\nconst OCCUPANT_SHOWN = 8\n\ninterface OccupantScan {\n staff: Map<string, string[]>\n equipment: Map<string, string[]>\n assets: Map<string, string[]>\n}\n\nasync function scanOccupants(locations: OperationalLocation[], domain: Domain): Promise<OccupantScan> {\n const keys = [...new Set(locations.flatMap(one => [one.id, one.name]).filter(Boolean))] as string[]\n\n if (keys.length === 0) {\n return { staff: new Map(), equipment: new Map(), assets: new Map() }\n }\n\n const of = async (Entity: any) => {\n const rows = await getRepository(Entity)\n .createQueryBuilder('row')\n .select(['row.id', 'row.name', 'row.homeLocation'])\n .where('row.domain_id = :domain', { domain: domain.id })\n .andWhere('row.home_location IN (:...keys)', { keys })\n .getMany()\n\n return indexReferrers((rows as any[]).map(one => ({ points: one.homeLocation, name: one.name })))\n }\n\n const [staff, equipment, assets] = await Promise.all([of(Person), of(Equipment), of(PhysicalAsset)])\n\n return { staff, equipment, assets }\n}\n\n/**\n * 이 줄의 답을 낸다.\n *\n * **페이지에 없으면 그 줄만 따로 묻는다.** 한 요청에 목록 조회가 둘 있으면 뒤엣것이 앞엣것의\n * 페이지를 덮어쓰고, 그때 남는 줄들이 「아무도 없다」로 나온다 — 자리가 비어 있는 것과 못 본 것이\n * 같아 보인다. 들어오는 관계는 **비어 있는 것이 기본**이라 이 거짓말이 특히 안 띈다.\n * 틀린 목록보다 질의 한 번이 낫다. `childCount` 가 같은 이유로 같은 자리를 둔다.\n */\nasync function occupantsOf(location: OperationalLocation, context: ResolverContext): Promise<OccupantScan> {\n const state = context.state as {\n domain: Domain\n locationPage?: OperationalLocation[]\n occupantScan?: Promise<OccupantScan>\n }\n\n const page = state.locationPage\n const inPage = !!page?.some(one => one.id === location.id)\n\n if (!inPage) {\n return scanOccupants([location], state.domain)\n }\n\n /* 요청 안에서 한 번만 훑는다. 약속을 담는다. */\n state.occupantScan = state.occupantScan || scanOccupants(page!, state.domain)\n\n return state.occupantScan\n}\n\n/**\n * 한 자리의 이름들을 낸다 — 아이디로도 이름으로도 걸린 것을 합친다.\n *\n * 자료가 어느 쪽으로 적혔는지 자리마다 다를 수 있어 둘 다 본다. 합칠 때 겹치는 것은 한 번만 센다.\n */\nfunction namesAt(index: Map<string, string[]>, location: OperationalLocation): string[] {\n const found = [...(index.get(location.id) ?? []), ...(index.get(location.name) ?? [])]\n\n return [...new Set(found)].sort()\n}\n\n@Resolver(OperationalLocation)\nexport class OperationalLocationResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => OperationalLocationList, { description: 'To fetch operational locations' })\n async operationalLocations(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<OperationalLocationList> {\n const { domain } = context.state\n const { items, total } = await listMaster('operationalLocation', params, domain)\n\n const locations = items as OperationalLocation[]\n\n /*\n * 여기서 개수를 세지 않는다. 이 페이지만 요청에 남겨 둔다 — `childCount` 를 **물어본 요청**이\n * 있으면 그 리졸버가 이것을 보고 한 번에 센다(위 머리말).\n */\n context.state.locationPage = locations\n\n return { items: locations, total }\n }\n\n /**\n * 이 자리 바로 아래에 몇이 있나.\n *\n * 계층을 한 단씩 걷는 화면이 이 값으로 「그 줄에 들어갈 것이 있나」를 말한다. 아이콘만으로는 그것을\n * 말하지 못한다 — 눌러 보기 전에는 안에 무엇이 있는지, 있기는 한지 알 수 없다.\n *\n * 세는 방식과 값은 `countChildren` 머리말에 적었다.\n */\n /**\n * 여기서 일하는 사람들.\n *\n * **넘치면 몇이 남았는지 말한다**(`occupantOverflow`). 조용히 자르면 「셋이 있다」와 「서른이\n * 있는데 셋만 보인다」가 같아 보이고, 그 칸을 보고 사람이 판단을 내린다.\n *\n * 아무도 없으면 빈 목록이다 — 없는 것은 없다고 낸다.\n */\n @FieldResolver(type => [String], { description: 'People whose home location is here' })\n async staff(@Root() location: OperationalLocation, @Ctx() context: ResolverContext): Promise<string[]> {\n return cappedList(namesAt((await occupantsOf(location, context)).staff, location), OCCUPANT_SHOWN).shown\n }\n\n /** 여기 있는 설비들. */\n @FieldResolver(type => [String], { description: 'Equipment stationed here' })\n async equipmentHere(@Root() location: OperationalLocation, @Ctx() context: ResolverContext): Promise<string[]> {\n return cappedList(namesAt((await occupantsOf(location, context)).equipment, location), OCCUPANT_SHOWN).shown\n }\n\n /** 여기 있는 자산들 — 공구 · 지그처럼 옮겨 다니는 것. */\n @FieldResolver(type => [String], { description: 'Physical assets kept here' })\n async assetsHere(@Root() location: OperationalLocation, @Ctx() context: ResolverContext): Promise<string[]> {\n return cappedList(namesAt((await occupantsOf(location, context)).assets, location), OCCUPANT_SHOWN).shown\n }\n\n /**\n * 위 세 칸에서 **안 보인 것이 몇인가.**\n *\n * 셋을 합쳐 하나로 낸다. 칸마다 따로 두면 화면이 숫자 셋을 더 들고 있어야 하는데, 사람이 알고\n * 싶은 것은 「이 자리에 더 있나」 하나다.\n */\n @FieldResolver(type => Int, { description: 'How many occupants are not shown in the lists above' })\n async occupantOverflow(@Root() location: OperationalLocation, @Ctx() context: ResolverContext): Promise<number> {\n const scan = await occupantsOf(location, context)\n\n return (\n cappedList(namesAt(scan.staff, location), OCCUPANT_SHOWN).hidden +\n cappedList(namesAt(scan.equipment, location), OCCUPANT_SHOWN).hidden +\n cappedList(namesAt(scan.assets, location), OCCUPANT_SHOWN).hidden\n )\n }\n\n @FieldResolver(type => Int, { description: 'How many locations sit directly under this one' })\n async childCount(@Root() location: OperationalLocation, @Ctx() context: ResolverContext): Promise<number> {\n const { domain, locationPage } = context.state as { domain: Domain; locationPage?: OperationalLocation[] }\n\n const page = locationPage as OperationalLocation[] | undefined\n const inPage = !!page?.some(one => one.id === location.id)\n\n /*\n * 목록 조회가 남긴 페이지에 없으면 그 줄만 센다.\n *\n * 한 요청에 목록 조회가 둘 있으면 뒤엣것이 앞엣것의 페이지를 덮어쓴다. 그때 남는 줄들을 조용히 0 으로\n * 두지 않는다 — 틀린 개수보다 질의 한 번이 낫다.\n */\n if (!inPage) {\n const counted = await countChildren([location], domain)\n return sumFor(location, counted)\n }\n\n /*\n * 요청 안에서 한 번만 센다. **약속을 담는다** — 줄들이 거의 동시에 묻기 때문에 결과를 담으면\n * 스무 개가 각자 질의를 띄운다.\n */\n const state = context.state as { locationChildCounts?: Promise<Map<string, number>> }\n state.locationChildCounts = state.locationChildCounts || countChildren(page!, domain)\n\n return sumFor(location, await state.locationChildCounts)\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 => [OperationalLocation], { description: 'To create, change or retire operational locations' })\n async updateMultipleOperationalLocation(\n @Arg('patches', type => [ScalarObject]) patches: MasterPatch[],\n @Ctx() context: ResolverContext\n ): Promise<OperationalLocation[]> {\n const { domain, user, tx } = context.state\n const axis = masterAxisOf('operationalLocation')\n\n const saved = await saveMasterPatches(tx, domain, axis.entity, patches, user, {\n hasEffectivePeriod: axis.hasEffectivePeriod\n })\n\n return saved as OperationalLocation[]\n }\n}\n"]}
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
export declare class LocationMaster {
|
|
2
2
|
locations: string;
|
|
3
|
+
/**
|
|
4
|
+
* 더 있나 — **이 값을 안 보고 쓰면 조용히 잘린 마스터로 트윈을 세우게 된다.**
|
|
5
|
+
*
|
|
6
|
+
* 거짓이 될 때까지 `next` 를 `after` 로 넘겨 이어 받는다.
|
|
7
|
+
*/
|
|
8
|
+
hasMore: boolean;
|
|
9
|
+
/** 이어 받을 자리. 더 없으면 없다. */
|
|
10
|
+
next?: string;
|
|
3
11
|
}
|
|
4
12
|
export declare class LocationQuery {
|
|
5
13
|
/** 자리 축 전체 — 자리가 상위 자리를 가리키므로 한 번에 낸다. */
|
|
6
|
-
locationMaster(context: ResolverContext): Promise<LocationMaster>;
|
|
14
|
+
locationMaster(after: string | undefined, limit: number | undefined, context: ResolverContext): Promise<LocationMaster>;
|
|
7
15
|
}
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.LocationQuery = exports.LocationMaster = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const type_graphql_1 = require("type-graphql");
|
|
6
|
-
const
|
|
6
|
+
const master_page_query_1 = require("../master-page-query");
|
|
7
7
|
const location_master_1 = require("./location-master");
|
|
8
8
|
const operational_location_1 = require("./operational-location");
|
|
9
9
|
let LocationMaster = class LocationMaster {
|
|
@@ -13,26 +13,41 @@ tslib_1.__decorate([
|
|
|
13
13
|
(0, type_graphql_1.Field)(type => String, { description: 'ReferenceMaster locations[] as JSON text' }),
|
|
14
14
|
tslib_1.__metadata("design:type", String)
|
|
15
15
|
], LocationMaster.prototype, "locations", void 0);
|
|
16
|
+
tslib_1.__decorate([
|
|
17
|
+
(0, type_graphql_1.Field)({ description: 'true when more rows remain — keep pulling with next as after' }),
|
|
18
|
+
tslib_1.__metadata("design:type", Boolean)
|
|
19
|
+
], LocationMaster.prototype, "hasMore", void 0);
|
|
20
|
+
tslib_1.__decorate([
|
|
21
|
+
(0, type_graphql_1.Field)(type => String, { nullable: true, description: 'cursor for the next page — the last name in this page' }),
|
|
22
|
+
tslib_1.__metadata("design:type", String)
|
|
23
|
+
], LocationMaster.prototype, "next", void 0);
|
|
16
24
|
exports.LocationMaster = LocationMaster = tslib_1.__decorate([
|
|
17
25
|
(0, type_graphql_1.ObjectType)({ description: 'Location master as the twin receives it' })
|
|
18
26
|
], LocationMaster);
|
|
19
27
|
let LocationQuery = class LocationQuery {
|
|
20
28
|
/** 자리 축 전체 — 자리가 상위 자리를 가리키므로 한 번에 낸다. */
|
|
21
|
-
async locationMaster(context) {
|
|
29
|
+
async locationMaster(after, limit, context) {
|
|
22
30
|
const { domain } = context.state;
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
const request = { after, limit };
|
|
32
|
+
const page = await (0, master_page_query_1.pullPage)(operational_location_1.OperationalLocation, domain, request);
|
|
33
|
+
/* 통째로 달라고 했는데 한도를 넘으면 **자르지 않고 거절한다**(§`master-page`). */
|
|
34
|
+
(0, master_page_query_1.refuseIfTooLarge)('자리', request, page);
|
|
35
|
+
const locations = page.rows;
|
|
36
|
+
return {
|
|
37
|
+
locations: JSON.stringify((0, location_master_1.locationMaster)(locations).locations),
|
|
38
|
+
hasMore: page.hasMore,
|
|
39
|
+
...(page.next ? { next: page.next } : {})
|
|
40
|
+
};
|
|
28
41
|
}
|
|
29
42
|
};
|
|
30
43
|
exports.LocationQuery = LocationQuery;
|
|
31
44
|
tslib_1.__decorate([
|
|
32
45
|
(0, type_graphql_1.Query)(returns => LocationMaster, { description: 'Location master for the twin to pull' }),
|
|
33
|
-
tslib_1.__param(0, (0, type_graphql_1.
|
|
46
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('after', { nullable: true, description: 'resume after this name — the previous page\'s next' })),
|
|
47
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('limit', type => type_graphql_1.Int, { nullable: true, description: 'rows per page — omit only when the axis is small enough to pull whole' })),
|
|
48
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
34
49
|
tslib_1.__metadata("design:type", Function),
|
|
35
|
-
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
50
|
+
tslib_1.__metadata("design:paramtypes", [String, Number, Object]),
|
|
36
51
|
tslib_1.__metadata("design:returntype", Promise)
|
|
37
52
|
], LocationQuery.prototype, "locationMaster", null);
|
|
38
53
|
exports.LocationQuery = LocationQuery = tslib_1.__decorate([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"location-query.js","sourceRoot":"","sources":["../../../server/service/location/location-query.ts"],"names":[],"mappings":";;;;AAAA,+
|
|
1
|
+
{"version":3,"file":"location-query.js","sourceRoot":"","sources":["../../../server/service/location/location-query.ts"],"names":[],"mappings":";;;;AAAA,+CAAgF;AAIhF,4DAAiE;AAEjE,uDAAyE;AACzE,iEAA4D;AAGrD,IAAM,cAAc,GAApB,MAAM,cAAc;CAgB1B,CAAA;AAhBY,wCAAc;AAEzB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,0CAA0C,EAAE,CAAC;;iDAClE;AAQjB;IADC,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,8DAA8D,EAAE,CAAC;;+CACvE;AAIhB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,uDAAuD,EAAE,CAAC;;4CACnG;yBAdF,cAAc;IAD1B,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,yCAAyC,EAAE,CAAC;GAC1D,cAAc,CAgB1B;AAGM,IAAM,aAAa,GAAnB,MAAM,aAAa;IACxB,0CAA0C;IAEpC,AAAN,KAAK,CAAC,cAAc,CACmF,KAAyB,EACO,KAAyB,EACvJ,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAEhC,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;QAChC,MAAM,IAAI,GAAG,MAAM,IAAA,4BAAQ,EAAsB,0CAAmB,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;QAEtF,0DAA0D;QAC1D,IAAA,oCAAgB,EAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;QAErC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAA;QAE3B,OAAO;YACL,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAA,gCAAmB,EAAC,SAAS,CAAC,CAAC,SAAS,CAAC;YACnE,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1C,CAAA;IACH,CAAC;CACF,CAAA;AAxBY,sCAAa;AAGlB;IADL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,cAAc,EAAE,EAAE,WAAW,EAAE,sCAAsC,EAAE,CAAC;IAEvF,mBAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,oDAAoD,EAAE,CAAC,CAAA;IACnG,mBAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,uEAAuE,EAAE,CAAC,CAAA;IACnI,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;mDAiBP;wBAvBU,aAAa;IADzB,IAAA,uBAAQ,EAAC,0CAAmB,CAAC;GACjB,aAAa,CAwBzB","sourcesContent":["import { Arg, Ctx, Field, Int, ObjectType, Query, Resolver } from 'type-graphql'\n\nimport { getRepository } from '@things-factory/shell'\n\nimport { pullPage, refuseIfTooLarge } from '../master-page-query'\n\nimport { locationMaster as buildLocationMaster } from './location-master'\nimport { OperationalLocation } from './operational-location'\n\n@ObjectType({ description: 'Location master as the twin receives it' })\nexport class LocationMaster {\n @Field(type => String, { description: 'ReferenceMaster locations[] as JSON text' })\n locations: string\n\n /**\n * 더 있나 — **이 값을 안 보고 쓰면 조용히 잘린 마스터로 트윈을 세우게 된다.**\n *\n * 거짓이 될 때까지 `next` 를 `after` 로 넘겨 이어 받는다.\n */\n @Field({ description: 'true when more rows remain — keep pulling with next as after' })\n hasMore: boolean\n\n /** 이어 받을 자리. 더 없으면 없다. */\n @Field(type => String, { nullable: true, description: 'cursor for the next page — the last name in this page' })\n next?: string\n\n}\n\n@Resolver(OperationalLocation)\nexport class LocationQuery {\n /** 자리 축 전체 — 자리가 상위 자리를 가리키므로 한 번에 낸다. */\n @Query(returns => LocationMaster, { description: 'Location master for the twin to pull' })\n async locationMaster(\n @Arg('after', { nullable: true, description: 'resume after this name — the previous page\\'s next' }) after: string | undefined,\n @Arg('limit', type => Int, { nullable: true, description: 'rows per page — omit only when the axis is small enough to pull whole' }) limit: number | undefined,\n @Ctx() context: ResolverContext\n ): Promise<LocationMaster> {\n const { domain } = context.state\n\n const request = { after, limit }\n const page = await pullPage<OperationalLocation>(OperationalLocation, domain, request)\n\n /* 통째로 달라고 했는데 한도를 넘으면 **자르지 않고 거절한다**(§`master-page`). */\n refuseIfTooLarge('자리', request, page)\n\n const locations = page.rows\n\n return {\n locations: JSON.stringify(buildLocationMaster(locations).locations),\n hasMore: page.hasMore,\n ...(page.next ? { next: page.next } : {})\n }\n }\n}\n"]}
|