diff --git a/src/main/java/io/swagger/api/germ/GermplasmApi.java b/src/main/java/io/swagger/api/germ/GermplasmApi.java index 1990ba83..a7f9d959 100644 --- a/src/main/java/io/swagger/api/germ/GermplasmApi.java +++ b/src/main/java/io/swagger/api/germ/GermplasmApi.java @@ -143,6 +143,7 @@ ResponseEntity germplasmGet( @ApiParam(value = "progenyDbId") @Valid @RequestParam(value = "progenyDbId", required = false) String progenyDbId, @ApiParam(value = "commonCropName") @Valid @RequestParam(value = "commonCropName", required = false) String commonCropName, @ApiParam(value = "programDbId") @Valid @RequestParam(value = "programDbId", required = false) String programDbId, + @ApiParam(value = "programName") @Valid @RequestParam(value = "programName", required = false) String programName, @ApiParam(value = "externalReferenceID") @Valid @RequestParam(value = "externalReferenceID", required = false) String externalReferenceID, @ApiParam(value = "externalReferenceId") @Valid @RequestParam(value = "externalReferenceId", required = false) String externalReferenceId, @ApiParam(value = "externalReferenceSource") @Valid @RequestParam(value = "externalReferenceSource", required = false) String externalReferenceSource, diff --git a/src/main/java/io/swagger/model/germ/GermplasmNewRequest.java b/src/main/java/io/swagger/model/germ/GermplasmNewRequest.java index 253783e7..7317f374 100644 --- a/src/main/java/io/swagger/model/germ/GermplasmNewRequest.java +++ b/src/main/java/io/swagger/model/germ/GermplasmNewRequest.java @@ -97,6 +97,12 @@ public class GermplasmNewRequest extends BrAPIDataModel { @JsonProperty("taxonIds") private List taxonIds = null; + @JsonProperty("programDbId") + private String programDbId = null; + + @JsonProperty("programName") + private String programName = null; + public String getBreedingMethodName() { return breedingMethodName; } @@ -510,6 +516,22 @@ public void setTaxonIds(List taxonIds) { this.taxonIds = taxonIds; } + public String getProgramDbId() { + return programDbId; + } + + public void setProgramDbId(String programDbId) { + this.programDbId = programDbId; + } + + public String getProgramName() { + return programName; + } + + public void setProgramName(String programName) { + this.programName = programName; + } + @Override public boolean equals(java.lang.Object o) { if (this == o) { @@ -550,7 +572,9 @@ public boolean equals(java.lang.Object o) { && Objects.equals(this.subtaxa, germplasmNewRequest.subtaxa) && Objects.equals(this.subtaxaAuthority, germplasmNewRequest.subtaxaAuthority) && Objects.equals(this.synonyms, germplasmNewRequest.synonyms) - && Objects.equals(this.taxonIds, germplasmNewRequest.taxonIds); + && Objects.equals(this.taxonIds, germplasmNewRequest.taxonIds) + && Objects.equals(this.programDbId, germplasmNewRequest.programDbId) + && Objects.equals(this.programName, germplasmNewRequest.programName); } @Override @@ -560,7 +584,7 @@ public int hashCode() { countryOfOriginCode, defaultDisplayName, documentationURL, donors, externalReferences, genus, germplasmName, germplasmOrigin, germplasmPUI, germplasmPreprocessing, instituteCode, instituteName, pedigree, seedSource, seedSourceDescription, species, speciesAuthority, storageTypes, subtaxa, - subtaxaAuthority, synonyms, taxonIds); + subtaxaAuthority, synonyms, taxonIds, programDbId, programName); } @Override @@ -600,6 +624,8 @@ public String toString() { sb.append(" subtaxaAuthority: ").append(toIndentedString(subtaxaAuthority)).append("\n"); sb.append(" synonyms: ").append(toIndentedString(synonyms)).append("\n"); sb.append(" taxonIds: ").append(toIndentedString(taxonIds)).append("\n"); + sb.append(" programDbId: ").append(toIndentedString(programDbId)).append("\n"); + sb.append(" programName: ").append(toIndentedString(programName)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/src/main/java/org/brapi/test/BrAPITestServer/controller/germ/GermplasmApiController.java b/src/main/java/org/brapi/test/BrAPITestServer/controller/germ/GermplasmApiController.java index 52e58a1d..dd462c4b 100644 --- a/src/main/java/org/brapi/test/BrAPITestServer/controller/germ/GermplasmApiController.java +++ b/src/main/java/org/brapi/test/BrAPITestServer/controller/germ/GermplasmApiController.java @@ -156,6 +156,7 @@ public ResponseEntity germplasmGet( @RequestParam(value = "progenyDbId", required = false) String progenyDbId, @RequestParam(value = "commonCropName", required = false) String commonCropName, @RequestParam(value = "programDbId", required = false) String programDbId, + @RequestParam(value = "programName", required = false) String programName, @RequestParam(value = "externalReferenceID", required = false) String externalReferenceID, @RequestParam(value = "externalReferenceId", required = false) String externalReferenceId, @RequestParam(value = "externalReferenceSource", required = false) String externalReferenceSource, @@ -170,7 +171,7 @@ public ResponseEntity germplasmGet( Metadata metadata = generateMetaDataTemplate(page, pageSize); List data = germplasmService.findGermplasm(germplasmPUI, germplasmDbId, germplasmName, accessionNumber, collection, binomialName, genus, species, trialDbId, studyDbId, synonym, parentDbId, - progenyDbId, commonCropName, programDbId, externalReferenceId, externalReferenceID, + progenyDbId, commonCropName, programDbId, programName, externalReferenceId, externalReferenceID, externalReferenceSource, metadata); return responseOK(new GermplasmListResponse(), new GermplasmListResponseResult(), data, metadata); } diff --git a/src/main/java/org/brapi/test/BrAPITestServer/model/entity/germ/GermplasmEntity.java b/src/main/java/org/brapi/test/BrAPITestServer/model/entity/germ/GermplasmEntity.java index 1c5192db..8b464b85 100644 --- a/src/main/java/org/brapi/test/BrAPITestServer/model/entity/germ/GermplasmEntity.java +++ b/src/main/java/org/brapi/test/BrAPITestServer/model/entity/germ/GermplasmEntity.java @@ -9,6 +9,7 @@ import org.brapi.test.BrAPITestServer.model.entity.BrAPIPrimaryEntity; import org.brapi.test.BrAPITestServer.model.entity.SearchRequestEntity; import org.brapi.test.BrAPITestServer.model.entity.core.CropEntity; +import org.brapi.test.BrAPITestServer.model.entity.core.ProgramEntity; import org.brapi.test.BrAPITestServer.model.entity.germ.GermplasmInstituteEntity.InstituteTypeEnum; import org.brapi.test.BrAPITestServer.model.entity.pheno.ObservationUnitEntity; import org.brapi.test.BrAPITestServer.model.entity.pheno.TaxonEntity; @@ -96,6 +97,8 @@ public class GermplasmEntity extends BrAPIPrimaryEntity { private List typeOfGermplasmStorageCode; @Column(name = "soft_deleted") private boolean softDeleted; + @ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY) + private ProgramEntity program; public GermplasmInstituteEntity getHostInstitute() { if (getInstitutes() != null) { @@ -368,4 +371,12 @@ public void setTypeOfGermplasmStorageCode(List typeOf public void setSoftDeleted(boolean sofDeleted) { this.softDeleted = sofDeleted; } + public ProgramEntity getProgram() { + return program; + } + + public void setProgram(ProgramEntity program) { + this.program = program; + } + } diff --git a/src/main/java/org/brapi/test/BrAPITestServer/service/core/ProgramService.java b/src/main/java/org/brapi/test/BrAPITestServer/service/core/ProgramService.java index 720f731b..9f11a8f7 100644 --- a/src/main/java/org/brapi/test/BrAPITestServer/service/core/ProgramService.java +++ b/src/main/java/org/brapi/test/BrAPITestServer/service/core/ProgramService.java @@ -1,9 +1,7 @@ package org.brapi.test.BrAPITestServer.service.core; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.UUID; +import java.util.*; +import java.util.stream.Collectors; import org.brapi.test.BrAPITestServer.exceptions.BrAPIServerDbIdNotFoundException; import org.brapi.test.BrAPITestServer.exceptions.BrAPIServerException; @@ -76,14 +74,33 @@ public List findPrograms(ProgramSearchRequest request, Metadata metadat return programs; } - public List findByIds(List programDbIds) { - var result = new ArrayList(); + public List findByIds(List programDbIds) throws BrAPIServerException { + List result = new ArrayList<>(); if (programDbIds.isEmpty()) { return result; } - return programRepository.findByIdIn(programDbIds.stream().map(UUID::fromString).toList()); + // Dedup programIds by loading into set + Set programDbIdSet = new HashSet<>(programDbIds); + + result = programRepository.findByIdIn(programDbIds.stream().map(UUID::fromString).toList()); + + if (programDbIdSet.size() != result.size()) { + List dbIdsNotFound = new ArrayList<>(); + + Set foundDbIds = result.stream().map(pe -> pe.getId().toString()).collect(Collectors.toSet()); + + programDbIdSet.forEach(dbId -> { + if (!foundDbIds.contains(dbId)) { + dbIdsNotFound.add(dbId); + } + }); + + throw new BrAPIServerException(HttpStatus.NOT_FOUND, String.format("The following submitted programDbIds were not found in the db: [%s]", dbIdsNotFound)); + } + + return result; } public Program getProgram(String programDbId) throws BrAPIServerException { diff --git a/src/main/java/org/brapi/test/BrAPITestServer/service/germ/GermplasmService.java b/src/main/java/org/brapi/test/BrAPITestServer/service/germ/GermplasmService.java index 2946fd58..a09abdad 100644 --- a/src/main/java/org/brapi/test/BrAPITestServer/service/germ/GermplasmService.java +++ b/src/main/java/org/brapi/test/BrAPITestServer/service/germ/GermplasmService.java @@ -4,6 +4,7 @@ import java.util.*; import java.util.stream.Collectors; +import io.swagger.model.core.ProgramSearchRequest; import io.swagger.model.germ.*; import jakarta.validation.Valid; @@ -12,6 +13,7 @@ import org.brapi.test.BrAPITestServer.model.entity.BrAPIBaseEntity; import org.brapi.test.BrAPITestServer.model.entity.ExternalReferenceEntity; import org.brapi.test.BrAPITestServer.model.entity.core.CropEntity; +import org.brapi.test.BrAPITestServer.model.entity.core.ProgramEntity; import org.brapi.test.BrAPITestServer.model.entity.germ.*; import org.brapi.test.BrAPITestServer.model.entity.germ.GermplasmInstituteEntity.InstituteTypeEnum; import org.brapi.test.BrAPITestServer.model.entity.pheno.TaxonEntity; @@ -23,6 +25,7 @@ import org.brapi.test.BrAPITestServer.service.SearchQueryBuilder; import org.brapi.test.BrAPITestServer.service.UpdateUtility; import org.brapi.test.BrAPITestServer.service.core.CropService; +import org.brapi.test.BrAPITestServer.service.core.ProgramService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -44,21 +47,23 @@ public class GermplasmService { private final GermplasmDonorRepository donorRepository; private final BreedingMethodService breedingMethodService; private final CropService cropService; + private final ProgramService programService; @Autowired public GermplasmService(GermplasmRepository germplasmRepository, GermplasmDonorRepository donorRepository, - BreedingMethodService breedingMethodService, CropService cropService) { + BreedingMethodService breedingMethodService, CropService cropService, ProgramService programService) { this.germplasmRepository = germplasmRepository; this.donorRepository = donorRepository; this.breedingMethodService = breedingMethodService; this.cropService = cropService; + this.programService = programService; } public List findGermplasm(String germplasmPUI, String germplasmDbId, String germplasmName, String accessionNumber, String collection, String binomialName, String genus, String species, String trialDbId, String studyDbId, String synonym, String parentDbId, String progenyDbId, - String commonCropName, String programDbId, String externalReferenceId, String externalReferenceID, + String commonCropName, String programDbId, String programName, String externalReferenceId, String externalReferenceID, String externalReferenceSource, Metadata metadata) throws BrAPIServerException { @@ -93,6 +98,8 @@ public List findGermplasm(String germplasmPUI, String germplasmDbId, request.addCommonCropNamesItem(commonCropName); if (programDbId != null) request.addProgramDbIdsItem(programDbId); + if (programName != null) + request.addProgramNamesItem(programName); request.addExternalReferenceItem(externalReferenceId, externalReferenceID, externalReferenceSource); @@ -171,12 +178,10 @@ private SearchQueryBuilder buildGermplasmSearchQuery(GermplasmS .leftJoinFetch("pedigree", "pedigree") .leftJoinFetch("*pedigree.crossingProject", "crossingProject"); - if (request.getProgramDbIds() != null || request.getProgramNames() != null || request.getTrialDbIds() != null + if (request.getTrialDbIds() != null || request.getTrialNames() != null || request.getStudyDbIds() != null || request.getStudyNames() != null) { searchQuery = searchQuery.join("observationUnits", "obsunit") - .appendList(request.getProgramDbIds(), "*obsunit.program.id") - .appendList(request.getProgramNames(), "*obsunit.program.name") .appendList(request.getTrialDbIds(), "*obsunit.trial.id") .appendList(request.getTrialNames(), "*obsunit.trial.name") .appendList(request.getStudyDbIds(), "*obsunit.study.id") @@ -197,6 +202,7 @@ private SearchQueryBuilder buildGermplasmSearchQuery(GermplasmS .appendList(request.getGermplasmNames(), "germplasmName") .appendList(request.getGermplasmPUIs(), "germplasmPUI") .appendList(request.getParentDbIds(), "pedigree.parent1.germplasm.id") + .appendList(request.getProgramDbIds(), "program.id").appendList(request.getProgramNames(), "program.name") // .appendList(request.getProgenyDbIds(), "*progeny.germplasmDbId") .appendList(request.getGenus(), "genus").appendList(request.getSpecies(), "species") .appendNamesList(request.getBinomialNames(), "genus", "genus", "species") @@ -528,6 +534,12 @@ private Germplasm convertFromEntity(GermplasmEntity entity) { germ.setCollection(entity.getCollection()); if (entity.getCrop() != null) germ.setCommonCropName(entity.getCrop().getCropName()); + + if (entity.getProgram() != null) { + germ.setProgramDbId(entity.getProgram().getId().toString()); + germ.setProgramName(entity.getProgram().getName()); + } + germ.setCountryOfOriginCode(entity.getCountryOfOriginCode()); germ.setDefaultDisplayName(entity.getDefaultDisplayName()); germ.setDocumentationURL(entity.getDocumentationURL()); @@ -581,6 +593,11 @@ private List createEntitiesInBatch(List bo .filter(Objects::nonNull) .collect(Collectors.toSet()); + Set programDbIds = body.stream() + .map(GermplasmNewRequest::getProgramDbId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + Map foundBreedingMethodsById = breedingMethodService.findBreedingMethodsByIds(breedingMethodIds) .stream() @@ -590,6 +607,11 @@ private List createEntitiesInBatch(List bo .stream() .collect(Collectors.toMap(CropEntity::getCropName, e -> e)); + Map foundProgramsByDbId + = programService.findByIds(new ArrayList<>(programDbIds)) + .stream() + .collect(Collectors.toMap(ProgramEntity::getId, e -> e)); + for (GermplasmNewRequest request : body) { GermplasmEntity entity = new GermplasmEntity(); @@ -604,7 +626,7 @@ private List createEntitiesInBatch(List bo if (request.getBiologicalStatusOfAccessionCode() != null) entity.setBiologicalStatusOfAccessionCode(request.getBiologicalStatusOfAccessionCode()); if (request.getBreedingMethodDbId() != null) { - entity.setBreedingMethod(foundBreedingMethodsById.get(request.getBreedingMethodDbId())); + entity.setBreedingMethod(foundBreedingMethodsById.get(UUID.fromString(request.getBreedingMethodDbId()))); } if (request.getCollection() != null) entity.setCollection(request.getCollection()); @@ -661,6 +683,10 @@ private List createEntitiesInBatch(List bo updateSynonymEntities(request.getSynonyms(), entity); if (request.getTaxonIds() != null) updateTaxonEntities(request.getTaxonIds(), entity); + if (!foundProgramsByDbId.isEmpty()) { + ProgramEntity program = foundProgramsByDbId.get(UUID.fromString(request.getProgramDbId())); + entity.setProgram(program); + } toSave.add(entity); } @@ -738,6 +764,10 @@ private void updateEntity(GermplasmEntity entity, GermplasmNewRequest request) t updateSynonymEntities(request.getSynonyms(), entity); if (request.getTaxonIds() != null) updateTaxonEntities(request.getTaxonIds(), entity); + if (request.getProgramDbId() != null) { + ProgramEntity program = programService.getProgramEntity(request.getProgramDbId()); + entity.setProgram(program); + } } private void updateTaxonEntities(List taxonIds, GermplasmEntity entity) { diff --git a/src/main/resources/db/migration/V006_003__add_program_id_to_germplasm_and_migrate.sql b/src/main/resources/db/migration/V006_003__add_program_id_to_germplasm_and_migrate.sql new file mode 100644 index 00000000..9f5b2aae --- /dev/null +++ b/src/main/resources/db/migration/V006_003__add_program_id_to_germplasm_and_migrate.sql @@ -0,0 +1,22 @@ +ALTER TABLE germplasm +ADD COLUMN program_id UUID; + +ALTER TABLE germplasm +ADD CONSTRAINT germplasm_program_fk + FOREIGN KEY (program_id) + REFERENCES public.program(id) + ON DELETE CASCADE; + +CREATE INDEX germplasm_program_idx ON germplasm (program_id, id); + +UPDATE germplasm set program_id = pquery.program_id +FROM ( + SELECT g.id AS germplasm_id, p.id AS program_id + from germplasm g + JOIN germplasm_external_references gex ON g.id = gex.germplasm_entity_id + JOIN external_reference ex ON ex.id = gex.external_references_id + JOIN external_reference ex2 ON ex2.external_reference_id = ex.external_reference_id + JOIN program_external_references pex ON pex.external_references_id = ex2.id + JOIN program p ON p.id = pex.program_entity_id +) pquery +where id = pquery.germplasm_id; \ No newline at end of file