From 702a1cc34f9ccc3c7c1c364cd7efc9ec8d1ff6b1 Mon Sep 17 00:00:00 2001 From: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> Date: Tue, 8 Sep 2026 11:32:20 +0800 Subject: [PATCH] perf(governance): batch hidden skill summaries Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> --- .../repository/JpaMySkillQueryRepository.java | 44 ++++++++++++++++++- .../repository/MySkillQueryRepository.java | 2 + .../skillhub/service/MySkillAppService.java | 4 +- .../JpaMySkillQueryRepositoryTest.java | 34 ++++++++++++++ 4 files changed, 82 insertions(+), 2 deletions(-) diff --git a/server/skillhub-app/src/main/java/com/iflytek/skillhub/repository/JpaMySkillQueryRepository.java b/server/skillhub-app/src/main/java/com/iflytek/skillhub/repository/JpaMySkillQueryRepository.java index 2ed0a5c5..b60f01fd 100644 --- a/server/skillhub-app/src/main/java/com/iflytek/skillhub/repository/JpaMySkillQueryRepository.java +++ b/server/skillhub-app/src/main/java/com/iflytek/skillhub/repository/JpaMySkillQueryRepository.java @@ -63,6 +63,33 @@ public class JpaMySkillQueryRepository implements MySkillQueryRepository { .toList(); } + @Override + public List getHiddenSkillSummaries(List skills) { + if (skills.isEmpty()) { + return List.of(); + } + Map namespacesById = namespaceRepository.findByIdIn( + skills.stream().map(Skill::getNamespaceId).distinct().toList()) + .stream() + .collect(Collectors.toMap(Namespace::getId, Function.identity())); + Map ownersById = userAccountRepository == null + ? Map.of() + : userAccountRepository.findByIdIn(skills.stream().map(Skill::getOwnerId).distinct().toList()) + .stream().collect(Collectors.toMap(UserAccount::getId, Function.identity())); + Map projections = + skillLifecycleProjectionService.projectPublishedSummaries(skills); + + return skills.stream() + .map(skill -> toSummaryResponse( + skill, + namespacesById, + ownersById, + projections.get(skill.getId()), + false + )) + .toList(); + } + private SkillSummaryResponse toSummaryResponse(Skill skill, String currentUserId, Map namespacesById, @@ -76,6 +103,21 @@ public class JpaMySkillQueryRepository implements MySkillQueryRepository { if (skill.getOwnerId().equals(currentUserId)) { projection = skillLifecycleProjectionService.projectForOwnerSummary(skill); } + return toSummaryResponse( + skill, + namespacesById, + ownersById, + projection, + canSubmitPromotion(skill, projection.publishedVersion(), namespace) + ); + } + + private SkillSummaryResponse toSummaryResponse(Skill skill, + Map namespacesById, + Map ownersById, + SkillLifecycleProjectionService.Projection projection, + boolean canSubmitPromotion) { + Namespace namespace = namespacesById.get(skill.getNamespaceId()); SkillLifecycleProjectionService.VersionProjection headlineVersion = projection.headlineVersion(); SkillLifecycleProjectionService.VersionProjection publishedVersion = projection.publishedVersion(); SkillLifecycleProjectionService.VersionProjection ownerPreviewVersion = projection.ownerPreviewVersion(); @@ -97,7 +139,7 @@ public class JpaMySkillQueryRepository implements MySkillQueryRepository { ownersById.get(skill.getOwnerId()) != null ? ownersById.get(skill.getOwnerId()).getDisplayName() : null, - canSubmitPromotion(skill, publishedVersion, namespace), + canSubmitPromotion, toLifecycleVersion(headlineVersion), toLifecycleVersion(publishedVersion), toLifecycleVersion(ownerPreviewVersion), diff --git a/server/skillhub-app/src/main/java/com/iflytek/skillhub/repository/MySkillQueryRepository.java b/server/skillhub-app/src/main/java/com/iflytek/skillhub/repository/MySkillQueryRepository.java index bdafe81c..a45b6821 100644 --- a/server/skillhub-app/src/main/java/com/iflytek/skillhub/repository/MySkillQueryRepository.java +++ b/server/skillhub-app/src/main/java/com/iflytek/skillhub/repository/MySkillQueryRepository.java @@ -10,4 +10,6 @@ import java.util.List; */ public interface MySkillQueryRepository { List getSkillSummaries(List skills, String currentUserId); + + List getHiddenSkillSummaries(List skills); } diff --git a/server/skillhub-app/src/main/java/com/iflytek/skillhub/service/MySkillAppService.java b/server/skillhub-app/src/main/java/com/iflytek/skillhub/service/MySkillAppService.java index aff1d07f..7e96572e 100644 --- a/server/skillhub-app/src/main/java/com/iflytek/skillhub/service/MySkillAppService.java +++ b/server/skillhub-app/src/main/java/com/iflytek/skillhub/service/MySkillAppService.java @@ -93,7 +93,9 @@ public class MySkillAppService { skillPage = filterSkills(userId, page, size, normalizedFilter, keyword, namespace, platformRoles); } - List items = mySkillQueryRepository.getSkillSummaries(skillPage.getContent(), userId); + List items = normalizedFilter == MySkillFilter.HIDDEN + ? mySkillQueryRepository.getHiddenSkillSummaries(skillPage.getContent()) + : mySkillQueryRepository.getSkillSummaries(skillPage.getContent(), userId); return new PageResponse<>(items, skillPage.getTotalElements(), skillPage.getNumber(), skillPage.getSize()); } diff --git a/server/skillhub-app/src/test/java/com/iflytek/skillhub/repository/JpaMySkillQueryRepositoryTest.java b/server/skillhub-app/src/test/java/com/iflytek/skillhub/repository/JpaMySkillQueryRepositoryTest.java index 48e05639..c739f5b4 100644 --- a/server/skillhub-app/src/test/java/com/iflytek/skillhub/repository/JpaMySkillQueryRepositoryTest.java +++ b/server/skillhub-app/src/test/java/com/iflytek/skillhub/repository/JpaMySkillQueryRepositoryTest.java @@ -2,6 +2,9 @@ package com.iflytek.skillhub.repository; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; import com.iflytek.skillhub.domain.namespace.Namespace; import com.iflytek.skillhub.domain.namespace.NamespaceRepository; @@ -132,4 +135,35 @@ class JpaMySkillQueryRepositoryTest { assertThat(responses.get(0).publishedVersion()).isNotNull(); assertThat(responses.get(0).canSubmitPromotion()).isFalse(); } + + @Test + void getHiddenSkillSummaries_batchesPublishedVersionProjection() { + Skill first = new Skill(101L, "first-hidden", "owner-1", SkillVisibility.PUBLIC); + Skill second = new Skill(101L, "second-hidden", "owner-2", SkillVisibility.PUBLIC); + ReflectionTestUtils.setField(first, "id", 10L); + ReflectionTestUtils.setField(second, "id", 20L); + first.setLatestVersionId(110L); + second.setLatestVersionId(120L); + + SkillVersion firstVersion = new SkillVersion(10L, "1.0.0", "owner-1"); + SkillVersion secondVersion = new SkillVersion(20L, "2.0.0", "owner-2"); + firstVersion.setStatus(SkillVersionStatus.PUBLISHED); + secondVersion.setStatus(SkillVersionStatus.PUBLISHED); + ReflectionTestUtils.setField(firstVersion, "id", 110L); + ReflectionTestUtils.setField(secondVersion, "id", 120L); + + Namespace namespace = new Namespace("team-ai", "Team AI", "owner-1"); + ReflectionTestUtils.setField(namespace, "id", 101L); + given(namespaceRepository.findByIdIn(List.of(101L))).willReturn(List.of(namespace)); + given(skillVersionRepository.findByIdIn(List.of(110L, 120L))) + .willReturn(List.of(firstVersion, secondVersion)); + + var responses = repository.getHiddenSkillSummaries(List.of(first, second)); + + assertThat(responses).extracting("slug").containsExactly("first-hidden", "second-hidden"); + assertThat(responses).allMatch(response -> !response.canSubmitPromotion()); + verify(skillVersionRepository).findByIdIn(List.of(110L, 120L)); + verifyNoMoreInteractions(skillVersionRepository); + verifyNoInteractions(promotionRequestRepository); + } }