diff --git a/backend/src/main/java/ca/bc/gov/backendstartapi/service/ParentTreeService.java b/backend/src/main/java/ca/bc/gov/backendstartapi/service/ParentTreeService.java index e40d35ee3..ccfb989c0 100644 --- a/backend/src/main/java/ca/bc/gov/backendstartapi/service/ParentTreeService.java +++ b/backend/src/main/java/ca/bc/gov/backendstartapi/service/ParentTreeService.java @@ -90,7 +90,7 @@ public PtCalculationResDto calculatePtVals(PtValsCalReqDto ptVals) { } // --col:W - if (varTotalConeCount.compareTo(BigDecimal.ZERO) > 0) { + if (varTotalPollenCount.compareTo(BigDecimal.ZERO) > 0) { varParentPropOrchPoll = ptPollenCount.divide(varTotalPollenCount, DIVISION_SCALE, halfUp); } diff --git a/oracle-api/src/main/java/ca/bc/gov/oracleapi/dto/ParentTreeGeoNodeDto.java b/oracle-api/src/main/java/ca/bc/gov/oracleapi/dto/ParentTreeGeoNodeDto.java new file mode 100644 index 000000000..e2e18827d --- /dev/null +++ b/oracle-api/src/main/java/ca/bc/gov/oracleapi/dto/ParentTreeGeoNodeDto.java @@ -0,0 +1,62 @@ +package ca.bc.gov.oracleapi.dto; + +import ca.bc.gov.oracleapi.entity.ParentTreeEntity; +import java.util.Optional; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** This class represents a GeoNode with all elevation, lat and long mean values. */ +@Setter +@NoArgsConstructor +public class ParentTreeGeoNodeDto { + + private Integer elevation; + private Integer latitudeDegrees; + private Integer latitudeMinutes; + private Integer latitudeSeconds; + private Integer longitudeDegrees; + private Integer longitudeMinutes; + private Integer longitudeSeconds; + + ParentTreeGeoNodeDto(ParentTreeEntity entity) { + this.elevation = entity.getElevation(); + this.latitudeDegrees = entity.getLatitudeDegrees(); + this.latitudeMinutes = entity.getLatitudeMinutes(); + this.latitudeSeconds = entity.getLatitudeSeconds(); + this.longitudeDegrees = entity.getLongitudeDegrees(); + this.longitudeMinutes = entity.getLongitudeMinutes(); + this.longitudeSeconds = entity.getLongitudeSeconds(); + } + + public Integer getElevation() { + return this.elevation; + } + + public int getElevationIntVal() { + return Optional.ofNullable(elevation).orElse(0); + } + + public int getLatitudeDegreesIntVal() { + return Optional.ofNullable(latitudeDegrees).orElse(0); + } + + public int getLatitudeMinutesIntVal() { + return Optional.ofNullable(latitudeMinutes).orElse(0); + } + + public int getLatitudeSecondsIntVal() { + return Optional.ofNullable(latitudeSeconds).orElse(0); + } + + public int getLongitudeDegreesIntVal() { + return Optional.ofNullable(longitudeDegrees).orElse(0); + } + + public int getLongitudeMinutesIntVal() { + return Optional.ofNullable(longitudeMinutes).orElse(0); + } + + public int getLongitudeSecondsIntVal() { + return Optional.ofNullable(longitudeSeconds).orElse(0); + } +} diff --git a/oracle-api/src/main/java/ca/bc/gov/oracleapi/dto/ParentTreeNodeDto.java b/oracle-api/src/main/java/ca/bc/gov/oracleapi/dto/ParentTreeNodeDto.java new file mode 100644 index 000000000..d912ac19f --- /dev/null +++ b/oracle-api/src/main/java/ca/bc/gov/oracleapi/dto/ParentTreeNodeDto.java @@ -0,0 +1,195 @@ +package ca.bc.gov.oracleapi.dto; + +import ca.bc.gov.oracleapi.config.SparLog; +import ca.bc.gov.oracleapi.entity.ParentTreeEntity; +import java.util.Optional; +import lombok.Getter; +import lombok.Setter; + +/** This class represents a parent tree node. */ +@Getter +@Setter +public class ParentTreeNodeDto { + + private final ParentTreeEntity value; + private ParentTreeNodeDto femaleParent; + private ParentTreeNodeDto maleParent; + private ParentTreeGeoNodeDto geoNode; + + /** + * Creates a Parent Tree Node. + * + * @param value The parent tree entity instance. + */ + public ParentTreeNodeDto(ParentTreeEntity value) { + this.value = value; + this.geoNode = new ParentTreeGeoNodeDto(value); + } + + /** + * Add a parent tree node female or male. + * + * @param parentTreeId the reference parent id tree to look for. + * @param entity the parent tree entity instance. + */ + public void add(Long parentTreeId, ParentTreeEntity entity) { + if (parentTreeId.equals(value.getFemaleParentTreeId())) { + femaleParent = new ParentTreeNodeDto(entity); + } else if (parentTreeId.equals(value.getMaleParentTreeId())) { + maleParent = new ParentTreeNodeDto(entity); + } else { + if (femaleParent != null) { + femaleParent.add(parentTreeId, entity); + } + if (maleParent != null) { + maleParent.add(parentTreeId, entity); + } + } + } + + /** + * Get a Parent tree's parent elevation (and all lat and long mean values), recursively, looking + * at parent's parent and finding the 'mean' value when required. The calculation piece of code + * was brought exactly as is in SPR_GET_PT_GEOG.prc file on SPAR Legacy. + * + * @param current Current node in the tree + * @param femaleNode Female parent node in the tree + * @param maleNode Male parent node in the tree + * @return A female node if female has data, or a new node with mean values from female and male. + */ + private ParentTreeGeoNodeDto getParentsMeanElevation( + ParentTreeNodeDto current, ParentTreeNodeDto femaleNode, ParentTreeNodeDto maleNode) { + if (current.geoNode.getElevation() != null) { + return current.geoNode; + } + ParentTreeGeoNodeDto femaleElevation = new ParentTreeGeoNodeDto(); + if (current.femaleParent != null) { + femaleElevation = + Optional.ofNullable( + getParentsMeanElevation( + current.femaleParent, + current.femaleParent.femaleParent, + current.femaleParent.maleParent)) + .orElse(new ParentTreeGeoNodeDto()); + } + ParentTreeGeoNodeDto maleElevation = new ParentTreeGeoNodeDto(); + if (current.maleParent != null) { + maleElevation = + Optional.ofNullable( + getParentsMeanElevation( + current.maleParent, + current.maleParent.femaleParent, + current.maleParent.maleParent)) + .orElse(new ParentTreeGeoNodeDto()); + } + if (maleElevation.getElevationIntVal() == 0 && femaleElevation.getElevationIntVal() > 0) { + return femaleElevation; + } else if (maleElevation.getElevationIntVal() > 0 && femaleElevation.getElevationIntVal() > 0) { + int noOfParents = 2; + ParentTreeGeoNodeDto meanNode = new ParentTreeGeoNodeDto(); + + // Elevation + int meanElevation = + (maleElevation.getElevationIntVal() + femaleElevation.getElevationIntVal()) / noOfParents; + meanNode.setElevation(meanElevation); + + // All other calculations (Lat and Long) + int calc = + (femaleElevation.getLatitudeDegreesIntVal() * 3600) + + (femaleElevation.getLatitudeMinutesIntVal() * 60) + + femaleElevation.getLatitudeSecondsIntVal(); + calc = + calc + + (maleElevation.getLatitudeDegreesIntVal() * 3600) + + (maleElevation.getLatitudeMinutesIntVal() * 60) + + maleElevation.getLatitudeSecondsIntVal(); + // --derive mean + calc = calc / noOfParents; + int latitudeDegrees = calc / 3600; + meanNode.setLatitudeDegrees(latitudeDegrees); + + int buff = calc % 3600; + int latitudeMinutes = buff / 60; + meanNode.setLatitudeMinutes(latitudeMinutes); + + buff = calc % 60; + int latitudeSeconds = buff; + meanNode.setLatitudeSeconds(latitudeSeconds); + + calc = + (femaleElevation.getLongitudeDegreesIntVal() * 3600) + + (femaleElevation.getLongitudeMinutesIntVal() * 60) + + femaleElevation.getLongitudeSecondsIntVal(); + calc = + calc + + (maleElevation.getLongitudeDegreesIntVal() * 3600) + + (maleElevation.getLongitudeMinutesIntVal() * 60) + + maleElevation.getLongitudeSecondsIntVal(); + // --derive mean + calc = calc / noOfParents; + int longitudeDegrees = calc / 3600; + meanNode.setLongitudeDegrees(longitudeDegrees); + + buff = calc % 3600; + int longitudeMinutes = buff / 60; + meanNode.setLongitudeMinutes(longitudeMinutes); + + buff = calc % 60; + int longitudeSeconds = buff; + meanNode.setLongitudeSeconds(longitudeSeconds); + + return meanNode; + } + return null; + } + + /** + * Get the parent tree mean elevation looking into parent trees family. + * + * @return an integer representing the mean elevation. + */ + public ParentTreeGeoNodeDto getParentTreeElevation() { + ParentTreeGeoNodeDto elevation = + getParentsMeanElevation(this, this.femaleParent, this.maleParent); + return elevation; + } + + /** + * Prints the current node. + * + * @param level Current level in the tree + */ + public String printLevel(int level) { + String message = String.format("Level %d - %s", level, toString()); + SparLog.info(message); + if (femaleParent != null) { + return femaleParent.printLevel(level + 1); + } + if (maleParent != null) { + return maleParent.printLevel(level + 1); + } + return message; + } + + /** Gets the string version of the node. */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder("ParentTreeId="); + sb.append(value.getId()); + sb.append(" (elev: ").append(value.getElevation()).append(") "); + sb.append("["); + boolean added = false; + if (value.getFemaleParentTreeId() != null) { + sb.append("femaleParentId=").append(value.getFemaleParentTreeId()); + added = true; + } + if (value.getMaleParentTreeId() != null) { + if (added) { + sb.append(", "); + } + sb.append("male=").append(value.getMaleParentTreeId()); + } + sb.append("]"); + return sb.toString(); + } +} diff --git a/oracle-api/src/main/java/ca/bc/gov/oracleapi/entity/ParentTreeEntity.java b/oracle-api/src/main/java/ca/bc/gov/oracleapi/entity/ParentTreeEntity.java index 9efbedba7..6d7b693b5 100644 --- a/oracle-api/src/main/java/ca/bc/gov/oracleapi/entity/ParentTreeEntity.java +++ b/oracle-api/src/main/java/ca/bc/gov/oracleapi/entity/ParentTreeEntity.java @@ -73,4 +73,9 @@ public class ParentTreeEntity { @Column(name = "ELEVATION") private Integer elevation; + + @Override + public String toString() { + return getId().toString(); + } } diff --git a/oracle-api/src/main/java/ca/bc/gov/oracleapi/repository/ParentTreeRepository.java b/oracle-api/src/main/java/ca/bc/gov/oracleapi/repository/ParentTreeRepository.java index 8e00c6a33..82ce715af 100644 --- a/oracle-api/src/main/java/ca/bc/gov/oracleapi/repository/ParentTreeRepository.java +++ b/oracle-api/src/main/java/ca/bc/gov/oracleapi/repository/ParentTreeRepository.java @@ -9,8 +9,7 @@ /** This class holds methods for retrieving {@link ParentTreeEntity} data from the database. */ public interface ParentTreeRepository extends JpaRepository { - @Query("from ParentTreeEntity where id in ?1") - List findAllIn(List ids); + List findAllByIdIn(List ids); @Query( value = diff --git a/oracle-api/src/main/java/ca/bc/gov/oracleapi/service/OrchardService.java b/oracle-api/src/main/java/ca/bc/gov/oracleapi/service/OrchardService.java index 74cb5ec3d..e2d045209 100644 --- a/oracle-api/src/main/java/ca/bc/gov/oracleapi/service/OrchardService.java +++ b/oracle-api/src/main/java/ca/bc/gov/oracleapi/service/OrchardService.java @@ -283,7 +283,7 @@ private List findAllParentTree( long endingFour = Instant.now().toEpochMilli(); SparLog.debug("Time elapsed mapping all parent tree orchard ids: {}", endingFour - endingThree); - List parentTreeList = parentTreeRepository.findAllIn(parentTreeIdList); + List parentTreeList = parentTreeRepository.findAllByIdIn(parentTreeIdList); long endingFive = Instant.now().toEpochMilli(); SparLog.debug("Time elapsed finding all parent tree (select in): {}", endingFive - endingFour); diff --git a/oracle-api/src/main/java/ca/bc/gov/oracleapi/service/ParentTreeService.java b/oracle-api/src/main/java/ca/bc/gov/oracleapi/service/ParentTreeService.java index 2e4ccb545..e93eac252 100644 --- a/oracle-api/src/main/java/ca/bc/gov/oracleapi/service/ParentTreeService.java +++ b/oracle-api/src/main/java/ca/bc/gov/oracleapi/service/ParentTreeService.java @@ -5,6 +5,8 @@ import ca.bc.gov.oracleapi.dto.GeospatialRespondDto; import ca.bc.gov.oracleapi.dto.ParentTreeByVegCodeDto; import ca.bc.gov.oracleapi.dto.ParentTreeGeneticQualityDto; +import ca.bc.gov.oracleapi.dto.ParentTreeGeoNodeDto; +import ca.bc.gov.oracleapi.dto.ParentTreeNodeDto; import ca.bc.gov.oracleapi.entity.ParentTreeEntity; import ca.bc.gov.oracleapi.entity.projection.ParentTreeProj; import ca.bc.gov.oracleapi.repository.ParentTreeRepository; @@ -25,6 +27,8 @@ public class ParentTreeService { private final ParentTreeRepository parentTreeRepository; + private static final Integer MAX_LEVELS = 5; + /** * Gets latitude, longite and elevation data for each parent tree given a list of Parent Tree ids. * @@ -35,30 +39,154 @@ public List getPtGeoSpatialData(List SparLog.info("Getting lat long elevation data for {} parent tree id(s)", ptIds); List idList = ptIds.stream().map(GeospatialRequestDto::parentTreeId).toList(); - List ptEntityList = parentTreeRepository.findAllIn(idList); + List ptEntityList = parentTreeRepository.findAllByIdIn(idList); + Map parentTreeRootMap; + + // If there's one or more null elevation, go up on the hierarchy + boolean isAnyMissing = parentTreeListHasAnyElevationMissing(ptEntityList); + if (isAnyMissing) { + parentTreeRootMap = checkParentTreeHierarchy(ptEntityList); + } else { + parentTreeRootMap = new HashMap<>(); + ptEntityList.forEach((pt) -> parentTreeRootMap.put(pt.getId(), new ParentTreeNodeDto(pt))); + } List resultList = new ArrayList<>(); + for (Map.Entry rootEntry : parentTreeRootMap.entrySet()) { + Long parentTreeId = rootEntry.getKey(); + + // navigate the tree here! + ParentTreeNodeDto root = rootEntry.getValue(); + SparLog.debug(root.printLevel(0)); - ptEntityList.forEach( - (pt) -> { - GeospatialRespondDto dto = - new GeospatialRespondDto( - pt.getId(), - Optional.ofNullable(pt.getLatitudeDegrees()).orElse(0), - Optional.ofNullable(pt.getLatitudeMinutes()).orElse(0), - Optional.ofNullable(pt.getLatitudeSeconds()).orElse(0), - Optional.ofNullable(pt.getLongitudeDegrees()).orElse(0), - Optional.ofNullable(pt.getLongitudeMinutes()).orElse(0), - Optional.ofNullable(pt.getLongitudeSeconds()).orElse(0), - Optional.ofNullable(pt.getElevation()).orElse(0)); - - resultList.add(dto); - }); + ParentTreeGeoNodeDto elevation = root.getParentTreeElevation(); + if (elevation == null) { + SparLog.error("No elevation for Parent tree ID {}", parentTreeId); + continue; + } + + GeospatialRespondDto dto = + new GeospatialRespondDto( + parentTreeId, + elevation.getLatitudeDegreesIntVal(), + elevation.getLatitudeMinutesIntVal(), + elevation.getLatitudeSecondsIntVal(), + elevation.getLongitudeDegreesIntVal(), + elevation.getLongitudeMinutesIntVal(), + elevation.getLongitudeSecondsIntVal(), + elevation.getElevation()); + + resultList.add(dto); + } SparLog.info("{} records found for lat long data", resultList.size()); return resultList; } + private Map checkParentTreeHierarchy( + List ptEntityList) { + // Map to store a combination of a ParentTree ID and it's parents in the tree architecture. + Map resultMap = new HashMap<>(); + + // Map to store a combination of a ParentTree ID and it's direct parents, for easily access + Map> parentTreeRelationMap = new HashMap<>(); + + // Create root level + for (ParentTreeEntity ptEntity : ptEntityList) { + resultMap.putIfAbsent(ptEntity.getId(), new ParentTreeNodeDto(ptEntity)); + } + + for (int i = 0; i < MAX_LEVELS; i++) { + SparLog.debug("Hierarchy level {}", i); + + List testList = new ArrayList<>(); + + // Loop through all ParentTree records, getting their female and male parents for the ones + // that has no elevation data + for (ParentTreeEntity ptEntity : ptEntityList) { + if (ptEntity.getElevation() == null) { + parentTreeRelationMap.put(ptEntity.getId(), new ArrayList<>(2)); + + if (ptEntity.getFemaleParentTreeId() != null) { + testList.add(ptEntity.getFemaleParentTreeId()); + parentTreeRelationMap.get(ptEntity.getId()).add(ptEntity.getFemaleParentTreeId()); + } + if (ptEntity.getMaleParentTreeId() != null) { + testList.add(ptEntity.getMaleParentTreeId()); + parentTreeRelationMap.get(ptEntity.getId()).add(ptEntity.getMaleParentTreeId()); + } + } + } + + // Query from the DB all female and male parents (gathered from the loop above) + List nextLevelList = parentTreeRepository.findAllByIdIn(testList); + + // Loop through the relation of ParentTree ids and its parents + for (Map.Entry> entry : parentTreeRelationMap.entrySet()) { + // The 'sonParentTreeId' represents the parent tree without elevation data + Long sonParentTreeId = entry.getKey(); + + // The 'femaleAndMaleParentsIds' represents their parents ids + List femaleAndMaleParentsIds = entry.getValue(); + + // Loop through the list of parent tree from DB, aiming to connect them with their sons + for (ParentTreeEntity ptEntity : nextLevelList) { + + // If 'femaleAndMaleParentsIds' contains the current parent tree id, it means that the + // current parent tree id is one of the parents, it could be either the female or male. + if (femaleAndMaleParentsIds.contains(ptEntity.getId())) { + + // If resultMap doesn't have 'sonParentTreeId' key, it means this is not the first level + // and it should look at the 'parentTreeRelationMap' who has ALL the parent tree + // 'son-parents' relation + if (resultMap.get(sonParentTreeId) == null) { + SparLog.debug("Key (sonParentTreeId) not found for PT id {}", sonParentTreeId); + for (Map.Entry> entryTwo : parentTreeRelationMap.entrySet()) { + if (entryTwo.getValue().contains(sonParentTreeId)) { + sonParentTreeId = entryTwo.getKey(); + break; + } + } + } + + // Get female parent tree data and connect with son. Female is always the first + Long femaleParentTreeId = femaleAndMaleParentsIds.get(0); + if (femaleParentTreeId.equals(ptEntity.getId())) { + SparLog.debug("{} is female parent of {}", ptEntity.getId(), sonParentTreeId); + resultMap.get(sonParentTreeId).add(femaleParentTreeId, ptEntity); + } + + // Get male parent tree data and connect with son. Male is optional + if (femaleAndMaleParentsIds.size() > 1) { + Long maleParentTreeId = entry.getValue().get(1); + if (maleParentTreeId.equals(ptEntity.getId())) { + SparLog.debug("{} is male parent of {}", ptEntity.getId(), sonParentTreeId); + resultMap.get(sonParentTreeId).add(maleParentTreeId, ptEntity); + } + } + } + } + } + + // After loop through all records, check if all parents now has elevation data + // If yes, leave. If not, keep going up looking for the parent's parent + boolean isAnyMissing = parentTreeListHasAnyElevationMissing(nextLevelList); + if (!isAnyMissing) { + SparLog.debug("All elevations has been found. Leaving!"); + break; + } else { + SparLog.debug("Not all elevations has been found. Going up on the hierarchy!"); + ptEntityList = new ArrayList<>(nextLevelList); + } + } + + return resultMap; + } + + private boolean parentTreeListHasAnyElevationMissing(List list) { + return list.stream().filter(tree -> tree.getElevation() == null).count() > 0; + } + /** * Find all parent trees under a vegCode. * diff --git a/oracle-api/src/test/java/ca/bc/gov/oracleapi/repository/ParentTreeRepositoryTest.java b/oracle-api/src/test/java/ca/bc/gov/oracleapi/repository/ParentTreeRepositoryTest.java index df201f803..cdf4394da 100644 --- a/oracle-api/src/test/java/ca/bc/gov/oracleapi/repository/ParentTreeRepositoryTest.java +++ b/oracle-api/src/test/java/ca/bc/gov/oracleapi/repository/ParentTreeRepositoryTest.java @@ -23,9 +23,10 @@ class ParentTreeRepositoryTest { @Autowired private ParentTreeRepository parentTreeRepository; @Test - @DisplayName("findAllInTest") - void findAllInTest() { - List parentTreeList = parentTreeRepository.findAllIn(List.of(4032L, 4033L)); + @DisplayName("findAllByIdInTest") + void findAllByIdInTest() { + List parentTreeList = + parentTreeRepository.findAllByIdIn(List.of(4032L, 4033L)); assertFalse(parentTreeList.isEmpty()); assertEquals(2, parentTreeList.size()); @@ -58,7 +59,7 @@ void findAllInTest() { @Test @DisplayName("getPtGeoSpatialData_successTest") void getPtGeoSpatialData_successTest() { - List ptreeEntity = parentTreeRepository.findAllIn(List.of(4032L)); + List ptreeEntity = parentTreeRepository.findAllByIdIn(List.of(4032L)); assertFalse(ptreeEntity.isEmpty()); assertEquals(1, ptreeEntity.size()); diff --git a/oracle-api/src/test/java/ca/bc/gov/oracleapi/service/OrchardServiceTest.java b/oracle-api/src/test/java/ca/bc/gov/oracleapi/service/OrchardServiceTest.java index 7965c6864..5a9b196c7 100644 --- a/oracle-api/src/test/java/ca/bc/gov/oracleapi/service/OrchardServiceTest.java +++ b/oracle-api/src/test/java/ca/bc/gov/oracleapi/service/OrchardServiceTest.java @@ -216,7 +216,7 @@ void findParentTreeGeneticQualityDataTest_Success() { parentTree.setTested(true); parentTree.setBreedingProgram(true); - when(parentTreeRepository.findAllIn(any())).thenReturn(List.of(parentTree)); + when(parentTreeRepository.findAllByIdIn(any())).thenReturn(List.of(parentTree)); Long spuId = 7L; diff --git a/oracle-api/src/test/java/ca/bc/gov/oracleapi/service/ParentTreeServiceTest.java b/oracle-api/src/test/java/ca/bc/gov/oracleapi/service/ParentTreeServiceTest.java index ae7bcb6f1..946f04c46 100644 --- a/oracle-api/src/test/java/ca/bc/gov/oracleapi/service/ParentTreeServiceTest.java +++ b/oracle-api/src/test/java/ca/bc/gov/oracleapi/service/ParentTreeServiceTest.java @@ -114,7 +114,7 @@ void getPtGeoSpatialData_successTest() { ptreeEntity.setLongitudeSeconds(0); ptreeEntity.setElevation(451); - when(parentTreeRepository.findAllIn(List.of(4110L))).thenReturn(List.of(ptreeEntity)); + when(parentTreeRepository.findAllByIdIn(List.of(4110L))).thenReturn(List.of(ptreeEntity)); List ptIds = new ArrayList<>(); ptIds.add(new GeospatialRequestDto(4110L)); @@ -135,7 +135,7 @@ void getPtGeoSpatialData_successTest() { @Test @DisplayName("getPtGeoSpatialData_emptyTest") void getPtGeoSpatialData_emptyTest() { - when(parentTreeRepository.findAllIn(List.of(4110L))).thenReturn(List.of()); + when(parentTreeRepository.findAllByIdIn(List.of(4110L))).thenReturn(List.of()); List ptIds = new ArrayList<>(); ptIds.add(new GeospatialRequestDto(4110L)); @@ -162,4 +162,199 @@ void findParentTreesWithVegCode_happyPath_shouldSucceed() { Assertions.assertEquals(1, response.size()); Assertions.assertTrue(response.containsKey("29")); } + + private ParentTreeEntity mock( + Long id, Integer elevation, Integer[] lat, Integer[] lng, Long femaleId, Long maleId) { + ParentTreeEntity ptreeEntityReq1 = new ParentTreeEntity(); + ptreeEntityReq1.setId(id); + ptreeEntityReq1.setLatitudeDegrees(lat == null ? null : lat[0]); + ptreeEntityReq1.setLatitudeMinutes(lat == null ? null : lat[1]); + ptreeEntityReq1.setLatitudeSeconds(lat == null ? null : lat[2]); + ptreeEntityReq1.setLongitudeDegrees(lng == null ? null : lng[0]); + ptreeEntityReq1.setLongitudeMinutes(lng == null ? null : lng[1]); + ptreeEntityReq1.setLongitudeSeconds(lng == null ? null : lng[2]); + ptreeEntityReq1.setElevation(elevation); + ptreeEntityReq1.setFemaleParentTreeId(femaleId); + ptreeEntityReq1.setMaleParentTreeId(maleId); + return ptreeEntityReq1; + } + + private ParentTreeEntity mockNull(Long id, Long femaleId, Long maleId) { + return mock(id, null, null, null, femaleId, maleId); + } + + @Test + @DisplayName("Get parent tree geo spatial data hierarchy tree should succeed") + void getPtGeoSpatialData_hierarchyTree_shouldSucceed() { + /* + * TEST CASE: PT id 1002614 = mean elevation is 675 - female parent id 4168 (elevation 610) - + * male parent id 4638 (elevation 740) PT id 1001097 = mean elevation is 465 - female parent id + * 4668 (elevation 823) - male parent id 4628 (elevation 107) PT id 1001096 = mean elevation is + * 465 - female parent id 4668 (elevation 823) - male parent id 4628 (elevation 107) PT id + * 1004423 = mean elevation is 526 - female parent id 1000031 = mean elevation is 573 - female + * parent id 4700 (elevation 628) - male parent id 4035 (elevation 518) - male parent id 1004424 + * = mean elevation is 480 - female parent id 4035 (elevation 518) - male parent id 4078 + * (elevation 442) PT id 1001093 = mean elevation is 84 - female parent id 4197 (elevation 61) - + * male parent id 4182 (elevation 107) + */ + + // First run start + ParentTreeEntity ptreeRoot1 = mockNull(1002614L, 4168L, 4638L); + ParentTreeEntity ptreeRoot2 = mockNull(1001097L, 4668L, 4628L); + ParentTreeEntity ptreeRoot3 = mockNull(1001096L, 4668L, 4628L); + ParentTreeEntity ptreeRoot4 = mockNull(1004423L, 1000031L, 1004424L); + ParentTreeEntity ptreeRoot5 = mockNull(1001093L, 4197L, 4182L); + + List firstRequestList = + List.of( + ptreeRoot1.getId(), + ptreeRoot2.getId(), + ptreeRoot3.getId(), + ptreeRoot4.getId(), + ptreeRoot5.getId()); + + List firstResponseList = + List.of(ptreeRoot1, ptreeRoot2, ptreeRoot3, ptreeRoot4, ptreeRoot5); + + when(parentTreeRepository.findAllByIdIn(firstRequestList)).thenReturn(firstResponseList); + // First run end + + // Second run start + ParentTreeEntity ptreeRoot1Mother = + mock(4168L, 610, new Integer[] {49, 7, 0}, new Integer[] {121, 36, 0}, null, null); + ParentTreeEntity ptreeRoot1Father = + mock(4638L, 740, new Integer[] {48, 5, 0}, new Integer[] {124, 0, 0}, null, null); + ParentTreeEntity ptreeRoot2Mother = + mock(4668L, 823, new Integer[] {49, 7, 0}, new Integer[] {121, 49, 0}, null, null); + ParentTreeEntity ptreeRoot2Father = + mock(4628L, 107, new Integer[] {49, 40, 0}, new Integer[] {125, 50, 3}, null, null); + ParentTreeEntity ptreeRoot3Mother = + mock(4668L, 823, new Integer[] {49, 7, 0}, new Integer[] {121, 49, 0}, null, null); + ParentTreeEntity ptreeRoot3Father = + mock(4628L, 107, new Integer[] {49, 40, 0}, new Integer[] {125, 50, 3}, null, null); + ParentTreeEntity ptreeRoot4Mother = mockNull(1000031L, 4700L, 4035L); + ParentTreeEntity ptreeRoot4Father = mockNull(1004424L, 4035L, 4078L); + ParentTreeEntity ptreeRoot5Mother = + mock(4197L, 61, new Integer[] {49, 54, 0}, new Integer[] {126, 49, 0}, null, null); + ParentTreeEntity ptreeRoot5Father = + mock(4182L, 107, new Integer[] {50, 1, 0}, new Integer[] {127, 16, 0}, null, null); + + List secondRequestList = + List.of( + ptreeRoot1Mother.getId(), + ptreeRoot1Father.getId(), + ptreeRoot2Mother.getId(), + ptreeRoot2Father.getId(), + ptreeRoot3Mother.getId(), + ptreeRoot3Father.getId(), + ptreeRoot4Mother.getId(), + ptreeRoot4Father.getId(), + ptreeRoot5Mother.getId(), + ptreeRoot5Father.getId()); + + List secondResponseList = + List.of( + ptreeRoot1Mother, + ptreeRoot1Father, + ptreeRoot2Mother, + ptreeRoot2Father, + ptreeRoot3Mother, + ptreeRoot3Father, + ptreeRoot4Mother, + ptreeRoot4Father, + ptreeRoot5Mother, + ptreeRoot5Father); + + when(parentTreeRepository.findAllByIdIn(secondRequestList)).thenReturn(secondResponseList); + // Second run end + + // Third run start + ParentTreeEntity ptreeRoot4MotherGranMother = + mock(4700L, 628, new Integer[] {49, 22, 0}, new Integer[] {123, 13, 0}, null, null); + ParentTreeEntity ptreeRoot4MotherGranFather = + mock(4035L, 518, new Integer[] {49, 2, 0}, new Integer[] {124, 3, 0}, null, null); + ParentTreeEntity ptreeRoot4FatherGranMother = + mock(4035L, 518, new Integer[] {49, 2, 0}, new Integer[] {124, 3, 0}, null, null); + ParentTreeEntity ptreeRoot4FatherGranFather = + mock(4078L, 442, new Integer[] {48, 28, 0}, new Integer[] {123, 40, 0}, null, null); + + List thirdRequestList = + List.of( + ptreeRoot4MotherGranMother.getId(), + ptreeRoot4MotherGranFather.getId(), + ptreeRoot4FatherGranMother.getId(), + ptreeRoot4FatherGranFather.getId()); + + List thirdResponseList = + List.of( + ptreeRoot4MotherGranMother, + ptreeRoot4MotherGranFather, + ptreeRoot4FatherGranMother, + ptreeRoot4FatherGranFather); + + when(parentTreeRepository.findAllByIdIn(thirdRequestList)).thenReturn(thirdResponseList); + // Third run end + + List ptIds = new ArrayList<>(); + ptIds.add(new GeospatialRequestDto(ptreeRoot1.getId())); + ptIds.add(new GeospatialRequestDto(ptreeRoot2.getId())); + ptIds.add(new GeospatialRequestDto(ptreeRoot3.getId())); + ptIds.add(new GeospatialRequestDto(ptreeRoot4.getId())); + ptIds.add(new GeospatialRequestDto(ptreeRoot5.getId())); + + List dtoList = parentTreeService.getPtGeoSpatialData(ptIds); + + Assertions.assertFalse(dtoList.isEmpty()); + Assertions.assertEquals(5, dtoList.size()); + + // First: 1001097 + Assertions.assertEquals(ptreeRoot2.getId(), dtoList.get(0).parentTreeId()); + Assertions.assertEquals(465, dtoList.get(0).elevation()); + Assertions.assertEquals(49, dtoList.get(0).latitudeDegree()); + Assertions.assertEquals(23, dtoList.get(0).latitudeMinute()); + Assertions.assertEquals(30, dtoList.get(0).latitudeSecond()); + Assertions.assertEquals(123, dtoList.get(0).longitudeDegree()); + Assertions.assertEquals(49, dtoList.get(0).longitudeMinute()); + Assertions.assertEquals(31, dtoList.get(0).longitudeSecond()); + + // Second: 1001096 + Assertions.assertEquals(ptreeRoot3.getId(), dtoList.get(1).parentTreeId()); + Assertions.assertEquals(465, dtoList.get(1).elevation()); + Assertions.assertEquals(49, dtoList.get(1).latitudeDegree()); + Assertions.assertEquals(23, dtoList.get(1).latitudeMinute()); + Assertions.assertEquals(30, dtoList.get(1).latitudeSecond()); + Assertions.assertEquals(123, dtoList.get(1).longitudeDegree()); + Assertions.assertEquals(49, dtoList.get(1).longitudeMinute()); + Assertions.assertEquals(31, dtoList.get(1).longitudeSecond()); + + // Third: 1004423 + Assertions.assertEquals(ptreeRoot4.getId(), dtoList.get(2).parentTreeId()); + Assertions.assertEquals(526, dtoList.get(2).elevation()); + Assertions.assertEquals(48, dtoList.get(2).latitudeDegree()); + Assertions.assertEquals(58, dtoList.get(2).latitudeMinute()); + Assertions.assertEquals(30, dtoList.get(2).latitudeSecond()); + Assertions.assertEquals(123, dtoList.get(2).longitudeDegree()); + Assertions.assertEquals(44, dtoList.get(2).longitudeMinute()); + Assertions.assertEquals(45, dtoList.get(2).longitudeSecond()); + + // Fourth: 1002614L + Assertions.assertEquals(ptreeRoot1.getId(), dtoList.get(3).parentTreeId()); + Assertions.assertEquals(675, dtoList.get(3).elevation()); + Assertions.assertEquals(48, dtoList.get(3).latitudeDegree()); + Assertions.assertEquals(36, dtoList.get(3).latitudeMinute()); + Assertions.assertEquals(0, dtoList.get(3).latitudeSecond()); + Assertions.assertEquals(122, dtoList.get(3).longitudeDegree()); + Assertions.assertEquals(48, dtoList.get(3).longitudeMinute()); + Assertions.assertEquals(0, dtoList.get(3).longitudeSecond()); + + // Fifth: 1001093L + Assertions.assertEquals(ptreeRoot5.getId(), dtoList.get(4).parentTreeId()); + Assertions.assertEquals(84, dtoList.get(4).elevation()); + Assertions.assertEquals(49, dtoList.get(4).latitudeDegree()); + Assertions.assertEquals(57, dtoList.get(4).latitudeMinute()); + Assertions.assertEquals(30, dtoList.get(4).latitudeSecond()); + Assertions.assertEquals(127, dtoList.get(4).longitudeDegree()); + Assertions.assertEquals(2, dtoList.get(4).longitudeMinute()); + Assertions.assertEquals(30, dtoList.get(4).longitudeSecond()); + } }