diff --git a/backend/src/main/java/fr/inra/urgi/faidare/repository/es/GermplasmRepository.java b/backend/src/main/java/fr/inra/urgi/faidare/repository/es/GermplasmRepository.java index 7c12185204b63e1ed9a3ccd6e6c9da7092a91dca..8fbd47d1273fcd733a96d6c0543bc5b1d6a133d1 100644 --- a/backend/src/main/java/fr/inra/urgi/faidare/repository/es/GermplasmRepository.java +++ b/backend/src/main/java/fr/inra/urgi/faidare/repository/es/GermplasmRepository.java @@ -58,6 +58,11 @@ public interface GermplasmRepository */ Iterator<GermplasmMcpdVO> scrollGermplasmMcpdsByIds(Set<String> ids, int fetchSize); + /** + * Scroll through all germplasm having one of the given IDs. + */ + Iterator<GermplasmVO> scrollGermplasmsByIds(Set<String> ids, int fetchSize); + /** * Find pedigree for germplasm by id. */ diff --git a/backend/src/main/java/fr/inra/urgi/faidare/repository/es/GermplasmRepositoryImpl.java b/backend/src/main/java/fr/inra/urgi/faidare/repository/es/GermplasmRepositoryImpl.java index 616a33d7e6083e9f1abc027f590b692a9a17573e..d5af326a0bb8df2f51206c0408ac2c6cc060255c 100644 --- a/backend/src/main/java/fr/inra/urgi/faidare/repository/es/GermplasmRepositoryImpl.java +++ b/backend/src/main/java/fr/inra/urgi/faidare/repository/es/GermplasmRepositoryImpl.java @@ -125,6 +125,13 @@ public class GermplasmRepositoryImpl implements GermplasmRepository { return new ESScrollIterator<>(client, requestFactory, parser, GermplasmMcpdVO.class, query, fetchSize); } + @Override + public Iterator<GermplasmVO> scrollGermplasmsByIds(Set<String> ids, + int fetchSize) { + QueryBuilder query = QueryBuilders.termsQuery("germplasmDbId", ids); + return new ESScrollIterator<>(client, requestFactory, parser, GermplasmVO.class, query, fetchSize); + } + @Override public GermplasmVO getById(String germplasmDbId) { return getByIdRepository.getById(germplasmDbId); diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmController.java b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmController.java index bfe7d484cb1b5afaed7e17f239db0c29ec5e8153..9cf89be05915532b1bc418c32108f865dfd330ac 100644 --- a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmController.java +++ b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmController.java @@ -49,17 +49,20 @@ public class GermplasmController { private final FaidareProperties faidareProperties; private final XRefDocumentRepository xRefDocumentRepository; private final GermplasmAttributeRepository germplasmAttributeRepository; + private final GermplasmMcpdExportService germplasmMcpdExportService; private final GermplasmExportService germplasmExportService; public GermplasmController(GermplasmRepository germplasmRepository, FaidareProperties faidareProperties, XRefDocumentRepository xRefDocumentRepository, GermplasmAttributeRepository germplasmAttributeRepository, + GermplasmMcpdExportService germplasmMcpdExportService, GermplasmExportService germplasmExportService) { this.germplasmRepository = germplasmRepository; this.faidareProperties = faidareProperties; this.xRefDocumentRepository = xRefDocumentRepository; this.germplasmAttributeRepository = germplasmAttributeRepository; + this.germplasmMcpdExportService = germplasmMcpdExportService; this.germplasmExportService = germplasmExportService; } @@ -86,13 +89,25 @@ public class GermplasmController { return toModelAndView(germplasms.get(0)); } - @PostMapping("/exports") + @PostMapping("/exports/mcpd") + @ResponseBody + public ResponseEntity<StreamingResponseBody> export(@Validated @RequestBody GermplasmMcpdExportCommand command) { + List<GermplasmMcpdExportableField> fields = getFieldsToExport(command); + + StreamingResponseBody body = out -> { + Iterator<GermplasmMcpdVO> iterator = germplasmRepository.scrollGermplasmMcpdsByIds(command.getIds(), 1000); + germplasmMcpdExportService.export(out, iterator, fields); + }; + return ResponseEntity.ok().contentType(MediaType.parseMediaType("text/csv")).body(body); + } + + @PostMapping("/exports/plant-material") @ResponseBody public ResponseEntity<StreamingResponseBody> export(@Validated @RequestBody GermplasmExportCommand command) { List<GermplasmExportableField> fields = getFieldsToExport(command); StreamingResponseBody body = out -> { - Iterator<GermplasmMcpdVO> iterator = germplasmRepository.scrollGermplasmMcpdsByIds(command.getIds(), 1000); + Iterator<GermplasmVO> iterator = germplasmRepository.scrollGermplasmsByIds(command.getIds(), 1000); germplasmExportService.export(out, iterator, fields); }; return ResponseEntity.ok().contentType(MediaType.parseMediaType("text/csv")).body(body); @@ -192,7 +207,17 @@ public class GermplasmController { return germplasmRepository.findPedigree(germplasm.getGermplasmDbId()); } - private List<GermplasmExportableField> getFieldsToExport(GermplasmExportCommand command) { + private List<GermplasmMcpdExportableField> getFieldsToExport( + GermplasmMcpdExportCommand command) { + List<GermplasmMcpdExportableField> fields = command.getFields(); + if (fields.isEmpty()) { + fields = Arrays.asList(GermplasmMcpdExportableField.values()); + } + return fields; + } + + private List<GermplasmExportableField> getFieldsToExport( + GermplasmExportCommand command) { List<GermplasmExportableField> fields = command.getFields(); if (fields.isEmpty()) { fields = Arrays.asList(GermplasmExportableField.values()); diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportService.java b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportService.java index dc8289ffdeff97c140b4f298ed62f0ae03dc2a82..b17538a92f5edf80493c0dcdf6374a3118030e95 100644 --- a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportService.java +++ b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportService.java @@ -17,9 +17,9 @@ import java.util.function.Function; import java.util.stream.Collectors; import com.opencsv.CSVWriter; -import fr.inra.urgi.faidare.domain.data.germplasm.DonorInfoVO; +import fr.inra.urgi.faidare.domain.data.germplasm.CollPopVO; import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmMcpdVO; -import fr.inra.urgi.faidare.domain.data.germplasm.InstituteVO; +import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmVO; import org.springframework.stereotype.Component; /** @@ -34,85 +34,19 @@ public class GermplasmExportService { public GermplasmExportService() { Map<GermplasmExportableField, GermplasmExportableFieldDescriptor> map = new HashMap<>(); - map.put(PUID, withFieldAsHeader(PUID, vo -> vo.getGermplasmPUI())); - map.put(INSTCODE, withFieldAsHeader(INSTCODE, vo -> vo.getInstituteCode())); - map.put(ACCENUMB, withFieldAsHeader(ACCENUMB, vo -> vo.getAccessionNumber())); - map.put(COLLNUMB, withFieldAsHeader(COLLNUMB, vo -> vo.getCollectingInfo().getCollectingNumber())); - map.put(COLLCODE, withFieldAsHeader(COLLCODE, vo -> - vo.getCollectingInfo() - .getCollectingInstitutes() - .stream() - .map(InstituteVO::getInstituteCode).collect(Collectors.joining(";")))); - map.put(COLLNAME, withFieldAsHeader(COLLNAME, vo -> - vo.getCollectingInfo() - .getCollectingInstitutes() - .stream() - .map(InstituteVO::getInstituteName) - .collect(Collectors.joining(";")))); - map.put(COLLINSTADDRESS, withFieldAsHeader(COLLINSTADDRESS, vo -> - vo.getCollectingInfo() - .getCollectingInstitutes() - .stream() - .map(InstituteVO::getAddress) - .collect(Collectors.joining(";")))); - map.put(COLLMISSID, withFieldAsHeader(COLLMISSID, vo -> vo.getCollectingInfo().getCollectingMissionIdentifier())); - map.put(GENUS, withFieldAsHeader(GENUS, vo -> vo.getGenus())); - map.put(SPECIES, withFieldAsHeader(SPECIES, vo -> vo.getSpecies())); - map.put(SPAUTHOR, withFieldAsHeader(SPAUTHOR, vo -> vo.getSpeciesAuthority())); - map.put(SUBTAXA, withFieldAsHeader(SUBTAXA, vo -> vo.getSubtaxon())); - map.put(SUBTAUTHOR, withFieldAsHeader(SUBTAUTHOR, vo -> vo.getSubtaxonAuthority())); - map.put(CROPNAME, withFieldAsHeader(CROPNAME, vo -> vo.getCommonCropName())); - map.put(ACCENAME, withFieldAsHeader(ACCENAME, vo -> String.join(";", vo.getAccessionNames()))); - map.put(ACQDATE, withFieldAsHeader(ACQDATE, vo -> vo.getAcquisitionDate())); - map.put(ORIGCTY, withFieldAsHeader(ORIGCTY, vo -> vo.getCountryOfOriginCode())); - map.put(COLLSITE, withFieldAsHeader(COLLSITE, vo -> vo.getCollectingInfo().getCollectingSite().getSiteName())); - map.put(DECLATITUDE, withFieldAsHeader(DECLATITUDE, vo -> vo.getCollectingInfo().getCollectingSite().getLatitudeDecimal())); - map.put(LATITUDE, withFieldAsHeader(LATITUDE, vo -> vo.getCollectingInfo().getCollectingSite().getLatitudeDegrees())); - map.put(DECLONGITUDE, withFieldAsHeader(DECLONGITUDE, vo -> vo.getCollectingInfo().getCollectingSite().getLongitudeDecimal())); - map.put(LONGITUDE, withFieldAsHeader(LONGITUDE, vo -> vo.getCollectingInfo().getCollectingSite().getLongitudeDegrees())); - map.put(COORDUNCERT, withFieldAsHeader(COORDUNCERT, vo -> vo.getCollectingInfo().getCollectingSite().getCoordinateUncertainty())); - map.put(COORDDATUM, withFieldAsHeader(COORDDATUM, vo -> vo.getCollectingInfo().getCollectingSite().getSpatialReferenceSystem())); - map.put(GEOREFMETH, withFieldAsHeader(GEOREFMETH, vo -> vo.getCollectingInfo().getCollectingSite().getGeoreferencingMethod())); - map.put(ELEVATION, withFieldAsHeader(ELEVATION, vo -> vo.getCollectingInfo().getCollectingSite().getElevation())); - map.put(COLLDATE, withFieldAsHeader(COLLDATE, vo -> vo.getCollectingInfo().getCollectingDate())); - map.put(BREDCODE, withFieldAsHeader(BREDCODE, vo -> - vo.getBreedingInstitutes() - .stream() - .map(InstituteVO::getInstituteCode) - .collect(Collectors.joining(";")))); - map.put(BREDNAME, withFieldAsHeader(BREDNAME, vo -> - vo.getBreedingInstitutes() - .stream() - .map(InstituteVO::getInstituteName) - .collect(Collectors.joining(";")))); - map.put(SAMPSTAT, withFieldAsHeader(SAMPSTAT, vo -> vo.getBiologicalStatusOfAccessionCode())); - map.put(ANCEST, withFieldAsHeader(ANCEST, vo -> vo.getAncestralData())); - map.put(COLLSRC, withFieldAsHeader(COLLSRC, vo -> vo.getAcquisitionSourceCode())); - map.put(DONORCODE, withFieldAsHeader(DONORCODE, vo -> - vo.getDonorInfo() - .stream() - .map(donorInfoVO -> donorInfoVO.getDonorInstitute().getInstituteCode()) - .collect(Collectors.joining(";")))); - map.put(DONORNAME, withFieldAsHeader(DONORNAME, vo -> - vo.getDonorInfo() - .stream() - .map(donorInfoVO -> donorInfoVO.getDonorInstitute().getInstituteName()) - .collect(Collectors.joining(";")))); - map.put(DONORNUMB, withFieldAsHeader(DONORNUMB, vo -> - vo.getDonorInfo() - .stream() - .map(DonorInfoVO::getDonorAccessionNumber) - .collect(Collectors.joining(";")))); - map.put(OTHERNUMB, withFieldAsHeader(OTHERNUMB, vo -> String.join(";", vo.getAlternateIDs()))); - map.put(DUPLSITE, withFieldAsHeader(DUPLSITE, vo -> null)); // no value available for DUPLSITE - map.put(DUPLINSTNAME, withFieldAsHeader(DUPLINSTNAME, vo -> - vo.getSafetyDuplicateInstitutes() - .stream() - .map(InstituteVO::getInstituteName) - .collect(Collectors.joining(";")))); - map.put(STORAGE, withFieldAsHeader(STORAGE, vo -> String.join(";", vo.getStorageTypeCodes()))); - map.put(MLSSTAT, withFieldAsHeader(MLSSTAT, vo -> vo.getMlsStatus())); - map.put(REMARKS, withFieldAsHeader(REMARKS, vo -> vo.getRemarks())); + map.put(DOI, new GermplasmExportableFieldDescriptor("DOI", vo -> vo.getGermplasmPUI())); + map.put(ACCESSION_NUMBER, new GermplasmExportableFieldDescriptor("Accession number", vo -> vo.getAccessionNumber())); + map.put(ACCESSION_NAME, new GermplasmExportableFieldDescriptor("Accession name", vo -> vo.getGermplasmName())); + map.put(TAXON_GROUP, new GermplasmExportableFieldDescriptor("Taxon group", vo -> vo.getCommonCropName())); + map.put(HOLDING_INSTITUTION, new GermplasmExportableFieldDescriptor("Holding institution", vo -> vo.getInstituteName())); + map.put(LOT_NAME, new GermplasmExportableFieldDescriptor("Lot name", vo -> null)); + map.put(LOT_SYNONYM, new GermplasmExportableFieldDescriptor("Lot synonym", vo -> null)); + map.put(COLLECTION_NAME, new GermplasmExportableFieldDescriptor("Collection name", vo -> vo.getCollection().stream().map( + CollPopVO::getName).collect(Collectors.joining(", ")))); + map.put(COLLECTION_TYPE, new GermplasmExportableFieldDescriptor("Collection type", vo -> null)); + map.put(PANEL_NAME, new GermplasmExportableFieldDescriptor("Panel name", vo -> vo.getPanel().stream().map(CollPopVO::getName).collect( + Collectors.joining(", ")))); + map.put(PANEL_SIZE, new GermplasmExportableFieldDescriptor("Panel size", vo -> null)); this.descriptors = Collections.unmodifiableMap(map); if (map.size() != GermplasmExportableField.values().length) { @@ -120,7 +54,7 @@ public class GermplasmExportService { } } - public void export(OutputStream out, Iterator<GermplasmMcpdVO> germplasms, List<GermplasmExportableField> fields) { + public void export(OutputStream out, Iterator<GermplasmVO> germplasms, List<GermplasmExportableField> fields) { try { CSVWriter csvWriter = new CSVWriter(new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8)), ';', '"', '\\', "\n"); String[] header = fields.stream() @@ -130,7 +64,7 @@ public class GermplasmExportService { csvWriter.writeNext(header); while (germplasms.hasNext()) { - GermplasmMcpdVO vo = germplasms.next(); + GermplasmVO vo = germplasms.next(); String[] line = fields.stream() .map(descriptors::get) @@ -144,17 +78,12 @@ public class GermplasmExportService { } } - private GermplasmExportableFieldDescriptor withFieldAsHeader(GermplasmExportableField field, - Function<GermplasmMcpdVO, String> exporter) { - return new GermplasmExportableFieldDescriptor(field.name(), exporter); - } - private static class GermplasmExportableFieldDescriptor { private final String header; - private final Function<GermplasmMcpdVO, String> exporter; + private final Function<GermplasmVO, String> exporter; public GermplasmExportableFieldDescriptor(String header, - Function<GermplasmMcpdVO, String> exporter) { + Function<GermplasmVO, String> exporter) { this.header = header; this.exporter = exporter; } @@ -163,7 +92,7 @@ public class GermplasmExportService { return this.header; } - public String export(GermplasmMcpdVO germplasm) { + public String export(GermplasmVO germplasm) { return this.exporter.apply(germplasm); } } diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportableField.java b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportableField.java index 5835bf3aedbf98b67d7d1a0eff4d49f0348b86e7..ecda40cbcdd5fb14532d9b4d9f37eb09b85d90ae 100644 --- a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportableField.java +++ b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportableField.java @@ -1,52 +1,20 @@ package fr.inra.urgi.faidare.web.germplasm; -import com.fasterxml.jackson.annotation.JsonValue; - /** * The fields of a germplasm that can be exported * * @author JB Nizet */ public enum GermplasmExportableField { - PUID, - INSTCODE, - ACCENUMB, - COLLNUMB, - COLLCODE, - COLLNAME, - COLLINSTADDRESS, - COLLMISSID, - GENUS, - SPECIES, - SPAUTHOR, - SUBTAXA, - SUBTAUTHOR, - CROPNAME, - ACCENAME, - ACQDATE, - ORIGCTY, - COLLSITE, - DECLATITUDE, - LATITUDE, - DECLONGITUDE, - LONGITUDE, - COORDUNCERT, - COORDDATUM, - GEOREFMETH, - ELEVATION, - COLLDATE, - BREDCODE, - BREDNAME, - SAMPSTAT, - ANCEST, - COLLSRC, - DONORCODE, - DONORNAME, - DONORNUMB, - OTHERNUMB, - DUPLSITE, - DUPLINSTNAME, - STORAGE, - MLSSTAT, - REMARKS + DOI, + ACCESSION_NUMBER, + ACCESSION_NAME, + TAXON_GROUP, + HOLDING_INSTITUTION, + LOT_NAME, + LOT_SYNONYM, + COLLECTION_NAME, + COLLECTION_TYPE, + PANEL_NAME, + PANEL_SIZE } diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportCommand.java b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..deefb113622f13aa13c55187b2f61a16b96ac041 --- /dev/null +++ b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportCommand.java @@ -0,0 +1,39 @@ +package fr.inra.urgi.faidare.web.germplasm; + +import java.util.Collections; +import java.util.List; +import java.util.Set; +import javax.validation.constraints.NotEmpty; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Command sent to export a list of germplasm MCPD IDs + * @author JB Nizet + */ +public class GermplasmMcpdExportCommand { + + @NotEmpty + private final Set<String> ids; + + /** + * The ordered list of fields to export. If empty, all fields are exported + */ + private final List<GermplasmMcpdExportableField> fields; + + @JsonCreator + public GermplasmMcpdExportCommand(@JsonProperty("ids") Set<String> ids, + @JsonProperty("fields") List<GermplasmMcpdExportableField> fields) { + this.ids = ids; + this.fields = fields == null ? Collections.emptyList() : fields; + } + + public Set<String> getIds() { + return ids; + } + + public List<GermplasmMcpdExportableField> getFields() { + return fields; + } +} diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportService.java b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportService.java new file mode 100644 index 0000000000000000000000000000000000000000..764eaf9fe40272333e7ac6c725c0c58f24b9d927 --- /dev/null +++ b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportService.java @@ -0,0 +1,178 @@ +package fr.inra.urgi.faidare.web.germplasm; + +import static fr.inra.urgi.faidare.web.germplasm.GermplasmMcpdExportableField.*; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import com.opencsv.CSVWriter; +import fr.inra.urgi.faidare.domain.data.germplasm.DonorInfoVO; +import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmMcpdVO; +import fr.inra.urgi.faidare.domain.data.germplasm.InstituteVO; +import org.springframework.stereotype.Component; + +/** + * Service allowing to export germplasm MCPDs as CSV + * @author JB Nizet + */ +@Component +public class GermplasmMcpdExportService { + + private final Map<GermplasmMcpdExportableField, GermplasmMcpdExportableFieldDescriptor> descriptors; + + public GermplasmMcpdExportService() { + Map<GermplasmMcpdExportableField, GermplasmMcpdExportableFieldDescriptor> map = new HashMap<>(); + + map.put(PUID, withFieldAsHeader(PUID, vo -> vo.getGermplasmPUI())); + map.put(INSTCODE, withFieldAsHeader(INSTCODE, vo -> vo.getInstituteCode())); + map.put(ACCENUMB, withFieldAsHeader(ACCENUMB, vo -> vo.getAccessionNumber())); + map.put(COLLNUMB, withFieldAsHeader(COLLNUMB, vo -> vo.getCollectingInfo().getCollectingNumber())); + map.put(COLLCODE, withFieldAsHeader(COLLCODE, vo -> + vo.getCollectingInfo() + .getCollectingInstitutes() + .stream() + .map(InstituteVO::getInstituteCode).collect(Collectors.joining(";")))); + map.put(COLLNAME, withFieldAsHeader(COLLNAME, vo -> + vo.getCollectingInfo() + .getCollectingInstitutes() + .stream() + .map(InstituteVO::getInstituteName) + .collect(Collectors.joining(";")))); + map.put(COLLINSTADDRESS, withFieldAsHeader(COLLINSTADDRESS, vo -> + vo.getCollectingInfo() + .getCollectingInstitutes() + .stream() + .map(InstituteVO::getAddress) + .collect(Collectors.joining(";")))); + map.put(COLLMISSID, withFieldAsHeader(COLLMISSID, vo -> vo.getCollectingInfo().getCollectingMissionIdentifier())); + map.put(GENUS, withFieldAsHeader(GENUS, vo -> vo.getGenus())); + map.put(SPECIES, withFieldAsHeader(SPECIES, vo -> vo.getSpecies())); + map.put(SPAUTHOR, withFieldAsHeader(SPAUTHOR, vo -> vo.getSpeciesAuthority())); + map.put(SUBTAXA, withFieldAsHeader(SUBTAXA, vo -> vo.getSubtaxon())); + map.put(SUBTAUTHOR, withFieldAsHeader(SUBTAUTHOR, vo -> vo.getSubtaxonAuthority())); + map.put(CROPNAME, withFieldAsHeader(CROPNAME, vo -> vo.getCommonCropName())); + map.put(ACCENAME, withFieldAsHeader(ACCENAME, vo -> String.join(";", vo.getAccessionNames()))); + map.put(ACQDATE, withFieldAsHeader(ACQDATE, vo -> vo.getAcquisitionDate())); + map.put(ORIGCTY, withFieldAsHeader(ORIGCTY, vo -> vo.getCountryOfOriginCode())); + map.put(COLLSITE, withFieldAsHeader(COLLSITE, vo -> vo.getCollectingInfo().getCollectingSite().getSiteName())); + map.put(DECLATITUDE, withFieldAsHeader(DECLATITUDE, vo -> vo.getCollectingInfo().getCollectingSite().getLatitudeDecimal())); + map.put(LATITUDE, withFieldAsHeader(LATITUDE, vo -> vo.getCollectingInfo().getCollectingSite().getLatitudeDegrees())); + map.put(DECLONGITUDE, withFieldAsHeader(DECLONGITUDE, vo -> vo.getCollectingInfo().getCollectingSite().getLongitudeDecimal())); + map.put(LONGITUDE, withFieldAsHeader(LONGITUDE, vo -> vo.getCollectingInfo().getCollectingSite().getLongitudeDegrees())); + map.put(COORDUNCERT, withFieldAsHeader(COORDUNCERT, vo -> vo.getCollectingInfo().getCollectingSite().getCoordinateUncertainty())); + map.put(COORDDATUM, withFieldAsHeader(COORDDATUM, vo -> vo.getCollectingInfo().getCollectingSite().getSpatialReferenceSystem())); + map.put(GEOREFMETH, withFieldAsHeader(GEOREFMETH, vo -> vo.getCollectingInfo().getCollectingSite().getGeoreferencingMethod())); + map.put(ELEVATION, withFieldAsHeader(ELEVATION, vo -> vo.getCollectingInfo().getCollectingSite().getElevation())); + map.put(COLLDATE, withFieldAsHeader(COLLDATE, vo -> vo.getCollectingInfo().getCollectingDate())); + map.put(BREDCODE, withFieldAsHeader(BREDCODE, vo -> + vo.getBreedingInstitutes() + .stream() + .map(InstituteVO::getInstituteCode) + .collect(Collectors.joining(";")))); + map.put(BREDNAME, withFieldAsHeader(BREDNAME, vo -> + vo.getBreedingInstitutes() + .stream() + .map(InstituteVO::getInstituteName) + .collect(Collectors.joining(";")))); + map.put(SAMPSTAT, withFieldAsHeader(SAMPSTAT, vo -> vo.getBiologicalStatusOfAccessionCode())); + map.put(ANCEST, withFieldAsHeader(ANCEST, vo -> vo.getAncestralData())); + map.put(COLLSRC, withFieldAsHeader(COLLSRC, vo -> vo.getAcquisitionSourceCode())); + map.put(DONORCODE, withFieldAsHeader(DONORCODE, vo -> + vo.getDonorInfo() + .stream() + .map(donorInfoVO -> donorInfoVO.getDonorInstitute().getInstituteCode()) + .collect(Collectors.joining(";")))); + map.put(DONORNAME, withFieldAsHeader(DONORNAME, vo -> + vo.getDonorInfo() + .stream() + .map(donorInfoVO -> donorInfoVO.getDonorInstitute().getInstituteName()) + .collect(Collectors.joining(";")))); + map.put(DONORNUMB, withFieldAsHeader(DONORNUMB, vo -> + vo.getDonorInfo() + .stream() + .map(DonorInfoVO::getDonorAccessionNumber) + .collect(Collectors.joining(";")))); + map.put(OTHERNUMB, withFieldAsHeader(OTHERNUMB, vo -> String.join(";", vo.getAlternateIDs()))); + map.put(DUPLSITE, withFieldAsHeader(DUPLSITE, vo -> + vo.getSafetyDuplicateInstitutes() + .stream() + .map(InstituteVO::getInstituteCode) + .collect(Collectors.joining(";")))); + map.put(DUPLINSTNAME, withFieldAsHeader(DUPLINSTNAME, vo -> + vo.getSafetyDuplicateInstitutes() + .stream() + .map(InstituteVO::getInstituteName) + .collect(Collectors.joining(";")))); + map.put(STORAGE, withFieldAsHeader(STORAGE, vo -> String.join(";", vo.getStorageTypeCodes()))); + map.put(MLSSTAT, withFieldAsHeader(MLSSTAT, vo -> vo.getMlsStatus())); + map.put(REMARKS, withFieldAsHeader(REMARKS, vo -> vo.getRemarks())); + + this.descriptors = Collections.unmodifiableMap(map); + + if (map.size() != GermplasmMcpdExportableField.values().length) { + throw new IllegalStateException("Missing field descriptor"); + } + } + + public void export(OutputStream out, Iterator<GermplasmMcpdVO> germplasms, List<GermplasmMcpdExportableField> fields) { + try { + CSVWriter csvWriter = new CSVWriter(new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8)), ';', '"', '\\', "\n"); + String[] header = fields.stream() + .map(descriptors::get) + .map(GermplasmMcpdExportableFieldDescriptor::getHeader) + .toArray(String[]::new); + csvWriter.writeNext(header); + + while (germplasms.hasNext()) { + GermplasmMcpdVO vo = germplasms.next(); + String[] line = + fields.stream() + .map(descriptors::get) + .map(descriptor -> descriptor.export(vo)) + .toArray(String[]::new); + csvWriter.writeNext(line); + } + csvWriter.flush(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private GermplasmMcpdExportableFieldDescriptor withFieldAsHeader( + GermplasmMcpdExportableField field, + Function<GermplasmMcpdVO, String> exporter) { + return new GermplasmMcpdExportableFieldDescriptor(field.name(), exporter); + } + + private static class GermplasmMcpdExportableFieldDescriptor { + private final String header; + private final Function<GermplasmMcpdVO, String> exporter; + + public GermplasmMcpdExportableFieldDescriptor(String header, + Function<GermplasmMcpdVO, String> exporter) { + this.header = header; + this.exporter = exporter; + } + + public String getHeader() { + return this.header; + } + + public String export(GermplasmMcpdVO germplasm) { + return this.exporter.apply(germplasm); + } + } +} + + diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportableField.java b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportableField.java new file mode 100644 index 0000000000000000000000000000000000000000..860003663cd5b5397bf1b7f59434e98acb46f972 --- /dev/null +++ b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportableField.java @@ -0,0 +1,52 @@ +package fr.inra.urgi.faidare.web.germplasm; + +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * The fields of a germplasm MCPD that can be exported + * + * @author JB Nizet + */ +public enum GermplasmMcpdExportableField { + PUID, + INSTCODE, + ACCENUMB, + COLLNUMB, + COLLCODE, + COLLNAME, + COLLINSTADDRESS, + COLLMISSID, + GENUS, + SPECIES, + SPAUTHOR, + SUBTAXA, + SUBTAUTHOR, + CROPNAME, + ACCENAME, + ACQDATE, + ORIGCTY, + COLLSITE, + DECLATITUDE, + LATITUDE, + DECLONGITUDE, + LONGITUDE, + COORDUNCERT, + COORDDATUM, + GEOREFMETH, + ELEVATION, + COLLDATE, + BREDCODE, + BREDNAME, + SAMPSTAT, + ANCEST, + COLLSRC, + DONORCODE, + DONORNAME, + DONORNUMB, + OTHERNUMB, + DUPLSITE, + DUPLINSTNAME, + STORAGE, + MLSSTAT, + REMARKS +} diff --git a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/GermplasmRepositoryTest.java b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/GermplasmRepositoryTest.java index 7ec9bb8e27fa23dbdb2a84b87e5c116334fae20c..4ba1d45b622eea6310e5e7bb99bc234201ace801 100644 --- a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/GermplasmRepositoryTest.java +++ b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/GermplasmRepositoryTest.java @@ -28,6 +28,7 @@ import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmMcpdVO; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Objects; @@ -140,7 +141,7 @@ class GermplasmRepositoryTest { void shouldScrollGermplasmMcpdsByIds() { Iterator<GermplasmMcpdVO> list = repository.scrollGermplasmMcpdsByIds(Collections.singleton("13705"), 1000); assertThat(list).toIterable() - .isNotEmpty() + .hasSize(1) .allMatch(vo -> !vo.getGermplasmDbId().isEmpty()); list = repository.scrollGermplasmMcpdsByIds(Collections.singleton("1370"), 1000); @@ -152,6 +153,27 @@ class GermplasmRepositoryTest { .isEmpty(); } + @Test + void shouldScrollGermplasmsByIds() { + Iterator<GermplasmVO> list = repository.scrollGermplasmsByIds( + new HashSet<>( + Arrays.asList( + "ZG9pOjEwLjE1NDU0LzEuNDkyMTc4NjM4MTc4MzY5NkUxMg==", + "ZG9pOjEwLjE1NDU0LzEuNDkyMTc4NjM4NDcyNjA1MkUxMg==") + ), 1000); + assertThat(list).toIterable() + .hasSize(2) + .allMatch(vo -> !vo.getGermplasmDbId().isEmpty()); + + list = repository.scrollGermplasmsByIds(Collections.singleton("ZG9pOjEwL"), 1000); + assertThat(list).toIterable() + .isEmpty(); + + list = repository.scrollGermplasmsByIds(Collections.singleton("ZG9pOjEwL"), 1000); + assertThat(list).toIterable() + .isEmpty(); + } + @Test void should_Scroll_By_accessionNumber() { GermplasmPOSTSearchCriteria criteria = new GermplasmPOSTSearchCriteria(); diff --git a/backend/src/test/java/fr/inra/urgi/faidare/web/germplasm/GermplasmControllerTest.java b/backend/src/test/java/fr/inra/urgi/faidare/web/germplasm/GermplasmControllerTest.java index 47695c75fe427ea226d278736d0ed05fd7c1e38b..37595c9b7669d49f357f49a4f365ebc12d0a3561 100644 --- a/backend/src/test/java/fr/inra/urgi/faidare/web/germplasm/GermplasmControllerTest.java +++ b/backend/src/test/java/fr/inra/urgi/faidare/web/germplasm/GermplasmControllerTest.java @@ -8,7 +8,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import java.util.Arrays; -import java.util.Collections; import java.util.List; import com.fasterxml.jackson.databind.ObjectMapper; @@ -40,7 +39,7 @@ import org.springframework.test.web.servlet.MvcResult; * @author JB Nizet */ @WebMvcTest(GermplasmController.class) -@Import(GermplasmExportService.class) +@Import({GermplasmMcpdExportService.class, GermplasmExportService.class}) public class GermplasmControllerTest { @Autowired @@ -131,20 +130,20 @@ public class GermplasmControllerTest { } @Test - void shouldExportGermplasms() throws Exception { + void shouldExportMcpds() throws Exception { List<GermplasmMcpdVO> germplasms = Arrays.asList( Fixtures.createGermplasmMcpd(), Fixtures.createGermplasmMcpd() ); - GermplasmExportCommand command = new GermplasmExportCommand( + GermplasmMcpdExportCommand command = new GermplasmMcpdExportCommand( Sets.newHashSet("g1", "g2"), - Arrays.asList(GermplasmExportableField.PUID, GermplasmExportableField.INSTCODE)); + Arrays.asList(GermplasmMcpdExportableField.PUID, GermplasmMcpdExportableField.INSTCODE)); when(mockGermplasmRepository.scrollGermplasmMcpdsByIds(eq(command.getIds()), anyInt())) .thenAnswer(invocation -> germplasms.iterator()); - MvcResult mvcResult = mockMvc.perform(post("/germplasms/exports") + MvcResult mvcResult = mockMvc.perform(post("/germplasms/exports/mcpd") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsBytes( command))) @@ -159,6 +158,37 @@ public class GermplasmControllerTest { "\"PUI1\";\"Inst1\"\n")); } + @Test + void shouldExporPlantMaterials() throws Exception { + List<GermplasmVO> germplasms = Arrays.asList( + Fixtures.createGermplasm(), + Fixtures.createGermplasm() + ); + + GermplasmExportCommand command = new GermplasmExportCommand( + Sets.newHashSet("g1", "g2"), + Arrays.asList(GermplasmExportableField.DOI, + GermplasmExportableField.ACCESSION_NUMBER, + GermplasmExportableField.ACCESSION_NAME)); + + when(mockGermplasmRepository.scrollGermplasmsByIds(eq(command.getIds()), anyInt())) + .thenAnswer(invocation -> germplasms.iterator()); + + MvcResult mvcResult = mockMvc.perform(post("/germplasms/exports/plant-material") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes( + command))) + .andExpect(request().asyncStarted()) + .andReturn(); + + this.mockMvc.perform(asyncDispatch(mvcResult)) + .andExpect(status().isOk()) + .andExpect(content().contentType("text/csv")) + .andExpect(content().string("\"DOI\";\"Accession number\";\"Accession name\"\n" + + "\"germplasmPUI\";\"1408\";\"BLE BARBU DU ROUSSILLON\"\n" + + "\"germplasmPUI\";\"1408\";\"BLE BARBU DU ROUSSILLON\"\n")); + } + private void testSitemap(int index, String expectedContent) throws Exception { MvcResult mvcResult = mockMvc.perform(get("/faidare/germplasms/sitemap-" + index + ".txt") .contextPath("/faidare")) @@ -169,6 +199,5 @@ public class GermplasmControllerTest { .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.TEXT_PLAIN)) .andExpect(content().string(expectedContent)); - } }