From e6e881d6b018b13f8bb9563f032d6812095b8fb2 Mon Sep 17 00:00:00 2001 From: jadz94 Date: Tue, 26 Nov 2024 11:07:45 +0100 Subject: [PATCH 1/5] chore: (ART-10688) refactor ckan mapper --- pom.xml | 13 + .../BeaconIndividualsRequestMapper.java | 11 +- .../ckan/mapper/CkanMapper.java | 100 ++++ .../persistence/CkanDatasetsRepository.java | 11 +- .../ckan/utils/CkanAgentParser.java | 44 -- .../ckan/utils/CkanDatetimeParser.java | 41 -- .../ckan/utils/CkanTagParser.java | 32 -- .../ckan/utils/CkanValueLabelParser.java | 37 -- .../ckan/utils/PackageSearchMapper.java | 45 -- .../ckan/utils/PackageShowMapper.java | 142 ----- .../services/PackageShowMapperTest.java | 483 ++++++++++-------- 11 files changed, 400 insertions(+), 559 deletions(-) create mode 100644 src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanMapper.java delete mode 100644 src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/CkanAgentParser.java delete mode 100644 src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/CkanDatetimeParser.java delete mode 100644 src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/CkanTagParser.java delete mode 100644 src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/CkanValueLabelParser.java delete mode 100644 src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/PackageSearchMapper.java delete mode 100644 src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/PackageShowMapper.java diff --git a/pom.xml b/pom.xml index e998356..6dd1003 100644 --- a/pom.xml +++ b/pom.xml @@ -23,6 +23,7 @@ 3.5.2 1.4.0 0.8.12 + 1.5.5.Final @@ -138,6 +139,17 @@ quarkus-jacoco test + + org.mapstruct + mapstruct + ${mapstruct.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + provided + @@ -172,6 +184,7 @@ -parameters + -Amapstruct.unmappedTargetPolicy=ERROR diff --git a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/beacon/persistence/BeaconIndividualsRequestMapper.java b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/beacon/persistence/BeaconIndividualsRequestMapper.java index 079a12c..fb06914 100644 --- a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/beacon/persistence/BeaconIndividualsRequestMapper.java +++ b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/beacon/persistence/BeaconIndividualsRequestMapper.java @@ -9,10 +9,7 @@ import static java.util.stream.Collectors.toMap; import io.github.genomicdatainfrastructure.discovery.datasets.domain.exceptions.InvalidFacetException; -import io.github.genomicdatainfrastructure.discovery.model.DatasetSearchQuery; -import io.github.genomicdatainfrastructure.discovery.model.DatasetSearchQueryFacet; -import io.github.genomicdatainfrastructure.discovery.model.FilterType; -import io.github.genomicdatainfrastructure.discovery.model.QueryEntry; +import io.github.genomicdatainfrastructure.discovery.model.*; import io.github.genomicdatainfrastructure.discovery.remote.beacon.model.BeaconIndividualsRequest; import io.github.genomicdatainfrastructure.discovery.remote.beacon.model.BeaconIndividualsRequestMeta; import io.github.genomicdatainfrastructure.discovery.remote.beacon.model.BeaconIndividualsRequestQuery; @@ -29,7 +26,7 @@ public class BeaconIndividualsRequestMapper { private static final String BEACON_FACET_GROUP = "beacon"; private static final String SCOPE = "individual"; - private static final String INCLUDE_RESULTSET_RESPONSES = "HIT"; + private static final String INCLUDE_RESULT_SET_RESPONSES = "HIT"; private static final String REQUESTED_GRANULARITY = "record"; public BeaconIndividualsRequest from( @@ -56,7 +53,7 @@ public BeaconIndividualsRequest from( return BeaconIndividualsRequest.builder() .meta(new BeaconIndividualsRequestMeta()) .query(BeaconIndividualsRequestQuery.builder() - .includeResultsetResponses(INCLUDE_RESULTSET_RESPONSES) + .includeResultsetResponses(INCLUDE_RESULT_SET_RESPONSES) .requestedGranularity(REQUESTED_GRANULARITY) .testMode(false) .pagination(new BeaconIndividualsRequestQueryPagination()) @@ -90,7 +87,7 @@ private BeaconIndividualsRequestQueryFilter buildDropdownBeaconFacet( private BeaconIndividualsRequestQueryFilter buildFreeTextBeaconFacet( DatasetSearchQueryFacet facet) { String operator = ofNullable(facet.getOperator()) - .map(it -> it.value()) + .map(Operator::value) .orElseThrow(() -> new InvalidFacetException( "Facet operator must not be null")); diff --git a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanMapper.java b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanMapper.java new file mode 100644 index 0000000..26fb158 --- /dev/null +++ b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanMapper.java @@ -0,0 +1,100 @@ +package io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.mapper; + +import io.github.genomicdatainfrastructure.discovery.model.RetrievedDataset; +import io.github.genomicdatainfrastructure.discovery.model.RetrievedDistribution; +import io.github.genomicdatainfrastructure.discovery.model.SearchedDataset; +import io.github.genomicdatainfrastructure.discovery.model.ValueLabel; +import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.*; +import org.apache.commons.lang3.StringUtils; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.NullValueMappingStrategy; + +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static org.mapstruct.CollectionMappingStrategy.ADDER_PREFERRED; +import static org.mapstruct.NullValueCheckStrategy.ALWAYS; + +@Mapper(componentModel = "jakarta", nullValueCheckStrategy = ALWAYS, nullValueIterableMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT, collectionMappingStrategy = ADDER_PREFERRED) +public interface CkanMapper { + + DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern( + "yyyy-MM-dd'T'HH:mm:ss.SSSSSS"); + + @Mapping(target = "description", source = "notes") + @Mapping(target = "themes", source = "theme") + @Mapping(target = "contacts", source = "contact") + @Mapping(target = "distributions", source = "resources") + @Mapping(target = "keywords", source = "tags") + @Mapping(target = "spatial", source = "spatialUri") + @Mapping(target = "createdAt", source = "issued") + @Mapping(target = "modifiedAt", source = "modified") + @Mapping(target = "creators", source = "creator") + @Mapping(target = "hasVersions", source = "hasVersion") + @Mapping(target = "publishers", source = "publisher") + @Mapping(target = "languages", source = "language") + @Mapping(target = "catalogue", ignore = true) + RetrievedDataset map(CkanPackage ckanPackage); + + @Mapping(target = "label", source = "displayName") + @Mapping(target = "value", source = "name") + @Mapping(target = "count", ignore = true) + ValueLabel map(CkanValueLabel ckanValueLabel); + + @Mapping(target = "label", source = "displayName") + @Mapping(target = "value", source = "name") + @Mapping(target = "count", ignore = true) + ValueLabel map(CkanTag ckanTag); + + @Mapping(target = "title", source = "name") + @Mapping(target = "createdAt", source = "issuedDate") + @Mapping(target = "modifiedAt", source = "modifiedDate") + @Mapping(target = "languages", source = "language") + RetrievedDistribution map(CkanResource ckanResource); + + default List map(PackagesSearchResult result) { + if (result == null || result.getResults() == null) { + return Collections.emptyList(); + } + return result.getResults().stream() + .map(this::mapToSearchedDataset) + .collect(Collectors.toList()); + } + + @Mapping(target = "description", source = "notes") + @Mapping(target = "themes", source = "theme") + @Mapping(target = "publishers", source = "publisher") + @Mapping(target = "keywords", source = "tags") + @Mapping(target = "modifiedAt", source = "modified") + @Mapping(target = "createdAt", source = "issued") + @Mapping(target = "distributionsCount", expression = "java(ckanPackage.getResources()!= null ? ckanPackage.getResources().size():0)") + @Mapping(target = "catalogue", ignore = true) + @Mapping(target = "recordsCount", ignore = true) + SearchedDataset mapToSearchedDataset(CkanPackage ckanPackage); + + default OffsetDateTime map(String date) { + if (StringUtils.isBlank(date)) { + return null; + } + + try { + return OffsetDateTime.parse(date); + } catch (DateTimeParseException e) { + var dateToParse = date; + if (dateToParse.matches("^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$")) { + dateToParse += "T00:00:00.000000"; + } + return LocalDateTime.parse(dateToParse, DATE_FORMATTER) + .truncatedTo(ChronoUnit.SECONDS) + .atOffset(ZoneOffset.UTC); + } + } +} diff --git a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/persistence/CkanDatasetsRepository.java b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/persistence/CkanDatasetsRepository.java index cbcac54..117897f 100644 --- a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/persistence/CkanDatasetsRepository.java +++ b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/persistence/CkanDatasetsRepository.java @@ -6,11 +6,10 @@ import io.github.genomicdatainfrastructure.discovery.datasets.application.ports.DatasetsRepository; import io.github.genomicdatainfrastructure.discovery.datasets.domain.exceptions.DatasetNotFoundException; +import io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.mapper.CkanMapper; import io.github.genomicdatainfrastructure.discovery.model.*; import io.github.genomicdatainfrastructure.discovery.remote.ckan.api.CkanQueryApi; import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.*; -import io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.utils.PackageSearchMapper; -import io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.utils.PackageShowMapper; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.WebApplicationException; @@ -26,12 +25,14 @@ public class CkanDatasetsRepository implements DatasetsRepository { private final CkanQueryApi ckanQueryApi; + private final CkanMapper ckanMapper; @Inject public CkanDatasetsRepository( - @RestClient CkanQueryApi ckanQueryApi + @RestClient CkanQueryApi ckanQueryApi, CkanMapper ckanMapper ) { this.ckanQueryApi = ckanQueryApi; + this.ckanMapper = ckanMapper; } @Override @@ -72,14 +73,14 @@ public List search( request ); - return PackageSearchMapper.from(response.getResult()); + return ckanMapper.map(response.getResult()); } @Override public RetrievedDataset findById(String id, String accessToken) { try { var ckanPackage = ckanQueryApi.packageShow(id); - return PackageShowMapper.from(ckanPackage.getResult()); + return ckanMapper.map(ckanPackage.getResult()); } catch (WebApplicationException e) { if (e.getResponse().getStatus() == 404) { throw new DatasetNotFoundException(id); diff --git a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/CkanAgentParser.java b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/CkanAgentParser.java deleted file mode 100644 index 7bc508b..0000000 --- a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/CkanAgentParser.java +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-FileCopyrightText: 2024 PNED G.I.E. -// -// SPDX-License-Identifier: Apache-2.0 - -package io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.utils; - -import io.github.genomicdatainfrastructure.discovery.model.Agent; -import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.CkanAgent; -import lombok.experimental.UtilityClass; - -import java.util.List; -import java.util.Objects; - -import static java.util.Optional.ofNullable; - -@UtilityClass -public class CkanAgentParser { - - public List agents(List agents) { - return ofNullable(agents) - .orElseGet(List::of) - .stream() - .map(CkanAgentParser::agent) - .filter(Objects::nonNull) - .toList(); - } - - public Agent agent(CkanAgent agent) { - if (agent == null) { - return null; - } - - return Agent.builder() - .name(agent.getName()) - .email(agent.getEmail()) - .url(agent.getUrl()) - .uri(agent.getUri()) - .type(agent.getType()) - .identifier(agent.getIdentifier()) - .build(); - - } - -} diff --git a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/CkanDatetimeParser.java b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/CkanDatetimeParser.java deleted file mode 100644 index b79c126..0000000 --- a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/CkanDatetimeParser.java +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-FileCopyrightText: 2024 PNED G.I.E. -// -// SPDX-License-Identifier: Apache-2.0 - -package io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.utils; - -import lombok.experimental.UtilityClass; -import org.apache.commons.lang3.StringUtils; - -import java.time.LocalDateTime; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; -import java.time.temporal.ChronoUnit; - -// TODO review original field and date format on resources -@UtilityClass -public class CkanDatetimeParser { - - private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern( - "yyyy-MM-dd'T'HH:mm:ss.SSSSSS"); - - public OffsetDateTime datetime(String date) { - if (StringUtils.isBlank(date)) { - return null; - } - - try { - return OffsetDateTime.parse(date); - } catch (DateTimeParseException e) { - var dateToParse = date; - if (dateToParse.matches("^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$")) { - dateToParse += "T00:00:00.000000"; - } - return LocalDateTime.parse(dateToParse, DATE_FORMATTER) - .truncatedTo(ChronoUnit.SECONDS) - .atOffset(ZoneOffset.UTC); - } - } -} diff --git a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/CkanTagParser.java b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/CkanTagParser.java deleted file mode 100644 index 216a85d..0000000 --- a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/CkanTagParser.java +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-FileCopyrightText: 2024 PNED G.I.E. -// -// SPDX-License-Identifier: Apache-2.0 - -package io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.utils; - -import io.github.genomicdatainfrastructure.discovery.model.ValueLabel; -import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.CkanTag; -import lombok.experimental.UtilityClass; - -import java.util.List; - -import static java.util.Optional.ofNullable; - -@UtilityClass -public class CkanTagParser { - - public List keywords(List tags) { - return ofNullable(tags) - .orElseGet(List::of) - .stream() - .map(CkanTagParser::keyword) - .toList(); - } - - private ValueLabel keyword(CkanTag ckanTag) { - return ValueLabel.builder() - .label(ckanTag.getDisplayName()) - .value(ckanTag.getName()) - .build(); - } -} diff --git a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/CkanValueLabelParser.java b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/CkanValueLabelParser.java deleted file mode 100644 index b699909..0000000 --- a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/CkanValueLabelParser.java +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-FileCopyrightText: 2024 PNED G.I.E. -// -// SPDX-License-Identifier: Apache-2.0 - -package io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.utils; - -import io.github.genomicdatainfrastructure.discovery.model.ValueLabel; -import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.CkanValueLabel; -import lombok.experimental.UtilityClass; - -import java.util.List; -import java.util.Objects; - -import static java.util.Optional.ofNullable; - -@UtilityClass -public class CkanValueLabelParser { - - public List values(List values) { - return ofNullable(values) - .orElseGet(List::of) - .stream() - .map(CkanValueLabelParser::value) - .filter(Objects::nonNull) - .toList(); - } - - public ValueLabel value(CkanValueLabel value) { - return ofNullable(value) - .map(it -> ValueLabel.builder() - .value(value.getName()) - .label(value.getDisplayName()) - .build()) - .orElse(null); - - } -} diff --git a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/PackageSearchMapper.java b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/PackageSearchMapper.java deleted file mode 100644 index 769cf66..0000000 --- a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/PackageSearchMapper.java +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-FileCopyrightText: 2024 PNED G.I.E. -// -// SPDX-License-Identifier: Apache-2.0 - -package io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.utils; - -import io.github.genomicdatainfrastructure.discovery.model.SearchedDataset; -import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.*; -import lombok.experimental.UtilityClass; -import org.apache.commons.lang3.ObjectUtils; - -import java.util.List; - -import static java.util.Optional.ofNullable; - -@UtilityClass -public class PackageSearchMapper { - - public List from(PackagesSearchResult result) { - var nonNullPackages = ofNullable(result) - .map(PackagesSearchResult::getResults) - .filter(ObjectUtils::isNotEmpty) - .orElseGet(List::of); - - return nonNullPackages.stream() - .map(PackageSearchMapper::result) - .toList(); - } - - private SearchedDataset result(CkanPackage ckanPackage) { - - return SearchedDataset.builder() - .id(ckanPackage.getId()) - .identifier(ckanPackage.getIdentifier()) - .title(ckanPackage.getTitle()) - .description(ckanPackage.getNotes()) - .themes(CkanValueLabelParser.values(ckanPackage.getTheme())) - .keywords(CkanTagParser.keywords(ckanPackage.getTags())) - .publishers(CkanAgentParser.agents(ckanPackage.getPublisher())) - .modifiedAt(CkanDatetimeParser.datetime(ckanPackage.getModified())) - .createdAt(CkanDatetimeParser.datetime(ckanPackage.getIssued())) - .distributionsCount(ckanPackage.getResources().size()) - .build(); - } -} diff --git a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/PackageShowMapper.java b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/PackageShowMapper.java deleted file mode 100644 index 80d1b1f..0000000 --- a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/utils/PackageShowMapper.java +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-FileCopyrightText: 2024 PNED G.I.E. -// -// SPDX-License-Identifier: Apache-2.0 - -package io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.utils; - -import io.github.genomicdatainfrastructure.discovery.model.*; -import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.*; -import lombok.experimental.UtilityClass; - -import java.util.List; -import java.util.Objects; - -import static java.util.Optional.ofNullable; - -// TODO review original field and date format on resources -@UtilityClass -public class PackageShowMapper { - - public RetrievedDataset from(CkanPackage ckanPackage) { - - return RetrievedDataset.builder() - .id(ckanPackage.getId()) - .identifier(ckanPackage.getIdentifier()) - .title(ckanPackage.getTitle()) - .description(ckanPackage.getNotes()) - .themes(CkanValueLabelParser.values(ckanPackage.getTheme())) - .publishers(CkanAgentParser.agents(ckanPackage.getPublisher())) - .createdAt(CkanDatetimeParser.datetime(ckanPackage.getIssued())) - .modifiedAt(CkanDatetimeParser.datetime(ckanPackage.getModified())) - .url(ckanPackage.getUrl()) - .languages(CkanValueLabelParser.values(ckanPackage.getLanguage())) - .creators(agents(ckanPackage.getCreator())) - .publishers(agents(ckanPackage.getPublisher())) - .hasVersions(CkanValueLabelParser.values(ckanPackage.getHasVersion())) - .accessRights(CkanValueLabelParser.value(ckanPackage.getAccessRights())) - .conformsTo(CkanValueLabelParser.values(ckanPackage.getConformsTo())) - .provenance(ckanPackage.getProvenance()) - .spatial(CkanValueLabelParser.value(ckanPackage.getSpatialUri())) - .distributions(distributions(ckanPackage.getResources())) - .keywords(CkanTagParser.keywords(ckanPackage.getTags())) - .contacts(contactPoint(ckanPackage.getContact())) - .datasetRelationships(relations(ckanPackage.getDatasetRelationships())) - .dataDictionary(dictionary(ckanPackage.getDataDictionary())) - .build(); - } - - private List contactPoint(List values) { - return ofNullable(values) - .orElseGet(List::of) - .stream() - .filter(Objects::nonNull) - .map(PackageShowMapper::contactPointEntry) - .toList(); - } - - private List relations(List values) { - return ofNullable(values) - .orElseGet(List::of) - .stream() - .filter(Objects::nonNull) - .map(PackageShowMapper::relation) - .toList(); - } - - private List dictionary(List values) { - return ofNullable(values) - .orElseGet(List::of) - .stream() - .filter(Objects::nonNull) - .map(PackageShowMapper::dictionaryEntry) - .toList(); - } - - private ContactPoint contactPointEntry(CkanContactPoint value) { - return ContactPoint.builder() - .name(value.getName()) - .email(value.getEmail()) - .uri(value.getUri()) - .identifier(value.getIdentifier()) - .build(); - } - - private DatasetRelationEntry relation(CkanDatasetRelationEntry value) { - return DatasetRelationEntry.builder() - .relation(value.getRelation()) - .target(value.getTarget()) - .build(); - } - - private DatasetDictionaryEntry dictionaryEntry(CkanDatasetDictionaryEntry value) { - return DatasetDictionaryEntry.builder() - .name(value.getName()) - .type(value.getType()) - .description(value.getDescription()) - .build(); - } - - private List distributions(List resources) { - return ofNullable(resources) - .orElseGet(List::of) - .stream() - .map(PackageShowMapper::distribution) - .toList(); - } - - private RetrievedDistribution distribution(CkanResource ckanResource) { - return RetrievedDistribution.builder() - .id(ckanResource.getId()) - .title(ckanResource.getName()) - .description(ckanResource.getDescription()) - .format(CkanValueLabelParser.value(ckanResource.getFormat())) - .createdAt(CkanDatetimeParser.datetime(ckanResource.getIssuedDate())) - .modifiedAt(CkanDatetimeParser.datetime(ckanResource.getModifiedDate())) - .accessUrl(ckanResource.getAccessUrl()) - .downloadUrl(ckanResource.getDownloadUrl()) - .languages(CkanValueLabelParser.values(ckanResource.getLanguage())) - .build(); - } - - private List agents(List creators) { - return ofNullable(creators) - .orElseGet(List::of) - .stream() - .map(PackageShowMapper::agent) - .filter(Objects::nonNull) - .toList(); - } - - private Agent agent(CkanAgent value) { - return ofNullable(value) - .map(it -> Agent.builder() - .name(value.getName()) - .email(value.getEmail()) - .type(value.getType()) - .identifier(value.getIdentifier()) - .url(value.getUrl()) - .uri(value.getUri()) - .build()) - .orElse(null); - } -} diff --git a/src/test/java/io/github/genomicdatainfrastructure/discovery/services/PackageShowMapperTest.java b/src/test/java/io/github/genomicdatainfrastructure/discovery/services/PackageShowMapperTest.java index e9de549..3901060 100644 --- a/src/test/java/io/github/genomicdatainfrastructure/discovery/services/PackageShowMapperTest.java +++ b/src/test/java/io/github/genomicdatainfrastructure/discovery/services/PackageShowMapperTest.java @@ -4,104 +4,214 @@ package io.github.genomicdatainfrastructure.discovery.services; -import io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.utils.PackageShowMapper; +import io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.mapper.CkanMapper; +import io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.mapper.CkanMapperImpl; import io.github.genomicdatainfrastructure.discovery.model.*; import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.*; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Nested; 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; +import java.time.OffsetDateTime; +import java.util.Collections; import java.util.List; +import java.util.stream.Stream; import static java.time.OffsetDateTime.parse; import static org.assertj.core.api.Assertions.assertThat; class PackageShowMapperTest { - @Test - void accepts_empty_package() { - var ckanPackage = CkanPackage.builder().build(); + private final CkanMapper mapper = new CkanMapperImpl(); - var actual = PackageShowMapper.from(ckanPackage); - var expected = RetrievedDataset.builder() - .conformsTo(List.of()) - .distributions(List.of()) - .hasVersions(List.of()) - .languages(List.of()) - .themes(List.of()) - .keywords(List.of()) - .contacts(List.of()) - .creators(List.of()) - .publishers(List.of()) - .datasetRelationships(List.of()) - .dataDictionary(List.of()) - .build(); + @Nested + class RetrievedDatasetTest { + + @Test + void given_ckanPackage_with_empty_collections_should_be_mapped_to_empty_Lists() { + final var ckanPackage = CkanPackage.builder().build(); + + final var actual = mapper.map(ckanPackage); + final var expected = RetrievedDataset.builder() + .conformsTo(List.of()) + .distributions(List.of()) + .hasVersions(List.of()) + .languages(List.of()) + .themes(List.of()) + .keywords(List.of()) + .contacts(List.of()) + .creators(List.of()) + .publishers(List.of()) + .datasetRelationships(List.of()) + .dataDictionary(List.of()) + .build(); + + assertThat(actual) + .usingRecursiveComparison() + .isEqualTo(expected); + } + + @Test + void given_ckanPackage_should_be_mapped_to_expected_values() { + final var ckanPackage = buildCkanPackage(); - assertThat(actual) - .usingRecursiveComparison() - .isEqualTo(expected); + final var actual = mapper.map(ckanPackage); + final var expected = RetrievedDataset.builder() + .id("id") + .identifier("identifier") + .title("title") + .description("notes") + .themes(List.of( + ValueLabel.builder() + .value("theme-name") + .label("theme") + .build())) + .createdAt(parse("2024-07-01T22:00:00+00:00")) + .modifiedAt(parse("2024-07-02T22:00:00+00:00")) + .url("url") + .languages(List.of( + ValueLabel.builder() + .value("en") + .label("language") + .build())) + .hasVersions(List.of( + ValueLabel.builder() + .value("1") + .label("version") + .build())) + .creators(List.of( + Agent.builder() + .name("creatorName") + .identifier("creatorIdentifier") + .email("email") + .url("url") + .type("type") + .uri("uri") + .build(), + Agent.builder() + .name("creatorName2") + .identifier("creatorIdentifier2") + .email("email2") + .url("url2") + .type("type2") + .uri("uri2") + .build() + )) + .publishers(List.of( + Agent.builder() + .name("publisherName") + .identifier("publisherIdentifier") + .email("email") + .url("url") + .type("type") + .uri("uri") + .build(), + Agent.builder() + .name("publisherName2") + .identifier("publisherIdentifier2") + .email("email2") + .url("url2") + .type("type2") + .uri("uri2") + .build() + )) + .accessRights(ValueLabel.builder() + .value("public") + .label("accessRights") + .build()) + .conformsTo(List.of( + ValueLabel.builder() + .value("conforms") + .label("conformsTo") + .build())) + .provenance("provenance") + .keywords(List.of(ValueLabel.builder() + .label("key-tag") + .value("key") + .build())) + .spatial(ValueLabel.builder() + .value("uri") + .label("spatial") + .build()) + .distributions(List.of( + RetrievedDistribution.builder() + .id("resource_id") + .title("resource_name") + .description("resource_description") + .createdAt(parse("2025-03-19T00:00Z")) + .modifiedAt(parse("2025-03-19T13:37:05Z")) + .format(ValueLabel.builder() + .value("pdf") + .label("format") + .build()) + .accessUrl("accessUrl") + .downloadUrl("downloadUrl") + .languages(List.of( + ValueLabel.builder() + .value("en") + .label("language") + .build())) + .build())) + .contacts(List.of( + ContactPoint.builder() + .name("Contact 1") + .email("contact1@example.com") + .identifier("contact-identifier-1") + .build(), + ContactPoint.builder() + .name("Contact 2") + .email("contact2@example.com") + .uri("http://example.com") + .identifier("contact-identifier-2") + .build() + )) + .datasetRelationships(List.of( + DatasetRelationEntry.builder().relation("Relation 1") + .target("Dataset 1") + .build(), + DatasetRelationEntry.builder().relation("Relation 2") + .target("Dataset 2") + .build() + )) + .dataDictionary(List.of( + DatasetDictionaryEntry.builder().name("Entry 1").type("Type 1") + .description( + "Description 1") + .build(), + DatasetDictionaryEntry.builder().name("Entry 2").type("Type 2") + .description( + "Description 2") + .build() + )) + .build(); + + assertThat(actual) + .usingRecursiveComparison() + .isEqualTo(expected); + } } - @Test - void can_parse() { - var ckanPackage = CkanPackage.builder() + private static CkanPackage buildCkanPackage() { + return CkanPackage.builder() .id("id") .identifier("identifier") .title("title") .notes("notes") - .theme(List.of(CkanValueLabel.builder() - .displayName("theme") - .name("theme-name") - .build())) + .theme(getValueLabels("theme", "theme-name")) .issued("2024-07-01T22:00:00+00:00") .modified("2024-07-02T22:00:00Z") - .tags(List.of(CkanTag.builder() - .displayName("key-tag") - .id("tag-id") - .name("key") - .build())) + .tags(getCkanTags()) .url("url") - .language(List.of( - CkanValueLabel.builder() - .displayName("language") - .name("en") - .build())) - .hasVersion(List.of( - CkanValueLabel.builder() - .displayName("version") - .name("1") - .build())) - .accessRights(CkanValueLabel.builder() - .displayName("accessRights") - .name("public") - .build()) - .conformsTo(List.of( - CkanValueLabel.builder() - .displayName("conformsTo") - .name("conforms") - .build())) + .language(getValueLabels("language", "en")) + .hasVersion(getValueLabels("version", "1")) + .accessRights(getCkanValueLabel("accessRights", "public")) + .conformsTo(getValueLabels("conformsTo", "conforms")) .provenance("provenance") - .spatialUri(CkanValueLabel.builder() - .displayName("spatial") - .name("uri") - .build()) - .resources(List.of( - CkanResource.builder() - .id("resource_id") - .name("resource_name") - .description("resource_description") - .format(CkanValueLabel.builder() - .displayName("format") - .name("pdf") - .build()) - .accessUrl("accessUrl") - .downloadUrl("downloadUrl") - .issuedDate("2025-03-19") - .modifiedDate("2025-03-19T13:37:05Z") - .language(List.of( - CkanValueLabel.builder() - .displayName("language") - .name("en") - .build())) - .build())) + .spatialUri(getCkanValueLabel("spatial", "uri")) + .resources(getCkanResources()) .contact(List.of( CkanContactPoint.builder() .name("Contact 1") @@ -164,139 +274,100 @@ void can_parse() { .description("Description 2").build() )) .build(); + } - var actual = PackageShowMapper.from(ckanPackage); - var expected = RetrievedDataset.builder() - .id("id") - .identifier("identifier") - .title("title") - .description("notes") - .themes(List.of( - ValueLabel.builder() - .value("theme-name") - .label("theme") - .build())) - .createdAt(parse("2024-07-01T22:00:00+00:00")) - .modifiedAt(parse("2024-07-02T22:00:00+00:00")) - .url("url") - .languages(List.of( - ValueLabel.builder() - .value("en") - .label("language") - .build())) - .hasVersions(List.of( - ValueLabel.builder() - .value("1") - .label("version") - .build())) - .creators(List.of( - Agent.builder() - .name("creatorName") - .identifier("creatorIdentifier") - .email("email") - .url("url") - .type("type") - .uri("uri") - .build(), - Agent.builder() - .name("creatorName2") - .identifier("creatorIdentifier2") - .email("email2") - .url("url2") - .type("type2") - .uri("uri2") - .build() - )) - .publishers(List.of( - Agent.builder() - .name("publisherName") - .identifier("publisherIdentifier") - .email("email") - .url("url") - .type("type") - .uri("uri") - .build(), - Agent.builder() - .name("publisherName2") - .identifier("publisherIdentifier2") - .email("email2") - .url("url2") - .type("type2") - .uri("uri2") - .build() - )) - .accessRights(ValueLabel.builder() - .value("public") - .label("accessRights") - .build()) - .conformsTo(List.of( - ValueLabel.builder() - .value("conforms") - .label("conformsTo") - .build())) - .provenance("provenance") - .keywords(List.of(ValueLabel.builder() - .label("key-tag") - .value("key") - .build())) - .spatial(ValueLabel.builder() - .value("uri") - .label("spatial") - .build()) - .distributions(List.of( - RetrievedDistribution.builder() - .id("resource_id") - .title("resource_name") - .description("resource_description") - .createdAt(parse("2025-03-19T00:00Z")) - .modifiedAt(parse("2025-03-19T13:37:05Z")) - .format(ValueLabel.builder() - .value("pdf") - .label("format") - .build()) - .accessUrl("accessUrl") - .downloadUrl("downloadUrl") - .languages(List.of( - ValueLabel.builder() - .value("en") - .label("language") - .build())) - .build())) - .contacts(List.of( - ContactPoint.builder() - .name("Contact 1") - .email("contact1@example.com") - .identifier("contact-identifier-1") - .build(), - ContactPoint.builder() - .name("Contact 2") - .email("contact2@example.com") - .uri("http://example.com") - .identifier("contact-identifier-2") - .build() - )) - .datasetRelationships(List.of( - DatasetRelationEntry.builder().relation("Relation 1") - .target("Dataset 1") - .build(), - DatasetRelationEntry.builder().relation("Relation 2") - .target("Dataset 2") - .build() - )) - .dataDictionary(List.of( - DatasetDictionaryEntry.builder().name("Entry 1").type("Type 1") - .description( - "Description 1") - .build(), - DatasetDictionaryEntry.builder().name("Entry 2").type("Type 2") - .description( - "Description 2") - .build() - )) + @Nested + class SearchedDatasetTest { + + static Stream arguments() { + return Stream.of( + Arguments.of(null, Collections.emptyList()), // null strings should be considered blank + Arguments.of(PackagesSearchResult.builder().results(Collections.emptyList()) + .build(), Collections.emptyList()), + Arguments.of(PackagesSearchResult.builder().results(List.of(buildCkanPackage())) + .build(), List.of(buildSearchedDataset())) + ); + } + + @ParameterizedTest + @MethodSource("arguments") + void given_list_of_SearchedDataset_it_should_be_mapped_properly(PackagesSearchResult result, + List expected) { + final var actual = mapper.map(result); + assertThat(actual) + .usingRecursiveComparison() + .isEqualTo(expected); + } + + @NotNull + private static SearchedDataset buildSearchedDataset() { + return SearchedDataset.builder() + .id("id") + .identifier("identifier") + .title("title") + .description("notes") + .publishers(List.of(Agent.builder() + .name("publisherName") + .email("email") + .url("url") + .identifier("publisherIdentifier") + .uri("uri") + .type("type") + .build(), + Agent.builder() + .name("publisherName2") + .email("email2") + .url("url2") + .identifier("publisherIdentifier2") + .uri("uri2") + .type("type2") + .build())) + .themes(List.of(ValueLabel.builder() + .value("theme-name") + .label("theme") + .build())) + .keywords(List.of(ValueLabel.builder() + .value("key") + .label("key-tag") + .build())) + .modifiedAt(OffsetDateTime.parse("2024-07-02T22:00Z")) + .createdAt(OffsetDateTime.parse("2024-07-01T22:00Z")) + .distributionsCount(1) + .build(); + } + } + + private static @NotNull List getCkanResources() { + return List.of( + CkanResource.builder() + .id("resource_id") + .name("resource_name") + .description("resource_description") + .format(getCkanValueLabel("format", "pdf")) + .accessUrl("accessUrl") + .downloadUrl("downloadUrl") + .issuedDate("2025-03-19") + .modifiedDate("2025-03-19T13:37:05Z") + .language(getValueLabels("language", "en")) + .build()); + } + + private static CkanValueLabel getCkanValueLabel(String spatial, String uri) { + return CkanValueLabel.builder() + .displayName(spatial) + .name(uri) .build(); + } + + private static @NotNull List getCkanTags() { + return List.of(CkanTag.builder() + .displayName("key-tag") + .id("tag-id") + .name("key") + .build()); + } - assertThat(actual) - .usingRecursiveComparison() - .isEqualTo(expected); + private static @NotNull List getValueLabels(String theme, String name) { + return List.of(getCkanValueLabel(theme, name)); } } From 3dbe99dde3b808c0ac335b1294651074d4961155 Mon Sep 17 00:00:00 2001 From: jadz94 Date: Tue, 26 Nov 2024 11:09:50 +0100 Subject: [PATCH 2/5] chore: (ART-10688) update license --- .../datasets/infrastructure/ckan/mapper/CkanMapper.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanMapper.java b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanMapper.java index 26fb158..39642be 100644 --- a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanMapper.java +++ b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanMapper.java @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2024 PNED G.I.E. +// +// SPDX-License-Identifier: Apache-2.0 + package io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.mapper; import io.github.genomicdatainfrastructure.discovery.model.RetrievedDataset; From 670f9a7ac70ca486248fb6425504511006afafd3 Mon Sep 17 00:00:00 2001 From: jadz94 Date: Tue, 26 Nov 2024 16:55:04 +0100 Subject: [PATCH 3/5] chore: (ART-10688) refactor --- .../datasets/infrastructure/ckan/mapper/CkanMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanMapper.java b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanMapper.java index 39642be..382a7b7 100644 --- a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanMapper.java +++ b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanMapper.java @@ -70,7 +70,7 @@ default List map(PackagesSearchResult result) { } return result.getResults().stream() .map(this::mapToSearchedDataset) - .collect(Collectors.toList()); + .toList(); } @Mapping(target = "description", source = "notes") From e97062ace9d8638a497b450be3e55bd4686105eb Mon Sep 17 00:00:00 2001 From: jadz94 Date: Fri, 29 Nov 2024 14:26:57 +0100 Subject: [PATCH 4/5] chore: (ART-10688) polishing --- ...kanMapper.java => CkanDatasetsMapper.java} | 3 +- .../persistence/CkanDatasetsRepository.java | 12 ++-- .../ckan/CkanFiltersRepository.java | 42 +++-------- .../mapper/CkanFilterMapper.java | 54 ++++++++++++++ .../ckan/mapper/CkanDatasetsMapperTest.java} | 8 +-- .../mapper/CkanFilterMapperTest.java | 72 +++++++++++++++++++ 6 files changed, 146 insertions(+), 45 deletions(-) rename src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/{CkanMapper.java => CkanDatasetsMapper.java} (98%) create mode 100644 src/main/java/io/github/genomicdatainfrastructure/discovery/filters/infrastructure/mapper/CkanFilterMapper.java rename src/test/java/io/github/genomicdatainfrastructure/discovery/{services/PackageShowMapperTest.java => datasets/infrastructure/ckan/mapper/CkanDatasetsMapperTest.java} (97%) create mode 100644 src/test/java/io/github/genomicdatainfrastructure/discovery/filters/infrastructure/mapper/CkanFilterMapperTest.java diff --git a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanMapper.java b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanDatasetsMapper.java similarity index 98% rename from src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanMapper.java rename to src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanDatasetsMapper.java index 382a7b7..37b4113 100644 --- a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanMapper.java +++ b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanDatasetsMapper.java @@ -22,13 +22,12 @@ import java.time.temporal.ChronoUnit; import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; import static org.mapstruct.CollectionMappingStrategy.ADDER_PREFERRED; import static org.mapstruct.NullValueCheckStrategy.ALWAYS; @Mapper(componentModel = "jakarta", nullValueCheckStrategy = ALWAYS, nullValueIterableMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT, collectionMappingStrategy = ADDER_PREFERRED) -public interface CkanMapper { +public interface CkanDatasetsMapper { DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern( "yyyy-MM-dd'T'HH:mm:ss.SSSSSS"); diff --git a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/persistence/CkanDatasetsRepository.java b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/persistence/CkanDatasetsRepository.java index 117897f..b8f1a07 100644 --- a/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/persistence/CkanDatasetsRepository.java +++ b/src/main/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/persistence/CkanDatasetsRepository.java @@ -6,7 +6,7 @@ import io.github.genomicdatainfrastructure.discovery.datasets.application.ports.DatasetsRepository; import io.github.genomicdatainfrastructure.discovery.datasets.domain.exceptions.DatasetNotFoundException; -import io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.mapper.CkanMapper; +import io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.mapper.CkanDatasetsMapper; import io.github.genomicdatainfrastructure.discovery.model.*; import io.github.genomicdatainfrastructure.discovery.remote.ckan.api.CkanQueryApi; import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.*; @@ -25,14 +25,14 @@ public class CkanDatasetsRepository implements DatasetsRepository { private final CkanQueryApi ckanQueryApi; - private final CkanMapper ckanMapper; + private final CkanDatasetsMapper ckanDatasetsMapper; @Inject public CkanDatasetsRepository( - @RestClient CkanQueryApi ckanQueryApi, CkanMapper ckanMapper + @RestClient CkanQueryApi ckanQueryApi, CkanDatasetsMapper ckanDatasetsMapper ) { this.ckanQueryApi = ckanQueryApi; - this.ckanMapper = ckanMapper; + this.ckanDatasetsMapper = ckanDatasetsMapper; } @Override @@ -73,14 +73,14 @@ public List search( request ); - return ckanMapper.map(response.getResult()); + return ckanDatasetsMapper.map(response.getResult()); } @Override public RetrievedDataset findById(String id, String accessToken) { try { var ckanPackage = ckanQueryApi.packageShow(id); - return ckanMapper.map(ckanPackage.getResult()); + return ckanDatasetsMapper.map(ckanPackage.getResult()); } catch (WebApplicationException e) { if (e.getResponse().getStatus() == 404) { throw new DatasetNotFoundException(id); diff --git a/src/main/java/io/github/genomicdatainfrastructure/discovery/filters/infrastructure/ckan/CkanFiltersRepository.java b/src/main/java/io/github/genomicdatainfrastructure/discovery/filters/infrastructure/ckan/CkanFiltersRepository.java index ca462fa..224e3f6 100644 --- a/src/main/java/io/github/genomicdatainfrastructure/discovery/filters/infrastructure/ckan/CkanFiltersRepository.java +++ b/src/main/java/io/github/genomicdatainfrastructure/discovery/filters/infrastructure/ckan/CkanFiltersRepository.java @@ -4,6 +4,7 @@ package io.github.genomicdatainfrastructure.discovery.filters.infrastructure.ckan; import io.github.genomicdatainfrastructure.discovery.filters.application.ports.FiltersRepository; +import io.github.genomicdatainfrastructure.discovery.filters.infrastructure.mapper.CkanFilterMapper; import io.github.genomicdatainfrastructure.discovery.model.ValueLabel; import io.github.genomicdatainfrastructure.discovery.remote.ckan.api.CkanQueryApi; import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.CkanFacet; @@ -23,52 +24,29 @@ public class CkanFiltersRepository implements FiltersRepository { private static final String SELECTED_FACETS_PATTERN = "[\"%s\"]"; private final CkanQueryApi ckanQueryApi; + private final CkanFilterMapper ckanFilterMapper; - public CkanFiltersRepository(@RestClient CkanQueryApi ckanQueryApi) { + public CkanFiltersRepository(@RestClient CkanQueryApi ckanQueryApi, + CkanFilterMapper ckanFilterMapper) { this.ckanQueryApi = ckanQueryApi; + this.ckanFilterMapper = ckanFilterMapper; } @Override - public List getValuesForFilter(String key) { + public List getValuesForFilter(final String key) { - var facetField = SELECTED_FACETS_PATTERN.formatted(key); + final var facetField = SELECTED_FACETS_PATTERN.formatted(key); - var request = PackageSearchRequest.builder() + final var request = PackageSearchRequest.builder() .facetField(facetField) .rows(0) .facetLimit(-1) .build(); - var response = ckanQueryApi.packageSearch( + final var response = ckanQueryApi.packageSearch( request ); - - var ckanFacet = ofNullable(response.getResult()) - .map(PackagesSearchResult::getSearchFacets) - .orElseGet(Map::of) - .get(key); - if (ckanFacet == null) { - return List.of(); - } - return filters(ckanFacet); - + return ckanFilterMapper.map(response, key); } - - private List filters(CkanFacet facet) { - - var values = ofNullable(facet.getItems()) - .orElseGet(List::of) - .stream() - .map(value -> ValueLabel.builder() - .value(value.getName()) - .label(value.getDisplayName()) - .count(value.getCount()) - .build() - ) - .toList(); - - return values; - } - } diff --git a/src/main/java/io/github/genomicdatainfrastructure/discovery/filters/infrastructure/mapper/CkanFilterMapper.java b/src/main/java/io/github/genomicdatainfrastructure/discovery/filters/infrastructure/mapper/CkanFilterMapper.java new file mode 100644 index 0000000..97abce7 --- /dev/null +++ b/src/main/java/io/github/genomicdatainfrastructure/discovery/filters/infrastructure/mapper/CkanFilterMapper.java @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2024 PNED G.I.E. +// +// SPDX-License-Identifier: Apache-2.0 + +package io.github.genomicdatainfrastructure.discovery.filters.infrastructure.mapper; + +import io.github.genomicdatainfrastructure.discovery.model.ValueLabel; +import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.CkanFacet; +import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.CkanValueLabel; +import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.PackagesSearchResponse; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.NullValueMappingStrategy; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static org.mapstruct.CollectionMappingStrategy.ADDER_PREFERRED; +import static org.mapstruct.NullValueCheckStrategy.ALWAYS; + +@Mapper(componentModel = "jakarta", nullValueCheckStrategy = ALWAYS, nullValueIterableMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT, collectionMappingStrategy = ADDER_PREFERRED) +public interface CkanFilterMapper { + + default List map(final PackagesSearchResponse packagesSearchResponse, + final String key) { + if (Objects.isNull(packagesSearchResponse) || Objects.isNull(packagesSearchResponse + .getResult())) { + return Collections.emptyList(); + } + return map(packagesSearchResponse.getResult().getSearchFacets(), key); + } + + default List map(final Map ckanFacets, final String key) { + if (Objects.isNull(ckanFacets)) { + return Collections.emptyList(); + } + return map(ckanFacets.get(key)); + } + + default List map(final CkanFacet ckanFacet) { + if (Objects.isNull(ckanFacet)) { + return Collections.emptyList(); + } + return map(ckanFacet.getItems()); + } + + List map(final List items); + + @Mapping(target = "value", source = "name") + @Mapping(target = "label", source = "displayName") + ValueLabel map(final CkanValueLabel valueLabel); +} diff --git a/src/test/java/io/github/genomicdatainfrastructure/discovery/services/PackageShowMapperTest.java b/src/test/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanDatasetsMapperTest.java similarity index 97% rename from src/test/java/io/github/genomicdatainfrastructure/discovery/services/PackageShowMapperTest.java rename to src/test/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanDatasetsMapperTest.java index 3901060..183aff1 100644 --- a/src/test/java/io/github/genomicdatainfrastructure/discovery/services/PackageShowMapperTest.java +++ b/src/test/java/io/github/genomicdatainfrastructure/discovery/datasets/infrastructure/ckan/mapper/CkanDatasetsMapperTest.java @@ -2,10 +2,8 @@ // // SPDX-License-Identifier: Apache-2.0 -package io.github.genomicdatainfrastructure.discovery.services; +package io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.mapper; -import io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.mapper.CkanMapper; -import io.github.genomicdatainfrastructure.discovery.datasets.infrastructure.ckan.mapper.CkanMapperImpl; import io.github.genomicdatainfrastructure.discovery.model.*; import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.*; import org.jetbrains.annotations.NotNull; @@ -23,9 +21,9 @@ import static java.time.OffsetDateTime.parse; import static org.assertj.core.api.Assertions.assertThat; -class PackageShowMapperTest { +class CkanDatasetsMapperTest { - private final CkanMapper mapper = new CkanMapperImpl(); + private final CkanDatasetsMapper mapper = new CkanDatasetsMapperImpl(); @Nested class RetrievedDatasetTest { diff --git a/src/test/java/io/github/genomicdatainfrastructure/discovery/filters/infrastructure/mapper/CkanFilterMapperTest.java b/src/test/java/io/github/genomicdatainfrastructure/discovery/filters/infrastructure/mapper/CkanFilterMapperTest.java new file mode 100644 index 0000000..d14145b --- /dev/null +++ b/src/test/java/io/github/genomicdatainfrastructure/discovery/filters/infrastructure/mapper/CkanFilterMapperTest.java @@ -0,0 +1,72 @@ +package io.github.genomicdatainfrastructure.discovery.filters.infrastructure.mapper; + +import io.github.genomicdatainfrastructure.discovery.model.ValueLabel; +import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.CkanFacet; +import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.CkanValueLabel; +import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.PackagesSearchResponse; +import io.github.genomicdatainfrastructure.discovery.remote.ckan.model.PackagesSearchResult; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; + +class CkanFilterMapperTest { + + private final CkanFilterMapper mapper = new CkanFilterMapperImpl(); + + static Stream edgeCases() { + return Stream.of( + null, + new PackagesSearchResponse().result(null), + new PackagesSearchResponse().result(new PackagesSearchResult().searchFacets(null)), + new PackagesSearchResponse().result(new PackagesSearchResult().searchFacets(Map.of( + "", new CkanFacet())))); + } + + @ParameterizedTest + @MethodSource("edgeCases") + void given_PackagesSearchResponse_but_with_null_objects_should_return_emptyList( + PackagesSearchResponse input) { + final var actual = mapper.map(input, "randomKey"); + assertThat(actual).isEmpty(); + } + + @Test + void given_PackagesSearchResponse_with_valid_input_should_return_expected_ListOfValueLabel() { + final var input = new PackagesSearchResponse() + .result(new PackagesSearchResult().searchFacets( + Map.of("requestedKey", new CkanFacet() + .items(List.of(new CkanValueLabel() + .name("CkanValueName1") + .count(1), + new CkanValueLabel() + .name("CkanValueName2") + .displayName("CkanValueDisplayName2"), + new CkanValueLabel() + .displayName("CkanValueDisplayName3") + .count(3))), + "notRequestedKey", new CkanFacet()) + )); + final var expected = List.of(new ValueLabel() + .value("CkanValueName1") + .count(1), + new ValueLabel() + .value("CkanValueName2") + .label("CkanValueDisplayName2"), + new ValueLabel() + .label("CkanValueDisplayName3") + .count(3) + ); + + final var actual = mapper.map(input, "requestedKey"); + + assertThat(actual).isNotEmpty(); + assertThat(actual).usingRecursiveComparison() + .isEqualTo(expected); + } +} \ No newline at end of file From 350c818aae7fc5f1d83b769a802b3a07bc2ada67 Mon Sep 17 00:00:00 2001 From: jadz94 Date: Fri, 29 Nov 2024 14:28:13 +0100 Subject: [PATCH 5/5] chore: (ART-10688) polishing --- .../filters/infrastructure/mapper/CkanFilterMapperTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/io/github/genomicdatainfrastructure/discovery/filters/infrastructure/mapper/CkanFilterMapperTest.java b/src/test/java/io/github/genomicdatainfrastructure/discovery/filters/infrastructure/mapper/CkanFilterMapperTest.java index d14145b..f279eec 100644 --- a/src/test/java/io/github/genomicdatainfrastructure/discovery/filters/infrastructure/mapper/CkanFilterMapperTest.java +++ b/src/test/java/io/github/genomicdatainfrastructure/discovery/filters/infrastructure/mapper/CkanFilterMapperTest.java @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2024 PNED G.I.E. +// +// SPDX-License-Identifier: Apache-2.0 + package io.github.genomicdatainfrastructure.discovery.filters.infrastructure.mapper; import io.github.genomicdatainfrastructure.discovery.model.ValueLabel;