From 51e969fea2c0948e3e233db065dc2400fbe47a9d Mon Sep 17 00:00:00 2001 From: mgaseta Date: Wed, 14 Aug 2024 11:44:56 -0300 Subject: [PATCH 1/9] feat: fetching hierarchy data initial commit --- .../oracleapi/entity/ParentTreeEntity.java | 5 ++ .../repository/ParentTreeRepository.java | 3 +- .../gov/oracleapi/service/OrchardService.java | 2 +- .../oracleapi/service/ParentTreeService.java | 55 ++++++++++++++++++- .../repository/ParentTreeRepositoryTest.java | 8 +-- .../oracleapi/service/OrchardServiceTest.java | 2 +- .../service/ParentTreeServiceTest.java | 4 +- 7 files changed, 67 insertions(+), 12 deletions(-) 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..ab7eef0f8 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 @@ -35,11 +35,54 @@ 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); List resultList = new ArrayList<>(); - ptEntityList.forEach( + Boolean isEmpty = ptEntityList.stream().filter(tree -> tree.getElevation() == null).count() == 0; + + Integer count = 1; + + Integer countCtrl = 0; + + + List finaList = new ArrayList<>(); + + if (isEmpty) { + finaList.addAll(ptEntityList); + } + + while(!isEmpty && countCtrl < 5) { + List testList = new ArrayList<>(); + for(ParentTreeEntity ptEntity: ptEntityList) { + if (ptEntity.getElevation() == null) { + if (ptEntity.getFemaleParentTreeId() != null) { + testList.add(ptEntity.getFemaleParentTreeId()); + } + if (ptEntity.getMaleParentTreeId() != null) { + testList.add(ptEntity.getMaleParentTreeId()); + } + } else { + finaList.add(ptEntity); + } + } + // testList = ptEntityList.stream().filter(tree -> tree.getElevation() == null).map(ParentTreeEntity::getId).toList(); + SparLog.info("test list = {}", testList); + ptEntityList = parentTreeRepository.findAllByIdIn(testList); + SparLog.info("cur list = {}", ptEntityList); + isEmpty = ptEntityList.stream().filter(tree -> tree.getElevation() == null).count() == 0; + if (isEmpty) { + finaList.addAll(ptEntityList); + } + SparLog.info("is empty {}", isEmpty); + count++; + countCtrl++; + SparLog.info("hierarchy level {}", count); + } + + SparLog.info("final list = {}", finaList); + + finaList.forEach( (pt) -> { GeospatialRespondDto dto = new GeospatialRespondDto( @@ -59,6 +102,14 @@ public List getPtGeoSpatialData(List return resultList; } + // private List findUpperHierarchyTrees(List pt) { + // List testList = new ArrayList<>(); + + // testList = pt.stream().filter(tree -> tree.getElevation() == null).map(ParentTreeEntity::getId).toList(); + + // return parentTreeRepository.findAllByIdIn(testList); + // } + /** * 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..757705391 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,9 @@ 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 +58,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 806c47b56..8a4d1eb4c 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 @@ -41,7 +41,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)); @@ -62,7 +62,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)); From a57d852ec2afe2a095ae93328e4cd07aed0d123c Mon Sep 17 00:00:00 2001 From: Ricardo Campos Date: Wed, 14 Aug 2024 20:49:14 -0300 Subject: [PATCH 2/9] feat: find mean elevation of the parent tree family issue #1498 --- .../gov/oracleapi/dto/ParentTreeNodeDto.java | 122 +++++++++++++ .../oracleapi/service/ParentTreeService.java | 164 ++++++++++++------ 2 files changed, 236 insertions(+), 50 deletions(-) create mode 100644 oracle-api/src/main/java/ca/bc/gov/oracleapi/dto/ParentTreeNodeDto.java 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..7f6e8de65 --- /dev/null +++ b/oracle-api/src/main/java/ca/bc/gov/oracleapi/dto/ParentTreeNodeDto.java @@ -0,0 +1,122 @@ +package ca.bc.gov.oracleapi.dto; + +import ca.bc.gov.oracleapi.config.SparLog; +import ca.bc.gov.oracleapi.entity.ParentTreeEntity; +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; + + /** + * Creates a Parent Tree Node. + * + * @param value The parent tree entity instance. + */ + public ParentTreeNodeDto(ParentTreeEntity value) { + this.value = 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); + } + } + } + + private int getParentsMeanElevation( + ParentTreeNodeDto current, ParentTreeNodeDto femaleNode, ParentTreeNodeDto maleNode) { + if (current.value.getElevation() != null) { + return current.value.getElevation(); + } + int femaleElevation = 0; + if (current.femaleParent != null) { + femaleElevation = + getParentsMeanElevation( + current.femaleParent, + current.femaleParent.femaleParent, + current.femaleParent.maleParent); + } + int maleElevation = 0; + if (current.maleParent != null) { + maleElevation = + getParentsMeanElevation( + current.maleParent, current.maleParent.femaleParent, current.maleParent.maleParent); + } + if (maleElevation == 0 && femaleElevation > 0) { + return femaleElevation; + } else if (maleElevation > 0 && femaleElevation > 0) { + int mean = (maleElevation + femaleElevation) / 2; + return mean; + } + return 0; + } + + /** + * Get the parent tree mean elevation looking into parent trees family. + * + * @return an integer representing the mean elevation. + */ + public int getParentTreeElevation() { + int elevation = getParentsMeanElevation(this, this.femaleParent, this.maleParent); + return elevation; + } + + /** + * Prints the current note. + * + * @param level Current level in the tree + */ + public void print(int level) { + String message = String.format("Level %d - %s", level, toString()); + SparLog.info(message); + if (femaleParent != null) { + femaleParent.print(level + 1); + } + if (maleParent != null) { + maleParent.print(level + 1); + } + } + + /** 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/service/ParentTreeService.java b/oracle-api/src/main/java/ca/bc/gov/oracleapi/service/ParentTreeService.java index ab7eef0f8..1566c0100 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,7 @@ 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.ParentTreeNodeDto; import ca.bc.gov.oracleapi.entity.ParentTreeEntity; import ca.bc.gov.oracleapi.entity.projection.ParentTreeProj; import ca.bc.gov.oracleapi.repository.ParentTreeRepository; @@ -37,79 +38,142 @@ public List getPtGeoSpatialData(List List ptEntityList = parentTreeRepository.findAllByIdIn(idList); - List resultList = new ArrayList<>(); + Optional hasAnyNullElevation = + ptEntityList.stream().filter(tree -> tree.getElevation() == null).findAny(); - Boolean isEmpty = ptEntityList.stream().filter(tree -> tree.getElevation() == null).count() == 0; + Map map; - Integer count = 1; + // If there's one or more null elevation, go up on the hierarchy + if (hasAnyNullElevation.isPresent()) { + map = checkParentTreeHierarchy(ptEntityList); + //SparLog.info("final map list = {}", map.values()); + } else { + map = new HashMap<>(); + ptEntityList.forEach((pt) -> map.put(pt.getId(), new ParentTreeNodeDto(pt))); + } - Integer countCtrl = 0; + List resultList = new ArrayList<>(); + for (Map.Entry entry : map.entrySet()) { + Long parentTreeId = entry.getKey(); + int latitudeDegrees = 0; + int latitudeMinutes = 0; + int latitudeSeconds = 0; + int longitudeDegrees = 0; + int longitudeMinutes = 0; + int longitudeSeconds = 0; + + // navigate the tree here! + ParentTreeNodeDto root = entry.getValue(); + root.print(0); + int elevation = root.getParentTreeElevation(); + SparLog.info("meanElevation {}", elevation); + + GeospatialRespondDto dto = + new GeospatialRespondDto( + parentTreeId, + latitudeDegrees, + latitudeMinutes, + latitudeSeconds, + longitudeDegrees, + longitudeMinutes, + longitudeSeconds, + elevation); + + resultList.add(dto); + } + SparLog.info("{} records found for lat long data", resultList.size()); + return resultList; + } - List finaList = new ArrayList<>(); + private Map checkParentTreeHierarchy( + List ptEntityList) { + int maxLevel = 5; - if (isEmpty) { - finaList.addAll(ptEntityList); + Map resultMap = new HashMap<>(); + Map> parentTreeRelationMap = new HashMap<>(); + + // Create root level + for (ParentTreeEntity ptEntity : ptEntityList) { + resultMap.putIfAbsent(ptEntity.getId(), new ParentTreeNodeDto(ptEntity)); } - while(!isEmpty && countCtrl < 5) { + for (int i = 0; i < maxLevel; i++) { + SparLog.info("hierarchy level {}", i); + List testList = new ArrayList<>(); - for(ParentTreeEntity ptEntity: ptEntityList) { + for (ParentTreeEntity ptEntity : ptEntityList) { if (ptEntity.getElevation() == null) { + parentTreeRelationMap.put(ptEntity.getId(), new ArrayList<>()); + 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()); } - } else { - finaList.add(ptEntity); } } - // testList = ptEntityList.stream().filter(tree -> tree.getElevation() == null).map(ParentTreeEntity::getId).toList(); - SparLog.info("test list = {}", testList); - ptEntityList = parentTreeRepository.findAllByIdIn(testList); - SparLog.info("cur list = {}", ptEntityList); - isEmpty = ptEntityList.stream().filter(tree -> tree.getElevation() == null).count() == 0; - if (isEmpty) { - finaList.addAll(ptEntityList); - } - SparLog.info("is empty {}", isEmpty); - count++; - countCtrl++; - SparLog.info("hierarchy level {}", count); - } - SparLog.info("final list = {}", finaList); - - finaList.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)); + List nextLevelList = parentTreeRepository.findAllByIdIn(testList); + // SparLog.info("nextLevelList list = {}", nextLevelList); + + for (ParentTreeEntity ptEntity : nextLevelList) { + // SparLog.info("Looking for root node id {}", ptEntity.getId()); + for (Map.Entry> entry : parentTreeRelationMap.entrySet()) { + if (entry.getValue().contains(ptEntity.getId())) { + // SparLog.info("Found list contains (parentTreeRelationMap)! list: {}, key: {}", entry.getValue(), entry.getKey()); + // does the magic + Long originalPtId = entry.getKey(); + + // it should not be null + if (resultMap.get(originalPtId) == null) { + for (Map.Entry> entryTwo : parentTreeRelationMap.entrySet()) { + if (entryTwo.getValue().contains(originalPtId)) { + // SparLog.info("Maybe this is the root!? {}", entryTwo.getKey()); + originalPtId = entryTwo.getKey(); + break; + } + } + //throw new RuntimeException("Original Parent Tree Node root is null!"); + } + // female is always the first + if (entry.getValue().size() > 0) { + Long female = entry.getValue().get(0); + if (female.equals(ptEntity.getId())) { + // SparLog.info("{} is female!", ptEntity.getId()); + resultMap.get(originalPtId).add(female, ptEntity); + } + } + // male is optional + if (entry.getValue().size() > 1) { + Long male = entry.getValue().get(1); + if (male.equals(ptEntity.getId())) { + // SparLog.info("{} is male!", ptEntity.getId()); + resultMap.get(originalPtId).add(male, ptEntity); + } + } + break; + } + } + } - resultList.add(dto); - }); + boolean allElevationFound = + nextLevelList.stream().filter(tree -> tree.getElevation() == null).count() == 0; + if (allElevationFound) { + // SparLog.info("All elevations has been found. Leaving!"); + break; + } else { + // SparLog.info("Not all elevations has been found. Going up on the hierarchy!"); + ptEntityList = new ArrayList<>(nextLevelList); + } + } - SparLog.info("{} records found for lat long data", resultList.size()); - return resultList; + return resultMap; } - // private List findUpperHierarchyTrees(List pt) { - // List testList = new ArrayList<>(); - - // testList = pt.stream().filter(tree -> tree.getElevation() == null).map(ParentTreeEntity::getId).toList(); - - // return parentTreeRepository.findAllByIdIn(testList); - // } - /** * Find all parent trees under a vegCode. * From b07ba17b431ecef9e2ce679fcbb6f87d5f23708b Mon Sep 17 00:00:00 2001 From: Ricardo Campos Date: Thu, 15 Aug 2024 15:30:22 -0300 Subject: [PATCH 3/9] feat: add lat and long mean calculations issue #1498 --- .../oracleapi/dto/ParentTreeGeoNodeDto.java | 61 +++++++++++++++++++ .../gov/oracleapi/dto/ParentTreeNodeDto.java | 59 ++++++++++++++---- .../oracleapi/service/ParentTreeService.java | 34 +++++------ 3 files changed, 123 insertions(+), 31 deletions(-) create mode 100644 oracle-api/src/main/java/ca/bc/gov/oracleapi/dto/ParentTreeGeoNodeDto.java 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..c371135e6 --- /dev/null +++ b/oracle-api/src/main/java/ca/bc/gov/oracleapi/dto/ParentTreeGeoNodeDto.java @@ -0,0 +1,61 @@ +package ca.bc.gov.oracleapi.dto; + +import ca.bc.gov.oracleapi.entity.ParentTreeEntity; +import java.util.Optional; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@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; + + public 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 index 7f6e8de65..fd5b13ac3 100644 --- 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 @@ -13,6 +13,7 @@ public class ParentTreeNodeDto { private final ParentTreeEntity value; private ParentTreeNodeDto femaleParent; private ParentTreeNodeDto maleParent; + private ParentTreeGeoNodeDto geoNode; /** * Creates a Parent Tree Node. @@ -21,6 +22,7 @@ public class ParentTreeNodeDto { */ public ParentTreeNodeDto(ParentTreeEntity value) { this.value = value; + this.geoNode = new ParentTreeGeoNodeDto(value); } /** @@ -44,12 +46,12 @@ public void add(Long parentTreeId, ParentTreeEntity entity) { } } - private int getParentsMeanElevation( + private ParentTreeGeoNodeDto getParentsMeanElevation( ParentTreeNodeDto current, ParentTreeNodeDto femaleNode, ParentTreeNodeDto maleNode) { - if (current.value.getElevation() != null) { - return current.value.getElevation(); + if (current.geoNode.getElevation() != null) { + return current.geoNode; } - int femaleElevation = 0; + ParentTreeGeoNodeDto femaleElevation = new ParentTreeGeoNodeDto(); if (current.femaleParent != null) { femaleElevation = getParentsMeanElevation( @@ -57,19 +59,51 @@ private int getParentsMeanElevation( current.femaleParent.femaleParent, current.femaleParent.maleParent); } - int maleElevation = 0; + ParentTreeGeoNodeDto maleElevation = new ParentTreeGeoNodeDto(); if (current.maleParent != null) { maleElevation = getParentsMeanElevation( current.maleParent, current.maleParent.femaleParent, current.maleParent.maleParent); } - if (maleElevation == 0 && femaleElevation > 0) { + if (maleElevation.getElevationIntVal() == 0 && femaleElevation.getElevationIntVal() > 0) { return femaleElevation; - } else if (maleElevation > 0 && femaleElevation > 0) { - int mean = (maleElevation + femaleElevation) / 2; - return mean; + } else if (maleElevation.getElevationIntVal() > 0 && femaleElevation.getElevationIntVal() > 0) { + int noOfParents = 2; + int meanElevation = + (maleElevation.getElevationIntVal() + femaleElevation.getElevationIntVal()) / noOfParents; + + // all other calculations + 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; + int buff = calc % 3600; + int latitudeMinutes = buff/60; + buff = calc % 60; + int latitudeSeconds = buff; + + 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; + buff = calc % 3600; + int longitudeMinutes = buff/60; + buff = calc % 60; + int longitudeSeconds = buff; + + ParentTreeGeoNodeDto meanNode = new ParentTreeGeoNodeDto(); + meanNode.setElevation(meanElevation); + meanNode.setLatitudeDegrees(latitudeDegrees); + meanNode.setLatitudeMinutes(latitudeMinutes); + meanNode.setLatitudeSeconds(latitudeSeconds); + meanNode.setLongitudeDegrees(longitudeDegrees); + meanNode.setLongitudeMinutes(longitudeMinutes); + meanNode.setLongitudeSeconds(longitudeSeconds); + return meanNode; } - return 0; + return null; } /** @@ -77,8 +111,9 @@ private int getParentsMeanElevation( * * @return an integer representing the mean elevation. */ - public int getParentTreeElevation() { - int elevation = getParentsMeanElevation(this, this.femaleParent, this.maleParent); + public ParentTreeGeoNodeDto getParentTreeElevation() { + ParentTreeGeoNodeDto elevation = + getParentsMeanElevation(this, this.femaleParent, this.maleParent); return elevation; } 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 1566c0100..378d60811 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,7 @@ 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; @@ -46,7 +47,7 @@ public List getPtGeoSpatialData(List // If there's one or more null elevation, go up on the hierarchy if (hasAnyNullElevation.isPresent()) { map = checkParentTreeHierarchy(ptEntityList); - //SparLog.info("final map list = {}", map.values()); + // SparLog.info("final map list = {}", map.values()); } else { map = new HashMap<>(); ptEntityList.forEach((pt) -> map.put(pt.getId(), new ParentTreeNodeDto(pt))); @@ -55,29 +56,23 @@ public List getPtGeoSpatialData(List List resultList = new ArrayList<>(); for (Map.Entry entry : map.entrySet()) { Long parentTreeId = entry.getKey(); - int latitudeDegrees = 0; - int latitudeMinutes = 0; - int latitudeSeconds = 0; - int longitudeDegrees = 0; - int longitudeMinutes = 0; - int longitudeSeconds = 0; // navigate the tree here! ParentTreeNodeDto root = entry.getValue(); root.print(0); - int elevation = root.getParentTreeElevation(); - SparLog.info("meanElevation {}", elevation); + ParentTreeGeoNodeDto elevation = root.getParentTreeElevation(); + SparLog.info("meanElevation {}", elevation.getElevation()); GeospatialRespondDto dto = new GeospatialRespondDto( parentTreeId, - latitudeDegrees, - latitudeMinutes, - latitudeSeconds, - longitudeDegrees, - longitudeMinutes, - longitudeSeconds, - elevation); + elevation.getLatitudeDegreesIntVal(), + elevation.getLatitudeMinutesIntVal(), + elevation.getLatitudeSecondsIntVal(), + elevation.getLongitudeDegreesIntVal(), + elevation.getLongitudeMinutesIntVal(), + elevation.getLongitudeSecondsIntVal(), + elevation.getElevation()); resultList.add(dto); } @@ -124,10 +119,11 @@ private Map checkParentTreeHierarchy( // SparLog.info("Looking for root node id {}", ptEntity.getId()); for (Map.Entry> entry : parentTreeRelationMap.entrySet()) { if (entry.getValue().contains(ptEntity.getId())) { - // SparLog.info("Found list contains (parentTreeRelationMap)! list: {}, key: {}", entry.getValue(), entry.getKey()); + // SparLog.info("Found list contains (parentTreeRelationMap)! list: {}, key: {}", + // entry.getValue(), entry.getKey()); // does the magic Long originalPtId = entry.getKey(); - + // it should not be null if (resultMap.get(originalPtId) == null) { for (Map.Entry> entryTwo : parentTreeRelationMap.entrySet()) { @@ -137,7 +133,7 @@ private Map checkParentTreeHierarchy( break; } } - //throw new RuntimeException("Original Parent Tree Node root is null!"); + // throw new RuntimeException("Original Parent Tree Node root is null!"); } // female is always the first if (entry.getValue().size() > 0) { From ed06179c12d2df697901657cbbed61028327e180 Mon Sep 17 00:00:00 2001 From: Ricardo Campos Date: Thu, 15 Aug 2024 19:42:18 -0300 Subject: [PATCH 4/9] fix: same parent fathers and mothers issue #1498 --- .../gov/oracleapi/dto/ParentTreeNodeDto.java | 53 ++++++++++++----- .../oracleapi/service/ParentTreeService.java | 59 ++++++++++++++++--- 2 files changed, 89 insertions(+), 23 deletions(-) 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 index fd5b13ac3..f93a61a9c 100644 --- 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 @@ -2,6 +2,7 @@ import ca.bc.gov.oracleapi.config.SparLog; import ca.bc.gov.oracleapi.entity.ParentTreeEntity; +import java.util.Optional; import lombok.Getter; import lombok.Setter; @@ -54,16 +55,22 @@ private ParentTreeGeoNodeDto getParentsMeanElevation( ParentTreeGeoNodeDto femaleElevation = new ParentTreeGeoNodeDto(); if (current.femaleParent != null) { femaleElevation = - getParentsMeanElevation( - current.femaleParent, - current.femaleParent.femaleParent, - current.femaleParent.maleParent); + Optional.ofNullable( + getParentsMeanElevation( + current.femaleParent, + current.femaleParent.femaleParent, + current.femaleParent.maleParent)) + .orElse(new ParentTreeGeoNodeDto()); } ParentTreeGeoNodeDto maleElevation = new ParentTreeGeoNodeDto(); if (current.maleParent != null) { maleElevation = - getParentsMeanElevation( - current.maleParent, current.maleParent.femaleParent, current.maleParent.maleParent); + Optional.ofNullable( + getParentsMeanElevation( + current.maleParent, + current.maleParent.femaleParent, + current.maleParent.maleParent)) + .orElse(new ParentTreeGeoNodeDto()); } if (maleElevation.getElevationIntVal() == 0 && femaleElevation.getElevationIntVal() > 0) { return femaleElevation; @@ -73,23 +80,37 @@ private ParentTreeGeoNodeDto getParentsMeanElevation( (maleElevation.getElevationIntVal() + femaleElevation.getElevationIntVal()) / noOfParents; // all other calculations - int calc = (femaleElevation.getLatitudeDegreesIntVal()*3600) + (femaleElevation.getLatitudeMinutesIntVal()*60) + femaleElevation.getLatitudeSecondsIntVal(); - calc = calc + (maleElevation.getLatitudeDegreesIntVal()*3600) + (maleElevation.getLatitudeMinutesIntVal()*60) + maleElevation.getLatitudeSecondsIntVal(); - // --derive mean + 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; + int latitudeDegrees = calc / 3600; int buff = calc % 3600; - int latitudeMinutes = buff/60; + int latitudeMinutes = buff / 60; buff = calc % 60; int latitudeSeconds = buff; - calc = (femaleElevation.getLongitudeDegreesIntVal()*3600) + (femaleElevation.getLongitudeMinutesIntVal()*60) + femaleElevation.getLongitudeSecondsIntVal(); - calc = calc + (maleElevation.getLongitudeDegreesIntVal()*3600) + (maleElevation.getLongitudeMinutesIntVal()*60) + maleElevation.getLongitudeSecondsIntVal(); - // --derive mean + 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; + int longitudeDegrees = calc / 3600; buff = calc % 3600; - int longitudeMinutes = buff/60; + int longitudeMinutes = buff / 60; buff = calc % 60; int longitudeSeconds = buff; 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 378d60811..5dba805de 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 @@ -61,6 +61,10 @@ public List getPtGeoSpatialData(List ParentTreeNodeDto root = entry.getValue(); root.print(0); ParentTreeGeoNodeDto elevation = root.getParentTreeElevation(); + if (elevation == null) { + SparLog.error("No elevation for Parent tree ID {}", parentTreeId); + continue; + } SparLog.info("meanElevation {}", elevation.getElevation()); GeospatialRespondDto dto = @@ -115,16 +119,52 @@ private Map checkParentTreeHierarchy( List nextLevelList = parentTreeRepository.findAllByIdIn(testList); // SparLog.info("nextLevelList list = {}", nextLevelList); + for (Map.Entry> entry : parentTreeRelationMap.entrySet()) { + Long sonPtId = entry.getKey(); + List femaleAndMaleParentsIds = entry.getValue(); + + for (ParentTreeEntity ptEntity : nextLevelList) { + if (femaleAndMaleParentsIds.contains(ptEntity.getId())) { + if (resultMap.get(sonPtId) == null) { + for (Map.Entry> entryTwo : parentTreeRelationMap.entrySet()) { + if (entryTwo.getValue().contains(sonPtId)) { + // SparLog.info("Maybe this is the root!? {}", entryTwo.getKey()); + sonPtId = entryTwo.getKey(); + break; + } + } + } + // female is always the first + if (entry.getValue().size() > 0) { + Long female = entry.getValue().get(0); + if (female.equals(ptEntity.getId())) { + // SparLog.info("{} is female!", ptEntity.getId()); + resultMap.get(sonPtId).add(female, ptEntity); + } + } + // male is optional + if (entry.getValue().size() > 1) { + Long male = entry.getValue().get(1); + if (male.equals(ptEntity.getId())) { + // SparLog.info("{} is male!", ptEntity.getId()); + resultMap.get(sonPtId).add(male, ptEntity); + } + } + } + } + } + + /* for (ParentTreeEntity ptEntity : nextLevelList) { // SparLog.info("Looking for root node id {}", ptEntity.getId()); + Long keyToRemove = null; for (Map.Entry> entry : parentTreeRelationMap.entrySet()) { - if (entry.getValue().contains(ptEntity.getId())) { - // SparLog.info("Found list contains (parentTreeRelationMap)! list: {}, key: {}", - // entry.getValue(), entry.getKey()); - // does the magic - Long originalPtId = entry.getKey(); + Long originalPtId = entry.getKey(); + SparLog.info("Son id: {}", originalPtId); + List femaleAndMaleIds = entry.getValue(); - // it should not be null + if (femaleAndMaleIds.contains(ptEntity.getId())) { + keyToRemove = originalPtId; if (resultMap.get(originalPtId) == null) { for (Map.Entry> entryTwo : parentTreeRelationMap.entrySet()) { if (entryTwo.getValue().contains(originalPtId)) { @@ -133,7 +173,6 @@ private Map checkParentTreeHierarchy( break; } } - // throw new RuntimeException("Original Parent Tree Node root is null!"); } // female is always the first if (entry.getValue().size() > 0) { @@ -154,7 +193,13 @@ private Map checkParentTreeHierarchy( break; } } + + // remove key + if (keyToRemove != null) { + parentTreeRelationMap.remove(keyToRemove); + } } + */ boolean allElevationFound = nextLevelList.stream().filter(tree -> tree.getElevation() == null).count() == 0; From ffdcb83db4a2b5a3506da0ff376fe1c3f33cdf1f Mon Sep 17 00:00:00 2001 From: Ricardo Campos Date: Thu, 15 Aug 2024 20:03:00 -0300 Subject: [PATCH 5/9] fix: wrong dividion by zero --- .../ca/bc/gov/backendstartapi/service/ParentTreeService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); } From cca86a861a25fd49278a14c9e30d0ac66375a4e5 Mon Sep 17 00:00:00 2001 From: Ricardo Campos Date: Fri, 16 Aug 2024 14:50:13 -0300 Subject: [PATCH 6/9] docs: add comments and improve variable naming issue #1498 --- .../gov/oracleapi/dto/ParentTreeNodeDto.java | 17 +- .../oracleapi/service/ParentTreeService.java | 152 +++++++----------- 2 files changed, 76 insertions(+), 93 deletions(-) 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 index f93a61a9c..7900ae486 100644 --- 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 @@ -47,6 +47,16 @@ public void add(Long parentTreeId, ParentTreeEntity 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) { @@ -143,15 +153,16 @@ public ParentTreeGeoNodeDto getParentTreeElevation() { * * @param level Current level in the tree */ - public void print(int level) { + public String printLevel(int level) { String message = String.format("Level %d - %s", level, toString()); SparLog.info(message); if (femaleParent != null) { - femaleParent.print(level + 1); + return femaleParent.printLevel(level + 1); } if (maleParent != null) { - maleParent.print(level + 1); + return maleParent.printLevel(level + 1); } + return message; } /** Gets the string version of the node. */ 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 5dba805de..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 @@ -27,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. * @@ -38,34 +40,30 @@ public List getPtGeoSpatialData(List List idList = ptIds.stream().map(GeospatialRequestDto::parentTreeId).toList(); List ptEntityList = parentTreeRepository.findAllByIdIn(idList); - - Optional hasAnyNullElevation = - ptEntityList.stream().filter(tree -> tree.getElevation() == null).findAny(); - - Map map; + Map parentTreeRootMap; // If there's one or more null elevation, go up on the hierarchy - if (hasAnyNullElevation.isPresent()) { - map = checkParentTreeHierarchy(ptEntityList); - // SparLog.info("final map list = {}", map.values()); + boolean isAnyMissing = parentTreeListHasAnyElevationMissing(ptEntityList); + if (isAnyMissing) { + parentTreeRootMap = checkParentTreeHierarchy(ptEntityList); } else { - map = new HashMap<>(); - ptEntityList.forEach((pt) -> map.put(pt.getId(), new ParentTreeNodeDto(pt))); + parentTreeRootMap = new HashMap<>(); + ptEntityList.forEach((pt) -> parentTreeRootMap.put(pt.getId(), new ParentTreeNodeDto(pt))); } List resultList = new ArrayList<>(); - for (Map.Entry entry : map.entrySet()) { - Long parentTreeId = entry.getKey(); + for (Map.Entry rootEntry : parentTreeRootMap.entrySet()) { + Long parentTreeId = rootEntry.getKey(); // navigate the tree here! - ParentTreeNodeDto root = entry.getValue(); - root.print(0); + ParentTreeNodeDto root = rootEntry.getValue(); + SparLog.debug(root.printLevel(0)); + ParentTreeGeoNodeDto elevation = root.getParentTreeElevation(); if (elevation == null) { SparLog.error("No elevation for Parent tree ID {}", parentTreeId); continue; } - SparLog.info("meanElevation {}", elevation.getElevation()); GeospatialRespondDto dto = new GeospatialRespondDto( @@ -87,9 +85,10 @@ public List getPtGeoSpatialData(List private Map checkParentTreeHierarchy( List ptEntityList) { - int maxLevel = 5; - + // 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 @@ -97,13 +96,16 @@ private Map checkParentTreeHierarchy( resultMap.putIfAbsent(ptEntity.getId(), new ParentTreeNodeDto(ptEntity)); } - for (int i = 0; i < maxLevel; i++) { - SparLog.info("hierarchy level {}", i); + 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<>()); + parentTreeRelationMap.put(ptEntity.getId(), new ArrayList<>(2)); if (ptEntity.getFemaleParentTreeId() != null) { testList.add(ptEntity.getFemaleParentTreeId()); @@ -116,98 +118,64 @@ private Map checkParentTreeHierarchy( } } + // Query from the DB all female and male parents (gathered from the loop above) List nextLevelList = parentTreeRepository.findAllByIdIn(testList); - // SparLog.info("nextLevelList list = {}", nextLevelList); + // Loop through the relation of ParentTree ids and its parents for (Map.Entry> entry : parentTreeRelationMap.entrySet()) { - Long sonPtId = entry.getKey(); + // 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.get(sonPtId) == null) { + + // 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(sonPtId)) { - // SparLog.info("Maybe this is the root!? {}", entryTwo.getKey()); - sonPtId = entryTwo.getKey(); + if (entryTwo.getValue().contains(sonParentTreeId)) { + sonParentTreeId = entryTwo.getKey(); break; } } } - // female is always the first - if (entry.getValue().size() > 0) { - Long female = entry.getValue().get(0); - if (female.equals(ptEntity.getId())) { - // SparLog.info("{} is female!", ptEntity.getId()); - resultMap.get(sonPtId).add(female, ptEntity); - } - } - // male is optional - if (entry.getValue().size() > 1) { - Long male = entry.getValue().get(1); - if (male.equals(ptEntity.getId())) { - // SparLog.info("{} is male!", ptEntity.getId()); - resultMap.get(sonPtId).add(male, ptEntity); - } + + // 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); } - } - } - } - /* - for (ParentTreeEntity ptEntity : nextLevelList) { - // SparLog.info("Looking for root node id {}", ptEntity.getId()); - Long keyToRemove = null; - for (Map.Entry> entry : parentTreeRelationMap.entrySet()) { - Long originalPtId = entry.getKey(); - SparLog.info("Son id: {}", originalPtId); - List femaleAndMaleIds = entry.getValue(); - - if (femaleAndMaleIds.contains(ptEntity.getId())) { - keyToRemove = originalPtId; - if (resultMap.get(originalPtId) == null) { - for (Map.Entry> entryTwo : parentTreeRelationMap.entrySet()) { - if (entryTwo.getValue().contains(originalPtId)) { - // SparLog.info("Maybe this is the root!? {}", entryTwo.getKey()); - originalPtId = entryTwo.getKey(); - break; - } - } - } - // female is always the first - if (entry.getValue().size() > 0) { - Long female = entry.getValue().get(0); - if (female.equals(ptEntity.getId())) { - // SparLog.info("{} is female!", ptEntity.getId()); - resultMap.get(originalPtId).add(female, 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); } } - // male is optional - if (entry.getValue().size() > 1) { - Long male = entry.getValue().get(1); - if (male.equals(ptEntity.getId())) { - // SparLog.info("{} is male!", ptEntity.getId()); - resultMap.get(originalPtId).add(male, ptEntity); - } - } - break; } } - - // remove key - if (keyToRemove != null) { - parentTreeRelationMap.remove(keyToRemove); - } } - */ - boolean allElevationFound = - nextLevelList.stream().filter(tree -> tree.getElevation() == null).count() == 0; - if (allElevationFound) { - // SparLog.info("All elevations has been found. Leaving!"); + // 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.info("Not all elevations has been found. Going up on the hierarchy!"); + SparLog.debug("Not all elevations has been found. Going up on the hierarchy!"); ptEntityList = new ArrayList<>(nextLevelList); } } @@ -215,6 +183,10 @@ private Map checkParentTreeHierarchy( return resultMap; } + private boolean parentTreeListHasAnyElevationMissing(List list) { + return list.stream().filter(tree -> tree.getElevation() == null).count() > 0; + } + /** * Find all parent trees under a vegCode. * From aa5313590e5e0f647ea2dc0c52a0f5a7eee6f25c Mon Sep 17 00:00:00 2001 From: Ricardo Campos Date: Fri, 16 Aug 2024 15:08:47 -0300 Subject: [PATCH 7/9] docs: fix checkstyle and add java docs issue #1498 --- .../oracleapi/dto/ParentTreeGeoNodeDto.java | 3 ++- .../gov/oracleapi/dto/ParentTreeNodeDto.java | 24 ++++++++++++------- .../repository/ParentTreeRepositoryTest.java | 3 ++- 3 files changed, 19 insertions(+), 11 deletions(-) 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 index c371135e6..e2e18827d 100644 --- 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 @@ -5,6 +5,7 @@ import lombok.NoArgsConstructor; import lombok.Setter; +/** This class represents a GeoNode with all elevation, lat and long mean values. */ @Setter @NoArgsConstructor public class ParentTreeGeoNodeDto { @@ -17,7 +18,7 @@ public class ParentTreeGeoNodeDto { private Integer longitudeMinutes; private Integer longitudeSeconds; - public ParentTreeGeoNodeDto(ParentTreeEntity entity) { + ParentTreeGeoNodeDto(ParentTreeEntity entity) { this.elevation = entity.getElevation(); this.latitudeDegrees = entity.getLatitudeDegrees(); this.latitudeMinutes = entity.getLatitudeMinutes(); 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 index 7900ae486..f96ec4439 100644 --- 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 @@ -86,10 +86,14 @@ private ParentTreeGeoNodeDto getParentsMeanElevation( 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 + // All other calculations (Lat and Long) int calc = (femaleElevation.getLatitudeDegreesIntVal() * 3600) + (femaleElevation.getLatitudeMinutesIntVal() * 60) @@ -102,10 +106,15 @@ private ParentTreeGeoNodeDto getParentsMeanElevation( // --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) @@ -119,19 +128,16 @@ private ParentTreeGeoNodeDto getParentsMeanElevation( // --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; - - ParentTreeGeoNodeDto meanNode = new ParentTreeGeoNodeDto(); - meanNode.setElevation(meanElevation); - meanNode.setLatitudeDegrees(latitudeDegrees); - meanNode.setLatitudeMinutes(latitudeMinutes); - meanNode.setLatitudeSeconds(latitudeSeconds); - meanNode.setLongitudeDegrees(longitudeDegrees); - meanNode.setLongitudeMinutes(longitudeMinutes); meanNode.setLongitudeSeconds(longitudeSeconds); + return meanNode; } return null; 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 757705391..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 @@ -25,7 +25,8 @@ class ParentTreeRepositoryTest { @Test @DisplayName("findAllByIdInTest") void findAllByIdInTest() { - List parentTreeList = parentTreeRepository.findAllByIdIn(List.of(4032L, 4033L)); + List parentTreeList = + parentTreeRepository.findAllByIdIn(List.of(4032L, 4033L)); assertFalse(parentTreeList.isEmpty()); assertEquals(2, parentTreeList.size()); From 7a8258b080ddea4f3201bebc410dd6927df86640 Mon Sep 17 00:00:00 2001 From: Ricardo Campos Date: Fri, 16 Aug 2024 16:58:25 -0300 Subject: [PATCH 8/9] test: add test case to parent tree geo hierarchy issue #1498 --- .../service/ParentTreeServiceTest.java | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) 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 5e88837fa..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 @@ -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()); + } } From 21199f6652787324d4120af9789ad4fa827d50af Mon Sep 17 00:00:00 2001 From: Craig Yu Date: Fri, 16 Aug 2024 14:51:23 -0700 Subject: [PATCH 9/9] fix: typo --- .../main/java/ca/bc/gov/oracleapi/dto/ParentTreeNodeDto.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index f96ec4439..d912ac19f 100644 --- 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 @@ -155,7 +155,7 @@ public ParentTreeGeoNodeDto getParentTreeElevation() { } /** - * Prints the current note. + * Prints the current node. * * @param level Current level in the tree */