X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=cps-ri%2Fsrc%2Fmain%2Fjava%2Forg%2Fonap%2Fcps%2Fspi%2Frepository%2FFragmentRepository.java;h=f389467a537ffd3072652993fc36b5e0306a4772;hb=1be9234c5234883be1e8d66baf7a780fa6be8ccf;hp=b9874484c0307a06154c0b9d4d8f25e3e6ce7e8a;hpb=c718b88511539c3b85d3fcd3d7c84e3baa89b749;p=cps.git 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 b9874484c..f389467a5 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 @@ -1,7 +1,9 @@ -/*- +/* * ============LICENSE_START======================================================= - * Copyright (C) 2020-201 Nordix Foundation. All rights reserved. - * Modifications Copyright (C) 2020-2021 Bell Canada. All rights reserved. + * Copyright (C) 2021-2023 Nordix Foundation. + * Modifications Copyright (C) 2020-2021 Bell Canada. + * Modifications Copyright (C) 2020-2021 Pantheon.tech. + * Modifications Copyright (C) 2023 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,11 +26,9 @@ package org.onap.cps.spi.repository; import java.util.Collection; import java.util.List; import java.util.Optional; -import javax.validation.constraints.NotNull; -import org.checkerframework.checker.nullness.qual.NonNull; import org.onap.cps.spi.entities.AnchorEntity; -import org.onap.cps.spi.entities.DataspaceEntity; import org.onap.cps.spi.entities.FragmentEntity; +import org.onap.cps.spi.entities.FragmentExtract; import org.onap.cps.spi.exceptions.DataNodeNotFoundException; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; @@ -37,50 +37,108 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @Repository -public interface FragmentRepository extends JpaRepository { +public interface FragmentRepository extends JpaRepository, FragmentRepositoryCpsPathQuery { - Optional findByDataspaceAndAnchorAndXpath(@NonNull DataspaceEntity dataspaceEntity, - @NonNull AnchorEntity anchorEntity, @NonNull String xpath); + Optional findByAnchorAndXpath(AnchorEntity anchorEntity, String xpath); - default FragmentEntity getByDataspaceAndAnchorAndXpath(@NonNull DataspaceEntity dataspaceEntity, - @NonNull AnchorEntity anchorEntity, @NonNull String xpath) { - return findByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity, xpath) - .orElseThrow(() -> new DataNodeNotFoundException(dataspaceEntity.getName(), anchorEntity.getName(), xpath)); + default FragmentEntity getByAnchorAndXpath(final AnchorEntity anchorEntity, final String xpath) { + return findByAnchorAndXpath(anchorEntity, xpath).orElseThrow(() -> + new DataNodeNotFoundException(anchorEntity.getDataspace().getName(), anchorEntity.getName(), xpath)); } - Optional findFirstByDataspaceAndAnchor(@NonNull DataspaceEntity dataspaceEntity, - @NonNull AnchorEntity anchorEntity); + boolean existsByAnchorId(int anchorId); - default FragmentEntity getFirstByDataspaceAndAnchor(@NonNull DataspaceEntity dataspaceEntity, - @NonNull AnchorEntity anchorEntity) { - return findFirstByDataspaceAndAnchor(dataspaceEntity, anchorEntity) - .orElseThrow(() -> new DataNodeNotFoundException(dataspaceEntity.getName(), anchorEntity.getName())); + @Query("SELECT f FROM FragmentEntity f WHERE anchor = :anchor") + List findAllExtractsByAnchor(@Param("anchor") AnchorEntity anchorEntity); + + @Query(value = "SELECT * FROM fragment WHERE xpath = ANY (:xpaths)", nativeQuery = true) + List findAllByXpathIn(@Param("xpaths") String[] xpath); + + default List findAllByXpathIn(final Collection xpaths) { + return findAllByXpathIn(xpaths.toArray(new String[0])); + } + + @Modifying + @Query(value = "DELETE FROM fragment WHERE anchor_id = ANY (:anchorIds)", nativeQuery = true) + void deleteByAnchorIdIn(@Param("anchorIds") int[] anchorIds); + + default void deleteByAnchorIn(final Collection anchorEntities) { + deleteByAnchorIdIn(anchorEntities.stream().map(AnchorEntity::getId).mapToInt(id -> id).toArray()); } @Modifying - @Query("DELETE FROM FragmentEntity fe WHERE fe.anchor IN (:anchors)") - void deleteByAnchorIn(@NotNull @Param("anchors") Collection anchorEntities); + @Query(value = "DELETE FROM fragment WHERE anchor_id = :anchorId AND xpath = ANY (:xpaths)", nativeQuery = true) + void deleteByAnchorIdAndXpaths(@Param("anchorId") int anchorId, @Param("xpaths") String[] xpaths); + + default void deleteByAnchorIdAndXpaths(final int anchorId, final Collection xpaths) { + deleteByAnchorIdAndXpaths(anchorId, xpaths.toArray(new String[0])); + } - @Query(value = - "SELECT * FROM FRAGMENT WHERE (anchor_id = :anchor) AND (xpath = (:xpath) OR xpath LIKE " - + "CONCAT(:xpath,'\\[@%]')) AND attributes @> jsonb_build_object(:leafName , :leafValue)", + @Modifying + @Query(value = "DELETE FROM fragment f WHERE anchor_id = :anchorId AND xpath LIKE ANY (:xpathPatterns)", nativeQuery = true) - // Above query will match an xpath with or without the index for a list [@key=value] and match anchor id, - // leaf name and leaf value - List getByAnchorAndXpathAndLeafAttributes(@Param("anchor") int anchorId, @Param("xpath") - String xpathPrefix, @Param("leafName") String leafName, @Param("leafValue") Object leafValue); + void deleteByAnchorIdAndXpathLikeAny(@Param("anchorId") int anchorId, + @Param("xpathPatterns") String[] xpathPatterns); + + default void deleteListsByAnchorIdAndXpaths(int anchorId, Collection xpaths) { + final String[] listXpathPatterns = xpaths.stream().map(xpath -> xpath + "[%").toArray(String[]::new); + deleteByAnchorIdAndXpathLikeAny(anchorId, listXpathPatterns); + } + + @Query("SELECT f FROM FragmentEntity f WHERE anchor = :anchor" + + " AND (xpath = :parentXpath OR xpath LIKE CONCAT(:parentXpath,'/%'))") + List findByAnchorAndParentXpath(@Param("anchor") AnchorEntity anchorEntity, + @Param("parentXpath") String parentXpath); - @Query(value = "SELECT * FROM FRAGMENT WHERE anchor_id = :anchor AND xpath LIKE CONCAT('%/',:descendantName)", + @Query(value = "SELECT id, anchor_id AS anchorId, xpath, parent_id AS parentId," + + " CAST(attributes AS TEXT) AS attributes" + + " FROM FRAGMENT WHERE anchor_id = :anchorId" + + " AND xpath ~ :xpathRegex", nativeQuery = true) - // Above query will match the anchor id and last descendant name - List getByAnchorAndXpathEndsInDescendantName(@Param("anchor") int anchorId, - @Param("descendantName") String descendantName); + List quickFindWithDescendants(@Param("anchorId") int anchorId, + @Param("xpathRegex") String xpathRegex); - @Query(value = "SELECT * FROM FRAGMENT WHERE anchor_id = :anchor AND (xpath LIKE CONCAT('%/',:descendantName) OR " - + "xpath LIKE CONCAT('%/', :descendantName,'\\[@%]')) AND attributes @> :leafDataAsJson\\:\\:jsonb", + @Query(value = "SELECT xpath FROM fragment WHERE anchor_id = :anchorId AND xpath = ANY (:xpaths)", nativeQuery = true) - // Above query will match the anchor id, last descendant name and all parameters passed into leafDataASJson with the - // attribute values of the requested data node eg: {"leaf_name":"value", "another_leaf_name":"another value"}​​​​​​ - List getByAnchorAndDescendentNameAndLeafValues(@Param("anchor") int anchorId, - @Param("descendantName") String descendantName, @Param("leafDataAsJson") String leafDataAsJson); + List findAllXpathByAnchorIdAndXpathIn(@Param("anchorId") int anchorId, + @Param("xpaths") String[] xpaths); + + default List findAllXpathByAnchorAndXpathIn(final AnchorEntity anchorEntity, + final Collection xpaths) { + return findAllXpathByAnchorIdAndXpathIn(anchorEntity.getId(), xpaths.toArray(new String[0])); + } + + boolean existsByAnchorAndXpathStartsWith(AnchorEntity anchorEntity, String xpath); + + @Query("SELECT xpath FROM FragmentEntity WHERE anchor = :anchor AND parentId IS NULL") + List findAllXpathByAnchorAndParentIdIsNull(@Param("anchor") AnchorEntity anchorEntity); + + @Query(value + = "WITH RECURSIVE parent_search AS (" + + " SELECT id, 0 AS depth " + + " FROM fragment " + + " WHERE anchor_id = :anchorId AND xpath = ANY (:xpaths) " + + " UNION " + + " SELECT c.id, depth + 1 " + + " FROM fragment c INNER JOIN parent_search p ON c.parent_id = p.id" + + " WHERE depth <= (SELECT CASE WHEN :maxDepth = -1 THEN " + Integer.MAX_VALUE + " ELSE :maxDepth END) " + + ") " + + "SELECT f.id, anchor_id AS anchorId, xpath, f.parent_id AS parentId, CAST(attributes AS TEXT) AS attributes " + + "FROM fragment f INNER JOIN parent_search p ON f.id = p.id", + nativeQuery = true + ) + List findExtractsWithDescendants(@Param("anchorId") int anchorId, + @Param("xpaths") String[] xpaths, + @Param("maxDepth") int maxDepth); + + default List findExtractsWithDescendants(final int anchorId, final Collection xpaths, + final int maxDepth) { + return findExtractsWithDescendants(anchorId, xpaths.toArray(new String[0]), maxDepth); + } + + @Query(value = "SELECT id, anchor_id AS anchorId, xpath, parent_id AS parentId," + + " CAST(attributes AS TEXT) AS attributes" + + " FROM FRAGMENT WHERE xpath ~ :xpathRegex", + nativeQuery = true) + List quickFindWithDescendantsAcrossAnchors(@Param("xpathRegex") String xpathRegex); }