From 20421465544eb005034a1d55a21888fde2fd8bfd Mon Sep 17 00:00:00 2001 From: ElenaShm Date: Thu, 22 Aug 2024 13:03:48 +0300 Subject: [PATCH 1/4] feature/MODELINKS-248 Extend-authorities --- NEWS.md | 1 + descriptors/ModuleDescriptor-template.json | 2 +- .../controller/converter/AuthorityMapper.java | 2 + .../converter/AuthorityUtilityMapper.java | 50 +++++++ .../entlinks/domain/entity/AuthorityBase.java | 8 + .../domain/entity/AuthorityConstants.java | 12 ++ .../db/changelog/changelog-master.xml | 2 + ...additional-fields-to-authority-archive.xml | 19 +++ .../add-additional-fields-to-authority.xml | 19 +++ .../authority-storage/authorityDto.yaml | 30 ++++ .../converter/AuthorityUtilityMapperTest.java | 138 ++++++++++++++++++ .../authority/AuthorityServiceTest.java | 12 ++ 12 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/db/changelog/changes/v3.1/add-additional-fields-to-authority-archive.xml create mode 100644 src/main/resources/db/changelog/changes/v3.1/add-additional-fields-to-authority.xml diff --git a/NEWS.md b/NEWS.md index dbfca9b3..e7284d80 100644 --- a/NEWS.md +++ b/NEWS.md @@ -66,6 +66,7 @@ * Fix authority record update and `updatedByUserId` field assignment ([MODELINKS-219](https://issues.folio.org/browse/MODELINKS-219)) * Fix saving of Authority file with empty Base URL when another Authority file with empty Base URL already exists ([MODELINKS-216](https://issues.folio.org/browse/MODELINKS-216)) * Fix handling of authority heading type change update event ([MODELINKS-242](https://issues.folio.org/browse/MODELINKS-242)) +* Extend authorities with additional fields for Advanced References Classification ([MODELINKS-248](https://issues.folio.org/browse/MODELINKS-248)) ### Tech Dept * Create custom Mockito verifies for Hibernate entities ([MODELINKS-209](https://issues.folio.org/browse/MODELINKS-209)) diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json index c20e2561..b03ee397 100644 --- a/descriptors/ModuleDescriptor-template.json +++ b/descriptors/ModuleDescriptor-template.json @@ -167,7 +167,7 @@ }, { "id": "authority-storage", - "version": "2.1", + "version": "2.2", "handlers": [ { "methods": [ diff --git a/src/main/java/org/folio/entlinks/controller/converter/AuthorityMapper.java b/src/main/java/org/folio/entlinks/controller/converter/AuthorityMapper.java index 5c4c49f5..21aeb963 100644 --- a/src/main/java/org/folio/entlinks/controller/converter/AuthorityMapper.java +++ b/src/main/java/org/folio/entlinks/controller/converter/AuthorityMapper.java @@ -93,6 +93,7 @@ default void authorityPostProcess(AuthorityDto source, @MappingTarget AuthorityB AuthorityUtilityMapper.extractAuthorityHeading(source, target); AuthorityUtilityMapper.extractAuthoritySftHeadings(source, target); AuthorityUtilityMapper.extractAuthoritySaftHeadings(source, target); + AuthorityUtilityMapper.extractAuthorityAdditionalHeadings(source, target); } @AfterMapping @@ -100,6 +101,7 @@ default void authorityDtoPostProcessing(AuthorityBase source, @MappingTarget Aut AuthorityUtilityMapper.extractAuthorityDtoHeadingValue(source, target); AuthorityUtilityMapper.extractAuthorityDtoSftHeadings(source, target); AuthorityUtilityMapper.extractAuthorityDtoSaftHeadings(source, target); + AuthorityUtilityMapper.extractAuthorityDtoAdditionalHeadings(source, target); } default OffsetDateTime map(Timestamp timestamp) { diff --git a/src/main/java/org/folio/entlinks/controller/converter/AuthorityUtilityMapper.java b/src/main/java/org/folio/entlinks/controller/converter/AuthorityUtilityMapper.java index 3addfb2c..7a3522bd 100644 --- a/src/main/java/org/folio/entlinks/controller/converter/AuthorityUtilityMapper.java +++ b/src/main/java/org/folio/entlinks/controller/converter/AuthorityUtilityMapper.java @@ -2,14 +2,20 @@ import static org.apache.commons.collections4.CollectionUtils.isEmpty; import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; +import static org.folio.entlinks.domain.entity.AuthorityConstants.BROADER_TERM; import static org.folio.entlinks.domain.entity.AuthorityConstants.CORPORATE_NAME_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.CORPORATE_NAME_TITLE_HEADING; +import static org.folio.entlinks.domain.entity.AuthorityConstants.EARLIER_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.GENRE_TERM_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.GEOGRAPHIC_NAME_HEADING; +import static org.folio.entlinks.domain.entity.AuthorityConstants.LATER_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.MEETING_NAME_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.MEETING_NAME_TITLE_HEADING; +import static org.folio.entlinks.domain.entity.AuthorityConstants.NARROWER_TERM; import static org.folio.entlinks.domain.entity.AuthorityConstants.PERSONAL_NAME_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.PERSONAL_NAME_TITLE_HEADING; +import static org.folio.entlinks.domain.entity.AuthorityConstants.SAFT_TERM; +import static org.folio.entlinks.domain.entity.AuthorityConstants.SFT_TERM; import static org.folio.entlinks.domain.entity.AuthorityConstants.TOPICAL_TERM_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.UNIFORM_TITLE_HEADING; @@ -148,6 +154,29 @@ public static void extractAuthoritySaftHeadings(AuthorityDto source, AuthorityBa target.setSaftHeadings(saftHeadings); } + public static void extractAuthorityAdditionalHeadings(AuthorityDto source, AuthorityBase target) { + List additionalHeadings = new ArrayList<>(); + if (isNotEmpty(source.getBroaderTerm())) { + additionalHeadings.addAll(asSftHeadings(source.getBroaderTerm(), BROADER_TERM)); + } + if (isNotEmpty(source.getNarrowerTerm())) { + additionalHeadings.addAll(asSftHeadings(source.getNarrowerTerm(), NARROWER_TERM)); + } + if (isNotEmpty(source.getEarlierHeading())) { + additionalHeadings.addAll(asSftHeadings(source.getEarlierHeading(), EARLIER_HEADING)); + } + if (isNotEmpty(source.getLaterHeading())) { + additionalHeadings.addAll(asSftHeadings(source.getLaterHeading(), LATER_HEADING)); + } + if (isNotEmpty(source.getSftTerm())) { + additionalHeadings.addAll(asSftHeadings(source.getSftTerm(), SFT_TERM)); + } + if (isNotEmpty(source.getSaftTerm())) { + additionalHeadings.addAll(asSftHeadings(source.getSaftTerm(), SAFT_TERM)); + } + target.setAdditionalHeadings(additionalHeadings); + } + public static void extractAuthorityDtoHeadingValue(AuthorityBase source, AuthorityDto target) { if (source.getHeadingType() == null || source.getHeading() == null) { return; @@ -181,6 +210,12 @@ public static void extractAuthorityDtoSaftHeadings(AuthorityBase source, Authori source.getSaftHeadings().forEach(headingRef -> extractAuthorityDtoSaftHeading(headingRef, target)); } + public static void extractAuthorityDtoAdditionalHeadings(AuthorityBase source, AuthorityDto target) { + if (isNotEmpty(source.getAdditionalHeadings())) { + source.getAdditionalHeadings().forEach(headingRef -> extractAuthorityDtoAdditionalHeading(headingRef, target)); + } + } + private void extractAuthorityDtoSftHeading(HeadingRef headingRef, AuthorityDto target) { if (headingRef == null || headingRef.getHeadingType() == null) { return; @@ -224,4 +259,19 @@ private static List asSftHeadings(List headingValues, String .map(headingValue -> new HeadingRef(headingType, headingValue)) .toList(); } + + private void extractAuthorityDtoAdditionalHeading(HeadingRef headingRef, AuthorityDto target) { + if (headingRef == null || headingRef.getHeadingType() == null) { + return; + } + switch (headingRef.getHeadingType()) { + case BROADER_TERM -> target.addBroaderTermItem(headingRef.getHeading()); + case NARROWER_TERM -> target.addNarrowerTermItem(headingRef.getHeading()); + case EARLIER_HEADING -> target.addEarlierHeadingItem(headingRef.getHeading()); + case LATER_HEADING -> target.addLaterHeadingItem(headingRef.getHeading()); + case SAFT_TERM -> target.addSaftTermItem(headingRef.getHeading()); + case SFT_TERM -> target.addSftTermItem(headingRef.getHeading()); + default -> log.warn("Invalid additional heading type - {} cannot be mapped", headingRef.getHeadingType()); + } + } } diff --git a/src/main/java/org/folio/entlinks/domain/entity/AuthorityBase.java b/src/main/java/org/folio/entlinks/domain/entity/AuthorityBase.java index dee2764e..2d7b0a9f 100644 --- a/src/main/java/org/folio/entlinks/domain/entity/AuthorityBase.java +++ b/src/main/java/org/folio/entlinks/domain/entity/AuthorityBase.java @@ -42,6 +42,7 @@ public class AuthorityBase extends MetadataEntity { public static final String DELETED_COLUMN = "deleted"; private static final String CONSORTIUM_SOURCE_PREFIX = "CONSORTIUM-"; + private static final String ADDITIONAL_HEADINGS_COLUMN = "additional_headings"; @Id @Column(name = ID_COLUMN, nullable = false) @@ -90,6 +91,10 @@ public class AuthorityBase extends MetadataEntity { @Column(name = DELETED_COLUMN) private boolean deleted = false; + @Column(name = ADDITIONAL_HEADINGS_COLUMN) + @JdbcTypeCode(SqlTypes.JSON) + private List additionalHeadings; + public AuthorityBase(AuthorityBase other) { super(other); this.id = other.id; @@ -116,6 +121,9 @@ public AuthorityBase(AuthorityBase other) { .map(AuthorityNote::new) .toList(); this.deleted = other.deleted; + this.additionalHeadings = Optional.ofNullable(other.getSaftHeadings()).orElse(List.of()).stream() + .map(HeadingRef::new) + .toList(); } public void makeAsConsortiumShadowCopy() { diff --git a/src/main/java/org/folio/entlinks/domain/entity/AuthorityConstants.java b/src/main/java/org/folio/entlinks/domain/entity/AuthorityConstants.java index 337529a3..feb80395 100644 --- a/src/main/java/org/folio/entlinks/domain/entity/AuthorityConstants.java +++ b/src/main/java/org/folio/entlinks/domain/entity/AuthorityConstants.java @@ -24,4 +24,16 @@ public class AuthorityConstants { public static final String GEOGRAPHIC_NAME_HEADING = "geographicName"; public static final String GENRE_TERM_HEADING = "genreTerm"; + + public static final String BROADER_TERM = "broaderTerm"; + + public static final String NARROWER_TERM = "narrowerTerm"; + + public static final String EARLIER_HEADING = "earlierHeading"; + + public static final String LATER_HEADING = "laterHeading"; + + public static final String SFT_TERM = "sftTerm"; + + public static final String SAFT_TERM = "saftTerm"; } diff --git a/src/main/resources/db/changelog/changelog-master.xml b/src/main/resources/db/changelog/changelog-master.xml index 906c7bf5..a4417124 100644 --- a/src/main/resources/db/changelog/changelog-master.xml +++ b/src/main/resources/db/changelog/changelog-master.xml @@ -23,4 +23,6 @@ + + diff --git a/src/main/resources/db/changelog/changes/v3.1/add-additional-fields-to-authority-archive.xml b/src/main/resources/db/changelog/changes/v3.1/add-additional-fields-to-authority-archive.xml new file mode 100644 index 00000000..404ed022 --- /dev/null +++ b/src/main/resources/db/changelog/changes/v3.1/add-additional-fields-to-authority-archive.xml @@ -0,0 +1,19 @@ + + + + + + + + + Add new jsonb fields to authority_archive table + + + + + + + diff --git a/src/main/resources/db/changelog/changes/v3.1/add-additional-fields-to-authority.xml b/src/main/resources/db/changelog/changes/v3.1/add-additional-fields-to-authority.xml new file mode 100644 index 00000000..80db8253 --- /dev/null +++ b/src/main/resources/db/changelog/changes/v3.1/add-additional-fields-to-authority.xml @@ -0,0 +1,19 @@ + + + + + + + + + Add new jsonb fields to authority table + + + + + + + diff --git a/src/main/resources/swagger.api/schemas/authority-storage/authorityDto.yaml b/src/main/resources/swagger.api/schemas/authority-storage/authorityDto.yaml index c3c3a6ee..aeb4a103 100644 --- a/src/main/resources/swagger.api/schemas/authority-storage/authorityDto.yaml +++ b/src/main/resources/swagger.api/schemas/authority-storage/authorityDto.yaml @@ -163,6 +163,36 @@ properties: description: Authority Natural ID metadata: $ref: '../common/metadata.yaml' + broaderTerm: + type: array + description: Terms that represents broader, more general concepts related to the authority record + items: + type: string + narrowerTerm: + type: array + description: Terms that represents narrower, more specific concepts derived from the authority record + items: + type: string + earlierHeading: + type: array + description: Heading that was previously used to represent the concept or entity described by the authority record. This field is used to track the evolution of terms or headings over time, facilitating the linking of historical and current data. + items: + type: string + laterHeading: + type: array + description: Heading that replaced the current heading used in the authority record. This field helps in maintaining the continuity of catalog records by linking past headings to their more current versions. + items: + type: string + sftTerm: + type: array + description: See from tracing term + items: + type: string + saftTerm: + type: array + description: See also from tracing term + items: + type: string required: - source - naturalId diff --git a/src/test/java/org/folio/entlinks/controller/converter/AuthorityUtilityMapperTest.java b/src/test/java/org/folio/entlinks/controller/converter/AuthorityUtilityMapperTest.java index fd7d5ab4..badc1409 100644 --- a/src/test/java/org/folio/entlinks/controller/converter/AuthorityUtilityMapperTest.java +++ b/src/test/java/org/folio/entlinks/controller/converter/AuthorityUtilityMapperTest.java @@ -2,17 +2,25 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Fail.fail; +import static org.folio.entlinks.domain.entity.AuthorityConstants.BROADER_TERM; import static org.folio.entlinks.domain.entity.AuthorityConstants.CORPORATE_NAME_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.CORPORATE_NAME_TITLE_HEADING; +import static org.folio.entlinks.domain.entity.AuthorityConstants.EARLIER_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.GENRE_TERM_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.GEOGRAPHIC_NAME_HEADING; +import static org.folio.entlinks.domain.entity.AuthorityConstants.LATER_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.MEETING_NAME_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.MEETING_NAME_TITLE_HEADING; +import static org.folio.entlinks.domain.entity.AuthorityConstants.NARROWER_TERM; import static org.folio.entlinks.domain.entity.AuthorityConstants.PERSONAL_NAME_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.PERSONAL_NAME_TITLE_HEADING; +import static org.folio.entlinks.domain.entity.AuthorityConstants.SAFT_TERM; +import static org.folio.entlinks.domain.entity.AuthorityConstants.SFT_TERM; import static org.folio.entlinks.domain.entity.AuthorityConstants.TOPICAL_TERM_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.UNIFORM_TITLE_HEADING; import static org.folio.support.base.TestConstants.TEST_STRING; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.params.provider.Arguments.arguments; @@ -24,6 +32,7 @@ import org.folio.entlinks.domain.entity.Authority; import org.folio.entlinks.domain.entity.HeadingRef; import org.folio.spring.testing.type.UnitTest; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -181,6 +190,124 @@ void testExtractAuthorityDtoHeadingValue(String headingType, String headingValue } } + @ParameterizedTest + @MethodSource("additionalHeadingTypeAndValuesProvider") + void testExtractAuthorityAdditionalHeadingsWithNonNullValues(String propertyType, List propertyValues) { + switch (propertyType) { + case BROADER_TERM -> source.setBroaderTerm(propertyValues); + case NARROWER_TERM -> source.setNarrowerTerm(propertyValues); + case EARLIER_HEADING -> source.setEarlierHeading(propertyValues); + case LATER_HEADING -> source.setLaterHeading(propertyValues); + case SAFT_TERM -> source.setSaftTerm(propertyValues); + case SFT_TERM -> source.setSftTerm(propertyValues); + default -> fail("Invalid heading type - {} cannot be mapped", propertyType); + } + + AuthorityUtilityMapper.extractAuthorityAdditionalHeadings(source, target); + + List additionalHeadings = target.getAdditionalHeadings(); + String[] targetHeadingValues = additionalHeadings.stream().map(HeadingRef::getHeading).toArray(String[]::new); + assertThat(additionalHeadings).hasSize(propertyValues.size()); + additionalHeadings.forEach(a -> assertEquals(propertyType, a.getHeadingType())); + assertArrayEquals(propertyValues.toArray(), targetHeadingValues); + } + + @ParameterizedTest + @MethodSource("additionalHeadingTypeAndValuesProvider") + void testExtractAuthorityAdditionalHeadingsWithNullValues(String propertyType, List propertyValues) { + switch (propertyType) { + case BROADER_TERM -> source.setBroaderTerm(null); + case NARROWER_TERM -> source.setNarrowerTerm(null); + case EARLIER_HEADING -> source.setEarlierHeading(null); + case LATER_HEADING -> source.setLaterHeading(null); + case SAFT_TERM -> source.setSaftTerm(null); + case SFT_TERM -> source.setSftTerm(null); + default -> fail("Invalid heading type - {} cannot be mapped", propertyType); + } + + AuthorityUtilityMapper.extractAuthorityAdditionalHeadings(source, target); + + assertThat(target.getAdditionalHeadings()).isEmpty(); + } + + @Test + void testExtractAuthorityAdditionalHeadingsWithMixedHeadingTypes() { + source.setBroaderTerm(List.of("boarderTerm1", "boarderTerm2")); + source.setNarrowerTerm(List.of("narrowerTerm")); + source.setEarlierHeading(List.of("earlierHeading")); + source.setLaterHeading(List.of("laterHeading")); + source.setSftTerm(List.of("sftTerm1", "sftTerm2", "sftTerm3")); + source.setSaftTerm(List.of("saftTerm1", "saftTerm2")); + + AuthorityUtilityMapper.extractAuthorityAdditionalHeadings(source, target); + + List additionalHeadings = target.getAdditionalHeadings(); + String[] targetHeadingTypes = additionalHeadings.stream().map(HeadingRef::getHeadingType).toArray(String[]::new); + String[] targetHeadingValues = additionalHeadings.stream().map(HeadingRef::getHeading).toArray(String[]::new); + assertThat(additionalHeadings).hasSize(10); + assertArrayEquals(new String[]{BROADER_TERM, BROADER_TERM, NARROWER_TERM, EARLIER_HEADING, LATER_HEADING, SFT_TERM, + SFT_TERM, SFT_TERM, SAFT_TERM, SAFT_TERM}, targetHeadingTypes); + assertArrayEquals(new String[]{"boarderTerm1", "boarderTerm2", "narrowerTerm", "earlierHeading", "laterHeading", + "sftTerm1", "sftTerm2", "sftTerm3", "saftTerm1", "saftTerm2"}, targetHeadingValues); + } + + @ParameterizedTest + @MethodSource("additionalHeadingTypeAndValuesProvider") + void testExtractAuthorityDtoAdditionalHeadingsWithNonNullValues(String headingType, List headingValues) { + List additionalHeadings = headingValues.stream().map(hv -> new HeadingRef(headingType, hv)).toList(); + target.setAdditionalHeadings(additionalHeadings); + + AuthorityUtilityMapper.extractAuthorityDtoAdditionalHeadings(target, source); + + switch (headingType) { + case BROADER_TERM -> assertArrayEquals(source.getBroaderTerm().toArray(), headingValues.toArray()); + case NARROWER_TERM -> assertArrayEquals(source.getNarrowerTerm().toArray(), headingValues.toArray()); + case EARLIER_HEADING -> assertArrayEquals(source.getEarlierHeading().toArray(), headingValues.toArray()); + case LATER_HEADING -> assertArrayEquals(source.getLaterHeading().toArray(), headingValues.toArray()); + case SFT_TERM -> assertArrayEquals(source.getSftTerm().toArray(), headingValues.toArray()); + case SAFT_TERM -> assertArrayEquals(source.getSaftTerm().toArray(), headingValues.toArray()); + default -> fail("Invalid saft heading type - {} cannot be mapped", headingType); + } + } + + @Test + void testExtractAuthorityDtoAdditionalHeadingsWithNullValues() { + + AuthorityUtilityMapper.extractAuthorityDtoAdditionalHeadings(target, source); + + assertTrue(source.getBroaderTerm().isEmpty()); + assertTrue(source.getNarrowerTerm().isEmpty()); + assertTrue(source.getEarlierHeading().isEmpty()); + assertTrue(source.getLaterHeading().isEmpty()); + assertTrue(source.getSftTerm().isEmpty()); + assertTrue(source.getSaftTerm().isEmpty()); + } + + @Test + void testExtractAuthorityDtoAdditionalHeadingsWithMixedHeadingTypes() { + List additionalHeadings = new ArrayList<>(); + additionalHeadings.add(new HeadingRef(BROADER_TERM, "broaderTerm")); + additionalHeadings.add(new HeadingRef(NARROWER_TERM, "narrowerTerm1")); + additionalHeadings.add(new HeadingRef(NARROWER_TERM, "narrowerTerm2")); + additionalHeadings.add(new HeadingRef(EARLIER_HEADING, "earlierHeading1")); + additionalHeadings.add(new HeadingRef(EARLIER_HEADING, "earlierHeading2")); + additionalHeadings.add(new HeadingRef(LATER_HEADING, "laterHeading")); + additionalHeadings.add(new HeadingRef(SFT_TERM, "sftTerm1")); + additionalHeadings.add(new HeadingRef(SFT_TERM, "sftTerm2")); + additionalHeadings.add(new HeadingRef(SAFT_TERM, "saftTerm1")); + additionalHeadings.add(new HeadingRef(SAFT_TERM, "saftTerm2")); + target.setAdditionalHeadings(additionalHeadings); + + AuthorityUtilityMapper.extractAuthorityDtoAdditionalHeadings(target, source); + + assertArrayEquals(new String[] {"broaderTerm"}, source.getBroaderTerm().toArray()); + assertArrayEquals(new String[] {"narrowerTerm1", "narrowerTerm2"}, source.getNarrowerTerm().toArray()); + assertArrayEquals(new String[] {"earlierHeading1", "earlierHeading2"}, source.getEarlierHeading().toArray()); + assertArrayEquals(new String[] {"laterHeading"}, source.getLaterHeading().toArray()); + assertArrayEquals(new String[] {"sftTerm1", "sftTerm2"}, source.getSftTerm().toArray()); + assertArrayEquals(new String[] {"saftTerm1", "saftTerm2"}, source.getSaftTerm().toArray()); + } + private static Stream headingTypeAndValueProvider() { return Stream.of( arguments(PERSONAL_NAME_HEADING, TEST_STRING), @@ -196,4 +323,15 @@ private static Stream headingTypeAndValueProvider() { ); } + private static Stream additionalHeadingTypeAndValuesProvider() { + return Stream.of( + arguments(BROADER_TERM, List.of(TEST_STRING)), + arguments(NARROWER_TERM, List.of(TEST_STRING, TEST_STRING)), + arguments(EARLIER_HEADING, List.of(TEST_STRING)), + arguments(LATER_HEADING, List.of(TEST_STRING, TEST_STRING)), + arguments(SFT_TERM, List.of(TEST_STRING, TEST_STRING)), + arguments(SAFT_TERM, List.of(TEST_STRING, TEST_STRING, TEST_STRING)), + arguments(SAFT_TERM, List.of()) + ); + } } diff --git a/src/test/java/org/folio/entlinks/service/authority/AuthorityServiceTest.java b/src/test/java/org/folio/entlinks/service/authority/AuthorityServiceTest.java index 412a69c3..79e12863 100644 --- a/src/test/java/org/folio/entlinks/service/authority/AuthorityServiceTest.java +++ b/src/test/java/org/folio/entlinks/service/authority/AuthorityServiceTest.java @@ -130,6 +130,12 @@ void shouldUpdateAuthority() { existed.setSftHeadings(List.of(new HeadingRef("personalName", "sft"))); existed.setNotes(List.of(new AuthorityNote(UUID.randomUUID(), "note", true))); existed.setIdentifiers(List.of(new AuthorityIdentifier("identifier", UUID.randomUUID()))); + existed.setAdditionalHeadings(List.of(new HeadingRef("broaderTerm", "broader"), + new HeadingRef("narrowerTerm", "narrower"), + new HeadingRef("earlierHeading", "earlier"), + new HeadingRef("laterHeading", "later"), + new HeadingRef("sftTerm", "sft"), + new HeadingRef("saftTerm", "saft"))); var sourceFileOld = new AuthoritySourceFile(); sourceFileOld.setId(UUID.randomUUID()); existed.setAuthoritySourceFile(sourceFileOld); @@ -145,6 +151,12 @@ void shouldUpdateAuthority() { modified.setSftHeadings(List.of(new HeadingRef("personalNameNew", "sftNew"))); modified.setNotes(List.of(new AuthorityNote(UUID.randomUUID(), "noteNew", true))); modified.setIdentifiers(List.of(new AuthorityIdentifier("identifierNew", UUID.randomUUID()))); + modified.setAdditionalHeadings(List.of(new HeadingRef("broaderTerm", "broaderNew"), + new HeadingRef("narrowerTerm", "narrowerNew"), + new HeadingRef("earlierHeading", "earlierNew"), + new HeadingRef("laterHeading", "laterNew"), + new HeadingRef("sftTerm", "sftNew"), + new HeadingRef("saftTerm", "saftNew"))); var sourceFileNew = new AuthoritySourceFile(); sourceFileNew.setId(UUID.randomUUID()); modified.setAuthoritySourceFile(sourceFileNew); From 31070bd6cfff77f5c335d3212aa58171f3197281 Mon Sep 17 00:00:00 2001 From: ElenaShm Date: Fri, 30 Aug 2024 16:05:47 +0300 Subject: [PATCH 2/4] feature/MODELINKS-248 split relationship fields to sft and saft --- .../controller/converter/AuthorityMapper.java | 2 - .../converter/AuthorityUtilityMapper.java | 116 +++++++---- .../entlinks/domain/entity/AuthorityBase.java | 8 - .../domain/entity/AuthorityConstants.java | 12 -- .../entlinks/domain/entity/HeadingRef.java | 11 ++ .../domain/entity/RelationshipType.java | 6 + .../db/changelog/changelog-master.xml | 2 - ...additional-fields-to-authority-archive.xml | 19 -- .../add-additional-fields-to-authority.xml | 19 -- .../authority-storage/authorityDto.yaml | 70 ++++--- .../converter/AuthorityUtilityMapperTest.java | 186 +++++++----------- .../authority/AuthorityServiceTest.java | 12 -- 12 files changed, 200 insertions(+), 263 deletions(-) create mode 100644 src/main/java/org/folio/entlinks/domain/entity/RelationshipType.java delete mode 100644 src/main/resources/db/changelog/changes/v3.1/add-additional-fields-to-authority-archive.xml delete mode 100644 src/main/resources/db/changelog/changes/v3.1/add-additional-fields-to-authority.xml diff --git a/src/main/java/org/folio/entlinks/controller/converter/AuthorityMapper.java b/src/main/java/org/folio/entlinks/controller/converter/AuthorityMapper.java index 21aeb963..5c4c49f5 100644 --- a/src/main/java/org/folio/entlinks/controller/converter/AuthorityMapper.java +++ b/src/main/java/org/folio/entlinks/controller/converter/AuthorityMapper.java @@ -93,7 +93,6 @@ default void authorityPostProcess(AuthorityDto source, @MappingTarget AuthorityB AuthorityUtilityMapper.extractAuthorityHeading(source, target); AuthorityUtilityMapper.extractAuthoritySftHeadings(source, target); AuthorityUtilityMapper.extractAuthoritySaftHeadings(source, target); - AuthorityUtilityMapper.extractAuthorityAdditionalHeadings(source, target); } @AfterMapping @@ -101,7 +100,6 @@ default void authorityDtoPostProcessing(AuthorityBase source, @MappingTarget Aut AuthorityUtilityMapper.extractAuthorityDtoHeadingValue(source, target); AuthorityUtilityMapper.extractAuthorityDtoSftHeadings(source, target); AuthorityUtilityMapper.extractAuthorityDtoSaftHeadings(source, target); - AuthorityUtilityMapper.extractAuthorityDtoAdditionalHeadings(source, target); } default OffsetDateTime map(Timestamp timestamp) { diff --git a/src/main/java/org/folio/entlinks/controller/converter/AuthorityUtilityMapper.java b/src/main/java/org/folio/entlinks/controller/converter/AuthorityUtilityMapper.java index 7a3522bd..18621c80 100644 --- a/src/main/java/org/folio/entlinks/controller/converter/AuthorityUtilityMapper.java +++ b/src/main/java/org/folio/entlinks/controller/converter/AuthorityUtilityMapper.java @@ -2,31 +2,28 @@ import static org.apache.commons.collections4.CollectionUtils.isEmpty; import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; -import static org.folio.entlinks.domain.entity.AuthorityConstants.BROADER_TERM; import static org.folio.entlinks.domain.entity.AuthorityConstants.CORPORATE_NAME_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.CORPORATE_NAME_TITLE_HEADING; -import static org.folio.entlinks.domain.entity.AuthorityConstants.EARLIER_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.GENRE_TERM_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.GEOGRAPHIC_NAME_HEADING; -import static org.folio.entlinks.domain.entity.AuthorityConstants.LATER_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.MEETING_NAME_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.MEETING_NAME_TITLE_HEADING; -import static org.folio.entlinks.domain.entity.AuthorityConstants.NARROWER_TERM; import static org.folio.entlinks.domain.entity.AuthorityConstants.PERSONAL_NAME_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.PERSONAL_NAME_TITLE_HEADING; -import static org.folio.entlinks.domain.entity.AuthorityConstants.SAFT_TERM; -import static org.folio.entlinks.domain.entity.AuthorityConstants.SFT_TERM; import static org.folio.entlinks.domain.entity.AuthorityConstants.TOPICAL_TERM_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.UNIFORM_TITLE_HEADING; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; import lombok.experimental.UtilityClass; import lombok.extern.log4j.Log4j2; import org.folio.entlinks.domain.dto.AuthorityDto; import org.folio.entlinks.domain.entity.AuthorityBase; import org.folio.entlinks.domain.entity.HeadingRef; +import org.folio.entlinks.domain.entity.RelationshipType; @UtilityClass @Log4j2 @@ -116,6 +113,7 @@ public static void extractAuthoritySftHeadings(AuthorityDto source, AuthorityBas if (isNotEmpty(source.getSftGenreTerm())) { sftHeadings.addAll(asSftHeadings(source.getSftGenreTerm(), GENRE_TERM_HEADING)); } + addRelationshipsToSftHeadings(source, sftHeadings); target.setSftHeadings(sftHeadings); } @@ -151,30 +149,34 @@ public static void extractAuthoritySaftHeadings(AuthorityDto source, AuthorityBa if (isNotEmpty(source.getSaftGenreTerm())) { saftHeadings.addAll(asSftHeadings(source.getSaftGenreTerm(), GENRE_TERM_HEADING)); } + addRelationshipsToSaftHeadings(source, saftHeadings); target.setSaftHeadings(saftHeadings); } - public static void extractAuthorityAdditionalHeadings(AuthorityDto source, AuthorityBase target) { - List additionalHeadings = new ArrayList<>(); - if (isNotEmpty(source.getBroaderTerm())) { - additionalHeadings.addAll(asSftHeadings(source.getBroaderTerm(), BROADER_TERM)); - } - if (isNotEmpty(source.getNarrowerTerm())) { - additionalHeadings.addAll(asSftHeadings(source.getNarrowerTerm(), NARROWER_TERM)); - } - if (isNotEmpty(source.getEarlierHeading())) { - additionalHeadings.addAll(asSftHeadings(source.getEarlierHeading(), EARLIER_HEADING)); - } - if (isNotEmpty(source.getLaterHeading())) { - additionalHeadings.addAll(asSftHeadings(source.getLaterHeading(), LATER_HEADING)); - } - if (isNotEmpty(source.getSftTerm())) { - additionalHeadings.addAll(asSftHeadings(source.getSftTerm(), SFT_TERM)); - } - if (isNotEmpty(source.getSaftTerm())) { - additionalHeadings.addAll(asSftHeadings(source.getSaftTerm(), SAFT_TERM)); + private static void addRelationshipsToSftHeadings(final AuthorityDto source, final List headingRefs) { + processRelationshipHeadings(source.getSftBroaderTerm(), headingRefs, RelationshipType.BROADER_TERM); + processRelationshipHeadings(source.getSftNarrowerTerm(), headingRefs, RelationshipType.NARROWER_TERM); + processRelationshipHeadings(source.getSftEarlierHeading(), headingRefs, RelationshipType.EARLIER_HEADING); + processRelationshipHeadings(source.getSftLaterHeading(), headingRefs, RelationshipType.LATER_HEADING); + } + + private static void addRelationshipsToSaftHeadings(final AuthorityDto source, final List headingRefs) { + processRelationshipHeadings(source.getSaftBroaderTerm(), headingRefs, RelationshipType.BROADER_TERM); + processRelationshipHeadings(source.getSaftNarrowerTerm(), headingRefs, RelationshipType.NARROWER_TERM); + processRelationshipHeadings(source.getSaftEarlierHeading(), headingRefs, RelationshipType.EARLIER_HEADING); + processRelationshipHeadings(source.getSaftLaterHeading(), headingRefs, RelationshipType.LATER_HEADING); + } + + private static void processRelationshipHeadings(List relationshipHeadings, final List headingRefs, + final RelationshipType relationshipType) { + if (isNotEmpty(relationshipHeadings)) { + headingRefs.forEach(headingRef -> { + if (relationshipHeadings.contains(headingRef.getHeading())) { + Set relationshipTypeSet = getOrCreateRelationshipTypeSet(headingRef); + relationshipTypeSet.add(relationshipType); + } + }); } - target.setAdditionalHeadings(additionalHeadings); } public static void extractAuthorityDtoHeadingValue(AuthorityBase source, AuthorityDto target) { @@ -210,12 +212,6 @@ public static void extractAuthorityDtoSaftHeadings(AuthorityBase source, Authori source.getSaftHeadings().forEach(headingRef -> extractAuthorityDtoSaftHeading(headingRef, target)); } - public static void extractAuthorityDtoAdditionalHeadings(AuthorityBase source, AuthorityDto target) { - if (isNotEmpty(source.getAdditionalHeadings())) { - source.getAdditionalHeadings().forEach(headingRef -> extractAuthorityDtoAdditionalHeading(headingRef, target)); - } - } - private void extractAuthorityDtoSftHeading(HeadingRef headingRef, AuthorityDto target) { if (headingRef == null || headingRef.getHeadingType() == null) { return; @@ -233,6 +229,7 @@ private void extractAuthorityDtoSftHeading(HeadingRef headingRef, AuthorityDto t case GENRE_TERM_HEADING -> target.addSftGenreTermItem(headingRef.getHeading()); default -> log.warn("Invalid sft heading type - {} cannot be mapped", headingRef.getHeadingType()); } + extractSftHeadingsRelationships(headingRef, target); } private void extractAuthorityDtoSaftHeading(HeadingRef headingRef, AuthorityDto target) { @@ -252,6 +249,39 @@ private void extractAuthorityDtoSaftHeading(HeadingRef headingRef, AuthorityDto case GENRE_TERM_HEADING -> target.addSaftGenreTermItem(headingRef.getHeading()); default -> log.warn("Invalid saft heading type - {} cannot be mapped", headingRef.getHeadingType()); } + extractSaftHeadingsRelationships(headingRef, target); + } + + private static void extractSftHeadingsRelationships(HeadingRef headingRef, AuthorityDto target) { + if (isNotEmpty(headingRef.getRelationshipType())) { + headingRef.getRelationshipType().forEach( + relationshipType -> { + switch (relationshipType) { + case BROADER_TERM -> addIfNotExists(target.getSftBroaderTerm(), headingRef.getHeading()); + case NARROWER_TERM -> addIfNotExists(target.getSftNarrowerTerm(), headingRef.getHeading()); + case EARLIER_HEADING -> addIfNotExists(target.getSftEarlierHeading(), headingRef.getHeading()); + case LATER_HEADING -> addIfNotExists(target.getSftLaterHeading(), headingRef.getHeading()); + default -> log.warn("Invalid sft relationship type - {} cannot be mapped", relationshipType); + } + } + ); + } + } + + private static void extractSaftHeadingsRelationships(HeadingRef headingRef, AuthorityDto target) { + if (isNotEmpty(headingRef.getRelationshipType())) { + headingRef.getRelationshipType().forEach( + relationshipType -> { + switch (relationshipType) { + case BROADER_TERM -> addIfNotExists(target.getSaftBroaderTerm(), headingRef.getHeading()); + case NARROWER_TERM -> addIfNotExists(target.getSaftNarrowerTerm(), headingRef.getHeading()); + case EARLIER_HEADING -> addIfNotExists(target.getSaftEarlierHeading(), headingRef.getHeading()); + case LATER_HEADING -> addIfNotExists(target.getSaftLaterHeading(), headingRef.getHeading()); + default -> log.warn("Invalid saft relationship type - {} cannot be mapped", relationshipType); + } + } + ); + } } private static List asSftHeadings(List headingValues, String headingType) { @@ -260,18 +290,18 @@ private static List asSftHeadings(List headingValues, String .toList(); } - private void extractAuthorityDtoAdditionalHeading(HeadingRef headingRef, AuthorityDto target) { - if (headingRef == null || headingRef.getHeadingType() == null) { - return; + private static Set getOrCreateRelationshipTypeSet(HeadingRef heading) { + Set relationshipTypeSet = heading.getRelationshipType(); + if (relationshipTypeSet == null) { + relationshipTypeSet = new HashSet<>(); + heading.setRelationshipType(relationshipTypeSet); } - switch (headingRef.getHeadingType()) { - case BROADER_TERM -> target.addBroaderTermItem(headingRef.getHeading()); - case NARROWER_TERM -> target.addNarrowerTermItem(headingRef.getHeading()); - case EARLIER_HEADING -> target.addEarlierHeadingItem(headingRef.getHeading()); - case LATER_HEADING -> target.addLaterHeadingItem(headingRef.getHeading()); - case SAFT_TERM -> target.addSaftTermItem(headingRef.getHeading()); - case SFT_TERM -> target.addSftTermItem(headingRef.getHeading()); - default -> log.warn("Invalid additional heading type - {} cannot be mapped", headingRef.getHeadingType()); + return relationshipTypeSet; + } + + private static void addIfNotExists(List headings, String heading) { + if (!headings.contains(heading)) { + headings.add(heading); } } } diff --git a/src/main/java/org/folio/entlinks/domain/entity/AuthorityBase.java b/src/main/java/org/folio/entlinks/domain/entity/AuthorityBase.java index 2d7b0a9f..dee2764e 100644 --- a/src/main/java/org/folio/entlinks/domain/entity/AuthorityBase.java +++ b/src/main/java/org/folio/entlinks/domain/entity/AuthorityBase.java @@ -42,7 +42,6 @@ public class AuthorityBase extends MetadataEntity { public static final String DELETED_COLUMN = "deleted"; private static final String CONSORTIUM_SOURCE_PREFIX = "CONSORTIUM-"; - private static final String ADDITIONAL_HEADINGS_COLUMN = "additional_headings"; @Id @Column(name = ID_COLUMN, nullable = false) @@ -91,10 +90,6 @@ public class AuthorityBase extends MetadataEntity { @Column(name = DELETED_COLUMN) private boolean deleted = false; - @Column(name = ADDITIONAL_HEADINGS_COLUMN) - @JdbcTypeCode(SqlTypes.JSON) - private List additionalHeadings; - public AuthorityBase(AuthorityBase other) { super(other); this.id = other.id; @@ -121,9 +116,6 @@ public AuthorityBase(AuthorityBase other) { .map(AuthorityNote::new) .toList(); this.deleted = other.deleted; - this.additionalHeadings = Optional.ofNullable(other.getSaftHeadings()).orElse(List.of()).stream() - .map(HeadingRef::new) - .toList(); } public void makeAsConsortiumShadowCopy() { diff --git a/src/main/java/org/folio/entlinks/domain/entity/AuthorityConstants.java b/src/main/java/org/folio/entlinks/domain/entity/AuthorityConstants.java index feb80395..337529a3 100644 --- a/src/main/java/org/folio/entlinks/domain/entity/AuthorityConstants.java +++ b/src/main/java/org/folio/entlinks/domain/entity/AuthorityConstants.java @@ -24,16 +24,4 @@ public class AuthorityConstants { public static final String GEOGRAPHIC_NAME_HEADING = "geographicName"; public static final String GENRE_TERM_HEADING = "genreTerm"; - - public static final String BROADER_TERM = "broaderTerm"; - - public static final String NARROWER_TERM = "narrowerTerm"; - - public static final String EARLIER_HEADING = "earlierHeading"; - - public static final String LATER_HEADING = "laterHeading"; - - public static final String SFT_TERM = "sftTerm"; - - public static final String SAFT_TERM = "saftTerm"; } diff --git a/src/main/java/org/folio/entlinks/domain/entity/HeadingRef.java b/src/main/java/org/folio/entlinks/domain/entity/HeadingRef.java index bf9b72a1..f74fc8f6 100644 --- a/src/main/java/org/folio/entlinks/domain/entity/HeadingRef.java +++ b/src/main/java/org/folio/entlinks/domain/entity/HeadingRef.java @@ -1,6 +1,8 @@ package org.folio.entlinks.domain.entity; +import com.fasterxml.jackson.annotation.JsonInclude; import java.io.Serializable; +import java.util.Set; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -14,14 +16,23 @@ @AllArgsConstructor @ToString @EqualsAndHashCode +@JsonInclude(JsonInclude.Include.NON_NULL) public class HeadingRef implements Serializable { private String headingType; private String heading; + private Set relationshipType; + public HeadingRef(HeadingRef other) { this.heading = other.heading; this.headingType = other.headingType; + this.relationshipType = other.relationshipType; + } + + public HeadingRef(String headingType, String heading) { + this.headingType = headingType; + this.heading = heading; } } diff --git a/src/main/java/org/folio/entlinks/domain/entity/RelationshipType.java b/src/main/java/org/folio/entlinks/domain/entity/RelationshipType.java new file mode 100644 index 00000000..b830b5b5 --- /dev/null +++ b/src/main/java/org/folio/entlinks/domain/entity/RelationshipType.java @@ -0,0 +1,6 @@ +package org.folio.entlinks.domain.entity; + +public enum RelationshipType { + + BROADER_TERM, NARROWER_TERM, EARLIER_HEADING, LATER_HEADING +} diff --git a/src/main/resources/db/changelog/changelog-master.xml b/src/main/resources/db/changelog/changelog-master.xml index a4417124..906c7bf5 100644 --- a/src/main/resources/db/changelog/changelog-master.xml +++ b/src/main/resources/db/changelog/changelog-master.xml @@ -23,6 +23,4 @@ - - diff --git a/src/main/resources/db/changelog/changes/v3.1/add-additional-fields-to-authority-archive.xml b/src/main/resources/db/changelog/changes/v3.1/add-additional-fields-to-authority-archive.xml deleted file mode 100644 index 404ed022..00000000 --- a/src/main/resources/db/changelog/changes/v3.1/add-additional-fields-to-authority-archive.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - Add new jsonb fields to authority_archive table - - - - - - - diff --git a/src/main/resources/db/changelog/changes/v3.1/add-additional-fields-to-authority.xml b/src/main/resources/db/changelog/changes/v3.1/add-additional-fields-to-authority.xml deleted file mode 100644 index 80db8253..00000000 --- a/src/main/resources/db/changelog/changes/v3.1/add-additional-fields-to-authority.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - Add new jsonb fields to authority table - - - - - - - diff --git a/src/main/resources/swagger.api/schemas/authority-storage/authorityDto.yaml b/src/main/resources/swagger.api/schemas/authority-storage/authorityDto.yaml index aeb4a103..9e67295e 100644 --- a/src/main/resources/swagger.api/schemas/authority-storage/authorityDto.yaml +++ b/src/main/resources/swagger.api/schemas/authority-storage/authorityDto.yaml @@ -110,6 +110,26 @@ properties: description: See from tracing topical term items: type: string + sftBroaderTerm: + type: array + description: See from tracing term that represents broader, more general concepts related to the authority record + items: + type: string + sftNarrowerTerm: + type: array + description: See from tracing term that that represents narrower, more specific concepts derived from the authority record + items: + type: string + sftEarlierHeading: + type: array + description: See from tracing heading that was previously used to represent the concept or entity described by the authority record. This field is used to track the evolution of terms or headings over time, facilitating the linking of historical and current data. + items: + type: string + sftLaterHeading: + type: array + description: See from tracing heading that replaced the current heading used in the authority record. This field helps in maintaining the continuity of catalog records by linking past headings to their more current versions. + items: + type: string saftTopicalTerm: type: array description: See also from tracing topical term @@ -144,6 +164,26 @@ properties: description: See also from tracing genre/form term items: type: string + saftBroaderTerm: + type: array + description: See also from tracing term that represents broader, more general concepts related to the authority record + items: + type: string + saftNarrowerTerm: + type: array + description: See also from tracing term that that represents narrower, more specific concepts derived from the authority record + items: + type: string + saftEarlierHeading: + type: array + description: See also from tracing heading that was previously used to represent the concept or entity described by the authority record. This field is used to track the evolution of terms or headings over time, facilitating the linking of historical and current data. + items: + type: string + saftLaterHeading: + type: array + description: See also from tracing heading that replaced the current heading used in the authority record. This field helps in maintaining the continuity of catalog records by linking past headings to their more current versions. + items: + type: string identifiers: type: array description: An extensible set of name-value pairs of identifiers associated with the resource @@ -163,36 +203,6 @@ properties: description: Authority Natural ID metadata: $ref: '../common/metadata.yaml' - broaderTerm: - type: array - description: Terms that represents broader, more general concepts related to the authority record - items: - type: string - narrowerTerm: - type: array - description: Terms that represents narrower, more specific concepts derived from the authority record - items: - type: string - earlierHeading: - type: array - description: Heading that was previously used to represent the concept or entity described by the authority record. This field is used to track the evolution of terms or headings over time, facilitating the linking of historical and current data. - items: - type: string - laterHeading: - type: array - description: Heading that replaced the current heading used in the authority record. This field helps in maintaining the continuity of catalog records by linking past headings to their more current versions. - items: - type: string - sftTerm: - type: array - description: See from tracing term - items: - type: string - saftTerm: - type: array - description: See also from tracing term - items: - type: string required: - source - naturalId diff --git a/src/test/java/org/folio/entlinks/controller/converter/AuthorityUtilityMapperTest.java b/src/test/java/org/folio/entlinks/controller/converter/AuthorityUtilityMapperTest.java index badc1409..29b838f5 100644 --- a/src/test/java/org/folio/entlinks/controller/converter/AuthorityUtilityMapperTest.java +++ b/src/test/java/org/folio/entlinks/controller/converter/AuthorityUtilityMapperTest.java @@ -2,20 +2,14 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Fail.fail; -import static org.folio.entlinks.domain.entity.AuthorityConstants.BROADER_TERM; import static org.folio.entlinks.domain.entity.AuthorityConstants.CORPORATE_NAME_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.CORPORATE_NAME_TITLE_HEADING; -import static org.folio.entlinks.domain.entity.AuthorityConstants.EARLIER_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.GENRE_TERM_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.GEOGRAPHIC_NAME_HEADING; -import static org.folio.entlinks.domain.entity.AuthorityConstants.LATER_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.MEETING_NAME_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.MEETING_NAME_TITLE_HEADING; -import static org.folio.entlinks.domain.entity.AuthorityConstants.NARROWER_TERM; import static org.folio.entlinks.domain.entity.AuthorityConstants.PERSONAL_NAME_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.PERSONAL_NAME_TITLE_HEADING; -import static org.folio.entlinks.domain.entity.AuthorityConstants.SAFT_TERM; -import static org.folio.entlinks.domain.entity.AuthorityConstants.SFT_TERM; import static org.folio.entlinks.domain.entity.AuthorityConstants.TOPICAL_TERM_HEADING; import static org.folio.entlinks.domain.entity.AuthorityConstants.UNIFORM_TITLE_HEADING; import static org.folio.support.base.TestConstants.TEST_STRING; @@ -27,10 +21,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.stream.Stream; import org.folio.entlinks.domain.dto.AuthorityDto; import org.folio.entlinks.domain.entity.Authority; import org.folio.entlinks.domain.entity.HeadingRef; +import org.folio.entlinks.domain.entity.RelationshipType; import org.folio.spring.testing.type.UnitTest; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -190,122 +186,50 @@ void testExtractAuthorityDtoHeadingValue(String headingType, String headingValue } } - @ParameterizedTest - @MethodSource("additionalHeadingTypeAndValuesProvider") - void testExtractAuthorityAdditionalHeadingsWithNonNullValues(String propertyType, List propertyValues) { - switch (propertyType) { - case BROADER_TERM -> source.setBroaderTerm(propertyValues); - case NARROWER_TERM -> source.setNarrowerTerm(propertyValues); - case EARLIER_HEADING -> source.setEarlierHeading(propertyValues); - case LATER_HEADING -> source.setLaterHeading(propertyValues); - case SAFT_TERM -> source.setSaftTerm(propertyValues); - case SFT_TERM -> source.setSftTerm(propertyValues); - default -> fail("Invalid heading type - {} cannot be mapped", propertyType); - } + @Test + void testExtractAuthoritySftHeadingsWithRelationships() { + final AuthorityDto authorityDto = getAuthorityDtoWithSftTerms(); + final List expectedHeadingRefs = getHeadingRefs(); - AuthorityUtilityMapper.extractAuthorityAdditionalHeadings(source, target); + AuthorityUtilityMapper.extractAuthoritySftHeadings(authorityDto, target); - List additionalHeadings = target.getAdditionalHeadings(); - String[] targetHeadingValues = additionalHeadings.stream().map(HeadingRef::getHeading).toArray(String[]::new); - assertThat(additionalHeadings).hasSize(propertyValues.size()); - additionalHeadings.forEach(a -> assertEquals(propertyType, a.getHeadingType())); - assertArrayEquals(propertyValues.toArray(), targetHeadingValues); + List sftHeadings = target.getSftHeadings(); + assertThat(sftHeadings).hasSize(11); + assertArrayEquals(expectedHeadingRefs.toArray(), sftHeadings.toArray()); } - @ParameterizedTest - @MethodSource("additionalHeadingTypeAndValuesProvider") - void testExtractAuthorityAdditionalHeadingsWithNullValues(String propertyType, List propertyValues) { - switch (propertyType) { - case BROADER_TERM -> source.setBroaderTerm(null); - case NARROWER_TERM -> source.setNarrowerTerm(null); - case EARLIER_HEADING -> source.setEarlierHeading(null); - case LATER_HEADING -> source.setLaterHeading(null); - case SAFT_TERM -> source.setSaftTerm(null); - case SFT_TERM -> source.setSftTerm(null); - default -> fail("Invalid heading type - {} cannot be mapped", propertyType); - } + @Test + void testExtractAuthorityDtoSftHeadingsWithRelationships() { + final List sftHeadings = getHeadingRefs(); + target.setSftHeadings(sftHeadings); + final AuthorityDto expectedAuthorityDto = getAuthorityDtoWithSftTerms(); - AuthorityUtilityMapper.extractAuthorityAdditionalHeadings(source, target); + AuthorityUtilityMapper.extractAuthorityDtoSftHeadings(target, source); - assertThat(target.getAdditionalHeadings()).isEmpty(); + assertEquals(expectedAuthorityDto, source); } @Test - void testExtractAuthorityAdditionalHeadingsWithMixedHeadingTypes() { - source.setBroaderTerm(List.of("boarderTerm1", "boarderTerm2")); - source.setNarrowerTerm(List.of("narrowerTerm")); - source.setEarlierHeading(List.of("earlierHeading")); - source.setLaterHeading(List.of("laterHeading")); - source.setSftTerm(List.of("sftTerm1", "sftTerm2", "sftTerm3")); - source.setSaftTerm(List.of("saftTerm1", "saftTerm2")); - - AuthorityUtilityMapper.extractAuthorityAdditionalHeadings(source, target); - - List additionalHeadings = target.getAdditionalHeadings(); - String[] targetHeadingTypes = additionalHeadings.stream().map(HeadingRef::getHeadingType).toArray(String[]::new); - String[] targetHeadingValues = additionalHeadings.stream().map(HeadingRef::getHeading).toArray(String[]::new); - assertThat(additionalHeadings).hasSize(10); - assertArrayEquals(new String[]{BROADER_TERM, BROADER_TERM, NARROWER_TERM, EARLIER_HEADING, LATER_HEADING, SFT_TERM, - SFT_TERM, SFT_TERM, SAFT_TERM, SAFT_TERM}, targetHeadingTypes); - assertArrayEquals(new String[]{"boarderTerm1", "boarderTerm2", "narrowerTerm", "earlierHeading", "laterHeading", - "sftTerm1", "sftTerm2", "sftTerm3", "saftTerm1", "saftTerm2"}, targetHeadingValues); - } - - @ParameterizedTest - @MethodSource("additionalHeadingTypeAndValuesProvider") - void testExtractAuthorityDtoAdditionalHeadingsWithNonNullValues(String headingType, List headingValues) { - List additionalHeadings = headingValues.stream().map(hv -> new HeadingRef(headingType, hv)).toList(); - target.setAdditionalHeadings(additionalHeadings); + void testExtractAuthoritySaftHeadingsWithRelationships() { + final AuthorityDto authorityDto = getAuthorityDtoWithSaftTerms(); + final List expectedHeadingRefs = getHeadingRefs(); - AuthorityUtilityMapper.extractAuthorityDtoAdditionalHeadings(target, source); + AuthorityUtilityMapper.extractAuthoritySaftHeadings(authorityDto, target); - switch (headingType) { - case BROADER_TERM -> assertArrayEquals(source.getBroaderTerm().toArray(), headingValues.toArray()); - case NARROWER_TERM -> assertArrayEquals(source.getNarrowerTerm().toArray(), headingValues.toArray()); - case EARLIER_HEADING -> assertArrayEquals(source.getEarlierHeading().toArray(), headingValues.toArray()); - case LATER_HEADING -> assertArrayEquals(source.getLaterHeading().toArray(), headingValues.toArray()); - case SFT_TERM -> assertArrayEquals(source.getSftTerm().toArray(), headingValues.toArray()); - case SAFT_TERM -> assertArrayEquals(source.getSaftTerm().toArray(), headingValues.toArray()); - default -> fail("Invalid saft heading type - {} cannot be mapped", headingType); - } + List sftHeadings = target.getSaftHeadings(); + assertThat(sftHeadings).hasSize(11); + assertArrayEquals(expectedHeadingRefs.toArray(), sftHeadings.toArray()); } @Test - void testExtractAuthorityDtoAdditionalHeadingsWithNullValues() { + void testExtractAuthorityDtoSaftHeadingsWithRelationships() { + final List saftHeadings = getHeadingRefs(); + target.setSaftHeadings(saftHeadings); + final AuthorityDto expectedAuthorityDto = getAuthorityDtoWithSaftTerms(); - AuthorityUtilityMapper.extractAuthorityDtoAdditionalHeadings(target, source); + AuthorityUtilityMapper.extractAuthorityDtoSaftHeadings(target, source); - assertTrue(source.getBroaderTerm().isEmpty()); - assertTrue(source.getNarrowerTerm().isEmpty()); - assertTrue(source.getEarlierHeading().isEmpty()); - assertTrue(source.getLaterHeading().isEmpty()); - assertTrue(source.getSftTerm().isEmpty()); - assertTrue(source.getSaftTerm().isEmpty()); - } - - @Test - void testExtractAuthorityDtoAdditionalHeadingsWithMixedHeadingTypes() { - List additionalHeadings = new ArrayList<>(); - additionalHeadings.add(new HeadingRef(BROADER_TERM, "broaderTerm")); - additionalHeadings.add(new HeadingRef(NARROWER_TERM, "narrowerTerm1")); - additionalHeadings.add(new HeadingRef(NARROWER_TERM, "narrowerTerm2")); - additionalHeadings.add(new HeadingRef(EARLIER_HEADING, "earlierHeading1")); - additionalHeadings.add(new HeadingRef(EARLIER_HEADING, "earlierHeading2")); - additionalHeadings.add(new HeadingRef(LATER_HEADING, "laterHeading")); - additionalHeadings.add(new HeadingRef(SFT_TERM, "sftTerm1")); - additionalHeadings.add(new HeadingRef(SFT_TERM, "sftTerm2")); - additionalHeadings.add(new HeadingRef(SAFT_TERM, "saftTerm1")); - additionalHeadings.add(new HeadingRef(SAFT_TERM, "saftTerm2")); - target.setAdditionalHeadings(additionalHeadings); - - AuthorityUtilityMapper.extractAuthorityDtoAdditionalHeadings(target, source); - - assertArrayEquals(new String[] {"broaderTerm"}, source.getBroaderTerm().toArray()); - assertArrayEquals(new String[] {"narrowerTerm1", "narrowerTerm2"}, source.getNarrowerTerm().toArray()); - assertArrayEquals(new String[] {"earlierHeading1", "earlierHeading2"}, source.getEarlierHeading().toArray()); - assertArrayEquals(new String[] {"laterHeading"}, source.getLaterHeading().toArray()); - assertArrayEquals(new String[] {"sftTerm1", "sftTerm2"}, source.getSftTerm().toArray()); - assertArrayEquals(new String[] {"saftTerm1", "saftTerm2"}, source.getSaftTerm().toArray()); + assertEquals(expectedAuthorityDto, source); } private static Stream headingTypeAndValueProvider() { @@ -323,15 +247,45 @@ private static Stream headingTypeAndValueProvider() { ); } - private static Stream additionalHeadingTypeAndValuesProvider() { - return Stream.of( - arguments(BROADER_TERM, List.of(TEST_STRING)), - arguments(NARROWER_TERM, List.of(TEST_STRING, TEST_STRING)), - arguments(EARLIER_HEADING, List.of(TEST_STRING)), - arguments(LATER_HEADING, List.of(TEST_STRING, TEST_STRING)), - arguments(SFT_TERM, List.of(TEST_STRING, TEST_STRING)), - arguments(SAFT_TERM, List.of(TEST_STRING, TEST_STRING, TEST_STRING)), - arguments(SAFT_TERM, List.of()) - ); + private static List getHeadingRefs() { + return List.of( + new HeadingRef(PERSONAL_NAME_HEADING, PERSONAL_NAME_HEADING), + new HeadingRef(PERSONAL_NAME_HEADING, "broaderTerm1", Set.of(RelationshipType.BROADER_TERM)), + new HeadingRef(CORPORATE_NAME_HEADING, CORPORATE_NAME_HEADING), + new HeadingRef(CORPORATE_NAME_HEADING, "broaderTerm2", Set.of(RelationshipType.BROADER_TERM)), + new HeadingRef(CORPORATE_NAME_HEADING, "laterHeading", Set.of(RelationshipType.LATER_HEADING)), + new HeadingRef(MEETING_NAME_HEADING, MEETING_NAME_HEADING), + new HeadingRef(MEETING_NAME_HEADING, "narrowerTerm", Set.of(RelationshipType.NARROWER_TERM)), + new HeadingRef(MEETING_NAME_HEADING, "narrower-later", Set.of(RelationshipType.NARROWER_TERM, + RelationshipType.LATER_HEADING)), + new HeadingRef(TOPICAL_TERM_HEADING, TOPICAL_TERM_HEADING), + new HeadingRef(TOPICAL_TERM_HEADING, "broaderTerm1", Set.of(RelationshipType.BROADER_TERM)), + new HeadingRef(TOPICAL_TERM_HEADING, "earlierHeading", Set.of(RelationshipType.EARLIER_HEADING))); + } + + private static AuthorityDto getAuthorityDtoWithSftTerms() { + AuthorityDto authorityDto = new AuthorityDto(); + authorityDto.setSftBroaderTerm(List.of("broaderTerm1", "broaderTerm2")); + authorityDto.setSftNarrowerTerm(List.of("narrowerTerm", "narrower-later")); + authorityDto.setSftEarlierHeading(List.of("earlierHeading")); + authorityDto.setSftLaterHeading(List.of("laterHeading", "narrower-later")); + authorityDto.setSftPersonalName(List.of(PERSONAL_NAME_HEADING, "broaderTerm1")); + authorityDto.setSftCorporateName(List.of(CORPORATE_NAME_HEADING, "broaderTerm2", "laterHeading")); + authorityDto.setSftMeetingName(List.of(MEETING_NAME_HEADING, "narrowerTerm", "narrower-later")); + authorityDto.setSftTopicalTerm(List.of(TOPICAL_TERM_HEADING, "broaderTerm1", "earlierHeading")); + return authorityDto; + } + + private static AuthorityDto getAuthorityDtoWithSaftTerms() { + AuthorityDto authorityDto = new AuthorityDto(); + authorityDto.setSaftBroaderTerm(List.of("broaderTerm1", "broaderTerm2")); + authorityDto.setSaftNarrowerTerm(List.of("narrowerTerm", "narrower-later")); + authorityDto.setSaftEarlierHeading(List.of("earlierHeading")); + authorityDto.setSaftLaterHeading(List.of("laterHeading", "narrower-later")); + authorityDto.setSaftPersonalName(List.of(PERSONAL_NAME_HEADING, "broaderTerm1")); + authorityDto.setSaftCorporateName(List.of(CORPORATE_NAME_HEADING, "broaderTerm2", "laterHeading")); + authorityDto.setSaftMeetingName(List.of(MEETING_NAME_HEADING, "narrowerTerm", "narrower-later")); + authorityDto.setSaftTopicalTerm(List.of(TOPICAL_TERM_HEADING, "broaderTerm1", "earlierHeading")); + return authorityDto; } } diff --git a/src/test/java/org/folio/entlinks/service/authority/AuthorityServiceTest.java b/src/test/java/org/folio/entlinks/service/authority/AuthorityServiceTest.java index 79e12863..412a69c3 100644 --- a/src/test/java/org/folio/entlinks/service/authority/AuthorityServiceTest.java +++ b/src/test/java/org/folio/entlinks/service/authority/AuthorityServiceTest.java @@ -130,12 +130,6 @@ void shouldUpdateAuthority() { existed.setSftHeadings(List.of(new HeadingRef("personalName", "sft"))); existed.setNotes(List.of(new AuthorityNote(UUID.randomUUID(), "note", true))); existed.setIdentifiers(List.of(new AuthorityIdentifier("identifier", UUID.randomUUID()))); - existed.setAdditionalHeadings(List.of(new HeadingRef("broaderTerm", "broader"), - new HeadingRef("narrowerTerm", "narrower"), - new HeadingRef("earlierHeading", "earlier"), - new HeadingRef("laterHeading", "later"), - new HeadingRef("sftTerm", "sft"), - new HeadingRef("saftTerm", "saft"))); var sourceFileOld = new AuthoritySourceFile(); sourceFileOld.setId(UUID.randomUUID()); existed.setAuthoritySourceFile(sourceFileOld); @@ -151,12 +145,6 @@ void shouldUpdateAuthority() { modified.setSftHeadings(List.of(new HeadingRef("personalNameNew", "sftNew"))); modified.setNotes(List.of(new AuthorityNote(UUID.randomUUID(), "noteNew", true))); modified.setIdentifiers(List.of(new AuthorityIdentifier("identifierNew", UUID.randomUUID()))); - modified.setAdditionalHeadings(List.of(new HeadingRef("broaderTerm", "broaderNew"), - new HeadingRef("narrowerTerm", "narrowerNew"), - new HeadingRef("earlierHeading", "earlierNew"), - new HeadingRef("laterHeading", "laterNew"), - new HeadingRef("sftTerm", "sftNew"), - new HeadingRef("saftTerm", "saftNew"))); var sourceFileNew = new AuthoritySourceFile(); sourceFileNew.setId(UUID.randomUUID()); modified.setAuthoritySourceFile(sourceFileNew); From 9db146ed7bb9e4970cd8bf33b3529a130e45084a Mon Sep 17 00:00:00 2001 From: ElenaShm Date: Fri, 30 Aug 2024 18:04:19 +0300 Subject: [PATCH 3/4] feature/MODELINKS-248 Cover new fields with integration tests --- .../org/folio/entlinks/controller/AuthorityControllerIT.java | 4 ++++ src/test/java/org/folio/support/TestDataUtils.java | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/test/java/org/folio/entlinks/controller/AuthorityControllerIT.java b/src/test/java/org/folio/entlinks/controller/AuthorityControllerIT.java index 9a1ed8f4..dfaeb961 100644 --- a/src/test/java/org/folio/entlinks/controller/AuthorityControllerIT.java +++ b/src/test/java/org/folio/entlinks/controller/AuthorityControllerIT.java @@ -417,6 +417,8 @@ void createAuthority_positive_entityCreatedWithNewId() throws Exception { assertEquals(dto.getIdentifiers(), created.getIdentifiers()); assertEquals(dto.getSftPersonalName(), created.getSftPersonalName()); assertEquals(dto.getSaftPersonalName(), created.getSaftPersonalName()); + assertEquals(dto.getSftNarrowerTerm(), created.getSftNarrowerTerm()); + assertEquals(dto.getSaftBroaderTerm(), created.getSaftBroaderTerm()); } @Test @@ -521,6 +523,8 @@ void updateAuthority_positive_entityUpdated() throws Exception { assertEquals(expected.getSaftPersonalName(), resultDto.getSaftPersonalName()); assertEquals(expected.getSftCorporateName(), resultDto.getSftCorporateName()); assertEquals(expected.getSaftCorporateName(), resultDto.getSaftCorporateName()); + assertEquals(dto.getSftNarrowerTerm(), resultDto.getSftNarrowerTerm()); + assertEquals(dto.getSaftBroaderTerm(), resultDto.getSaftBroaderTerm()); var event = getConsumedEvent(); awaitUntilAsserted(() -> diff --git a/src/test/java/org/folio/support/TestDataUtils.java b/src/test/java/org/folio/support/TestDataUtils.java index 2c29083e..8bfa5a30 100644 --- a/src/test/java/org/folio/support/TestDataUtils.java +++ b/src/test/java/org/folio/support/TestDataUtils.java @@ -412,6 +412,9 @@ public static AuthorityDto authorityDto(int authorityIdNum, int sourceFileIdNum) dto.addSftMeetingNameItem("sftMeetingNameItem2"); dto.addSaftMeetingNameItem("sftMeetingNameItem1"); dto.addSaftMeetingNameItem("sftMeetingNameItem2"); + dto.addSftNarrowerTermItem("sftPersonalName2"); + dto.addSftNarrowerTermItem("sftMeetingNameItem1"); + dto.addSaftBroaderTermItem("saftPersonalName1"); return dto; } From 7b5f55aa6236d1a8e2cb8faa0a3a5679ffe99bd5 Mon Sep 17 00:00:00 2001 From: ElenaShm Date: Fri, 6 Sep 2024 07:36:38 +0300 Subject: [PATCH 4/4] feature/MODELINKS-248 Add description to authorityStatsDto schema --- .../schemas/authority/control/authorityStatsDto.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/resources/swagger.api/schemas/authority/control/authorityStatsDto.json b/src/main/resources/swagger.api/schemas/authority/control/authorityStatsDto.json index 9842e9da..bbf0cfc8 100644 --- a/src/main/resources/swagger.api/schemas/authority/control/authorityStatsDto.json +++ b/src/main/resources/swagger.api/schemas/authority/control/authorityStatsDto.json @@ -14,7 +14,8 @@ "description": "Authority ID" }, "action": { - "$ref": "linkAction.json" + "$ref": "linkAction.json", + "description": "Type of change" }, "naturalIdOld": { "type": "string", @@ -61,7 +62,8 @@ "description": "Amount of linked bib fields that was failed to update during authority update" }, "metadata": { - "$ref": "authorityControlMetadata.json" + "$ref": "authorityControlMetadata.json", + "description": "Meta data for authority control" } } }