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
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.swagger.model.pheno.ObservationLevelNewRequest;
import io.swagger.model.pheno.ObservationUnitHierarchyLevel;
import io.swagger.model.pheno.ObservationUnitLevel;
import org.apache.commons.lang3.StringUtils;
import org.brapi.test.BrAPITestServer.exceptions.BrAPIServerDbIdNotFoundException;
import org.brapi.test.BrAPITestServer.exceptions.BrAPIServerException;
Expand Down Expand Up @@ -30,6 +31,10 @@ public class ObservationUnitLevelNameService {
private final static String GLOBAL_AND_PROGRAMMATIC_SET_MSG = "Both programDbId and global=true attributes are set. " +
"A level name cannot be both related to a program and be globally accessible. Choose one.";

private final static String NO_DB_ID_PROVIDED_MSG = "A level name associated with a program was provided that has more than one level order associated with it." +
" Once this kind of level name is in the database it is recommended to always provide levelNameDbIds for the level names submitted to get the correct level order." +
" Please search for the levelNameDbId for the submitted level names in the GET /observationlevelnames endpoint and provide them.";

private final static String GLOBAL_KEY_FOR_FOUND_ENTITIES = "global";

@Autowired
Expand All @@ -40,74 +45,70 @@ public ObservationUnitLevelNameService(ObservationUnitLevelNameRepository observ
}

/**
* Returns the verified level name entity. Should only be used with a list of size 1.
* Returns the verified level name entity. Should only be used with a list of size 1, lists are only used here
* to use the wildcard since there are different children of ObservationUnitLevel used in the callers of this method.
*/
public ObservationUnitLevelNameEntity verifyObservationUnitLevelName(String parentProgramDbId,
List<? extends ObservationUnitHierarchyLevel> submittedLevelName,
List<? extends ObservationUnitLevel> submittedLevelNames,
Map<String, ObservationUnitLevelNameEntity> foundLevelEntitiesByDbId,
Map<String, List<ObservationUnitLevelNameEntity>> foundLevelEntitiesGroupedByProgramId)
throws BrAPIServerException {

return verifyObservationUnitLevelNames(parentProgramDbId, submittedLevelName,
foundLevelEntitiesByDbId,
foundLevelEntitiesGroupedByProgramId).get(submittedLevelName.getFirst().getLevelName());
}

public Map<String, ObservationUnitLevelNameEntity> verifyObservationUnitLevelNames(String parentProgramDbId,
List<? extends ObservationUnitHierarchyLevel> submittedLevelNames,
Map<String, ObservationUnitLevelNameEntity> foundLevelEntitiesByDbId,
Map<String, List<ObservationUnitLevelNameEntity>> foundLevelEntitiesGroupedByProgramId)
throws BrAPIServerException {

Map<String, ObservationUnitLevelNameEntity> verifiedEntitiesByLevelName = new HashMap<>();
List<ObservationUnitHierarchyLevel> levelNamesNotFound = new ArrayList<>();

submittedLevelNames.forEach(sln -> {
if (submittedLevelNames.size() > 1) {
throw new IllegalArgumentException();
}

var verifiedLevelNamesCurrentSize = verifiedEntitiesByLevelName.size();
ObservationUnitLevel submittedLevelName = submittedLevelNames.getFirst();

if (StringUtils.isNotBlank(sln.getLevelNameDbId()) && foundLevelEntitiesByDbId.containsKey(sln.getLevelNameDbId())) {
ObservationUnitLevelNameEntity entity = foundLevelEntitiesByDbId.get(sln.getLevelNameDbId());
verifiedEntitiesByLevelName.put(entity.getLevelName(), entity);
} else if (StringUtils.isNotBlank(parentProgramDbId) && StringUtils.isNotBlank(sln.getLevelName()) && foundLevelEntitiesGroupedByProgramId.get(parentProgramDbId) != null) {
List<ObservationUnitLevelNameEntity> entities = foundLevelEntitiesGroupedByProgramId.get(parentProgramDbId);
ObservationUnitLevelNameEntity verifiedEntity = null;

entities.stream()
.filter(ouln -> ouln.getLevelName().equals(sln.getLevelName()))
.findFirst()
.ifPresent(ouln -> verifiedEntitiesByLevelName.put(ouln.getLevelName(), ouln));
} else if (StringUtils.isNotBlank(sln.getProgramDbId()) && StringUtils.isNotBlank(sln.getLevelName()) && foundLevelEntitiesGroupedByProgramId.get(sln.getProgramDbId()) != null) {
List<ObservationUnitLevelNameEntity> entities = foundLevelEntitiesGroupedByProgramId.get(sln.getProgramDbId());
if (StringUtils.isNotBlank(submittedLevelName.getLevelNameDbId()) && foundLevelEntitiesByDbId.containsKey(submittedLevelName.getLevelNameDbId())) {
verifiedEntity = foundLevelEntitiesByDbId.get(submittedLevelName.getLevelNameDbId());
} else if (StringUtils.isNotBlank(parentProgramDbId) && StringUtils.isNotBlank(submittedLevelName.getLevelName()) && foundLevelEntitiesGroupedByProgramId.get(parentProgramDbId) != null) {
// If parent programDbId is provided, utilize it to look up the level name.
List<ObservationUnitLevelNameEntity> entitiesMatchedByName = foundLevelEntitiesGroupedByProgramId.get(parentProgramDbId)
.stream()
.filter(ouln -> ouln.getLevelName().equals(submittedLevelName.getLevelName()))
.limit(2)
.toList();

entities.stream()
.filter(ouln -> ouln.getLevelName().equals(sln.getLevelName()))
.findFirst()
.ifPresent(ouln -> verifiedEntitiesByLevelName.put(ouln.getLevelName(), ouln));
if (entitiesMatchedByName.size() > 1) {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST, NO_DB_ID_PROVIDED_MSG);
} else if (entitiesMatchedByName.size() == 1) {
verifiedEntity = entitiesMatchedByName.getFirst();
}

if (verifiedLevelNamesCurrentSize == verifiedEntitiesByLevelName.size() && foundLevelEntitiesGroupedByProgramId.get(GLOBAL_KEY_FOR_FOUND_ENTITIES) != null) {
// All other ways of detecting the level name have failed so far, try the global ones as a last-ditch effort
List<ObservationUnitLevelNameEntity> globalEntities = foundLevelEntitiesGroupedByProgramId.get(GLOBAL_KEY_FOR_FOUND_ENTITIES);

globalEntities.stream()
.filter(ouln -> ouln.getLevelName().equals(sln.getLevelName()))
.findFirst()
.ifPresent(ouln -> verifiedEntitiesByLevelName.put(ouln.getLevelName(), ouln));
} else if (StringUtils.isNotBlank(submittedLevelName.getProgramDbId()) && StringUtils.isNotBlank(submittedLevelName.getLevelName()) && foundLevelEntitiesGroupedByProgramId.get(submittedLevelName.getProgramDbId()) != null) {
// Parent programDbId was not provided, if there's a programDbId inside the levelName itself try using that to get the level name.
List<ObservationUnitLevelNameEntity> entitiesMatchByName = foundLevelEntitiesGroupedByProgramId.get(submittedLevelName.getProgramDbId())
.stream()
.filter(ouln -> ouln.getLevelName().equals(submittedLevelName.getLevelName()))
.limit(2)
.toList();

if (entitiesMatchByName.size() > 1) {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST, NO_DB_ID_PROVIDED_MSG);
} else if (entitiesMatchByName.size() == 1) {
verifiedEntity = entitiesMatchByName.getFirst();
}
}

if (verifiedLevelNamesCurrentSize == verifiedEntitiesByLevelName.size()) {
// This level name was not found. Add it to the list to notify user which level names are invalid.
levelNamesNotFound.add(sln);
}
});
if (verifiedEntity == null && foundLevelEntitiesGroupedByProgramId.get(GLOBAL_KEY_FOR_FOUND_ENTITIES) != null) {
// All other ways of detecting the level name have failed so far, try the global ones as a last-ditch effort
List<ObservationUnitLevelNameEntity> globalEntities = foundLevelEntitiesGroupedByProgramId.get(GLOBAL_KEY_FOR_FOUND_ENTITIES);

verifiedEntity = globalEntities.stream()
.filter(ouln -> ouln.getLevelName().equals(submittedLevelName.getLevelName()))
.findFirst()
.orElse(null);
}

if (!levelNamesNotFound.isEmpty()) {
if (verifiedEntity == null) {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST, String.format("The following submitted level names were not found: [%s]. " +
" Please check that these level names exist in the DB by using the /observationlevelnames endpoints. If they do not exist, they can be added there.",
levelNamesNotFound));
" Please check that these level names exist in the DB by using the /observationlevelnames endpoints. If they do not exist, they can be added there.",
submittedLevelName));
}

