diff --git a/src/main/java/org/brapi/test/BrAPITestServer/service/pheno/ObservationUnitLevelNameService.java b/src/main/java/org/brapi/test/BrAPITestServer/service/pheno/ObservationUnitLevelNameService.java index 1d918e1a..5f317429 100644 --- a/src/main/java/org/brapi/test/BrAPITestServer/service/pheno/ObservationUnitLevelNameService.java +++ b/src/main/java/org/brapi/test/BrAPITestServer/service/pheno/ObservationUnitLevelNameService.java @@ -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; @@ -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 @@ -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 submittedLevelName, + List submittedLevelNames, Map foundLevelEntitiesByDbId, Map> foundLevelEntitiesGroupedByProgramId) throws BrAPIServerException { - return verifyObservationUnitLevelNames(parentProgramDbId, submittedLevelName, - foundLevelEntitiesByDbId, - foundLevelEntitiesGroupedByProgramId).get(submittedLevelName.getFirst().getLevelName()); - } - - public Map verifyObservationUnitLevelNames(String parentProgramDbId, - List submittedLevelNames, - Map foundLevelEntitiesByDbId, - Map> foundLevelEntitiesGroupedByProgramId) - throws BrAPIServerException { - - Map verifiedEntitiesByLevelName = new HashMap<>(); - List 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 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 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 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 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 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 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; } /** diff --git a/src/main/java/org/brapi/test/BrAPITestServer/service/pheno/ObservationUnitService.java b/src/main/java/org/brapi/test/BrAPITestServer/service/pheno/ObservationUnitService.java index 5a7ba02d..cd819320 100644 --- a/src/main/java/org/brapi/test/BrAPITestServer/service/pheno/ObservationUnitService.java +++ b/src/main/java/org/brapi/test/BrAPITestServer/service/pheno/ObservationUnitService.java @@ -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); @@ -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(); 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); diff --git a/src/main/resources/db/migration/U005.004__revert_level_name_schema.sql b/src/main/resources/db/migration/U005.004__revert_level_name_schema.sql new file mode 100644 index 00000000..141e801e --- /dev/null +++ b/src/main/resources/db/migration/U005.004__revert_level_name_schema.sql @@ -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); \ No newline at end of file diff --git a/src/main/resources/db/migration/V005.004__level_name_schema_update.sql b/src/main/resources/db/migration/V005.004__level_name_schema_update.sql new file mode 100644 index 00000000..4fad5ff8 --- /dev/null +++ b/src/main/resources/db/migration/V005.004__level_name_schema_update.sql @@ -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);