Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

import java.math.BigInteger;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Supplier;
Expand Down Expand Up @@ -303,8 +304,15 @@ public BrAPIObservation constructBrAPIObservation(
String value,
String variableName,
String seasonDbId,
BrAPIObservationUnit obsUnit
) {
BrAPIObservationUnit obsUnit,
boolean commit,
Program program,
User user,
String referenceSource,
UUID trialID,
UUID studyID,
UUID obsUnitID,
UUID id) {
BrAPIObservation observation = new BrAPIObservation();
observation.setGermplasmName(getGermplasmName());
if (getEnv() != null) {
Expand All @@ -320,11 +328,21 @@ public BrAPIObservation constructBrAPIObservation(
season.setSeasonDbId(seasonDbId);
observation.setSeason(season);

if(commit) {
Map<String, Object> createdBy = new HashMap<>();
createdBy.put(BrAPIAdditionalInfoFields.CREATED_BY_USER_ID, user.getId());
createdBy.put(BrAPIAdditionalInfoFields.CREATED_BY_USER_NAME, user.getName());
observation.putAdditionalInfoItem(BrAPIAdditionalInfoFields.CREATED_BY, createdBy);
observation.putAdditionalInfoItem(BrAPIAdditionalInfoFields.CREATED_DATE, DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(OffsetDateTime.now()));

observation.setExternalReferences(getObservationExternalReferences(program, referenceSource, trialID, studyID, obsUnitID, id));
}

return observation;
}

private List<BrAPIExternalReference> getBrAPIExternalReferences(
Program program, String referenceSourceBaseName, UUID trialId, UUID studyId, UUID obsUnitId) {
Program program, String referenceSourceBaseName, UUID trialId, UUID studyId, UUID obsUnitId, UUID observationId) {
List<BrAPIExternalReference> refs = new ArrayList<>();

addReference(refs, program.getId(), referenceSourceBaseName, ExternalReferenceSource.PROGRAMS);
Expand All @@ -337,23 +355,31 @@ private List<BrAPIExternalReference> getBrAPIExternalReferences(
if (obsUnitId != null) {
addReference(refs, obsUnitId, referenceSourceBaseName, ExternalReferenceSource.OBSERVATION_UNITS);
}
if (observationId != null) {
addReference(refs, observationId, referenceSourceBaseName, ExternalReferenceSource.OBSERVATIONS);
}

return refs;
}

private List<BrAPIExternalReference> getTrialExternalReferences(
Program program, String referenceSourceBaseName, UUID trialId) {
return getBrAPIExternalReferences(program, referenceSourceBaseName, trialId, null, null);
return getBrAPIExternalReferences(program, referenceSourceBaseName, trialId, null, null, null);
}

private List<BrAPIExternalReference> getStudyExternalReferences(
Program program, String referenceSourceBaseName, UUID trialId, UUID studyId) {
return getBrAPIExternalReferences(program, referenceSourceBaseName, trialId, studyId, null);
return getBrAPIExternalReferences(program, referenceSourceBaseName, trialId, studyId, null, null);
}

private List<BrAPIExternalReference> getObsUnitExternalReferences(
Program program, String referenceSourceBaseName, UUID trialId, UUID studyId, UUID obsUnitId) {
return getBrAPIExternalReferences(program, referenceSourceBaseName, trialId, studyId, obsUnitId);
return getBrAPIExternalReferences(program, referenceSourceBaseName, trialId, studyId, obsUnitId, null);
}

private List<BrAPIExternalReference> getObservationExternalReferences(
Program program, String referenceSourceBaseName, UUID trialId, UUID studyId, UUID obsUnitId, UUID observationId) {
return getBrAPIExternalReferences(program, referenceSourceBaseName, trialId, studyId, obsUnitId, observationId);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ public enum ExternalReferenceSource {
STUDIES("studies"),
OBSERVATION_UNITS("observationunits"),
DATASET("dataset"),
LISTS("lists");
LISTS("lists"),
OBSERVATIONS("observations");

private String name;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,9 +388,8 @@ private void prepareDataForValidation(List<BrAPIImport> importRows, List<Column<
mappedImportRow.setObservationUnit(this.observationUnitByNameNoScope.get(createObservationUnitKey(importRow)));

// loop over phenotype column observation data for current row
List<PendingImportObject<BrAPIObservation>> observations = mappedImportRow.getObservations();
for (Column<?> column : phenotypeCols) {
List<PendingImportObject<BrAPIObservation>> observations = mappedImportRow.getObservations();

// if value was blank won't be entry in map for this observation
observations.add(this.observationByHash.get(getImportObservationHash(importRow, getVariableNameFromColumn(column))));
}
Expand Down Expand Up @@ -516,7 +515,7 @@ private void initNewBrapiData(List<BrAPIImport> importRows, List<Column<?>> phen
}
//column.name() gets phenotype name
String seasonDbId = this.yearToSeasonDbId(importRow.getEnvYear(), program.getId());
fetchOrCreateObservationPIO(importRow, column.name(), column.getString(rowNum), dateTimeValue, commit, seasonDbId, obsUnitPIO);
fetchOrCreateObservationPIO(program, user, importRow, column.name(), column.getString(rowNum), dateTimeValue, commit, seasonDbId, obsUnitPIO);
}
}
}
Expand Down Expand Up @@ -618,12 +617,18 @@ private Map<String, BrAPIObservation> fetchExistingObservations(List<Trait> refe

private void validateObservations(ValidationErrors validationErrors, int rowNum, ExperimentObservation importRow, List<Column<?>> phenotypeCols, Map<String, Trait> colVarMap, Map<String, BrAPIObservation> existingObservations) {
phenotypeCols.forEach(phenoCol -> {
if(existingObservations.containsKey(getImportObservationHash(importRow, phenoCol.name()))) {
var importHash = getImportObservationHash(importRow, phenoCol.name());
if(existingObservations.containsKey(importHash) && StringUtils.isNotBlank(phenoCol.getString(rowNum)) && !existingObservations.get(importHash).getValue().equals(phenoCol.getString(rowNum))) {
addRowError(
phenoCol.name(),
String.format("Value already exists for ObsUnitId: %s, Phenotype: %s", importRow.getObsUnitID(), phenoCol.name()),
validationErrors, rowNum
);
} else if(existingObservations.containsKey(importHash) && (StringUtils.isBlank(phenoCol.getString(rowNum)) || existingObservations.get(importHash).getValue().equals(phenoCol.getString(rowNum)))) {
BrAPIObservation existingObs = existingObservations.get(importHash);
existingObs.setObservationVariableName(phenoCol.name());
observationByHash.get(importHash).setState(ImportObjectState.EXISTING);
observationByHash.get(importHash).setBrAPIObject(existingObs);
} else {
validateObservationValue(colVarMap.get(phenoCol.name()), phenoCol.getString(rowNum), phenoCol.name(), validationErrors, rowNum);

Expand Down Expand Up @@ -808,7 +813,9 @@ private PendingImportObject<BrAPIObservationUnit> fetchOrCreateObsUnitPIO(Progra
}


private PendingImportObject<BrAPIObservation> fetchOrCreateObservationPIO(ExperimentObservation importRow,
private PendingImportObject<BrAPIObservation> fetchOrCreateObservationPIO(Program program,
User user,
ExperimentObservation importRow,
String variableName,
String value,
String timeStampValue,
Expand All @@ -820,7 +827,12 @@ private PendingImportObject<BrAPIObservation> fetchOrCreateObservationPIO(Experi
if (this.observationByHash.containsKey(key)) {
pio = observationByHash.get(key);
} else {
BrAPIObservation newObservation = importRow.constructBrAPIObservation(value, variableName, seasonDbId, obsUnitPIO.getBrAPIObject());
PendingImportObject<BrAPITrial> trialPIO = this.trialByNameNoScope.get(importRow.getExpTitle());
UUID trialID = trialPIO.getId();
PendingImportObject<BrAPIStudy> studyPIO = this.studyByNameNoScope.get(importRow.getEnv());
UUID studyID = studyPIO.getId();
UUID id = UUID.randomUUID();
BrAPIObservation newObservation = importRow.constructBrAPIObservation(value, variableName, seasonDbId, obsUnitPIO.getBrAPIObject(), commit, program, user, BRAPI_REFERENCE_SOURCE, trialID, studyID, obsUnitPIO.getId(), id);
//NOTE: Can't parse invalid timestamp value, so have to skip if invalid.
// Validation error should be thrown for offending value, but that doesn't happen until later downstream
if (timeStampValue != null && !timeStampValue.isBlank() && (validDateValue(timeStampValue) || validDateTimeValue(timeStampValue))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,158 @@ public void importSecondExpAfterFirstExpWithObs() {
assertRowSaved(newExpB, program, traits);
}

/*
Scenario:
- an experiment was created with observations
- do a second upload with additional observations for the experiment
- verify the second set of observations get uploaded successfully
*/
@ParameterizedTest
@ValueSource(booleans = {true, false})
@SneakyThrows
public void importNewObsAfterFirstExpWithObs(boolean commit) {
List<Trait> traits = createTraits(2);
Program program = createProgram("Exp with additional Uploads "+(commit ? "C" : "P"), "EXAU"+(commit ? "C" : "P"), "EXAU"+(commit ? "C" : "P"), BRAPI_REFERENCE_SOURCE, createGermplasm(1), traits);
Map<String, Object> newExp = new HashMap<>();
newExp.put(Columns.GERMPLASM_GID, "1");
newExp.put(Columns.TEST_CHECK, "T");
newExp.put(Columns.EXP_TITLE, "Test Exp");
newExp.put(Columns.EXP_UNIT, "Plot");
newExp.put(Columns.EXP_TYPE, "Phenotyping");
newExp.put(Columns.ENV, "New Env");
newExp.put(Columns.ENV_LOCATION, "Location A");
newExp.put(Columns.ENV_YEAR, "2023");
newExp.put(Columns.EXP_UNIT_ID, "a-1");
newExp.put(Columns.REP_NUM, "1");
newExp.put(Columns.BLOCK_NUM, "1");
newExp.put(Columns.ROW, "1");
newExp.put(Columns.COLUMN, "1");
newExp.put(traits.get(0).getObservationVariableName(), "1");

importTestUtils.uploadAndFetch(writeDataToFile(List.of(newExp), traits), null, true, client, program, mappingId);

BrAPITrial brAPITrial = brAPITrialDAO.getTrialsByName(List.of(Utilities.appendProgramKey((String)newExp.get(Columns.EXP_TITLE), program.getKey())), program).get(0);
Optional<BrAPIExternalReference> trialIdXref = Utilities.getExternalReference(brAPITrial.getExternalReferences(), String.format("%s/%s", BRAPI_REFERENCE_SOURCE, ExternalReferenceSource.TRIALS.getName()));
assertTrue(trialIdXref.isPresent());
BrAPIStudy brAPIStudy = brAPIStudyDAO.getStudiesByExperimentID(UUID.fromString(trialIdXref.get().getReferenceID()), program).get(0);

BrAPIObservationUnit ou = ouDAO.getObservationUnitsForStudyDbId(brAPIStudy.getStudyDbId(), program).get(0);
Optional<BrAPIExternalReference> ouIdXref = Utilities.getExternalReference(ou.getExternalReferences(), String.format("%s/%s", BRAPI_REFERENCE_SOURCE, ExternalReferenceSource.OBSERVATION_UNITS.getName()));
assertTrue(ouIdXref.isPresent());

Map<String, Object> newObservation = new HashMap<>();
newObservation.put(Columns.GERMPLASM_GID, "1");
newObservation.put(Columns.TEST_CHECK, "T");
newObservation.put(Columns.EXP_TITLE, "Test Exp");
newObservation.put(Columns.EXP_UNIT, "Plot");
newObservation.put(Columns.EXP_TYPE, "Phenotyping");
newObservation.put(Columns.ENV, "New Env");
newObservation.put(Columns.ENV_LOCATION, "Location A");
newObservation.put(Columns.ENV_YEAR, "2023");
newObservation.put(Columns.EXP_UNIT_ID, "a-1");
newObservation.put(Columns.REP_NUM, "1");
newObservation.put(Columns.BLOCK_NUM, "1");
newObservation.put(Columns.ROW, "1");
newObservation.put(Columns.COLUMN, "1");
newObservation.put(Columns.OBS_UNIT_ID, ouIdXref.get().getReferenceID());
newObservation.put(traits.get(0).getObservationVariableName(), "1");
newObservation.put(traits.get(1).getObservationVariableName(), "2");

JsonObject result = importTestUtils.uploadAndFetch(writeDataToFile(List.of(newObservation), traits), null, commit, client, program, mappingId);

JsonArray previewRows = result.get("preview").getAsJsonObject().get("rows").getAsJsonArray();
assertEquals(1, previewRows.size());
JsonObject row = previewRows.get(0).getAsJsonObject();

assertEquals("EXISTING", row.getAsJsonObject("trial").get("state").getAsString());
assertEquals("EXISTING", row.getAsJsonObject("location").get("state").getAsString());
assertEquals("EXISTING", row.getAsJsonObject("study").get("state").getAsString());
assertEquals("EXISTING", row.getAsJsonObject("observationUnit").get("state").getAsString());
if(commit) {
assertRowSaved(newObservation, program, traits);
} else {
assertValidPreviewRow(newObservation, row, program, traits);
}
}

/*
Scenario:
- an experiment was created with observations
- do a second upload with additional observations for the experiment. Make sure the original observations are blank values
- verify the second set of observations get uploaded successfully
*/
@ParameterizedTest
@ValueSource(booleans = {true, false})
@SneakyThrows
public void importNewObsAfterFirstExpWithObs_blank(boolean commit) {
List<Trait> traits = createTraits(2);
Program program = createProgram("Exp with additional Uploads (blank) "+(commit ? "C" : "P"), "EXAUB"+(commit ? "C" : "P"), "EXAUB"+(commit ? "C" : "P"), BRAPI_REFERENCE_SOURCE, createGermplasm(1), traits);
Map<String, Object> newExp = new HashMap<>();
newExp.put(Columns.GERMPLASM_GID, "1");
newExp.put(Columns.TEST_CHECK, "T");
newExp.put(Columns.EXP_TITLE, "Test Exp");
newExp.put(Columns.EXP_UNIT, "Plot");
newExp.put(Columns.EXP_TYPE, "Phenotyping");
newExp.put(Columns.ENV, "New Env");
newExp.put(Columns.ENV_LOCATION, "Location A");
newExp.put(Columns.ENV_YEAR, "2023");
newExp.put(Columns.EXP_UNIT_ID, "a-1");
newExp.put(Columns.REP_NUM, "1");
newExp.put(Columns.BLOCK_NUM, "1");
newExp.put(Columns.ROW, "1");
newExp.put(Columns.COLUMN, "1");
newExp.put(traits.get(0).getObservationVariableName(), "1");

importTestUtils.uploadAndFetch(writeDataToFile(List.of(newExp), traits), null, true, client, program, mappingId);

BrAPITrial brAPITrial = brAPITrialDAO.getTrialsByName(List.of(Utilities.appendProgramKey((String)newExp.get(Columns.EXP_TITLE), program.getKey())), program).get(0);
Optional<BrAPIExternalReference> trialIdXref = Utilities.getExternalReference(brAPITrial.getExternalReferences(), String.format("%s/%s", BRAPI_REFERENCE_SOURCE, ExternalReferenceSource.TRIALS.getName()));
assertTrue(trialIdXref.isPresent());
BrAPIStudy brAPIStudy = brAPIStudyDAO.getStudiesByExperimentID(UUID.fromString(trialIdXref.get().getReferenceID()), program).get(0);

BrAPIObservationUnit ou = ouDAO.getObservationUnitsForStudyDbId(brAPIStudy.getStudyDbId(), program).get(0);
Optional<BrAPIExternalReference> ouIdXref = Utilities.getExternalReference(ou.getExternalReferences(), String.format("%s/%s", BRAPI_REFERENCE_SOURCE, ExternalReferenceSource.OBSERVATION_UNITS.getName()));
assertTrue(ouIdXref.isPresent());

assertRowSaved(newExp, program, traits);

Map<String, Object> newObservation = new HashMap<>();
newObservation.put(Columns.GERMPLASM_GID, "1");
newObservation.put(Columns.TEST_CHECK, "T");
newObservation.put(Columns.EXP_TITLE, "Test Exp");
newObservation.put(Columns.EXP_UNIT, "Plot");
newObservation.put(Columns.EXP_TYPE, "Phenotyping");
newObservation.put(Columns.ENV, "New Env");
newObservation.put(Columns.ENV_LOCATION, "Location A");
newObservation.put(Columns.ENV_YEAR, "2023");
newObservation.put(Columns.EXP_UNIT_ID, "a-1");
newObservation.put(Columns.REP_NUM, "1");
newObservation.put(Columns.BLOCK_NUM, "1");
newObservation.put(Columns.ROW, "1");
newObservation.put(Columns.COLUMN, "1");
newObservation.put(Columns.OBS_UNIT_ID, ouIdXref.get().getReferenceID());
newObservation.put(traits.get(0).getObservationVariableName(), "");
newObservation.put(traits.get(1).getObservationVariableName(), "2");

JsonObject result = importTestUtils.uploadAndFetch(writeDataToFile(List.of(newObservation), traits), null, commit, client, program, mappingId);

JsonArray previewRows = result.get("preview").getAsJsonObject().get("rows").getAsJsonArray();
assertEquals(1, previewRows.size());
JsonObject row = previewRows.get(0).getAsJsonObject();

assertEquals("EXISTING", row.getAsJsonObject("trial").get("state").getAsString());
assertEquals("EXISTING", row.getAsJsonObject("location").get("state").getAsString());
assertEquals("EXISTING", row.getAsJsonObject("study").get("state").getAsString());
assertEquals("EXISTING", row.getAsJsonObject("observationUnit").get("state").getAsString());

newObservation.put(traits.get(0).getObservationVariableName(), "1");
if(commit) {
assertRowSaved(newObservation, program, traits);
} else {
assertValidPreviewRow(newObservation, row, program, traits);
}
}

private Map<String, Object> assertRowSaved(Map<String, Object> expected, Program program, List<Trait> traits) throws ApiException {
Map<String, Object> ret = new HashMap<>();

Expand Down