Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/main/java/io/swagger/api/germ/GermplasmApi.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -143,6 +143,7 @@ ResponseEntity<GermplasmListResponse> 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,
Expand Down
30 changes: 28 additions & 2 deletions src/main/java/io/swagger/model/germ/GermplasmNewRequest.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -97,6 +97,12 @@ public class GermplasmNewRequest extends BrAPIDataModel {
@JsonProperty("taxonIds")
private List<TaxonID> taxonIds = null;

@JsonProperty("programDbId")
private String programDbId = null;

@JsonProperty("programName")
private String programName = null;

public String getBreedingMethodName() {
return breedingMethodName;
}
Expand DownExpand Up@@ -510,6 +516,22 @@ public void setTaxonIds(List<TaxonID> 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) {
Expand DownExpand Up@@ -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
Expand All@@ -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
Expand DownExpand Up@@ -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();
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -156,6 +156,7 @@ public ResponseEntity<GermplasmListResponse> 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,
Expand All@@ -170,7 +171,7 @@ public ResponseEntity<GermplasmListResponse> germplasmGet(
Metadata metadata = generateMetaDataTemplate(page, pageSize);
List<Germplasm> 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);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -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;
Expand DownExpand Up@@ -96,6 +97,8 @@ public class GermplasmEntity extends BrAPIPrimaryEntity {
private List<GermplasmStorageTypesEnum> typeOfGermplasmStorageCode;
@Column(name = "soft_deleted")
private boolean softDeleted;
@ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
private ProgramEntity program;

public GermplasmInstituteEntity getHostInstitute() {
if (getInstitutes() != null) {
Expand DownExpand Up@@ -368,4 +371,12 @@ public void setTypeOfGermplasmStorageCode(List<GermplasmStorageTypesEnum> typeOf

public void setSoftDeleted(boolean sofDeleted) { this.softDeleted = sofDeleted; }

public ProgramEntity getProgram() {
return program;
}

public void setProgram(ProgramEntity program) {
this.program = program;
}

}
Original file line numberDiff line numberDiff line change
@@ -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;
Expand DownExpand Up@@ -76,14 +74,33 @@ public List<Program> findPrograms(ProgramSearchRequest request, Metadata metadat
return programs;
}

public List<ProgramEntity> findByIds(List<String> programDbIds) {
var result = new ArrayList<ProgramEntity>();
public List<ProgramEntity> findByIds(List<String> programDbIds) throws BrAPIServerException {
List<ProgramEntity> result = new ArrayList<>();

if (programDbIds.isEmpty()) {
return result;
}

return programRepository.findByIdIn(programDbIds.stream().map(UUID::fromString).toList());
// Dedup programIds by loading into set
Set<String> programDbIdSet = new HashSet<>(programDbIds);

result = programRepository.findByIdIn(programDbIds.stream().map(UUID::fromString).toList());

if (programDbIdSet.size() != result.size()) {
List<String> dbIdsNotFound = new ArrayList<>();

Set<String> 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 {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -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;

Expand All@@ -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;
Expand All@@ -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;
Expand All@@ -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<Germplasm> 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 {

Expand DownExpand Up@@ -93,6 +98,8 @@ public List<Germplasm> 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);

Expand DownExpand Up@@ -172,12 +179,10 @@ private SearchQueryBuilder<GermplasmEntity> 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")
Expand All@@ -198,6 +203,7 @@ private SearchQueryBuilder<GermplasmEntity> 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")
Expand DownExpand Up@@ -529,6 +535,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());
Expand DownExpand Up@@ -582,6 +594,11 @@ private List<GermplasmEntity> createEntitiesInBatch(List<GermplasmNewRequest> bo
.filter(Objects::nonNull)
.collect(Collectors.toSet());

Set<String> programDbIds = body.stream()
.map(GermplasmNewRequest::getProgramDbId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());

Map<UUID, BreedingMethodEntity> foundBreedingMethodsById
= breedingMethodService.findBreedingMethodsByIds(breedingMethodIds)
.stream()
Expand All@@ -591,6 +608,11 @@ private List<GermplasmEntity> createEntitiesInBatch(List<GermplasmNewRequest> bo
.stream()
.collect(Collectors.toMap(CropEntity::getCropName, e -> e));

Map<UUID, ProgramEntity> foundProgramsByDbId
= programService.findByIds(new ArrayList<>(programDbIds))
.stream()
.collect(Collectors.toMap(ProgramEntity::getId, e -> e));

for (GermplasmNewRequest request : body) {
GermplasmEntity entity = new GermplasmEntity();

Expand All@@ -605,7 +627,7 @@ private List<GermplasmEntity> createEntitiesInBatch(List<GermplasmNewRequest> 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());
Expand DownExpand Up@@ -662,6 +684,10 @@ private List<GermplasmEntity> createEntitiesInBatch(List<GermplasmNewRequest> bo
updateSynonymEntities(request.getSynonyms(), entity);
if (request.getTaxonIds() != null)
updateTaxonEntities(request.getTaxonIds(), entity);
if (!foundProgramsByDbId.isEmpty()) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not applicable for deltabreed use case but may want to fix for general usage. Since foundProgramsByDbId is shared across germplasm in the batch if some germplasm have a program id and some don't then this could result in a NullPointerException on the UUID.fromString call because request.getProgramDbId() could be null.

Something like this should resolve it:

 if (request.getProgramDbId() != null) {
ProgramEntity program =
foundProgramsByDbId.get(UUID.fromString(request.getProgramDbId()));
entity.setProgram(program);
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oop, yea, that's just a big old brain fart. I implemented that for other entities exactly as you described, just did this one wrong.

ProgramEntity program = foundProgramsByDbId.get(UUID.fromString(request.getProgramDbId()));
entity.setProgram(program);
}

toSave.add(entity);
}
Expand DownExpand Up@@ -739,6 +765,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<TaxonID> taxonIds, GermplasmEntity entity) {
Expand Down
Original file line numberDiff line numberDiff line change
@@ -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;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wonder if we should not cascade, seems the convention for other entities related to program like trials and studies, etc. is no action.


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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should also constrain on the germplasm exref source being breedinginsight.org/programs

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;