perf(governance): batch hidden skill summaries

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
This commit is contained in:
XiaoSeS 2026-09-08 11:32:20 +08:00
parent 4efd6c6366
commit 702a1cc34f
4 changed files with 82 additions and 2 deletions

View file

@ -63,6 +63,33 @@ public class JpaMySkillQueryRepository implements MySkillQueryRepository {
.toList();
}
@Override
public List<SkillSummaryResponse> getHiddenSkillSummaries(List<Skill> skills) {
if (skills.isEmpty()) {
return List.of();
}
Map<Long, Namespace> namespacesById = namespaceRepository.findByIdIn(
skills.stream().map(Skill::getNamespaceId).distinct().toList())
.stream()
.collect(Collectors.toMap(Namespace::getId, Function.identity()));
Map<String, UserAccount> ownersById = userAccountRepository == null
? Map.of()
: userAccountRepository.findByIdIn(skills.stream().map(Skill::getOwnerId).distinct().toList())
.stream().collect(Collectors.toMap(UserAccount::getId, Function.identity()));
Map<Long, SkillLifecycleProjectionService.Projection> 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<Long, Namespace> 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<Long, Namespace> namespacesById,
Map<String, UserAccount> 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),

View file

@ -10,4 +10,6 @@ import java.util.List;
*/
public interface MySkillQueryRepository {
List<SkillSummaryResponse> getSkillSummaries(List<Skill> skills, String currentUserId);
List<SkillSummaryResponse> getHiddenSkillSummaries(List<Skill> skills);
}

View file

@ -93,7 +93,9 @@ public class MySkillAppService {
skillPage = filterSkills(userId, page, size, normalizedFilter, keyword, namespace, platformRoles);
}
List<SkillSummaryResponse> items = mySkillQueryRepository.getSkillSummaries(skillPage.getContent(), userId);
List<SkillSummaryResponse> items = normalizedFilter == MySkillFilter.HIDDEN
? mySkillQueryRepository.getHiddenSkillSummaries(skillPage.getContent())
: mySkillQueryRepository.getSkillSummaries(skillPage.getContent(), userId);
return new PageResponse<>(items, skillPage.getTotalElements(), skillPage.getNumber(), skillPage.getSize());
}

View file

@ -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);
}
}