diff options
5 files changed, 41 insertions, 12 deletions
diff --git a/cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java index 52fd7f2be1..ac6fe38ee7 100644 --- a/cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2024 Nordix Foundation + * Copyright (C) 2021-2025 Nordix Foundation * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2022-2023 TechMahindra Ltd. @@ -37,6 +37,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.TreeMap; import java.util.stream.Collectors; @@ -230,6 +231,27 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService } @Override + public <T> Set<T> queryDataLeaf(final String dataspaceName, final String anchorName, final String cpsPath, + final Class<T> targetClass) { + final CpsPathQuery cpsPathQuery = getCpsPathQuery(cpsPath); + if (!cpsPathQuery.hasAttributeAxis()) { + throw new IllegalArgumentException( + "Only Cps Path Queries with attribute-axis are supported by queryDataLeaf"); + } + + final String attributeName = cpsPathQuery.getAttributeAxisAttributeName(); + final List<DataNode> dataNodes = queryDataNodes(dataspaceName, anchorName, cpsPath, + FetchDescendantsOption.OMIT_DESCENDANTS); + return dataNodes.stream() + .map(dataNode -> { + final Object attributeValue = dataNode.getLeaves().get(attributeName); + return targetClass.isInstance(attributeValue) ? targetClass.cast(attributeValue) : null; + }) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + + @Override @Timed(value = "cps.data.persistence.service.datanode.query.anchors", description = "Time taken to query data nodes across all anchors or list of anchors") public List<DataNode> queryDataNodesAcrossAnchors(final String dataspaceName, final String cpsPath, diff --git a/cps-service/src/main/java/org/onap/cps/impl/CpsQueryServiceImpl.java b/cps-service/src/main/java/org/onap/cps/impl/CpsQueryServiceImpl.java index 2687d8faee..508a1b2449 100644 --- a/cps-service/src/main/java/org/onap/cps/impl/CpsQueryServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/impl/CpsQueryServiceImpl.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2024 Nordix Foundation + * Copyright (C) 2021-2025 Nordix Foundation * Modifications Copyright (C) 2022-2023 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -54,7 +54,7 @@ public class CpsQueryServiceImpl implements CpsQueryService { public <T> Set<T> queryDataLeaf(final String dataspaceName, final String anchorName, final String cpsPath, final Class<T> targetClass) { cpsValidator.validateNameCharacters(dataspaceName, anchorName); - throw new UnsupportedOperationException("Query by attribute-axis not implemented yet!"); + return cpsDataPersistenceService.queryDataLeaf(dataspaceName, anchorName, cpsPath, targetClass); } @Override diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java index 5be5b1e2e0..a4f05cdb53 100644 --- a/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java +++ b/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020-2024 Nordix Foundation. + * Copyright (C) 2020-2025 Nordix Foundation. * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2022 Bell Canada * Modifications Copyright (C) 2022-2023 TechMahindra Ltd. @@ -27,6 +27,7 @@ import java.io.Serializable; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; import org.onap.cps.api.model.DataNode; import org.onap.cps.api.parameters.FetchDescendantsOption; import org.onap.cps.api.parameters.PaginationOption; @@ -185,6 +186,17 @@ public interface CpsDataPersistenceService { String cpsPath, FetchDescendantsOption fetchDescendantsOption); /** + * Get data leaf for the given dataspace and anchor by cps path. + * + * @param dataspaceName dataspace name + * @param anchorName anchor name + * @param cpsPath cps path + * @param targetClass class of the expected data type + * @return a collection of data objects of expected type + */ + <T> Set<T> queryDataLeaf(String dataspaceName, String anchorName, String cpsPath, Class<T> targetClass); + + /** * Get a datanode by dataspace name and cps path across all anchors. * * @param dataspaceName dataspace name diff --git a/cps-service/src/test/groovy/org/onap/cps/impl/CpsQueryServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/impl/CpsQueryServiceImplSpec.groovy index 237e4e4592..b15ee72370 100644 --- a/cps-service/src/test/groovy/org/onap/cps/impl/CpsQueryServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/impl/CpsQueryServiceImplSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation + * Copyright (C) 2021-2025 Nordix Foundation * Modifications Copyright (C) 2023 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -73,11 +73,10 @@ class CpsQueryServiceImplSpec extends Specification { 1 * mockCpsDataPersistenceService.countAnchorsForDataspaceAndCpsPath("some-dataspace", "/cps-path") } - // TODO will be implemented in CPS-2416 def 'Query data leaf.'() { when: 'a query for a specific leaf is executed' objectUnderTest.queryDataLeaf('some-dataspace', 'some-anchor', '/cps-path/@id', Object.class) then: 'solution is not implemented yet' - thrown(UnsupportedOperationException) + 1 * mockCpsDataPersistenceService.queryDataLeaf('some-dataspace', 'some-anchor', '/cps-path/@id', Object.class) } } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/QueryServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/QueryServiceIntegrationSpec.groovy index e4d75aa378..d1b445f5a4 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/QueryServiceIntegrationSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/QueryServiceIntegrationSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023-2024 Nordix Foundation + * Copyright (C) 2023-2025 Nordix Foundation * Modifications Copyright (C) 2023-2025 TechMahindra Ltd * ================================================================================ * Licensed under the Apache License, Version 2.0 (the 'License'); @@ -27,7 +27,6 @@ import org.onap.cps.integration.base.FunctionalSpecBase import org.onap.cps.api.parameters.FetchDescendantsOption import org.onap.cps.api.parameters.PaginationOption import org.onap.cps.api.exceptions.CpsPathException -import spock.lang.Ignore import static org.onap.cps.api.parameters.FetchDescendantsOption.DIRECT_CHILDREN_ONLY import static org.onap.cps.api.parameters.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS @@ -57,7 +56,6 @@ class QueryServiceIntegrationSpec extends FunctionalSpecBase { 'the AND is used where result does not exist' | '//books[@lang="English" and @price=1000]' || 0 | [] } - @Ignore // TODO will be implemented in CPS-2416 def 'Query data leaf using CPS path for #scenario.'() { when: 'query data leaf for bookstore container' def result = objectUnderTest.queryDataLeaf(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, cpsPath, Object.class) @@ -70,7 +68,6 @@ class QueryServiceIntegrationSpec extends FunctionalSpecBase { 'non-existing path' | '/non-existing/@title' || 0 } - @Ignore def 'Query data leaf with type #leafType using CPS path.'() { given: 'a cps path query for two books, returning only #leafName' def cpsPath = '//books[@title="Matilda" or @title="Good Omens"]/@' + leafName @@ -85,7 +82,6 @@ class QueryServiceIntegrationSpec extends FunctionalSpecBase { 'editions' | List.class || [[1988, 2000], [2006]] } - @Ignore def 'Query data leaf using CPS path with ancestor axis.'() { given: 'a cps path query that will return the names of the categories of two books' def cpsPath = '//books[@title="Matilda" or @title="Good Omens"]/ancestor::categories/@name' |