4 changed files with 489 additions and 0 deletions
@ -0,0 +1,95 @@ |
|||||
|
package com.mydreamjob.skill; |
||||
|
|
||||
|
import com.mydreamjob.skill.domain.SkillCategory; |
||||
|
import com.mydreamjob.skill.dto.SkillCloudItem; |
||||
|
import com.mydreamjob.skill.dto.SkillLearningPathItem; |
||||
|
import com.mydreamjob.skill.dto.SkillLearningPathResponse; |
||||
|
import com.mydreamjob.skill.dto.SkillMatchResponse; |
||||
|
import com.mydreamjob.skill.repository.SkillCategoryRepository; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import java.util.Locale; |
||||
|
import java.util.stream.IntStream; |
||||
|
|
||||
|
@Service |
||||
|
@Transactional(readOnly = true) |
||||
|
public class SkillLearningPathService { |
||||
|
|
||||
|
private final SkillMatchService skillMatchService; |
||||
|
private final SkillCategoryRepository skillCategoryRepository; |
||||
|
|
||||
|
public SkillLearningPathService(SkillMatchService skillMatchService, |
||||
|
SkillCategoryRepository skillCategoryRepository) { |
||||
|
this.skillMatchService = skillMatchService; |
||||
|
this.skillCategoryRepository = skillCategoryRepository; |
||||
|
} |
||||
|
|
||||
|
public SkillLearningPathResponse generate(Long studentUserId, |
||||
|
Long industryId, |
||||
|
Long occupationId, |
||||
|
Long categoryId) { |
||||
|
SkillMatchResponse matchResponse = skillMatchService.match( |
||||
|
studentUserId, industryId, occupationId, categoryId); |
||||
|
List<SkillCloudItem> missingSkills = matchResponse.missingSkills(); |
||||
|
List<SkillLearningPathItem> items = IntStream.range(0, missingSkills.size()) |
||||
|
.mapToObj(index -> toItem(missingSkills.get(index), index + 1, occupationId)) |
||||
|
.toList(); |
||||
|
|
||||
|
return new SkillLearningPathResponse(items.size(), items); |
||||
|
} |
||||
|
|
||||
|
private SkillLearningPathItem toItem(SkillCloudItem skill, int priority, Long occupationId) { |
||||
|
SuggestionTemplate template = resolveTemplate(skill, occupationId); |
||||
|
String skillName = skill.nameZh(); |
||||
|
return new SkillLearningPathItem( |
||||
|
priority, |
||||
|
skill.skillId(), |
||||
|
skillName, |
||||
|
skill.categoryId(), |
||||
|
skill.categoryName(), |
||||
|
template.render(skillName) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private SuggestionTemplate resolveTemplate(SkillCloudItem skill, Long occupationId) { |
||||
|
if (skill.categoryId() == null) { |
||||
|
return SuggestionTemplate.GENERAL; |
||||
|
} |
||||
|
|
||||
|
String templateCode = skillCategoryRepository |
||||
|
.findByIdAndOccupationId(skill.categoryId(), occupationId) |
||||
|
.map(SkillCategory::getSuggestionTemplateCode) |
||||
|
.orElse(null); |
||||
|
return SuggestionTemplate.fromCode(templateCode); |
||||
|
} |
||||
|
|
||||
|
private enum SuggestionTemplate { |
||||
|
PROGRAMMING_LANGUAGE("先掌握{skill}的基础语法和常见数据结构,再完成至少一个编码练习。"), |
||||
|
FRAMEWORK("先理解{skill}的核心概念与生命周期,再通过一个小型项目练习集成。"), |
||||
|
TOOL("先完成{skill}的安装与基础配置,再结合现有工程完成一次实际操作。"), |
||||
|
GENERAL("先了解{skill}的核心概念和常见应用场景,再通过一个简短实践巩固。"); |
||||
|
|
||||
|
private final String template; |
||||
|
|
||||
|
SuggestionTemplate(String template) { |
||||
|
this.template = template; |
||||
|
} |
||||
|
|
||||
|
String render(String skillName) { |
||||
|
return template.replace("{skill}", skillName); |
||||
|
} |
||||
|
|
||||
|
static SuggestionTemplate fromCode(String code) { |
||||
|
if (code == null || code.isBlank()) { |
||||
|
return GENERAL; |
||||
|
} |
||||
|
try { |
||||
|
return valueOf(code.trim().toUpperCase(Locale.ROOT)); |
||||
|
} catch (IllegalArgumentException exception) { |
||||
|
return GENERAL; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
package com.mydreamjob.skill.dto; |
||||
|
|
||||
|
public record SkillLearningPathItem( |
||||
|
int priority, |
||||
|
Long skillId, |
||||
|
String skillName, |
||||
|
Long categoryId, |
||||
|
String categoryName, |
||||
|
String suggestion |
||||
|
) { |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
package com.mydreamjob.skill.dto; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
public record SkillLearningPathResponse( |
||||
|
int total, |
||||
|
List<SkillLearningPathItem> items |
||||
|
) { |
||||
|
public SkillLearningPathResponse { |
||||
|
items = List.copyOf(items); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,371 @@ |
|||||
|
package com.mydreamjob.skill; |
||||
|
|
||||
|
import com.mydreamjob.skill.domain.SkillCategory; |
||||
|
import com.mydreamjob.skill.dto.SkillCloudItem; |
||||
|
import com.mydreamjob.skill.dto.SkillLearningPathItem; |
||||
|
import com.mydreamjob.skill.dto.SkillLearningPathResponse; |
||||
|
import com.mydreamjob.skill.dto.SkillMatchResponse; |
||||
|
import com.mydreamjob.skill.repository.SkillCategoryRepository; |
||||
|
import org.hibernate.boot.model.relational.Namespace; |
||||
|
import org.hibernate.boot.model.relational.Sequence; |
||||
|
import org.hibernate.mapping.Table; |
||||
|
import org.hibernate.tool.schema.spi.SchemaFilter; |
||||
|
import org.hibernate.tool.schema.spi.SchemaFilterProvider; |
||||
|
import org.junit.jupiter.api.Nested; |
||||
|
import org.junit.jupiter.api.Test; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.boot.test.context.SpringBootTest; |
||||
|
import org.springframework.boot.test.mock.mockito.MockBean; |
||||
|
import org.springframework.data.redis.core.RedisTemplate; |
||||
|
import org.springframework.test.context.ActiveProfiles; |
||||
|
import org.springframework.test.context.TestPropertySource; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
|
||||
|
import java.math.BigDecimal; |
||||
|
import java.util.List; |
||||
|
import java.util.Locale; |
||||
|
import java.util.Optional; |
||||
|
import java.util.Set; |
||||
|
|
||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
import static org.mockito.Mockito.mock; |
||||
|
import static org.mockito.Mockito.verify; |
||||
|
import static org.mockito.Mockito.verifyNoInteractions; |
||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions; |
||||
|
import static org.mockito.Mockito.when; |
||||
|
|
||||
|
@SpringBootTest |
||||
|
@TestPropertySource(properties = { |
||||
|
"spring.datasource.url=jdbc:h2:mem:integrationdb_skill_learning_path;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE", |
||||
|
"spring.jpa.hibernate.ddl-auto=validate", |
||||
|
"spring.jpa.properties.hibernate.hbm2ddl.schema_filter_provider=com.mydreamjob.skill.SkillLearningPathServiceTest$SkillLearningPathSchemaFilterProvider" |
||||
|
}) |
||||
|
@ActiveProfiles("integration-test") |
||||
|
@Transactional |
||||
|
class SkillLearningPathServiceTest { |
||||
|
|
||||
|
private static final Long USER_ID = 7001L; |
||||
|
private static final Long INDUSTRY_ID = 1L; |
||||
|
private static final Long OCCUPATION_ID = 1L; |
||||
|
private static final Long CATEGORY_ID = 101L; |
||||
|
|
||||
|
@Autowired |
||||
|
private SkillLearningPathService learningPathService; |
||||
|
|
||||
|
@Autowired |
||||
|
private SkillMatchService matchService; |
||||
|
|
||||
|
@MockBean |
||||
|
private RedisTemplate<String, Object> redisTemplate; |
||||
|
|
||||
|
@Test |
||||
|
void v36LearningPathReusesMatchMissingSkillsWithoutReordering() { |
||||
|
SkillMatchResponse matchResponse = matchService.match(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null); |
||||
|
SkillLearningPathResponse response = learningPathService.generate( |
||||
|
USER_ID, INDUSTRY_ID, OCCUPATION_ID, null); |
||||
|
|
||||
|
assertThat(matchResponse.missingSkills()).hasSize(10); |
||||
|
assertThat(response.total()).isEqualTo(matchResponse.missingSkills().size()); |
||||
|
assertThat(response.items()) |
||||
|
.extracting(SkillLearningPathItem::skillId) |
||||
|
.containsExactlyElementsOf(matchResponse.missingSkills().stream() |
||||
|
.map(SkillCloudItem::skillId) |
||||
|
.toList()); |
||||
|
assertThat(response.items()) |
||||
|
.extracting(SkillLearningPathItem::priority) |
||||
|
.containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); |
||||
|
assertThat(response.items()).allSatisfy(item -> { |
||||
|
assertThat(item.skillName()).isNotBlank(); |
||||
|
assertThat(item.categoryId()).isNotNull(); |
||||
|
assertThat(item.categoryName()).isNotBlank(); |
||||
|
assertThat(item.suggestion()).contains(item.skillName()); |
||||
|
assertNoForbiddenContent(item.suggestion()); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
@Nested |
||||
|
class TemplateAndOrderingTests { |
||||
|
|
||||
|
private final SkillMatchService matchService = mock(SkillMatchService.class); |
||||
|
private final SkillCategoryRepository categoryRepository = mock(SkillCategoryRepository.class); |
||||
|
private final SkillLearningPathService service = |
||||
|
new SkillLearningPathService(matchService, categoryRepository); |
||||
|
|
||||
|
@Test |
||||
|
void usesOnlyMissingSkillsAndPreservesMissingOrderWithContiguousPriorities() { |
||||
|
SkillCloudItem matched = skill(11L, "Matched", "Matched", CATEGORY_ID, |
||||
|
"编程语言", new BigDecimal("9.00")); |
||||
|
List<SkillCloudItem> missing = List.of( |
||||
|
skill(31L, "First", "First", 101L, "编程语言", new BigDecimal("1.00")), |
||||
|
skill(32L, "Second", "Second", 102L, "框架", new BigDecimal("10.00")), |
||||
|
skill(33L, "Third", "Third", 103L, "工具", new BigDecimal("5.00")) |
||||
|
); |
||||
|
when(matchService.match(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null)) |
||||
|
.thenReturn(matchResponse(List.of(matched), missing)); |
||||
|
stubCategory(101L, "PROGRAMMING_LANGUAGE"); |
||||
|
stubCategory(102L, "FRAMEWORK"); |
||||
|
stubCategory(103L, "TOOL"); |
||||
|
|
||||
|
SkillLearningPathResponse response = service.generate(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null); |
||||
|
|
||||
|
assertThat(response.total()).isEqualTo(3); |
||||
|
assertThat(response.items()) |
||||
|
.extracting(SkillLearningPathItem::skillId) |
||||
|
.containsExactly(31L, 32L, 33L); |
||||
|
assertThat(response.items()) |
||||
|
.extracting(SkillLearningPathItem::priority) |
||||
|
.containsExactly(1, 2, 3); |
||||
|
assertThat(response.items()) |
||||
|
.extracting(SkillLearningPathItem::skillName) |
||||
|
.containsExactly("First", "Second", "Third"); |
||||
|
assertThat(response.items()) |
||||
|
.noneMatch(item -> item.skillId().equals(matched.skillId())); |
||||
|
verify(matchService).match(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null); |
||||
|
verifyNoMoreInteractions(matchService); |
||||
|
verify(categoryRepository).findByIdAndOccupationId(101L, OCCUPATION_ID); |
||||
|
verify(categoryRepository).findByIdAndOccupationId(102L, OCCUPATION_ID); |
||||
|
verify(categoryRepository).findByIdAndOccupationId(103L, OCCUPATION_ID); |
||||
|
verifyNoMoreInteractions(categoryRepository); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void generatesProgrammingLanguageSuggestion() { |
||||
|
SkillCloudItem missing = skill(41L, "Java", "Java", CATEGORY_ID, |
||||
|
"编程语言", BigDecimal.ONE); |
||||
|
when(matchService.match(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null)) |
||||
|
.thenReturn(matchResponse(List.of(), List.of(missing))); |
||||
|
stubCategory(CATEGORY_ID, "PROGRAMMING_LANGUAGE"); |
||||
|
|
||||
|
SkillLearningPathItem item = service.generate(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null) |
||||
|
.items().get(0); |
||||
|
|
||||
|
assertThat(item.suggestion()).isEqualTo( |
||||
|
"先掌握Java的基础语法和常见数据结构,再完成至少一个编码练习。"); |
||||
|
assertNoForbiddenContent(item.suggestion()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void generatesFrameworkSuggestion() { |
||||
|
SkillCloudItem missing = skill(42L, "Spring Boot", "Spring Boot", CATEGORY_ID, |
||||
|
"框架", BigDecimal.ONE); |
||||
|
when(matchService.match(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null)) |
||||
|
.thenReturn(matchResponse(List.of(), List.of(missing))); |
||||
|
stubCategory(CATEGORY_ID, "FRAMEWORK"); |
||||
|
|
||||
|
SkillLearningPathItem item = service.generate(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null) |
||||
|
.items().get(0); |
||||
|
|
||||
|
assertThat(item.suggestion()).isEqualTo( |
||||
|
"先理解Spring Boot的核心概念与生命周期,再通过一个小型项目练习集成。"); |
||||
|
assertNoForbiddenContent(item.suggestion()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void generatesToolSuggestion() { |
||||
|
SkillCloudItem missing = skill(43L, "Docker", "Docker", CATEGORY_ID, |
||||
|
"工具", BigDecimal.ONE); |
||||
|
when(matchService.match(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null)) |
||||
|
.thenReturn(matchResponse(List.of(), List.of(missing))); |
||||
|
stubCategory(CATEGORY_ID, "TOOL"); |
||||
|
|
||||
|
SkillLearningPathItem item = service.generate(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null) |
||||
|
.items().get(0); |
||||
|
|
||||
|
assertThat(item.suggestion()).isEqualTo( |
||||
|
"先完成Docker的安装与基础配置,再结合现有工程完成一次实际操作。"); |
||||
|
assertNoForbiddenContent(item.suggestion()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void generatesGeneralSuggestion() { |
||||
|
SkillCloudItem missing = skill(44L, "沟通能力", "Communication", CATEGORY_ID, |
||||
|
"通用能力", BigDecimal.ONE); |
||||
|
when(matchService.match(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null)) |
||||
|
.thenReturn(matchResponse(List.of(), List.of(missing))); |
||||
|
stubCategory(CATEGORY_ID, "GENERAL"); |
||||
|
|
||||
|
SkillLearningPathItem item = service.generate(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null) |
||||
|
.items().get(0); |
||||
|
|
||||
|
assertThat(item.suggestion()).isEqualTo( |
||||
|
"先了解沟通能力的核心概念和常见应用场景,再通过一个简短实践巩固。"); |
||||
|
assertNoForbiddenContent(item.suggestion()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void fallsBackToGeneralForUnknownNullAndMissingTemplateCodes() { |
||||
|
List<SkillCloudItem> missing = List.of( |
||||
|
skill(51L, "Unknown", "Unknown", 101L, "分类 A", BigDecimal.ONE), |
||||
|
skill(52L, "NullCode", "NullCode", 102L, "分类 B", BigDecimal.ONE), |
||||
|
skill(53L, "MissingCategory", "MissingCategory", 103L, "分类 C", BigDecimal.ONE) |
||||
|
); |
||||
|
when(matchService.match(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null)) |
||||
|
.thenReturn(matchResponse(List.of(), missing)); |
||||
|
when(categoryRepository.findByIdAndOccupationId(101L, OCCUPATION_ID)) |
||||
|
.thenReturn(Optional.of(category(101L, "UNKNOWN_TEMPLATE"))); |
||||
|
when(categoryRepository.findByIdAndOccupationId(102L, OCCUPATION_ID)) |
||||
|
.thenReturn(Optional.of(category(102L, null))); |
||||
|
when(categoryRepository.findByIdAndOccupationId(103L, OCCUPATION_ID)) |
||||
|
.thenReturn(Optional.empty()); |
||||
|
|
||||
|
SkillLearningPathResponse response = service.generate(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null); |
||||
|
|
||||
|
assertThat(response.items()) |
||||
|
.extracting(SkillLearningPathItem::suggestion) |
||||
|
.containsExactly( |
||||
|
"先了解Unknown的核心概念和常见应用场景,再通过一个简短实践巩固。", |
||||
|
"先了解NullCode的核心概念和常见应用场景,再通过一个简短实践巩固。", |
||||
|
"先了解MissingCategory的核心概念和常见应用场景,再通过一个简短实践巩固。" |
||||
|
); |
||||
|
response.items().forEach(item -> assertNoForbiddenContent(item.suggestion())); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void returnsEmptyPathAndDoesNotReadCategoriesWhenThereAreNoGaps() { |
||||
|
SkillCloudItem matched = skill(61L, "Java", "Java", CATEGORY_ID, |
||||
|
"编程语言", BigDecimal.ONE); |
||||
|
when(matchService.match(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null)) |
||||
|
.thenReturn(matchResponse(List.of(matched), List.of())); |
||||
|
|
||||
|
SkillLearningPathResponse response = service.generate(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null); |
||||
|
|
||||
|
assertThat(response.total()).isZero(); |
||||
|
assertThat(response.items()).isEmpty(); |
||||
|
verifyNoInteractions(categoryRepository); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void repeatedCallsProduceIdenticalOrderPrioritiesAndText() { |
||||
|
List<SkillCloudItem> missing = List.of( |
||||
|
skill(71L, "Java", "Java", 101L, "编程语言", BigDecimal.ONE), |
||||
|
skill(72L, "Docker", "Docker", 102L, "工具", BigDecimal.ONE) |
||||
|
); |
||||
|
when(matchService.match(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null)) |
||||
|
.thenReturn(matchResponse(List.of(), missing)); |
||||
|
stubCategory(101L, "PROGRAMMING_LANGUAGE"); |
||||
|
stubCategory(102L, "TOOL"); |
||||
|
|
||||
|
SkillLearningPathResponse first = service.generate(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null); |
||||
|
SkillLearningPathResponse second = service.generate(USER_ID, INDUSTRY_ID, OCCUPATION_ID, null); |
||||
|
|
||||
|
assertThat(second).isEqualTo(first); |
||||
|
assertThat(second.items()) |
||||
|
.extracting(SkillLearningPathItem::skillId) |
||||
|
.containsExactly(71L, 72L); |
||||
|
assertThat(second.items()) |
||||
|
.extracting(SkillLearningPathItem::priority) |
||||
|
.containsExactly(1, 2); |
||||
|
assertThat(second.items()) |
||||
|
.extracting(SkillLearningPathItem::suggestion) |
||||
|
.containsExactly( |
||||
|
"先掌握Java的基础语法和常见数据结构,再完成至少一个编码练习。", |
||||
|
"先完成Docker的安装与基础配置,再结合现有工程完成一次实际操作。" |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private void stubCategory(Long categoryId, String templateCode) { |
||||
|
when(categoryRepository.findByIdAndOccupationId(categoryId, OCCUPATION_ID)) |
||||
|
.thenReturn(Optional.of(category(categoryId, templateCode))); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static SkillMatchResponse matchResponse(List<SkillCloudItem> matched, |
||||
|
List<SkillCloudItem> missing) { |
||||
|
int total = matched.size() + missing.size(); |
||||
|
int score = total == 0 ? 0 : (int) Math.round(matched.size() * 100.0 / total); |
||||
|
return new SkillMatchResponse(score, matched.size(), total, matched, missing); |
||||
|
} |
||||
|
|
||||
|
private static SkillCloudItem skill(Long skillId, |
||||
|
String nameZh, |
||||
|
String nameEn, |
||||
|
Long categoryId, |
||||
|
String categoryName, |
||||
|
BigDecimal heat) { |
||||
|
return new SkillCloudItem( |
||||
|
skillId.intValue(), |
||||
|
skillId, |
||||
|
"SKILL_" + skillId, |
||||
|
nameZh, |
||||
|
nameEn, |
||||
|
"ESCO", |
||||
|
"source-" + skillId, |
||||
|
categoryId, |
||||
|
categoryName, |
||||
|
heat, |
||||
|
"15-1254.00", |
||||
|
"2.E.7.h", |
||||
|
false |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private static SkillCategory category(Long categoryId, String templateCode) { |
||||
|
return SkillCategory.builder() |
||||
|
.id(categoryId) |
||||
|
.occupationId(OCCUPATION_ID) |
||||
|
.code("CATEGORY_" + categoryId) |
||||
|
.nameZh("分类 " + categoryId) |
||||
|
.suggestionTemplateCode(templateCode) |
||||
|
.sortOrder(categoryId.intValue()) |
||||
|
.build(); |
||||
|
} |
||||
|
|
||||
|
private static void assertNoForbiddenContent(String suggestion) { |
||||
|
assertThat(suggestion) |
||||
|
.doesNotContain("http://", "https://", "课程", "讲师", "价格", "时长", |
||||
|
"分钟", "小时", "完成度", "AI"); |
||||
|
} |
||||
|
|
||||
|
public static class SkillLearningPathSchemaFilterProvider implements SchemaFilterProvider { |
||||
|
|
||||
|
private static final Set<String> VALIDATED_TABLES = Set.of( |
||||
|
"skill_source_versions", |
||||
|
"skill_industries", |
||||
|
"skill_occupations", |
||||
|
"skill_categories", |
||||
|
"skills", |
||||
|
"skill_aliases", |
||||
|
"occupation_skills" |
||||
|
); |
||||
|
|
||||
|
@Override |
||||
|
public SchemaFilter getCreateFilter() { |
||||
|
return SchemaFilter.ALL; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public SchemaFilter getDropFilter() { |
||||
|
return SchemaFilter.ALL; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public SchemaFilter getTruncatorFilter() { |
||||
|
return SchemaFilter.ALL; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public SchemaFilter getMigrateFilter() { |
||||
|
return SchemaFilter.ALL; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public SchemaFilter getValidateFilter() { |
||||
|
return new SchemaFilter() { |
||||
|
@Override |
||||
|
public boolean includeNamespace(Namespace namespace) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean includeTable(Table table) { |
||||
|
return VALIDATED_TABLES.contains(table.getName().toLowerCase(Locale.ROOT)); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean includeSequence(Sequence sequence) { |
||||
|
return false; |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue