@things-factory/kpi 10.1.154 → 10.1.156

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.
@@ -5,7 +5,6 @@ const typeorm_1 = require("typeorm");
5
5
  const shell_1 = require("@things-factory/shell");
6
6
  const kpi_metric_1 = require("../service/kpi-metric/kpi-metric");
7
7
  const kpi_metric_value_1 = require("../service/kpi-metric-value/kpi-metric-value");
8
- const domain_inheritance_1 = require("../service/utils/domain-inheritance");
9
8
  class KpiMetricValueProvider {
10
9
  constructor(options) {
11
10
  this.options = options;
@@ -17,7 +16,7 @@ class KpiMetricValueProvider {
17
16
  // 현재 도메인(this.options.domainId)으로만 한정한다 — 조상을 포함하면 부모/템플릿·타 테넌트
18
17
  // 값을 집어 도메인 격리가 깨질 수 있다.
19
18
  const domain = await (0, shell_1.getRepository)(shell_1.Domain, this.options.tx).findOne({ where: { id: this.options.domainId } });
20
- const domainIds = domain ? await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain) : [this.options.domainId];
19
+ const domainIds = domain ? await (0, shell_1.getDomainIdsWithAncestors)(domain) : [this.options.domainId];
21
20
  const metric = await metricRepo.findOne({ where: { name, domain: { id: (0, typeorm_1.In)(domainIds) } } });
22
21
  if (!metric)
23
22
  throw new Error(`Metric not found: ${name}`);
@@ -1 +1 @@
1
- {"version":3,"file":"kpi-metric-value-provider.js","sourceRoot":"","sources":["../../server/controllers/kpi-metric-value-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { In } from 'typeorm'\nimport { Domain, getRepository } from '@things-factory/shell'\nimport { KpiMetric } from '../service/kpi-metric/kpi-metric'\nimport { KpiMetricValue } from '../service/kpi-metric-value/kpi-metric-value'\nimport { ValueProvider } from '../calculator/provider'\nimport { getDomainIdsWithAncestors } from '../service/utils/domain-inheritance'\n\nexport class KpiMetricValueProvider implements ValueProvider {\n constructor(\n private options: {\n valueDate: string\n org?: string\n domainId: string\n tx?: any\n }\n ) {}\n\n async get(name: string) {\n const metricRepo = getRepository(KpiMetric, this.options.tx)\n\n // KpiMetric '정의' 는 부모(admin) 도메인에 있을 수 있어 조상 도메인까지 포함해 조회한다.\n // 단, KpiMetricValue '값' 은 테넌트(현재 도메인)에만 저장되므로 값 조회는 반드시\n // 현재 도메인(this.options.domainId)으로만 한정한다 — 조상을 포함하면 부모/템플릿·타 테넌트\n // 값을 집어 도메인 격리가 깨질 수 있다.\n const domain = await getRepository(Domain, this.options.tx).findOne({ where: { id: this.options.domainId } })\n const domainIds = domain ? await getDomainIdsWithAncestors(domain) : [this.options.domainId]\n\n const metric = await metricRepo.findOne({ where: { name, domain: { id: In(domainIds) } } })\n if (!metric) throw new Error(`Metric not found: ${name}`)\n\n // ALLTIME 타입인 경우 valueDate 무시하고 최신 값 조회\n if (metric.periodType === 'ALLTIME') {\n const valueRepo = getRepository(KpiMetricValue, this.options.tx)\n const value = await valueRepo.findOne({\n where: {\n metric: { id: metric.id },\n org: this.options.org ?? '',\n domain: { id: this.options.domainId }\n },\n order: { createdAt: 'DESC' }\n })\n if (!value) {\n throw new Error(`Metric value not found: metric='${name}', org='${this.options.org ?? ''}' (ALLTIME type)`)\n }\n return value.value\n }\n\n const valueRepo = getRepository(KpiMetricValue, this.options.tx)\n\n // valueDate 미지정 (예: KPI 재계산) → 그 metric 의 '최신 월'(가장 최근 valueDate) 값을\n // 대표값으로 사용한다. 완료평가/'월별 데이터' 탭에서 최신월을 수정하면 이 값이 곧 KPI\n // 계산 입력이 된다.\n // (MONTH 는 valueDate 를 'YYYY-MM-01' 로 저장하는데, 과거엔 current-month('YYYY-MM')\n // exact 조회라 포맷 불일치로 못 찾고 우연히 아래 fallback 으로만 동작했음 — 명시적 최신월 조회)\n if (!this.options.valueDate) {\n const latest = await valueRepo.findOne({\n where: {\n metric: { id: metric.id },\n org: this.options.org ?? '',\n domain: { id: this.options.domainId },\n // metric 의 periodType 과 같은 값만 — MONTH 지표인데 섞여 있는 DAY 행이 valueDate 로\n // 더 최신이라 잘못 집히던 문제 방지 (예: 실적공정률 MONTH 2026-05 vs 잔여 DAY 2026-06-15).\n periodType: metric.periodType\n },\n order: { valueDate: 'DESC' }\n })\n if (!latest) {\n throw new Error(`Metric value not found: metric='${name}', org='${this.options.org ?? ''}' (latest)`)\n }\n return latest.value\n }\n\n // 명시적 valueDate 가 주어진 경우: 해당 기간 조회 (없으면 최신 fallback).\n let valueDate = this.options.valueDate\n // valueDate가 metric.periodType에 맞는 포맷인지 검사, 아니면 보정\n if (metric.periodType === 'MONTH' && valueDate.length > 7) valueDate = valueDate.slice(0, 7)\n if (metric.periodType === 'DAY' && valueDate.length > 10) valueDate = valueDate.slice(0, 10)\n var value = await valueRepo.findOne({\n where: {\n metric: { id: metric.id },\n valueDate,\n org: this.options.org ?? '',\n domain: { id: this.options.domainId },\n periodType: metric.periodType\n }\n })\n if (!value) {\n // 해당 기간 데이터 없으면 최신 데이터로 fallback.\n value = await valueRepo.findOne({\n where: {\n metric: { id: metric.id },\n org: this.options.org ?? '',\n domain: { id: this.options.domainId },\n periodType: metric.periodType\n },\n order: { valueDate: 'DESC' }\n })\n\n if (!value) {\n throw new Error(\n `Metric value not found: metric='${name}', org='${this.options.org ?? ''}', valueDate='${valueDate}', periodType='${metric.periodType}'`\n )\n }\n }\n\n return value.value\n }\n}\n"]}
1
+ {"version":3,"file":"kpi-metric-value-provider.js","sourceRoot":"","sources":["../../server/controllers/kpi-metric-value-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { In } from 'typeorm'\nimport { Domain, getRepository, getDomainIdsWithAncestors } from '@things-factory/shell'\nimport { KpiMetric } from '../service/kpi-metric/kpi-metric'\nimport { KpiMetricValue } from '../service/kpi-metric-value/kpi-metric-value'\nimport { ValueProvider } from '../calculator/provider'\n\nexport class KpiMetricValueProvider implements ValueProvider {\n constructor(\n private options: {\n valueDate: string\n org?: string\n domainId: string\n tx?: any\n }\n ) {}\n\n async get(name: string) {\n const metricRepo = getRepository(KpiMetric, this.options.tx)\n\n // KpiMetric '정의' 는 부모(admin) 도메인에 있을 수 있어 조상 도메인까지 포함해 조회한다.\n // 단, KpiMetricValue '값' 은 테넌트(현재 도메인)에만 저장되므로 값 조회는 반드시\n // 현재 도메인(this.options.domainId)으로만 한정한다 — 조상을 포함하면 부모/템플릿·타 테넌트\n // 값을 집어 도메인 격리가 깨질 수 있다.\n const domain = await getRepository(Domain, this.options.tx).findOne({ where: { id: this.options.domainId } })\n const domainIds = domain ? await getDomainIdsWithAncestors(domain) : [this.options.domainId]\n\n const metric = await metricRepo.findOne({ where: { name, domain: { id: In(domainIds) } } })\n if (!metric) throw new Error(`Metric not found: ${name}`)\n\n // ALLTIME 타입인 경우 valueDate 무시하고 최신 값 조회\n if (metric.periodType === 'ALLTIME') {\n const valueRepo = getRepository(KpiMetricValue, this.options.tx)\n const value = await valueRepo.findOne({\n where: {\n metric: { id: metric.id },\n org: this.options.org ?? '',\n domain: { id: this.options.domainId }\n },\n order: { createdAt: 'DESC' }\n })\n if (!value) {\n throw new Error(`Metric value not found: metric='${name}', org='${this.options.org ?? ''}' (ALLTIME type)`)\n }\n return value.value\n }\n\n const valueRepo = getRepository(KpiMetricValue, this.options.tx)\n\n // valueDate 미지정 (예: KPI 재계산) → 그 metric 의 '최신 월'(가장 최근 valueDate) 값을\n // 대표값으로 사용한다. 완료평가/'월별 데이터' 탭에서 최신월을 수정하면 이 값이 곧 KPI\n // 계산 입력이 된다.\n // (MONTH 는 valueDate 를 'YYYY-MM-01' 로 저장하는데, 과거엔 current-month('YYYY-MM')\n // exact 조회라 포맷 불일치로 못 찾고 우연히 아래 fallback 으로만 동작했음 — 명시적 최신월 조회)\n if (!this.options.valueDate) {\n const latest = await valueRepo.findOne({\n where: {\n metric: { id: metric.id },\n org: this.options.org ?? '',\n domain: { id: this.options.domainId },\n // metric 의 periodType 과 같은 값만 — MONTH 지표인데 섞여 있는 DAY 행이 valueDate 로\n // 더 최신이라 잘못 집히던 문제 방지 (예: 실적공정률 MONTH 2026-05 vs 잔여 DAY 2026-06-15).\n periodType: metric.periodType\n },\n order: { valueDate: 'DESC' }\n })\n if (!latest) {\n throw new Error(`Metric value not found: metric='${name}', org='${this.options.org ?? ''}' (latest)`)\n }\n return latest.value\n }\n\n // 명시적 valueDate 가 주어진 경우: 해당 기간 조회 (없으면 최신 fallback).\n let valueDate = this.options.valueDate\n // valueDate가 metric.periodType에 맞는 포맷인지 검사, 아니면 보정\n if (metric.periodType === 'MONTH' && valueDate.length > 7) valueDate = valueDate.slice(0, 7)\n if (metric.periodType === 'DAY' && valueDate.length > 10) valueDate = valueDate.slice(0, 10)\n var value = await valueRepo.findOne({\n where: {\n metric: { id: metric.id },\n valueDate,\n org: this.options.org ?? '',\n domain: { id: this.options.domainId },\n periodType: metric.periodType\n }\n })\n if (!value) {\n // 해당 기간 데이터 없으면 최신 데이터로 fallback.\n value = await valueRepo.findOne({\n where: {\n metric: { id: metric.id },\n org: this.options.org ?? '',\n domain: { id: this.options.domainId },\n periodType: metric.periodType\n },\n order: { valueDate: 'DESC' }\n })\n\n if (!value) {\n throw new Error(\n `Metric value not found: metric='${name}', org='${this.options.org ?? ''}', valueDate='${valueDate}', periodType='${metric.periodType}'`\n )\n }\n }\n\n return value.value\n }\n}\n"]}
@@ -12,11 +12,10 @@ const kpi_type_1 = require("./kpi-type");
12
12
  const kpi_value_1 = require("../kpi-value/kpi-value");
13
13
  const kpi_history_1 = require("./kpi-history");
14
14
  const type_graphql_2 = require("type-graphql");
15
- const domain_inheritance_1 = require("../utils/domain-inheritance");
16
15
  let KpiQuery = class KpiQuery {
17
16
  async kpisLevel0(context) {
18
17
  const { domain } = context.state;
19
- const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
18
+ const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
20
19
  return await (0, shell_1.getRepository)(kpi_1.Kpi).find({
21
20
  where: { domain: { id: (0, typeorm_1.In)(domainIds) }, parent: (0, typeorm_1.IsNull)() },
22
21
  order: { name: 'ASC' }
@@ -24,7 +23,7 @@ let KpiQuery = class KpiQuery {
24
23
  }
25
24
  async kpisLevel1(rootId, context) {
26
25
  const { domain } = context.state;
27
- const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
26
+ const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
28
27
  let whereCondition = { domain: { id: (0, typeorm_1.In)(domainIds) } };
29
28
  if (rootId) {
30
29
  // 특정 부모의 자식들
@@ -55,14 +54,14 @@ let KpiQuery = class KpiQuery {
55
54
  }
56
55
  async kpi(id, context) {
57
56
  const { domain } = context.state;
58
- const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
57
+ const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
59
58
  return await (0, shell_1.getRepository)(kpi_1.Kpi).findOne({
60
59
  where: { domain: { id: (0, typeorm_1.In)(domainIds) }, id }
61
60
  });
62
61
  }
63
62
  async kpis(params, context) {
64
63
  const { domain } = context.state;
65
- const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
64
+ const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
66
65
  // closest-wins dedup 을 위해 pagination 은 dedup 이후 직접 적용한다.
67
66
  const { pagination, ...rest } = params || {};
68
67
  const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
@@ -79,7 +78,7 @@ let KpiQuery = class KpiQuery {
79
78
  ancestorDomainIds: domainIds
80
79
  });
81
80
  const allItems = await queryBuilder.getMany();
82
- const deduped = (0, domain_inheritance_1.dedupByClosestDomain)(allItems, domainIds, k => k.name);
81
+ const deduped = (0, shell_1.dedupByClosestDomain)(allItems, domainIds, k => k.name);
83
82
  const { page = 1, limit } = pagination || {};
84
83
  const total = deduped.length;
85
84
  const items = limit && limit > 0 ? deduped.slice(Math.max(0, (page - 1) * limit), Math.max(0, (page - 1) * limit) + limit) : deduped;
@@ -87,7 +86,7 @@ let KpiQuery = class KpiQuery {
87
86
  }
88
87
  async children(kpi, context) {
89
88
  const { domain } = context.state;
90
- const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
89
+ const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
91
90
  return await (0, shell_1.getRepository)(kpi_1.Kpi).find({
92
91
  where: { domain: { id: (0, typeorm_1.In)(domainIds) }, parent: { id: kpi.id } }
93
92
  });
@@ -113,7 +112,7 @@ let KpiQuery = class KpiQuery {
113
112
  }
114
113
  async value(kpi, context, orgScope) {
115
114
  const { domain } = context.state;
116
- const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
115
+ const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
117
116
  let whereCondition = {
118
117
  domain: { id: (0, typeorm_1.In)(domainIds) },
119
118
  kpi: { id: kpi.id }
@@ -141,7 +140,7 @@ let KpiQuery = class KpiQuery {
141
140
  }
142
141
  async histories(kpi, context, limit) {
143
142
  const { domain } = context.state;
144
- const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
143
+ const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
145
144
  const qb = (0, shell_1.getRepository)(kpi_history_1.KpiHistory)
146
145
  .createQueryBuilder('history')
147
146
  .where('history.domain IN (:...domainIds)', { domainIds })
@@ -155,7 +154,7 @@ let KpiQuery = class KpiQuery {
155
154
  }
156
155
  async kpiTree(context) {
157
156
  const { domain } = context.state;
158
- const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
157
+ const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
159
158
  return await (0, shell_1.getRepository)(kpi_1.Kpi).find({
160
159
  where: { domain: { id: (0, typeorm_1.In)(domainIds) }, parent: (0, typeorm_1.IsNull)() },
161
160
  relations: ['children', 'children.children', 'children.children.children'],
@@ -164,7 +163,7 @@ let KpiQuery = class KpiQuery {
164
163
  }
165
164
  async kpiChildren(parentId, context) {
166
165
  const { domain } = context.state;
167
- const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
166
+ const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
168
167
  return await (0, shell_1.getRepository)(kpi_1.Kpi).find({
169
168
  where: { domain: { id: (0, typeorm_1.In)(domainIds) }, parent: { id: parentId } },
170
169
  order: { name: 'ASC' }
@@ -1 +1 @@
1
- {"version":3,"file":"kpi-query.js","sourceRoot":"","sources":["../../../server/service/kpi/kpi-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { In, IsNull } from 'typeorm'\nimport { Resolver, Query, FieldResolver, Root, Args, Arg, Ctx, Directive } from 'type-graphql'\nimport { Attachment } from '@things-factory/attachment-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport type ResolverContext from '@things-factory/auth-base'\nimport { Kpi } from './kpi'\nimport { KpiList } from './kpi-type'\nimport { KpiValue } from '../kpi-value/kpi-value'\nimport { KpiHistory } from './kpi-history'\nimport { Int } from 'type-graphql'\nimport { dedupByClosestDomain, getDomainIdsWithAncestors } from '../utils/domain-inheritance'\n\n@Resolver(Kpi)\nexport class KpiQuery {\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => [Kpi], { description: 'Fetch root KPIs (KPIs without parent)' })\n async kpisLevel0(@Ctx() context: ResolverContext): Promise<Kpi[]> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(Kpi).find({\n where: { domain: { id: In(domainIds) }, parent: IsNull() },\n order: { name: 'ASC' }\n })\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => [Kpi], {\n description:\n 'Fetch first level child KPIs. If rootId is provided, get children of that parent. If not, get all level 1 KPIs (children of root KPIs)'\n })\n async kpisLevel1(\n @Arg('rootId', {\n nullable: true,\n description: 'ID of the parent KPI to get level 1 children. If not provided, returns all level 1 KPIs'\n })\n rootId: string,\n @Ctx() context: ResolverContext\n ): Promise<Kpi[]> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n let whereCondition: any = { domain: { id: In(domainIds) } }\n\n if (rootId) {\n // 특정 부모의 자식들\n whereCondition.parent = { id: rootId }\n } else {\n // 모든 level 1 KPI들 (root KPI들의 직계 자식들)\n // 부모가 있으면서 부모의 부모가 null인 KPI들\n const kpis = await getRepository(Kpi)\n .createQueryBuilder('kpi')\n .leftJoinAndSelect('kpi.parent', 'parent')\n .leftJoinAndSelect('kpi.children', 'children')\n .leftJoinAndSelect('children.children', 'grandchildren')\n .where('kpi.domain IN (:...domainIds)', { domainIds })\n .andWhere('parent.id IS NOT NULL')\n .andWhere('parent.parent IS NULL')\n .orderBy('kpi.name', 'ASC')\n .getMany()\n\n return kpis\n }\n\n // rootId 제공된 경우\n const kpis = await getRepository(Kpi).find({\n where: whereCondition,\n relations: ['children', 'children.children'],\n order: { name: 'ASC' }\n })\n\n return kpis\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => Kpi!, { nullable: true, description: 'Fetch a single KPI by its unique identifier.' })\n async kpi(\n @Arg('id', { description: 'Unique identifier of the KPI to fetch.' }) id: string,\n @Ctx() context: ResolverContext\n ): Promise<Kpi> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(Kpi).findOne({\n where: { domain: { id: In(domainIds) }, id }\n })\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiList, { description: 'To fetch multiple Kpis' })\n async kpis(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<KpiList> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n // closest-wins dedup 을 위해 pagination 은 dedup 이후 직접 적용한다.\n const { pagination, ...rest } = params || ({} as ListParam)\n\n const queryBuilder = getQueryBuilderFromListParams({\n // domain 필터링은 ancestor 기반으로 직접 적용 (shell helper 는 single-parent 만 지원)\n domain: undefined,\n params: rest as ListParam,\n repository: getRepository(Kpi),\n searchables: ['name', 'description'],\n filtersMap: {\n parent: { columnName: 'id', relationColumn: 'parent' }\n }\n })\n\n queryBuilder.andWhere(`${queryBuilder.alias}.domain IN (:...ancestorDomainIds)`, {\n ancestorDomainIds: domainIds\n })\n\n const allItems = await queryBuilder.getMany()\n const deduped = dedupByClosestDomain(allItems, domainIds, k => k.name)\n\n const { page = 1, limit } = pagination || {}\n const total = deduped.length\n const items =\n limit && limit > 0 ? deduped.slice(Math.max(0, (page - 1) * limit), Math.max(0, (page - 1) * limit) + limit) : deduped\n\n return { items, total }\n }\n\n @FieldResolver(type => [Kpi])\n async children(@Root() kpi: Kpi, @Ctx() context: ResolverContext): Promise<Kpi[]> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(Kpi).find({\n where: { domain: { id: In(domainIds) }, parent: { id: kpi.id } }\n })\n }\n\n @FieldResolver(type => String)\n async thumbnail(@Root() kpi: Kpi): Promise<string | undefined> {\n const attachment: Attachment = await getRepository(Attachment).findOne({\n where: {\n domain: { id: kpi.domainId },\n refType: Kpi.name,\n refBy: kpi.id\n }\n })\n\n return attachment?.fullpath\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() kpi: Kpi): Promise<Domain> {\n return kpi.domainId && (await getRepository(Domain).findOneBy({ id: kpi.domainId }))\n }\n\n @FieldResolver(type => User)\n async updater(@Root() kpi: Kpi): Promise<User> {\n return kpi.updaterId && (await getRepository(User).findOneBy({ id: kpi.updaterId }))\n }\n\n @FieldResolver(type => User)\n async creator(@Root() kpi: Kpi): Promise<User> {\n return kpi.creatorId && (await getRepository(User).findOneBy({ id: kpi.creatorId }))\n }\n\n @FieldResolver(type => KpiValue, { nullable: true })\n async value(\n @Root() kpi: Kpi,\n @Ctx() context,\n @Arg('orgScope', { nullable: true, description: 'Organization scope filter for value' }) orgScope?: string\n ): Promise<KpiValue | null> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n let whereCondition: any = {\n domain: { id: In(domainIds) },\n kpi: { id: kpi.id }\n }\n\n // orgScope 필터가 있으면 KpiOrgScope로 필터링\n if (orgScope) {\n whereCondition.kpiOrgScope = { org: orgScope }\n }\n\n return await getRepository(KpiValue).findOne({\n where: whereCondition,\n relations: ['kpiOrgScope'],\n order: { valueDate: 'DESC' }\n })\n }\n\n @FieldResolver(type => Number, { nullable: true })\n targetValue(@Root() kpi: Kpi): number | undefined {\n return kpi.vizMeta?.targetValue\n }\n\n @FieldResolver(type => String, { nullable: true })\n unit(@Root() kpi: Kpi): string | undefined {\n return kpi.vizMeta?.unit\n }\n\n @FieldResolver(type => Kpi, { nullable: true })\n async parent(@Root() kpi: Kpi): Promise<Kpi | null> {\n if (!kpi.parentId) return null\n return await getRepository(Kpi).findOneBy({ id: kpi.parentId })\n }\n\n @FieldResolver(type => [KpiHistory], { nullable: true })\n async histories(\n @Root() kpi: Kpi,\n @Ctx() context,\n @Arg('limit', type => Int, { nullable: true }) limit?: number\n ): Promise<KpiHistory[]> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n const qb = getRepository(KpiHistory)\n .createQueryBuilder('history')\n .where('history.domain IN (:...domainIds)', { domainIds })\n .andWhere('history.originalId = :kpiId', { kpiId: kpi.id })\n .orderBy('history.updatedAt', 'DESC')\n if (limit) qb.limit(limit)\n else qb.limit(1)\n return await qb.getMany()\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => [Kpi], { description: 'Fetch KPIs in hierarchical tree structure' })\n async kpiTree(@Ctx() context: ResolverContext): Promise<Kpi[]> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(Kpi).find({\n where: { domain: { id: In(domainIds) }, parent: IsNull() },\n relations: ['children', 'children.children', 'children.children.children'],\n order: { name: 'ASC' }\n })\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => [Kpi], { description: 'Fetch child KPIs of a given parent KPI' })\n async kpiChildren(\n @Arg('parentId', { description: 'ID of the parent KPI' }) parentId: string,\n @Ctx() context: ResolverContext\n ): Promise<Kpi[]> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(Kpi).find({\n where: { domain: { id: In(domainIds) }, parent: { id: parentId } },\n order: { name: 'ASC' }\n })\n }\n}\n"]}
1
+ {"version":3,"file":"kpi-query.js","sourceRoot":"","sources":["../../../server/service/kpi/kpi-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { In, IsNull } from 'typeorm'\nimport { Resolver, Query, FieldResolver, Root, Args, Arg, Ctx, Directive } from 'type-graphql'\nimport { Attachment } from '@things-factory/attachment-base'\nimport {\n Domain,\n getQueryBuilderFromListParams,\n getRepository,\n ListParam,\n dedupByClosestDomain,\n getDomainIdsWithAncestors\n} from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport type ResolverContext from '@things-factory/auth-base'\nimport { Kpi } from './kpi'\nimport { KpiList } from './kpi-type'\nimport { KpiValue } from '../kpi-value/kpi-value'\nimport { KpiHistory } from './kpi-history'\nimport { Int } from 'type-graphql'\n\n@Resolver(Kpi)\nexport class KpiQuery {\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => [Kpi], { description: 'Fetch root KPIs (KPIs without parent)' })\n async kpisLevel0(@Ctx() context: ResolverContext): Promise<Kpi[]> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(Kpi).find({\n where: { domain: { id: In(domainIds) }, parent: IsNull() },\n order: { name: 'ASC' }\n })\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => [Kpi], {\n description:\n 'Fetch first level child KPIs. If rootId is provided, get children of that parent. If not, get all level 1 KPIs (children of root KPIs)'\n })\n async kpisLevel1(\n @Arg('rootId', {\n nullable: true,\n description: 'ID of the parent KPI to get level 1 children. If not provided, returns all level 1 KPIs'\n })\n rootId: string,\n @Ctx() context: ResolverContext\n ): Promise<Kpi[]> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n let whereCondition: any = { domain: { id: In(domainIds) } }\n\n if (rootId) {\n // 특정 부모의 자식들\n whereCondition.parent = { id: rootId }\n } else {\n // 모든 level 1 KPI들 (root KPI들의 직계 자식들)\n // 부모가 있으면서 부모의 부모가 null인 KPI들\n const kpis = await getRepository(Kpi)\n .createQueryBuilder('kpi')\n .leftJoinAndSelect('kpi.parent', 'parent')\n .leftJoinAndSelect('kpi.children', 'children')\n .leftJoinAndSelect('children.children', 'grandchildren')\n .where('kpi.domain IN (:...domainIds)', { domainIds })\n .andWhere('parent.id IS NOT NULL')\n .andWhere('parent.parent IS NULL')\n .orderBy('kpi.name', 'ASC')\n .getMany()\n\n return kpis\n }\n\n // rootId 제공된 경우\n const kpis = await getRepository(Kpi).find({\n where: whereCondition,\n relations: ['children', 'children.children'],\n order: { name: 'ASC' }\n })\n\n return kpis\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => Kpi!, { nullable: true, description: 'Fetch a single KPI by its unique identifier.' })\n async kpi(\n @Arg('id', { description: 'Unique identifier of the KPI to fetch.' }) id: string,\n @Ctx() context: ResolverContext\n ): Promise<Kpi> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(Kpi).findOne({\n where: { domain: { id: In(domainIds) }, id }\n })\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiList, { description: 'To fetch multiple Kpis' })\n async kpis(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<KpiList> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n // closest-wins dedup 을 위해 pagination 은 dedup 이후 직접 적용한다.\n const { pagination, ...rest } = params || ({} as ListParam)\n\n const queryBuilder = getQueryBuilderFromListParams({\n // domain 필터링은 ancestor 기반으로 직접 적용 (shell helper 는 single-parent 만 지원)\n domain: undefined,\n params: rest as ListParam,\n repository: getRepository(Kpi),\n searchables: ['name', 'description'],\n filtersMap: {\n parent: { columnName: 'id', relationColumn: 'parent' }\n }\n })\n\n queryBuilder.andWhere(`${queryBuilder.alias}.domain IN (:...ancestorDomainIds)`, {\n ancestorDomainIds: domainIds\n })\n\n const allItems = await queryBuilder.getMany()\n const deduped = dedupByClosestDomain(allItems, domainIds, k => k.name)\n\n const { page = 1, limit } = pagination || {}\n const total = deduped.length\n const items =\n limit && limit > 0 ? deduped.slice(Math.max(0, (page - 1) * limit), Math.max(0, (page - 1) * limit) + limit) : deduped\n\n return { items, total }\n }\n\n @FieldResolver(type => [Kpi])\n async children(@Root() kpi: Kpi, @Ctx() context: ResolverContext): Promise<Kpi[]> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(Kpi).find({\n where: { domain: { id: In(domainIds) }, parent: { id: kpi.id } }\n })\n }\n\n @FieldResolver(type => String)\n async thumbnail(@Root() kpi: Kpi): Promise<string | undefined> {\n const attachment: Attachment = await getRepository(Attachment).findOne({\n where: {\n domain: { id: kpi.domainId },\n refType: Kpi.name,\n refBy: kpi.id\n }\n })\n\n return attachment?.fullpath\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() kpi: Kpi): Promise<Domain> {\n return kpi.domainId && (await getRepository(Domain).findOneBy({ id: kpi.domainId }))\n }\n\n @FieldResolver(type => User)\n async updater(@Root() kpi: Kpi): Promise<User> {\n return kpi.updaterId && (await getRepository(User).findOneBy({ id: kpi.updaterId }))\n }\n\n @FieldResolver(type => User)\n async creator(@Root() kpi: Kpi): Promise<User> {\n return kpi.creatorId && (await getRepository(User).findOneBy({ id: kpi.creatorId }))\n }\n\n @FieldResolver(type => KpiValue, { nullable: true })\n async value(\n @Root() kpi: Kpi,\n @Ctx() context,\n @Arg('orgScope', { nullable: true, description: 'Organization scope filter for value' }) orgScope?: string\n ): Promise<KpiValue | null> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n let whereCondition: any = {\n domain: { id: In(domainIds) },\n kpi: { id: kpi.id }\n }\n\n // orgScope 필터가 있으면 KpiOrgScope로 필터링\n if (orgScope) {\n whereCondition.kpiOrgScope = { org: orgScope }\n }\n\n return await getRepository(KpiValue).findOne({\n where: whereCondition,\n relations: ['kpiOrgScope'],\n order: { valueDate: 'DESC' }\n })\n }\n\n @FieldResolver(type => Number, { nullable: true })\n targetValue(@Root() kpi: Kpi): number | undefined {\n return kpi.vizMeta?.targetValue\n }\n\n @FieldResolver(type => String, { nullable: true })\n unit(@Root() kpi: Kpi): string | undefined {\n return kpi.vizMeta?.unit\n }\n\n @FieldResolver(type => Kpi, { nullable: true })\n async parent(@Root() kpi: Kpi): Promise<Kpi | null> {\n if (!kpi.parentId) return null\n return await getRepository(Kpi).findOneBy({ id: kpi.parentId })\n }\n\n @FieldResolver(type => [KpiHistory], { nullable: true })\n async histories(\n @Root() kpi: Kpi,\n @Ctx() context,\n @Arg('limit', type => Int, { nullable: true }) limit?: number\n ): Promise<KpiHistory[]> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n const qb = getRepository(KpiHistory)\n .createQueryBuilder('history')\n .where('history.domain IN (:...domainIds)', { domainIds })\n .andWhere('history.originalId = :kpiId', { kpiId: kpi.id })\n .orderBy('history.updatedAt', 'DESC')\n if (limit) qb.limit(limit)\n else qb.limit(1)\n return await qb.getMany()\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => [Kpi], { description: 'Fetch KPIs in hierarchical tree structure' })\n async kpiTree(@Ctx() context: ResolverContext): Promise<Kpi[]> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(Kpi).find({\n where: { domain: { id: In(domainIds) }, parent: IsNull() },\n relations: ['children', 'children.children', 'children.children.children'],\n order: { name: 'ASC' }\n })\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => [Kpi], { description: 'Fetch child KPIs of a given parent KPI' })\n async kpiChildren(\n @Arg('parentId', { description: 'ID of the parent KPI' }) parentId: string,\n @Ctx() context: ResolverContext\n ): Promise<Kpi[]> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(Kpi).find({\n where: { domain: { id: In(domainIds) }, parent: { id: parentId } },\n order: { name: 'ASC' }\n })\n }\n}\n"]}
@@ -10,11 +10,10 @@ const auth_base_1 = require("@things-factory/auth-base");
10
10
  const kpi_metric_1 = require("./kpi-metric");
11
11
  const kpi_metric_type_1 = require("./kpi-metric-type");
12
12
  const dataset_1 = require("@things-factory/dataset");
13
- const domain_inheritance_1 = require("../utils/domain-inheritance");
14
13
  let KpiMetricQuery = class KpiMetricQuery {
15
14
  async kpiMetric(id, context) {
16
15
  const { domain } = context.state;
17
- const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
16
+ const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
18
17
  return await (0, shell_1.getRepository)(kpi_metric_1.KpiMetric).findOne({
19
18
  where: { domain: { id: (0, typeorm_1.In)(domainIds) }, id },
20
19
  relations: ['dataSet']
@@ -22,7 +21,7 @@ let KpiMetricQuery = class KpiMetricQuery {
22
21
  }
23
22
  async kpiMetrics(params, context) {
24
23
  const { domain } = context.state;
25
- const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
24
+ const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
26
25
  // closest-wins dedup 을 위해 pagination 은 dedup 이후 직접 적용한다.
27
26
  const { pagination, ...rest } = params || {};
28
27
  // alias 를 명시해야 정렬 식별자가 `<alias>.rank` 로 한정(qualified)되어
@@ -38,7 +37,7 @@ let KpiMetricQuery = class KpiMetricQuery {
38
37
  ancestorDomainIds: domainIds
39
38
  });
40
39
  const allItems = await queryBuilder.getMany();
41
- const deduped = (0, domain_inheritance_1.dedupByClosestDomain)(allItems, domainIds, m => m.name);
40
+ const deduped = (0, shell_1.dedupByClosestDomain)(allItems, domainIds, m => m.name);
42
41
  const { page = 1, limit } = pagination || {};
43
42
  const total = deduped.length;
44
43
  const items = limit && limit > 0 ? deduped.slice(Math.max(0, (page - 1) * limit), Math.max(0, (page - 1) * limit) + limit) : deduped;
@@ -1 +1 @@
1
- {"version":3,"file":"kpi-metric-query.js","sourceRoot":"","sources":["../../../server/service/kpi-metric/kpi-metric-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { In } from 'typeorm'\nimport { Resolver, Query, FieldResolver, Root, Args, Arg, Ctx, Directive } from 'type-graphql'\nimport { Attachment } from '@things-factory/attachment-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { KpiMetric } from './kpi-metric'\nimport { KpiMetricList } from './kpi-metric-type'\nimport { DataSet } from '@things-factory/dataset'\nimport { dedupByClosestDomain, getDomainIdsWithAncestors } from '../utils/domain-inheritance'\n\n@Resolver(KpiMetric)\nexport class KpiMetricQuery {\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiMetric!, { nullable: true, description: 'Fetch a single KPI metric by its unique identifier.' })\n async kpiMetric(\n @Arg('id', { description: 'Unique identifier of the KPI metric to fetch.' }) id: string,\n @Ctx() context: ResolverContext\n ): Promise<KpiMetric> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(KpiMetric).findOne({\n where: { domain: { id: In(domainIds) }, id },\n relations: ['dataSet']\n })\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiMetricList, { description: 'To fetch multiple KpiMetrics' })\n async kpiMetrics(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<KpiMetricList> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n // closest-wins dedup 을 위해 pagination 은 dedup 이후 직접 적용한다.\n const { pagination, ...rest } = params || ({} as ListParam)\n\n // alias 를 명시해야 정렬 식별자가 `<alias>.rank` 로 한정(qualified)되어\n // rank(예약어)도 정상 정렬된다. alias 미지정 시 bare `rank` 로 나가 집계함수로 오인됨.\n const queryBuilder = getQueryBuilderFromListParams({\n domain: undefined,\n params: rest as ListParam,\n repository: getRepository(KpiMetric),\n alias: 'kpiMetric',\n searchables: ['name', 'description']\n })\n\n queryBuilder.andWhere(`${queryBuilder.alias}.domain IN (:...ancestorDomainIds)`, {\n ancestorDomainIds: domainIds\n })\n\n const allItems = await queryBuilder.getMany()\n const deduped = dedupByClosestDomain(allItems, domainIds, m => m.name)\n\n const { page = 1, limit } = pagination || {}\n const total = deduped.length\n const items =\n limit && limit > 0 ? deduped.slice(Math.max(0, (page - 1) * limit), Math.max(0, (page - 1) * limit) + limit) : deduped\n\n return { items, total }\n }\n\n @FieldResolver(type => String)\n async thumbnail(@Root() kpiMetric: KpiMetric): Promise<string | undefined> {\n const attachment: Attachment = await getRepository(Attachment).findOne({\n where: {\n domain: { id: kpiMetric.domainId },\n refType: KpiMetric.name,\n refBy: kpiMetric.id\n }\n })\n\n return attachment?.fullpath\n }\n\n @FieldResolver(type => String)\n async dataSet(@Root() kpiMetric: KpiMetric): Promise<DataSet> {\n return kpiMetric.dataSetId && (await getRepository(DataSet).findOneBy({ id: kpiMetric.dataSetId }))\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() kpiMetric: KpiMetric): Promise<Domain> {\n return kpiMetric.domainId && (await getRepository(Domain).findOneBy({ id: kpiMetric.domainId }))\n }\n\n @FieldResolver(type => User)\n async updater(@Root() kpiMetric: KpiMetric): Promise<User> {\n return kpiMetric.updaterId && (await getRepository(User).findOneBy({ id: kpiMetric.updaterId }))\n }\n\n @FieldResolver(type => User)\n async creator(@Root() kpiMetric: KpiMetric): Promise<User> {\n return kpiMetric.creatorId && (await getRepository(User).findOneBy({ id: kpiMetric.creatorId }))\n }\n}\n"]}
1
+ {"version":3,"file":"kpi-metric-query.js","sourceRoot":"","sources":["../../../server/service/kpi-metric/kpi-metric-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { In } from 'typeorm'\nimport { Resolver, Query, FieldResolver, Root, Args, Arg, Ctx, Directive } from 'type-graphql'\nimport { Attachment } from '@things-factory/attachment-base'\nimport {\n Domain,\n getQueryBuilderFromListParams,\n getRepository,\n ListParam,\n dedupByClosestDomain,\n getDomainIdsWithAncestors\n} from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { KpiMetric } from './kpi-metric'\nimport { KpiMetricList } from './kpi-metric-type'\nimport { DataSet } from '@things-factory/dataset'\n\n@Resolver(KpiMetric)\nexport class KpiMetricQuery {\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiMetric!, { nullable: true, description: 'Fetch a single KPI metric by its unique identifier.' })\n async kpiMetric(\n @Arg('id', { description: 'Unique identifier of the KPI metric to fetch.' }) id: string,\n @Ctx() context: ResolverContext\n ): Promise<KpiMetric> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(KpiMetric).findOne({\n where: { domain: { id: In(domainIds) }, id },\n relations: ['dataSet']\n })\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiMetricList, { description: 'To fetch multiple KpiMetrics' })\n async kpiMetrics(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<KpiMetricList> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n // closest-wins dedup 을 위해 pagination 은 dedup 이후 직접 적용한다.\n const { pagination, ...rest } = params || ({} as ListParam)\n\n // alias 를 명시해야 정렬 식별자가 `<alias>.rank` 로 한정(qualified)되어\n // rank(예약어)도 정상 정렬된다. alias 미지정 시 bare `rank` 로 나가 집계함수로 오인됨.\n const queryBuilder = getQueryBuilderFromListParams({\n domain: undefined,\n params: rest as ListParam,\n repository: getRepository(KpiMetric),\n alias: 'kpiMetric',\n searchables: ['name', 'description']\n })\n\n queryBuilder.andWhere(`${queryBuilder.alias}.domain IN (:...ancestorDomainIds)`, {\n ancestorDomainIds: domainIds\n })\n\n const allItems = await queryBuilder.getMany()\n const deduped = dedupByClosestDomain(allItems, domainIds, m => m.name)\n\n const { page = 1, limit } = pagination || {}\n const total = deduped.length\n const items =\n limit && limit > 0 ? deduped.slice(Math.max(0, (page - 1) * limit), Math.max(0, (page - 1) * limit) + limit) : deduped\n\n return { items, total }\n }\n\n @FieldResolver(type => String)\n async thumbnail(@Root() kpiMetric: KpiMetric): Promise<string | undefined> {\n const attachment: Attachment = await getRepository(Attachment).findOne({\n where: {\n domain: { id: kpiMetric.domainId },\n refType: KpiMetric.name,\n refBy: kpiMetric.id\n }\n })\n\n return attachment?.fullpath\n }\n\n @FieldResolver(type => String)\n async dataSet(@Root() kpiMetric: KpiMetric): Promise<DataSet> {\n return kpiMetric.dataSetId && (await getRepository(DataSet).findOneBy({ id: kpiMetric.dataSetId }))\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() kpiMetric: KpiMetric): Promise<Domain> {\n return kpiMetric.domainId && (await getRepository(Domain).findOneBy({ id: kpiMetric.domainId }))\n }\n\n @FieldResolver(type => User)\n async updater(@Root() kpiMetric: KpiMetric): Promise<User> {\n return kpiMetric.updaterId && (await getRepository(User).findOneBy({ id: kpiMetric.updaterId }))\n }\n\n @FieldResolver(type => User)\n async creator(@Root() kpiMetric: KpiMetric): Promise<User> {\n return kpiMetric.creatorId && (await getRepository(User).findOneBy({ id: kpiMetric.creatorId }))\n }\n}\n"]}
@@ -9,11 +9,10 @@ const auth_base_1 = require("@things-factory/auth-base");
9
9
  const kpi_metric_value_1 = require("./kpi-metric-value");
10
10
  const kpi_metric_value_type_1 = require("./kpi-metric-value-type");
11
11
  const kpi_metric_1 = require("../kpi-metric/kpi-metric");
12
- const domain_inheritance_1 = require("../utils/domain-inheritance");
13
12
  let KpiMetricValueQuery = class KpiMetricValueQuery {
14
13
  async kpiMetricValues(params, context) {
15
14
  const { domain } = context.state;
16
- const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
15
+ const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
17
16
  const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
18
17
  domain: undefined,
19
18
  params,
@@ -31,7 +30,7 @@ let KpiMetricValueQuery = class KpiMetricValueQuery {
31
30
  }
32
31
  async kpiMetricValue(id, context) {
33
32
  const { domain } = context.state;
34
- const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
33
+ const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
35
34
  return await (0, shell_1.getRepository)(kpi_metric_value_1.KpiMetricValue).findOne({
36
35
  where: { domain: { id: (0, typeorm_1.In)(domainIds) }, id }
37
36
  });
@@ -1 +1 @@
1
- {"version":3,"file":"kpi-metric-value-query.js","sourceRoot":"","sources":["../../../server/service/kpi-metric-value/kpi-metric-value-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { In } from 'typeorm'\nimport { Directive, Resolver, Query, Args, Arg, Ctx, FieldResolver, Root } from 'type-graphql'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { KpiMetricValue } from './kpi-metric-value'\nimport { KpiMetricValueList } from './kpi-metric-value-type'\nimport { KpiMetric } from '../kpi-metric/kpi-metric'\nimport { getDomainIdsWithAncestors } from '../utils/domain-inheritance'\n\n@Resolver(KpiMetricValue)\nexport class KpiMetricValueQuery {\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiMetricValueList, { description: 'To fetch multiple KpiMetricValues' })\n async kpiMetricValues(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<KpiMetricValueList> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain: undefined,\n params,\n repository: getRepository(KpiMetricValue),\n /* The metric by its name, not metricId: that is the uuid join column, and LOWER(uuid) is an\n error on postgres. And no group: this entity has none, and an unknown name throws. Either way\n the list's search would answer with an error instead of rows. */\n searchables: ['metric', 'valueDate']\n })\n\n queryBuilder.andWhere(`${queryBuilder.alias}.domain IN (:...ancestorDomainIds)`, {\n ancestorDomainIds: domainIds\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n return { items, total }\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiMetricValue, {\n nullable: true,\n description: 'Fetch a single metric value by its unique identifier.'\n })\n async kpiMetricValue(\n @Arg('id', { description: 'Unique identifier of the metric value to fetch.' }) id: string,\n @Ctx() context: ResolverContext\n ): Promise<KpiMetricValue | null> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n return await getRepository(KpiMetricValue).findOne({\n where: { domain: { id: In(domainIds) }, id }\n })\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() metricValue: KpiMetricValue): Promise<Domain> {\n return metricValue.domainId && (await getRepository(Domain).findOneBy({ id: metricValue.domainId }))\n }\n\n @FieldResolver(type => User)\n async updater(@Root() metricValue: KpiMetricValue): Promise<User> {\n return metricValue.updaterId && (await getRepository(User).findOneBy({ id: metricValue.updaterId }))\n }\n\n @FieldResolver(type => User)\n async creator(@Root() metricValue: KpiMetricValue): Promise<User> {\n return metricValue.creatorId && (await getRepository(User).findOneBy({ id: metricValue.creatorId }))\n }\n\n @FieldResolver(type => KpiMetric)\n async metric(@Root() metricValue: KpiMetricValue): Promise<KpiMetric | null> {\n if (!metricValue.metricId) return null\n return await getRepository(KpiMetric).findOneBy({ id: metricValue.metricId })\n }\n}\n"]}
1
+ {"version":3,"file":"kpi-metric-value-query.js","sourceRoot":"","sources":["../../../server/service/kpi-metric-value/kpi-metric-value-query.ts"],"names":[],"mappings":";;;;AAAA,qCAA4B;AAC5B,+CAA8F;AAC9F,iDAM8B;AAC9B,yDAAgD;AAChD,yDAAmD;AACnD,mEAA4D;AAC5D,yDAAoD;AAG7C,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAGxB,AAAN,KAAK,CAAC,eAAe,CACM,MAAiB,EACnC,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAChC,MAAM,SAAS,GAAG,MAAM,IAAA,iCAAyB,EAAC,MAAM,CAAC,CAAA;QAEzD,MAAM,YAAY,GAAG,IAAA,qCAA6B,EAAC;YACjD,MAAM,EAAE,SAAS;YACjB,MAAM;YACN,UAAU,EAAE,IAAA,qBAAa,EAAC,iCAAc,CAAC;YACzC;;+EAEmE;YACnE,WAAW,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC;SACrC,CAAC,CAAA;QAEF,YAAY,CAAC,QAAQ,CAAC,GAAG,YAAY,CAAC,KAAK,oCAAoC,EAAE;YAC/E,iBAAiB,EAAE,SAAS;SAC7B,CAAC,CAAA;QAEF,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,YAAY,CAAC,eAAe,EAAE,CAAA;QAC3D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;IACzB,CAAC;IAOK,AAAN,KAAK,CAAC,cAAc,CAC6D,EAAU,EAClF,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAChC,MAAM,SAAS,GAAG,MAAM,IAAA,iCAAyB,EAAC,MAAM,CAAC,CAAA;QACzD,OAAO,MAAM,IAAA,qBAAa,EAAC,iCAAc,CAAC,CAAC,OAAO,CAAC;YACjD,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAA,YAAE,EAAC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE;SAC7C,CAAC,CAAA;IACJ,CAAC;IAGK,AAAN,KAAK,CAAC,MAAM,CAAS,WAA2B;QAC9C,OAAO,WAAW,CAAC,QAAQ,IAAI,CAAC,MAAM,IAAA,qBAAa,EAAC,cAAM,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;IACtG,CAAC;IAGK,AAAN,KAAK,CAAC,OAAO,CAAS,WAA2B;QAC/C,OAAO,WAAW,CAAC,SAAS,IAAI,CAAC,MAAM,IAAA,qBAAa,EAAC,gBAAI,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,WAAW,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;IACtG,CAAC;IAGK,AAAN,KAAK,CAAC,OAAO,CAAS,WAA2B;QAC/C,OAAO,WAAW,CAAC,SAAS,IAAI,CAAC,MAAM,IAAA,qBAAa,EAAC,gBAAI,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,WAAW,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;IACtG,CAAC;IAGK,AAAN,KAAK,CAAC,MAAM,CAAS,WAA2B;QAC9C,IAAI,CAAC,WAAW,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAA;QACtC,OAAO,MAAM,IAAA,qBAAa,EAAC,sBAAS,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAA;IAC/E,CAAC;CACF,CAAA;AAhEY,kDAAmB;AAGxB;IAFL,IAAA,wBAAS,EAAC,mGAAmG,CAAC;IAC9G,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,0CAAkB,EAAE,EAAE,WAAW,EAAE,mCAAmC,EAAE,CAAC;IAExF,mBAAA,IAAA,mBAAI,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAS,CAAC,CAAA;IACvB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAD2B,iBAAS;;0DAsB3C;AAOK;IALL,IAAA,wBAAS,EAAC,mGAAmG,CAAC;IAC9G,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,iCAAc,EAAE;QAChC,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,uDAAuD;KACrE,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,IAAI,EAAE,EAAE,WAAW,EAAE,iDAAiD,EAAE,CAAC,CAAA;IAC7E,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;yDAOP;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,CAAC;IAChB,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAc,iCAAc;;iDAE/C;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,CAAC;IACb,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAc,iCAAc;;kDAEhD;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,CAAC;IACb,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAc,iCAAc;;kDAEhD;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,sBAAS,CAAC;IACnB,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAc,iCAAc;;iDAG/C;8BA/DU,mBAAmB;IAD/B,IAAA,uBAAQ,EAAC,iCAAc,CAAC;GACZ,mBAAmB,CAgE/B","sourcesContent":["import { In } from 'typeorm'\nimport { Directive, Resolver, Query, Args, Arg, Ctx, FieldResolver, Root } from 'type-graphql'\nimport {\n Domain,\n getQueryBuilderFromListParams,\n getRepository,\n ListParam,\n getDomainIdsWithAncestors\n} from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { KpiMetricValue } from './kpi-metric-value'\nimport { KpiMetricValueList } from './kpi-metric-value-type'\nimport { KpiMetric } from '../kpi-metric/kpi-metric'\n\n@Resolver(KpiMetricValue)\nexport class KpiMetricValueQuery {\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiMetricValueList, { description: 'To fetch multiple KpiMetricValues' })\n async kpiMetricValues(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<KpiMetricValueList> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain: undefined,\n params,\n repository: getRepository(KpiMetricValue),\n /* The metric by its name, not metricId: that is the uuid join column, and LOWER(uuid) is an\n error on postgres. And no group: this entity has none, and an unknown name throws. Either way\n the list's search would answer with an error instead of rows. */\n searchables: ['metric', 'valueDate']\n })\n\n queryBuilder.andWhere(`${queryBuilder.alias}.domain IN (:...ancestorDomainIds)`, {\n ancestorDomainIds: domainIds\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n return { items, total }\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiMetricValue, {\n nullable: true,\n description: 'Fetch a single metric value by its unique identifier.'\n })\n async kpiMetricValue(\n @Arg('id', { description: 'Unique identifier of the metric value to fetch.' }) id: string,\n @Ctx() context: ResolverContext\n ): Promise<KpiMetricValue | null> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n return await getRepository(KpiMetricValue).findOne({\n where: { domain: { id: In(domainIds) }, id }\n })\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() metricValue: KpiMetricValue): Promise<Domain> {\n return metricValue.domainId && (await getRepository(Domain).findOneBy({ id: metricValue.domainId }))\n }\n\n @FieldResolver(type => User)\n async updater(@Root() metricValue: KpiMetricValue): Promise<User> {\n return metricValue.updaterId && (await getRepository(User).findOneBy({ id: metricValue.updaterId }))\n }\n\n @FieldResolver(type => User)\n async creator(@Root() metricValue: KpiMetricValue): Promise<User> {\n return metricValue.creatorId && (await getRepository(User).findOneBy({ id: metricValue.creatorId }))\n }\n\n @FieldResolver(type => KpiMetric)\n async metric(@Root() metricValue: KpiMetricValue): Promise<KpiMetric | null> {\n if (!metricValue.metricId) return null\n return await getRepository(KpiMetric).findOneBy({ id: metricValue.metricId })\n }\n}\n"]}
@@ -9,18 +9,17 @@ const auth_base_1 = require("@things-factory/auth-base");
9
9
  const kpi_value_1 = require("./kpi-value");
10
10
  const kpi_value_type_1 = require("./kpi-value-type");
11
11
  const kpi_1 = require("../kpi/kpi");
12
- const domain_inheritance_1 = require("../utils/domain-inheritance");
13
12
  let KpiValueQuery = class KpiValueQuery {
14
13
  async kpiValue(id, context) {
15
14
  const { domain } = context.state;
16
- const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
15
+ const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
17
16
  return await (0, shell_1.getRepository)(kpi_value_1.KpiValue).findOne({
18
17
  where: { domain: { id: (0, typeorm_1.In)(domainIds) }, id }
19
18
  });
20
19
  }
21
20
  async kpiValues(params, context) {
22
21
  const { domain } = context.state;
23
- const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
22
+ const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
24
23
  const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
25
24
  domain: undefined,
26
25
  params,
@@ -43,7 +42,7 @@ let KpiValueQuery = class KpiValueQuery {
43
42
  */
44
43
  async latestKpiValues(params, context) {
45
44
  const { domain } = context.state;
46
- const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
45
+ const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
47
46
  const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
48
47
  domain: undefined,
49
48
  params,
@@ -1 +1 @@
1
- {"version":3,"file":"kpi-value-query.js","sourceRoot":"","sources":["../../../server/service/kpi-value/kpi-value-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { In } from 'typeorm'\nimport { Resolver, Query, FieldResolver, Root, Args, Arg, Ctx, Directive, Float } from 'type-graphql'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { KpiValue } from './kpi-value'\nimport { KpiValueList } from './kpi-value-type'\nimport { Kpi } from '../kpi/kpi'\nimport { KpiValueScoreService } from './kpi-value-score.service'\nimport { getDomainIdsWithAncestors } from '../utils/domain-inheritance'\n\n@Resolver(KpiValue)\nexport class KpiValueQuery {\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiValue!, { nullable: true, description: 'Fetch a single KPI value by its unique identifier.' })\n async kpiValue(\n @Arg('id', { description: 'Unique identifier of the KPI value to fetch.' }) id: string,\n @Ctx() context: ResolverContext\n ): Promise<KpiValue> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(KpiValue).findOne({\n where: { domain: { id: In(domainIds) }, id }\n })\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiValueList, { description: 'To fetch multiple KpiValues' })\n async kpiValues(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<KpiValueList> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain: undefined,\n params,\n repository: getRepository(KpiValue),\n searchables: ['kpi', 'group', 'valueDate']\n })\n\n queryBuilder.andWhere(`${queryBuilder.alias}.domain IN (:...ancestorDomainIds)`, {\n ancestorDomainIds: domainIds\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n /**\n * 같은 (domain, kpi, valueDate, kpiOrgScope) 좌표에서 version 이 가장 큰 row 만 반환.\n * 차트·최종 KPI 계산 등 \"최신 상태\" 만 필요한 사용처용.\n *\n * 구현: subquery 로 (domain, kpi, valueDate, kpiOrgScope) 그룹별 MAX(version) 를 구한 뒤\n * 본 테이블과 매칭. 기존 kpiValues 와 동일하게 ListParam (filters/sortings/pagination)\n * 지원, 도메인 inheritance 적용.\n */\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiValueList, {\n description: 'Fetch latest-version KpiValues only — one row per (domain, kpi, valueDate, kpiOrgScope).'\n })\n async latestKpiValues(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<KpiValueList> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain: undefined,\n params,\n repository: getRepository(KpiValue),\n searchables: ['kpi', 'group', 'valueDate']\n })\n\n queryBuilder.andWhere(`${queryBuilder.alias}.domain IN (:...ancestorDomainIds)`, {\n ancestorDomainIds: domainIds\n })\n\n // 같은 (domain, kpi, valueDate, kpiOrgScope) 좌표에서 가장 높은 version 만 통과.\n // 운영 DB 가 PostgreSQL 이라 DISTINCT ON 활용 — TypeORM QueryBuilder 의 정식 메서드.\n queryBuilder\n .distinctOn([\n `${queryBuilder.alias}.domainId`,\n `${queryBuilder.alias}.kpiId`,\n `${queryBuilder.alias}.valueDate`,\n `${queryBuilder.alias}.kpiOrgScope`\n ])\n .addOrderBy(`${queryBuilder.alias}.domainId`, 'ASC')\n .addOrderBy(`${queryBuilder.alias}.kpiId`, 'ASC')\n .addOrderBy(`${queryBuilder.alias}.valueDate`, 'ASC')\n .addOrderBy(`${queryBuilder.alias}.kpiOrgScope`, 'ASC')\n .addOrderBy(`${queryBuilder.alias}.version`, 'DESC')\n\n const items = await queryBuilder.getMany()\n\n return { items, total: items.length }\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() kpiValue: KpiValue): Promise<Domain> {\n return kpiValue.domainId && (await getRepository(Domain).findOneBy({ id: kpiValue.domainId }))\n }\n\n @FieldResolver(type => User)\n async updater(@Root() kpiValue: KpiValue): Promise<User> {\n return kpiValue.updaterId && (await getRepository(User).findOneBy({ id: kpiValue.updaterId }))\n }\n\n @FieldResolver(type => User)\n async creator(@Root() kpiValue: KpiValue): Promise<User> {\n return kpiValue.creatorId && (await getRepository(User).findOneBy({ id: kpiValue.creatorId }))\n }\n\n @FieldResolver(type => Kpi)\n async kpi(@Root() kpiValue: KpiValue): Promise<Kpi | null> {\n if (!kpiValue.kpiId) return null\n return await getRepository(Kpi).findOneBy({ id: kpiValue.kpiId })\n }\n}\n"]}
1
+ {"version":3,"file":"kpi-value-query.js","sourceRoot":"","sources":["../../../server/service/kpi-value/kpi-value-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { In } from 'typeorm'\nimport { Resolver, Query, FieldResolver, Root, Args, Arg, Ctx, Directive, Float } from 'type-graphql'\nimport {\n Domain,\n getQueryBuilderFromListParams,\n getRepository,\n ListParam,\n getDomainIdsWithAncestors\n} from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { KpiValue } from './kpi-value'\nimport { KpiValueList } from './kpi-value-type'\nimport { Kpi } from '../kpi/kpi'\nimport { KpiValueScoreService } from './kpi-value-score.service'\n\n@Resolver(KpiValue)\nexport class KpiValueQuery {\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiValue!, { nullable: true, description: 'Fetch a single KPI value by its unique identifier.' })\n async kpiValue(\n @Arg('id', { description: 'Unique identifier of the KPI value to fetch.' }) id: string,\n @Ctx() context: ResolverContext\n ): Promise<KpiValue> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(KpiValue).findOne({\n where: { domain: { id: In(domainIds) }, id }\n })\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiValueList, { description: 'To fetch multiple KpiValues' })\n async kpiValues(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<KpiValueList> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain: undefined,\n params,\n repository: getRepository(KpiValue),\n searchables: ['kpi', 'group', 'valueDate']\n })\n\n queryBuilder.andWhere(`${queryBuilder.alias}.domain IN (:...ancestorDomainIds)`, {\n ancestorDomainIds: domainIds\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n /**\n * 같은 (domain, kpi, valueDate, kpiOrgScope) 좌표에서 version 이 가장 큰 row 만 반환.\n * 차트·최종 KPI 계산 등 \"최신 상태\" 만 필요한 사용처용.\n *\n * 구현: subquery 로 (domain, kpi, valueDate, kpiOrgScope) 그룹별 MAX(version) 를 구한 뒤\n * 본 테이블과 매칭. 기존 kpiValues 와 동일하게 ListParam (filters/sortings/pagination)\n * 지원, 도메인 inheritance 적용.\n */\n @Directive('@privilege(category: \"kpi\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiValueList, {\n description: 'Fetch latest-version KpiValues only — one row per (domain, kpi, valueDate, kpiOrgScope).'\n })\n async latestKpiValues(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<KpiValueList> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain: undefined,\n params,\n repository: getRepository(KpiValue),\n searchables: ['kpi', 'group', 'valueDate']\n })\n\n queryBuilder.andWhere(`${queryBuilder.alias}.domain IN (:...ancestorDomainIds)`, {\n ancestorDomainIds: domainIds\n })\n\n // 같은 (domain, kpi, valueDate, kpiOrgScope) 좌표에서 가장 높은 version 만 통과.\n // 운영 DB 가 PostgreSQL 이라 DISTINCT ON 활용 — TypeORM QueryBuilder 의 정식 메서드.\n queryBuilder\n .distinctOn([\n `${queryBuilder.alias}.domainId`,\n `${queryBuilder.alias}.kpiId`,\n `${queryBuilder.alias}.valueDate`,\n `${queryBuilder.alias}.kpiOrgScope`\n ])\n .addOrderBy(`${queryBuilder.alias}.domainId`, 'ASC')\n .addOrderBy(`${queryBuilder.alias}.kpiId`, 'ASC')\n .addOrderBy(`${queryBuilder.alias}.valueDate`, 'ASC')\n .addOrderBy(`${queryBuilder.alias}.kpiOrgScope`, 'ASC')\n .addOrderBy(`${queryBuilder.alias}.version`, 'DESC')\n\n const items = await queryBuilder.getMany()\n\n return { items, total: items.length }\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() kpiValue: KpiValue): Promise<Domain> {\n return kpiValue.domainId && (await getRepository(Domain).findOneBy({ id: kpiValue.domainId }))\n }\n\n @FieldResolver(type => User)\n async updater(@Root() kpiValue: KpiValue): Promise<User> {\n return kpiValue.updaterId && (await getRepository(User).findOneBy({ id: kpiValue.updaterId }))\n }\n\n @FieldResolver(type => User)\n async creator(@Root() kpiValue: KpiValue): Promise<User> {\n return kpiValue.creatorId && (await getRepository(User).findOneBy({ id: kpiValue.creatorId }))\n }\n\n @FieldResolver(type => Kpi)\n async kpi(@Root() kpiValue: KpiValue): Promise<Kpi | null> {\n if (!kpiValue.kpiId) return null\n return await getRepository(Kpi).findOneBy({ id: kpiValue.kpiId })\n }\n}\n"]}