diff options
4 files changed, 97 insertions, 108 deletions
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java b/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java index 00d1d98df3..2fdfa0528f 100755 --- a/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java @@ -70,6 +70,9 @@ public class FragmentEntity implements Serializable { @Column(columnDefinition = "text") private String xpath; + @Column(name = "parent_id") + private Long parentId; + @Type(type = "jsonb") @Column(columnDefinition = "jsonb") private String attributes; 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 ed414fc30c..04804726c9 100644 --- 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 @@ -73,41 +73,38 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService private final JsonObjectMapper jsonObjectMapper; - private static final String REG_EX_FOR_OPTIONAL_LIST_INDEX = "(\\[@[\\s\\S]+?]){0,1})"; private static final Pattern REG_EX_PATTERN_FOR_LIST_ELEMENT_KEY_PREDICATE = Pattern.compile("\\[(\\@([^\\/]{0,9999}))\\]$"); @Override - public void addChildDataNode(final String dataspaceName, final String anchorName, final String parentXpath, - final DataNode dataNode) { - final FragmentEntity parentFragment = getFragmentByXpath(dataspaceName, anchorName, parentXpath); - final FragmentEntity fragmentEntity = - toFragmentEntity(parentFragment.getDataspace(), parentFragment.getAnchor(), dataNode); - parentFragment.getChildFragments().add(fragmentEntity); - try { - fragmentRepository.save(parentFragment); - } catch (final DataIntegrityViolationException exception) { - throw AlreadyDefinedException.forDataNode(dataNode.getXpath(), anchorName, exception); - } + @Transactional + public void addChildDataNode(final String dataspaceName, final String anchorName, final String parentNodeXpath, + final DataNode newChildDataNode) { + addChildDataNodes(dataspaceName, anchorName, parentNodeXpath, Collections.singleton(newChildDataNode)); } @Override + @Transactional public void addListElements(final String dataspaceName, final String anchorName, final String parentNodeXpath, - final Collection<DataNode> dataNodes) { - final FragmentEntity parentFragment = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath); - final List<FragmentEntity> newFragmentEntities = - dataNodes.stream().map( - dataNode -> toFragmentEntity(parentFragment.getDataspace(), parentFragment.getAnchor(), dataNode) - ).collect(Collectors.toUnmodifiableList()); - parentFragment.getChildFragments().addAll(newFragmentEntities); + final Collection<DataNode> newListElements) { + addChildDataNodes(dataspaceName, anchorName, parentNodeXpath, newListElements); + } + + private void addChildDataNodes(final String dataspaceName, final String anchorName, final String parentNodeXpath, + final Collection<DataNode> newChildren) { + final FragmentEntity parentFragmentEntity = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath); try { - fragmentRepository.save(parentFragment); - dataNodes.forEach( - dataNode -> getChildFragments(dataspaceName, anchorName, dataNode) - ); + for (final DataNode newChildAsDataNode : newChildren) { + final FragmentEntity newChildAsFragmentEntity = convertToFragmentWithAllDescendants( + parentFragmentEntity.getDataspace(), + parentFragmentEntity.getAnchor(), + newChildAsDataNode); + newChildAsFragmentEntity.setParentId(parentFragmentEntity.getId()); + fragmentRepository.save(newChildAsFragmentEntity); + } } catch (final DataIntegrityViolationException exception) { - final List<String> conflictXpaths = dataNodes.stream() + final List<String> conflictXpaths = newChildren.stream() .map(DataNode::getXpath) .collect(Collectors.toList()); throw AlreadyDefinedException.forDataNodes(conflictXpaths, anchorName, exception); @@ -150,17 +147,6 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService return parentFragment; } - private void getChildFragments(final String dataspaceName, final String anchorName, final DataNode dataNode) { - for (final DataNode childDataNode: dataNode.getChildDataNodes()) { - final FragmentEntity getChildsParentFragmentByXPath = - getFragmentByXpath(dataspaceName, anchorName, dataNode.getXpath()); - final FragmentEntity childFragmentEntity = toFragmentEntity(getChildsParentFragmentByXPath.getDataspace(), - getChildsParentFragmentByXPath.getAnchor(), childDataNode); - getChildsParentFragmentByXPath.getChildFragments().add(childFragmentEntity); - fragmentRepository.save(getChildsParentFragmentByXPath); - } - } - private FragmentEntity toFragmentEntity(final DataspaceEntity dataspaceEntity, final AnchorEntity anchorEntity, final DataNode dataNode) { return FragmentEntity.builder() diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy index 41e7a419a5..2277377a5c 100755 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy @@ -155,25 +155,25 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { } @Sql([CLEAR_DATA, SET_DATA]) - def 'Add multiple list elements including an element with a child datanode.'() { - given: 'two new data nodes for an existing list' + def 'Add multiple new list elements including an element with a child datanode.'() { + given: 'two new child list elements for an existing parent' def listElementXpaths = ['/parent-201/child-204[@key="NEW1"]', '/parent-201/child-204[@key="NEW2"]'] def listElements = toDataNodes(listElementXpaths) - and: 'a child node for one of the new data nodes' - def childDataNode = buildDataNode('/parent-201/child-204[@key="NEW1"]/grand-child-204[@key2="NEW1-CHILD"]', [leave:'value'], []) - listElements[0].childDataNodes = [childDataNode] - when: 'the data nodes (list elements) are added to existing parent node' + and: 'a (grand)child data node for one of the new list elements' + def grandChild = buildDataNode('/parent-201/child-204[@key="NEW1"]/grand-child-204[@key2="NEW1-CHILD"]', [leave:'value'], []) + listElements[0].childDataNodes = [grandChild] + when: 'the new data node (list elements) are added to an existing parent node' objectUnderTest.addListElements(DATASPACE_NAME, ANCHOR_NAME3, '/parent-201', listElements) - then: 'new entries successfully persisted, parent node now contains 5 children (2 new + 3 existing before)' + then: 'new entries are successfully persisted, parent node now contains 5 children (2 new + 3 existing before)' def parentFragment = fragmentRepository.getById(LIST_DATA_NODE_PARENT201_FRAGMENT_ID) def allChildXpaths = parentFragment.childFragments.collect { it.xpath } assert allChildXpaths.size() == 5 assert allChildXpaths.containsAll(listElementXpaths) - and: 'the child node of the new list entry is also present' + and: 'the (grand)child node of the new list entry is also present' def dataspaceEntity = dataspaceRepository.getByName(DATASPACE_NAME) def anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, ANCHOR_NAME3) - def listElementChild = fragmentRepository.findByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity, childDataNode.xpath) - assert listElementChild.isPresent() + def grandChildFragmentEntity = fragmentRepository.findByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity, grandChild.xpath) + assert grandChildFragmentEntity.isPresent() } @Sql([CLEAR_DATA, SET_DATA]) diff --git a/csit/plans/cps/pnfsim/netconf-config/stores.yang b/csit/plans/cps/pnfsim/netconf-config/stores.yang index b24ac0e1ac..59051f2a28 100644 --- a/csit/plans/cps/pnfsim/netconf-config/stores.yang +++ b/csit/plans/cps/pnfsim/netconf-config/stores.yang @@ -1,63 +1,63 @@ -module stores {
-
- yang-version 1.1;
-
- namespace "org:onap:ccsdk:sample";
-
- prefix book-store;
-
- import ietf-yang-types { prefix yang; }
- import ietf-inet-types { prefix inet; }
-
- revision "2020-09-15" {
- description
- "Sample Model";
- }
-
- typedef year {
- type uint16 {
- range "1000..9999";
- }
- }
-
- container bookstore {
-
- leaf bookstore-name {
- type string;
- }
-
- list categories {
-
- key "code";
-
- leaf code {
- type string;
- }
-
- leaf name {
- type string;
- }
-
- list books {
- key title;
-
- leaf title {
- type string;
- }
- leaf lang {
- type string;
- }
- leaf-list authors {
- type string;
- }
- leaf pub_year {
- type year;
- }
- leaf price {
- type uint64;
- }
- }
- }
- }
-}
-
+module stores { + + yang-version 1.1; + + namespace "org:onap:ccsdk:sample"; + + prefix book-store; + + import ietf-yang-types { prefix yang; } + import ietf-inet-types { prefix inet; } + + revision "2020-09-15" { + description + "Sample Model"; + } + + typedef year { + type uint16 { + range "1000..9999"; + } + } + + container bookstore { + + leaf bookstore-name { + type string; + } + + list categories { + + key "code"; + + leaf code { + type string; + } + + leaf name { + type string; + } + + list books { + key title; + + leaf title { + type string; + } + leaf lang { + type string; + } + leaf-list authors { + type string; + } + leaf pub_year { + type year; + } + leaf price { + type uint64; + } + } + } + } +} + |