diff options
author | Bruno Sakoto <bruno.sakoto@bell.ca> | 2021-04-26 14:37:57 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@onap.org> | 2021-04-26 14:37:57 +0000 |
commit | 8895ce4bc508874e95321f97acc014f5e5be7fa7 (patch) | |
tree | e9238c39d2fced59f3a8e9ade2f040e639a34141 | |
parent | 51ddaf6a3e004e9e9940d6ae3dc9b9e01188a85b (diff) | |
parent | 2b7d23c2ffa067732df1ecc3879d252646dad2da (diff) |
Merge "Get Data under anchor using single root"
8 files changed, 62 insertions, 20 deletions
diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java index 3385f35fe8..ddd3ac48ec 100755 --- a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java +++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java @@ -60,13 +60,10 @@ public class DataRestController implements CpsDataApi { @Override public ResponseEntity<Object> getNodeByDataspaceAndAnchor(final String dataspaceName, final String anchorName, final String xpath, final Boolean includeDescendants) { - if (isRootXpath(xpath)) { - return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); - } final FetchDescendantsOption fetchDescendantsOption = Boolean.TRUE.equals(includeDescendants) ? FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS : FetchDescendantsOption.OMIT_DESCENDANTS; - final DataNode dataNode = - cpsDataService.getDataNode(dataspaceName, anchorName, xpath, fetchDescendantsOption); + final DataNode dataNode = cpsDataService.getDataNode(dataspaceName, anchorName, xpath, + fetchDescendantsOption); return new ResponseEntity<>(DataMapUtils.toDataMap(dataNode), HttpStatus.OK); } diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy index 713dda1403..299299ce28 100755 --- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy +++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy @@ -191,7 +191,7 @@ class DataRestControllerSpec extends Specification { 'no dataspace' | '/x-path' | new DataspaceNotFoundException('') || HttpStatus.BAD_REQUEST 'no anchor' | '/x-path' | new AnchorNotFoundException('', '') || HttpStatus.BAD_REQUEST 'no data' | '/x-path' | new DataNodeNotFoundException('', '', '') || HttpStatus.NOT_FOUND - 'empty path' | '' | new IllegalStateException() || HttpStatus.NOT_IMPLEMENTED + 'root path' | '/' | new DataNodeNotFoundException('', '') || HttpStatus.NOT_FOUND 'already defined' | '/x-path' | new AlreadyDefinedException('', new Throwable()) || HttpStatus.CONFLICT } diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java index fa13c7d14d..a02b193d9e 100644..100755 --- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java @@ -130,7 +130,12 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService final String xpath) { final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName); final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName); - return fragmentRepository.getByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity, xpath); + if (isRootXpath(xpath)) { + return fragmentRepository.getFirstByDataspaceAndAnchor(dataspaceEntity, anchorEntity); + } else { + return fragmentRepository.getByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity, + xpath); + } } @Override @@ -205,4 +210,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService fragmentEntity.setChildFragments(Collections.emptySet()); fragmentRepository.save(fragmentEntity); } + + private boolean isRootXpath(final String xpath) { + return "/".equals(xpath) || "".equals(xpath); + } } diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java index b896fe86d0..74d04613d9 100755 --- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java @@ -48,6 +48,15 @@ public interface FragmentRepository extends JpaRepository<FragmentEntity, Long> .orElseThrow(() -> new DataNodeNotFoundException(dataspaceEntity.getName(), anchorEntity.getName(), xpath));
}
+ Optional<FragmentEntity> findFirstByDataspaceAndAnchor(@NonNull DataspaceEntity dataspaceEntity,
+ @NonNull AnchorEntity anchorEntity);
+
+ default FragmentEntity getFirstByDataspaceAndAnchor(@NonNull DataspaceEntity dataspaceEntity,
+ @NonNull AnchorEntity anchorEntity) {
+ return findFirstByDataspaceAndAnchor(dataspaceEntity, anchorEntity)
+ .orElseThrow(() -> new DataNodeNotFoundException(dataspaceEntity.getName(), anchorEntity.getName()));
+ }
+
@Modifying
@Query("DELETE FROM FragmentEntity fe WHERE fe.anchor IN (:anchors)")
void deleteByAnchorIn(@NotNull @Param("anchors") Collection<AnchorEntity> anchorEntities);
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy index a47bd65d02..ea6b26923a 100644..100755 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy @@ -167,23 +167,30 @@ class CpsDataPersistenceServiceSpec extends CpsPersistenceSpecBase { return fragmentRepository.findByDataspaceAndAnchorAndXpath(dataspace, anchor, xpath).orElseThrow() } + @Unroll @Sql([CLEAR_DATA, SET_DATA]) def 'Get data node by xpath without descendants.'() { when: 'data node is requested' def result = objectUnderTest.getDataNode(DATASPACE_NAME, ANCHOR_FOR_DATA_NODES_WITH_LEAVES, - XPATH_DATA_NODE_WITH_LEAVES, OMIT_DESCENDANTS) + inputXPath, OMIT_DESCENDANTS) then: 'data node is returned with no descendants' assert result.getXpath() == XPATH_DATA_NODE_WITH_LEAVES and: 'expected leaves' assert result.getChildDataNodes().size() == 0 assertLeavesMaps(result.getLeaves(), expectedLeavesByXpathMap[XPATH_DATA_NODE_WITH_LEAVES]) + where: 'the following data is used' + scenario | inputXPath + 'some xpath' |'/parent-100' + 'root xpath' |'/' + 'empty xpath' |'' } + @Unroll @Sql([CLEAR_DATA, SET_DATA]) def 'Get data node by xpath with all descendants.'() { when: 'data node is requested with all descendants' def result = objectUnderTest.getDataNode(DATASPACE_NAME, ANCHOR_FOR_DATA_NODES_WITH_LEAVES, - XPATH_DATA_NODE_WITH_LEAVES, INCLUDE_ALL_DESCENDANTS) + inputXPath, INCLUDE_ALL_DESCENDANTS) def mappedResult = treeToFlatMapByXpath(new HashMap<>(), result) then: 'data node is returned with all the descendants populated' assert mappedResult.size() == 4 @@ -192,9 +199,12 @@ class CpsDataPersistenceServiceSpec extends CpsPersistenceSpecBase { assert mappedResult.get('/parent-100/child-002').getChildDataNodes().size() == 1 and: 'extracted leaves maps are matching expected' mappedResult.forEach( - (xpath, dataNode) -> - assertLeavesMaps(dataNode.getLeaves(), expectedLeavesByXpathMap[xpath]) - ) + (inputXPath, dataNode) -> assertLeavesMaps(dataNode.getLeaves(), expectedLeavesByXpathMap[inputXPath])) + where: 'the following data is used' + scenario | inputXPath + 'some xpath' |'/parent-100' + 'root xpath' |'/' + 'empty xpath' |'' } def static assertLeavesMaps(actualLeavesMap, expectedLeavesMap) { diff --git a/cps-ri/src/test/resources/data/fragment.sql b/cps-ri/src/test/resources/data/fragment.sql index b6dc2ca307..d252fbbb59 100644..100755 --- a/cps-ri/src/test/resources/data/fragment.sql +++ b/cps-ri/src/test/resources/data/fragment.sql @@ -8,13 +8,13 @@ INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES (3001, 'ANCHOR-001', 1001, 2001), (3003, 'ANCHOR-003', 1001, 2001); -INSERT INTO FRAGMENT (ID, XPATH, ANCHOR_ID, PARENT_ID, DATASPACE_ID) VALUES - (4001, '/parent-1', 3001, null, 1001), - (4002, '/parent-2', 3001, null, 1001), - (4003, '/parent-3', 3001, null, 1001), - (4004, '/parent-1/child-1', 3001, 4001, 1001), - (4005, '/parent-2/child-2', 3001, 4002, 1001), - (4006, '/parent-1/child-1/grandchild-1', 3001, 4004, 1001); +INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH) VALUES + (4001, 1001, 3001, null, '/parent-1'), + (4002, 1001, 3001, null, '/parent-2'), + (4003, 1001, 3001, null, '/parent-3'), + (4004, 1001, 3001, 4001, '/parent-1/child-1'), + (4005, 1001, 3001, 4002, '/parent-2/child-2'), + (4006, 1001, 3001, 4004, '/parent-1/child-1/grandchild-1'); INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES (4101, 1001, 3003, null, '/parent-100', '{"parent-leaf": "parent-leaf value"}'), diff --git a/cps-service/src/main/java/org/onap/cps/spi/exceptions/DataNodeNotFoundException.java b/cps-service/src/main/java/org/onap/cps/spi/exceptions/DataNodeNotFoundException.java index 125b93d70a..6e7ac3b897 100644..100755 --- a/cps-service/src/main/java/org/onap/cps/spi/exceptions/DataNodeNotFoundException.java +++ b/cps-service/src/main/java/org/onap/cps/spi/exceptions/DataNodeNotFoundException.java @@ -39,4 +39,15 @@ public class DataNodeNotFoundException extends DataValidationException { .format("DataNode with xpath %s was not found for anchor %s and dataspace %s.", xpath, anchorName, dataspaceName)); } + + /** + * Constructor. + * + * @param dataspaceName the name of the dataspace + * @param anchorName the anchor name + */ + public DataNodeNotFoundException(final String dataspaceName, final String anchorName) { + super("DataNode not found", String.format( + "DataNode not found for anchor %s and dataspace %s.", anchorName, dataspaceName)); + } } diff --git a/cps-service/src/test/groovy/org/onap/cps/spi/exceptions/CpsExceptionsSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/spi/exceptions/CpsExceptionsSpec.groovy index d2f43c9362..8592af908d 100755 --- a/cps-service/src/test/groovy/org/onap/cps/spi/exceptions/CpsExceptionsSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/spi/exceptions/CpsExceptionsSpec.groovy @@ -119,12 +119,18 @@ class CpsExceptionsSpec extends Specification { + "Anchor records associated.") } - def 'Creating a exception that a datanode does not exist.'() { + def 'Creating a exception that a datanode with a specified xpath does not exist.'() { expect: 'the exception details contains the correct message with dataspace name and xpath.' (new DataNodeNotFoundException(dataspaceName, anchorName, xpath)).details == "DataNode with xpath ${xpath} was not found for anchor ${anchorName} and dataspace ${dataspaceName}." } + def 'Creating a exception that a datanode does not exist.'() { + expect: 'the exception details contains the correct message with dataspace name and anchor.' + (new DataNodeNotFoundException(dataspaceName, anchorName)).details + == "DataNode not found for anchor ${anchorName} and dataspace ${dataspaceName}." + } + def 'Creating a exception that a dataspace already exists.'() { expect: 'the exception details contains the correct message with dataspace name.' (AlreadyDefinedException.forDataspace(dataspaceName, rootCause)).details |