From 54ba396fb34a475b622656a448d7d34770ac36c9 Mon Sep 17 00:00:00 2001 From: Jason Loux Date: Fri, 23 Oct 2026 16:40:37 -0400 Subject: [PATCH 1/2] Add script to migrate associate program_id with observation_variable --- ...id_to_observation_variable_and_migrate.sql | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/main/resources/db/migration/V006_005__add_program_id_to_observation_variable_and_migrate.sql diff --git a/src/main/resources/db/migration/V006_005__add_program_id_to_observation_variable_and_migrate.sql b/src/main/resources/db/migration/V006_005__add_program_id_to_observation_variable_and_migrate.sql new file mode 100644 index 00000000..03f888dc --- /dev/null +++ b/src/main/resources/db/migration/V006_005__add_program_id_to_observation_variable_and_migrate.sql @@ -0,0 +1,40 @@ +ALTER TABLE observation_variable + ADD COLUMN program_id UUID; + +ALTER TABLE observation_variable + ADD CONSTRAINT observation_variable_program_fk + FOREIGN KEY (program_id) + REFERENCES public.program(id); + +CREATE INDEX observation_var_program_idx ON observation_variable (program_id, id); + +UPDATE observation_variable set program_id = pquery.program_id + FROM ( + SELECT ov.id AS obs_var_id, p.id AS program_id + FROM observation_variable ov + JOIN variable_base_entity_external_references ovex ON ov.id = ovex.variable_base_entity_id + JOIN external_reference ex ON ex.id = ovex.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 + WHERE ex.external_reference_source = 'breedinginsight.org/programs' AND ex2.external_reference_source = 'breedinginsight.org') pquery +WHERE id = pquery.obs_var_id; + +-- Assertion to ensure all observation variables are now associated with a program +DO $$ + DECLARE +obs_vars_without_program_count integer; + +BEGIN +SELECT COUNT(*) +INTO obs_vars_without_program_count +FROM observation_variable ov +WHERE ov.program_id IS NULL; + +IF obs_vars_without_program_count <> 0 THEN + RAISE EXCEPTION + 'V006.005 After migration, expected all observation_variable rows to have program_id set, but there are % rows with program_id not set', + obs_vars_without_program_count; +END IF; +END +$$; \ No newline at end of file From 1bd38d19489c019bc66adce02e79317502e90fd2 Mon Sep 17 00:00:00 2001 From: Jason Loux Date: Mon, 26 Oct 2026 15:43:02 -0400 Subject: [PATCH 2/2] Alter model and services to support program lookups --- .../model/pheno/ObservationVariable.java | 21 +++++++++++++++ .../pheno/ObservationVariableNewRequest.java | 12 +++++++++ .../pheno/ObservationVariableEntity.java | 9 +++++++ .../pheno/ObservationVariableService.java | 26 ++++++++++++++++--- 4 files changed, 64 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/swagger/model/pheno/ObservationVariable.java b/src/main/java/io/swagger/model/pheno/ObservationVariable.java index d1938816..7e67d76d 100644 --- a/src/main/java/io/swagger/model/pheno/ObservationVariable.java +++ b/src/main/java/io/swagger/model/pheno/ObservationVariable.java @@ -21,6 +21,12 @@ public class ObservationVariable extends VariableBaseClass { @JsonProperty("observationVariableName") private String observationVariableName = null; + @JsonProperty("programDbId") + private String programDbId = null; + + @JsonProperty("programName") + private String programName = null; + public ObservationVariable observationVariableDbId(String observationVariableDbId) { this.observationVariableDbId = observationVariableDbId; return this; @@ -61,6 +67,21 @@ public void setObservationVariableName(String observationVariableName) { this.observationVariableName = observationVariableName; } + 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) { diff --git a/src/main/java/io/swagger/model/pheno/ObservationVariableNewRequest.java b/src/main/java/io/swagger/model/pheno/ObservationVariableNewRequest.java index c6ecfeaa..7295a245 100644 --- a/src/main/java/io/swagger/model/pheno/ObservationVariableNewRequest.java +++ b/src/main/java/io/swagger/model/pheno/ObservationVariableNewRequest.java @@ -17,6 +17,9 @@ public class ObservationVariableNewRequest extends VariableBaseClass { @JsonProperty("observationVariableName") private Optional observationVariableName = null; + @JsonProperty("programDbId") + private String programDbId = null; + public ObservationVariableNewRequest observationVariableName(String observationVariableName) { this.observationVariableName = UpdateUtility.setField(observationVariableName); return this; @@ -30,6 +33,14 @@ public void setObservationVariableName(String observationVariableName) { this.observationVariableName = UpdateUtility.setField(observationVariableName); } + public String getProgramDbId() { + return programDbId; + } + + public void setProgramDbId(String programDbId) { + this.programDbId = programDbId; + } + @Override public boolean equals(java.lang.Object o) { if (this == o) { @@ -54,6 +65,7 @@ public String toString() { sb.append("class ObservationVariableNewRequest {\n"); sb.append(" ").append(toIndentedString(super.toString())).append("\n"); sb.append(" observationVariableName: ").append(toIndentedString(observationVariableName)).append("\n"); + sb.append(" programDbId: ").append(toIndentedString(programDbId)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/src/main/java/org/brapi/test/BrAPITestServer/model/entity/pheno/ObservationVariableEntity.java b/src/main/java/org/brapi/test/BrAPITestServer/model/entity/pheno/ObservationVariableEntity.java index e5d35839..a89e9dce 100644 --- a/src/main/java/org/brapi/test/BrAPITestServer/model/entity/pheno/ObservationVariableEntity.java +++ b/src/main/java/org/brapi/test/BrAPITestServer/model/entity/pheno/ObservationVariableEntity.java @@ -1,6 +1,7 @@ package org.brapi.test.BrAPITestServer.model.entity.pheno; import jakarta.persistence.*; +import org.brapi.test.BrAPITestServer.model.entity.core.ProgramEntity; import java.util.List; @@ -13,6 +14,8 @@ public class ObservationVariableEntity extends VariableBaseEntity{ private String pui; @OneToMany(mappedBy="observationVariable", fetch = FetchType.LAZY) private List observations; + @ManyToOne(fetch = FetchType.LAZY) + private ProgramEntity program; public String getPui() { return pui; @@ -32,4 +35,10 @@ public List getObservations() { public void setObservations(List observations) { this.observations = observations; } + public ProgramEntity getProgram() { + return program; + } + public void setProgram(ProgramEntity program) { + this.program = program; + } } diff --git a/src/main/java/org/brapi/test/BrAPITestServer/service/pheno/ObservationVariableService.java b/src/main/java/org/brapi/test/BrAPITestServer/service/pheno/ObservationVariableService.java index 42944b47..2b6ceefb 100644 --- a/src/main/java/org/brapi/test/BrAPITestServer/service/pheno/ObservationVariableService.java +++ b/src/main/java/org/brapi/test/BrAPITestServer/service/pheno/ObservationVariableService.java @@ -7,6 +7,7 @@ import org.brapi.test.BrAPITestServer.exceptions.BrAPIServerDbIdNotFoundException; import org.brapi.test.BrAPITestServer.exceptions.BrAPIServerException; 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.pheno.*; import org.brapi.test.BrAPITestServer.repository.primaryEntities.core.TraitRepository; import org.brapi.test.BrAPITestServer.repository.primaryEntities.pheno.MethodRepository; @@ -17,6 +18,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; @@ -47,11 +49,12 @@ public class ObservationVariableService { private final MethodService methodService; private final ScaleService scaleService; private final TraitService traitService; + private final ProgramService programService; @Autowired public ObservationVariableService(ObservationVariableRepository observationVariableRepository, - OntologyService ontologyService, CropService cropService, MethodService methodService, - ScaleService scaleService, TraitService traitService, MethodRepository methodRepository, ScaleRepository scaleRepository, TraitRepository traitRepository) { + OntologyService ontologyService, CropService cropService, MethodService methodService, + ScaleService scaleService, TraitService traitService, MethodRepository methodRepository, ScaleRepository scaleRepository, TraitRepository traitRepository, ProgramService programService) { this.observationVariableRepository = observationVariableRepository; this.methodRepository = methodRepository; this.scaleRepository = scaleRepository; @@ -61,6 +64,7 @@ public ObservationVariableService(ObservationVariableRepository observationVaria this.methodService = methodService; this.scaleService = scaleService; this.traitService = traitService; + this.programService = programService; } public List findObservationVariables(String observationVariableDbId, @@ -124,7 +128,8 @@ public List findObservationVariables(ObservationVariableSea .leftJoinFetch("method", "varMethod") .leftJoinFetch("ontology", "varOntology") .leftJoinFetch("scale", "varScale") - .leftJoinFetch("trait", "varTrait"); + .leftJoinFetch("trait", "varTrait") + .leftJoinFetch("program", "varProgram"); if (request.getStudyDbId() != null) { searchQuery = searchQuery.join("observations", "observation").appendList(request.getStudyDbId(), "*observation.observationUnit.study.id"); @@ -136,7 +141,10 @@ public List findObservationVariables(ObservationVariableSea .appendList(request.getOntologyDbIds(), "ontology.id").appendList(request.getScaleDbIds(), "scale.id") .appendList(request.getTraitClasses(), "trait.traitClass") .appendList(request.getTraitDbIds(), "trait.id") - .appendEnumList(request.getDataTypes(), "scale.dataType"); + .appendList(request.getTraitNames(), "trait.name") + .appendEnumList(request.getDataTypes(), "scale.dataType") + .appendList(request.getProgramDbIds(), "program.id") + .appendList(request.getProgramNames(), "program.name"); log.debug("Starting variable search"); Page page = observationVariableRepository.findAllBySearchAndPaginate(searchQuery, pageReq); @@ -201,6 +209,11 @@ private ObservationVariable convertFromEntity(ObservationVariableEntity entity) var.setObservationVariableName(entity.getName()); var.setObservationVariableDbId(entity.getId().toString()); + if (entity.getProgram() != null) { + var.setProgramDbId(entity.getProgram().getId().toString()); + var.setProgramName(entity.getProgram().getName()); + } + return var; } @@ -240,6 +253,11 @@ private void updateEntity(ObservationVariableEntity entity, ObservationVariableN throws BrAPIServerException { updateBaseEntity(entity, request); entity.setName(UpdateUtility.replaceField(request.getObservationVariableName(), entity.getName())); + + if (request.getProgramDbId() != null) { + ProgramEntity programEntity = programService.getProgramEntity(request.getProgramDbId()); + entity.setProgram(programEntity); + } } public void updateBaseEntity(VariableBaseEntity entity, VariableBaseClass request) throws BrAPIServerException {