return verifiedEntitiesByLevelName;
return verifiedEntity;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,7 @@ private void updateOUPosition(ObservationUnitPosition position,
if (position.getObservationLevel() != null) {
if (position.getObservationLevel().getLevelCode() != null)
pEntity.setLevelCode(position.getObservationLevel().getLevelCode());
if (position.getObservationLevel().getLevelName() != null) {
if (position.getObservationLevel() != null) {
var parentProgramDbId = Optional.ofNullable(ouEntity.getProgram())
.map(p -> p.getId().toString())
.orElse(null);
Expand Down Expand Up @@ -860,17 +860,19 @@ private void updateOULevelRelationships(ObservationUnitEntity ouEntity,
.map(p -> p.getId().toString())
.orElse(null);

var foundOULevelNames = observationUnitLevelNameService.verifyObservationUnitLevelNames(programDbId,
position.getObservationLevelRelationships(),
foundLevelNameEntitiesByDbId,
foundLevelNamesGroupedByProgramId);

var relationshipEntities = new ArrayList<ObservationUnitLevelRelationshipEntity>();

for (ObservationUnitLevelRelationship level : position.getObservationLevelRelationships()) {
ObservationUnitLevelRelationshipEntity relationshipEntity = new ObservationUnitLevelRelationshipEntity();
relationshipEntity.setLevelCode(level.getLevelCode());
relationshipEntity.setLevelName(foundOULevelNames.get(level.getLevelName()));

var foundOULevelName = observationUnitLevelNameService.verifyObservationUnitLevelName(programDbId,
List.of(level),
foundLevelNameEntitiesByDbId,
foundLevelNamesGroupedByProgramId);

relationshipEntity.setLevelName(foundOULevelName);

if (level.getObservationUnitDbId() != null) {
ObservationUnitEntity parentEntity = getObservationUnitEntity(level.getObservationUnitDbId());
relationshipEntity.setObservationUnit(parentEntity);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DROP INDEX lvl_name_program_order_idx;

CREATE UNIQUE INDEX lvl_name_program_id_idx ON observation_unit_level_name (level_name, program_id);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DROP INDEX lvl_name_program_id_idx;

CREATE UNIQUE INDEX lvl_name_program_order_idx ON observation_unit_level_name (level_name, program_id, level_order);