aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy17
-rw-r--r--cps-service/src/main/java/org/onap/cps/impl/CpsFacadeImpl.java10
-rw-r--r--cps-service/src/main/java/org/onap/cps/utils/DataMapper.java11
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/impl/CpsFacadeImplSpec.groovy15
4 files changed, 51 insertions, 2 deletions
diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy
index 5f6de2ec4c..b49afb4798 100644
--- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy
+++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy
@@ -94,6 +94,23 @@ class QueryRestControllerSpec extends Specification {
'descendants XML' | '2' | MediaType.APPLICATION_XML || 2 || '<prefixedPath><path><leaf>value</leaf></path></prefixedPath>'
}
+ def 'Query data node (v2) by cps path for given dataspace and anchor with attribute-axis and #scenario'() {
+ given: 'the query endpoint'
+ def dataNodeEndpointV2 = "$basePath/v2/dataspaces/my_dataspace/anchors/my_anchor/nodes/query"
+ when: 'query data nodes API is invoked'
+ def response = mvc.perform(get(dataNodeEndpointV2).contentType(contentType).param('cps-path', '/my/path/@myAttribute').param('descendants', '0'))
+ .andReturn().response
+ then: 'the call is delegated to the cps service facade which returns a list containing two attributes as maps'
+ 1 * mockCpsFacade.executeAnchorQuery('my_dataspace', 'my_anchor', '/my/path/@myAttribute', OMIT_DESCENDANTS) >> [['myAttribute':'value1'], ['myAttribute':'value2']]
+ and: 'the response contains the datanode in the expected format'
+ assert response.status == HttpStatus.OK.value()
+ assert response.getContentAsString() == expectedOutput
+ where: 'the following options for content type are provided in the request'
+ scenario | contentType || expectedOutput
+ 'JSON' | MediaType.APPLICATION_JSON || '[{"myAttribute":"value1"},{"myAttribute":"value2"}]'
+ 'XML' | MediaType.APPLICATION_XML || '<myAttribute>value1</myAttribute><myAttribute>value2</myAttribute>'
+ }
+
def 'Query data node by cps path for given dataspace across all anchors'() {
given: 'the query endpoint'
def dataNodeEndpoint = "$basePath/v2/dataspaces/my_dataspace/nodes/query"
diff --git a/cps-service/src/main/java/org/onap/cps/impl/CpsFacadeImpl.java b/cps-service/src/main/java/org/onap/cps/impl/CpsFacadeImpl.java
index 4ac0d5d8e8..35a03685b6 100644
--- a/cps-service/src/main/java/org/onap/cps/impl/CpsFacadeImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/impl/CpsFacadeImpl.java
@@ -23,6 +23,7 @@ package org.onap.cps.impl;
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.onap.cps.api.CpsDataService;
import org.onap.cps.api.CpsFacade;
@@ -30,6 +31,8 @@ import org.onap.cps.api.CpsQueryService;
import org.onap.cps.api.model.DataNode;
import org.onap.cps.api.parameters.FetchDescendantsOption;
import org.onap.cps.api.parameters.PaginationOption;
+import org.onap.cps.cpspath.parser.CpsPathQuery;
+import org.onap.cps.cpspath.parser.CpsPathUtil;
import org.onap.cps.utils.DataMapper;
import org.springframework.stereotype.Service;
@@ -66,6 +69,13 @@ public class CpsFacadeImpl implements CpsFacade {
final String anchorName,
final String cpsPath,
final FetchDescendantsOption fetchDescendantsOption) {
+ final CpsPathQuery cpsPathQuery = CpsPathUtil.getCpsPathQuery(cpsPath);
+ if (cpsPathQuery.hasAttributeAxis()) {
+ final String attributeName = cpsPathQuery.getAttributeAxisAttributeName();
+ final Set<Object> attributeValues =
+ cpsQueryService.queryDataLeaf(dataspaceName, anchorName, cpsPath, Object.class);
+ return dataMapper.toAttributeMaps(attributeName, attributeValues);
+ }
final Collection<DataNode> dataNodes =
cpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption);
return dataMapper.toDataMaps(dataspaceName, anchorName, dataNodes);
diff --git a/cps-service/src/main/java/org/onap/cps/utils/DataMapper.java b/cps-service/src/main/java/org/onap/cps/utils/DataMapper.java
index 6e7eff9132..29d61ffcc4 100644
--- a/cps-service/src/main/java/org/onap/cps/utils/DataMapper.java
+++ b/cps-service/src/main/java/org/onap/cps/utils/DataMapper.java
@@ -107,6 +107,17 @@ public class DataMapper {
}
/**
+ * Converts list of attributes values to a list of data maps.
+ * @param attributeName attribute name
+ * @param attributeValues attribute values
+ * @return a list of maps representing the attribute values
+ */
+ public List<Map<String, Object>> toAttributeMaps(final String attributeName,
+ final Collection<Object> attributeValues) {
+ return attributeValues.stream().map(attributeValue -> Map.of(attributeName, attributeValue)).toList();
+ }
+
+ /**
* Convert a collection of data nodes to a data map.
*
* @param anchor the anchor
diff --git a/cps-service/src/test/groovy/org/onap/cps/impl/CpsFacadeImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/impl/CpsFacadeImplSpec.groovy
index c754970518..4351631ee1 100644
--- a/cps-service/src/test/groovy/org/onap/cps/impl/CpsFacadeImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/impl/CpsFacadeImplSpec.groovy
@@ -75,15 +75,26 @@ class CpsFacadeImplSpec extends Specification {
def 'Execute anchor query.'() {
given: 'the cps query service returns two data nodes'
- mockCpsQueryService.queryDataNodes('my dataspace', 'my anchor', 'my cps path', myFetchDescendantsOption) >> [ dataNode1, dataNode2]
+ mockCpsQueryService.queryDataNodes('my dataspace', 'my anchor', '/my/path', myFetchDescendantsOption) >> [ dataNode1, dataNode2]
when: 'get data node by dataspace and anchor'
- def result = objectUnderTest.executeAnchorQuery('my dataspace', 'my anchor', 'my cps path', myFetchDescendantsOption)
+ def result = objectUnderTest.executeAnchorQuery('my dataspace', 'my anchor', '/my/path', myFetchDescendantsOption)
then: 'all nodes (from the query service result) are returned'
assert result.size() == 2
assert result[0].keySet()[0] == 'prefix1:path1'
assert result[1].keySet()[0] == 'prefix2:path2'
}
+ def 'Execute anchor query with attribute-axis.'() {
+ given: 'the cps query service returns two attribute values'
+ mockCpsQueryService.queryDataLeaf('my dataspace', 'my anchor', '/my/path/@myAttribute', Object) >> ['value1', 'value2']
+ when: 'get data using attribute axis'
+ def result = objectUnderTest.executeAnchorQuery('my dataspace', 'my anchor', '/my/path/@myAttribute', myFetchDescendantsOption)
+ then: 'attribute values (from the query service result) are returned'
+ assert result.size() == 2
+ assert result[0] == ['myAttribute': 'value1']
+ assert result[1] == ['myAttribute': 'value2']
+ }
+
def 'Execute dataspace query.'() {
given: 'the cps query service returns two data nodes (on two different anchors)'
mockCpsQueryService.queryDataNodesAcrossAnchors('my dataspace', 'my cps path', myFetchDescendantsOption, myPaginationOption) >> [ dataNode1, dataNode2, dataNode3 ]