You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

160 lines
6.7 KiB

package com.mydreamjob.skill;
import com.mydreamjob.common.exception.BusinessException;
import com.mydreamjob.common.exception.ErrorCode;
import com.mydreamjob.skill.domain.SkillCategory;
import com.mydreamjob.skill.domain.SkillIndustry;
import com.mydreamjob.skill.domain.SkillOccupation;
import com.mydreamjob.skill.dto.SkillCloudItem;
import com.mydreamjob.skill.dto.SkillCloudNode;
import com.mydreamjob.skill.dto.SkillCloudResponse;
import com.mydreamjob.skill.dto.SkillCloudSkillProjection;
import com.mydreamjob.skill.repository.OccupationSkillRepository;
import com.mydreamjob.skill.repository.SkillCategoryRepository;
import com.mydreamjob.skill.repository.SkillIndustryRepository;
import com.mydreamjob.skill.repository.SkillOccupationRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.stream.IntStream;
@Service
@Transactional(readOnly = true)
public class SkillCloudQueryService {
private static final Comparator<SkillCloudSkillProjection> SKILL_ORDER = (left, right) -> {
int heatComparison = compareHeat(left.importance(), right.importance());
if (heatComparison != 0) {
return heatComparison;
}
int nameComparison = compareNullable(left.nameZh(), right.nameZh());
if (nameComparison != 0) {
return nameComparison;
}
return compareNullable(left.skillId(), right.skillId());
};
private final SkillIndustryRepository industryRepository;
private final SkillOccupationRepository occupationRepository;
private final SkillCategoryRepository categoryRepository;
private final OccupationSkillRepository occupationSkillRepository;
public SkillCloudQueryService(SkillIndustryRepository industryRepository,
SkillOccupationRepository occupationRepository,
SkillCategoryRepository categoryRepository,
OccupationSkillRepository occupationSkillRepository) {
this.industryRepository = industryRepository;
this.occupationRepository = occupationRepository;
this.categoryRepository = categoryRepository;
this.occupationSkillRepository = occupationSkillRepository;
}
public SkillCloudResponse query(Long industryId, Long occupationId, Long categoryId) {
long validatedIndustryId = requirePositive(industryId, "industryId");
long validatedOccupationId = requirePositive(occupationId, "occupationId");
Long validatedCategoryId = categoryId == null ? null : requirePositive(categoryId, "categoryId");
SkillIndustry industry = industryRepository.findById(validatedIndustryId)
.orElseThrow(() -> badRequest("industry not found: industryId=" + validatedIndustryId));
SkillOccupation occupation = occupationRepository.findById(validatedOccupationId)
.orElseThrow(() -> badRequest("occupation not found: occupationId=" + validatedOccupationId));
if (!occupation.getIndustryId().equals(validatedIndustryId)) {
throw badRequest("occupation does not belong to industry: occupationId="
+ validatedOccupationId + ", industryId=" + validatedIndustryId);
}
SkillCategory category = null;
if (validatedCategoryId != null) {
category = categoryRepository.findById(validatedCategoryId)
.orElseThrow(() -> badRequest("category not found: categoryId=" + validatedCategoryId));
if (!category.getOccupationId().equals(validatedOccupationId)) {
throw badRequest("category does not belong to occupation: categoryId="
+ validatedCategoryId + ", occupationId=" + validatedOccupationId);
}
}
List<SkillCloudSkillProjection> projections = validatedCategoryId == null
? occupationSkillRepository.findSkillProjectionsByOccupationId(validatedOccupationId)
: occupationSkillRepository.findSkillProjectionsByOccupationIdAndCategoryId(
validatedOccupationId, validatedCategoryId);
List<SkillCloudSkillProjection> sortedProjections = projections.stream()
.sorted(SKILL_ORDER)
.toList();
List<SkillCloudItem> items = IntStream.range(0, sortedProjections.size())
.mapToObj(index -> toItem(sortedProjections.get(index), index + 1))
.toList();
return new SkillCloudResponse(
toNode(industry.getId(), industry.getCode(), industry.getNameZh()),
toNode(occupation.getId(), occupation.getCode(), occupation.getNameZh()),
category == null ? null : toNode(category.getId(), category.getCode(), category.getNameZh()),
items.size(),
items
);
}
private SkillCloudItem toItem(SkillCloudSkillProjection projection, int rank) {
return new SkillCloudItem(
rank,
projection.skillId(),
projection.skillCode(),
projection.nameZh(),
projection.nameEn(),
projection.sourceType(),
projection.sourceCode(),
projection.categoryId(),
projection.categoryName(),
projection.importance(),
projection.importanceSourceCode(),
projection.importanceElementId(),
projection.importanceIsProxy()
);
}
private static int compareHeat(BigDecimal left, BigDecimal right) {
if (left == null && right == null) {
return 0;
}
if (left == null) {
return 1;
}
if (right == null) {
return -1;
}
return right.compareTo(left);
}
private static <T extends Comparable<? super T>> int compareNullable(T left, T right) {
if (left == null && right == null) {
return 0;
}
if (left == null) {
return 1;
}
if (right == null) {
return -1;
}
return left.compareTo(right);
}
private static SkillCloudNode toNode(Long id, String code, String name) {
return new SkillCloudNode(id, code, name);
}
private static long requirePositive(Long value, String parameterName) {
if (value == null || value <= 0) {
throw badRequest(parameterName + " must be a positive integer");
}
return value;
}
private static BusinessException badRequest(String detail) {
return new BusinessException(ErrorCode.BAD_REQUEST, detail);
}
}