CpsPath Query Optimization
[cps.git] / cps-ri / src / main / java / org / onap / cps / spi / repository / FragmentRepositoryCpsPathQueryImpl.java
index 1d61416..6e8f05f 100644 (file)
 
 package org.onap.cps.spi.repository;
 
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import javax.persistence.EntityManager;
 import javax.persistence.PersistenceContext;
 import javax.persistence.Query;
 import javax.transaction.Transactional;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.cpspath.parser.CpsPathPrefixType;
 import org.onap.cps.cpspath.parser.CpsPathQuery;
 import org.onap.cps.spi.entities.FragmentEntity;
-import org.onap.cps.utils.JsonObjectMapper;
 
 @RequiredArgsConstructor
 @Slf4j
 public class FragmentRepositoryCpsPathQueryImpl implements FragmentRepositoryCpsPathQuery {
 
-    public static final String REGEX_ABSOLUTE_PATH_PREFIX = ".*\\/";
-    public static final String REGEX_OPTIONAL_LIST_INDEX_POSTFIX = "(\\[@(?!.*\\[).*?])?$";
-
     @PersistenceContext
     private EntityManager entityManager;
-    private final JsonObjectMapper jsonObjectMapper;
+
+    private final FragmentQueryBuilder fragmentQueryBuilder;
 
     @Override
     @Transactional
     public List<FragmentEntity> findByAnchorAndCpsPath(final int anchorId, final CpsPathQuery cpsPathQuery) {
-        final StringBuilder sqlStringBuilder = new StringBuilder("SELECT * FROM FRAGMENT WHERE anchor_id = :anchorId");
-        final Map<String, Object> queryParameters = new HashMap<>();
-        queryParameters.put("anchorId", anchorId);
-        sqlStringBuilder.append(" AND xpath ~ :xpathRegex");
-        final String xpathRegex = getXpathSqlRegex(cpsPathQuery);
-        queryParameters.put("xpathRegex", xpathRegex);
-        if (cpsPathQuery.hasLeafConditions()) {
-            sqlStringBuilder.append(" AND attributes @> :leafDataAsJson\\:\\:jsonb");
-            queryParameters.put("leafDataAsJson", jsonObjectMapper.asJsonString(
-                cpsPathQuery.getLeavesData()));
-        }
-
-        addTextFunctionCondition(cpsPathQuery, sqlStringBuilder, queryParameters);
-        final Query query = entityManager.createNativeQuery(sqlStringBuilder.toString(), FragmentEntity.class);
-        setQueryParameters(query, queryParameters);
+        final Query query = fragmentQueryBuilder.getQueryForAnchorAndCpsPath(anchorId, cpsPathQuery);
         final List<FragmentEntity> fragmentEntities = query.getResultList();
         log.debug("Fetched {} fragment entities by anchor and cps path.", fragmentEntities.size());
         return fragmentEntities;
     }
 
-    private static String getXpathSqlRegex(final CpsPathQuery cpsPathQuery) {
-        final StringBuilder xpathRegexBuilder = new StringBuilder();
-        if (CpsPathPrefixType.ABSOLUTE.equals(cpsPathQuery.getCpsPathPrefixType())) {
-            xpathRegexBuilder.append(escapeXpath(cpsPathQuery.getXpathPrefix()));
-        } else {
-            xpathRegexBuilder.append(REGEX_ABSOLUTE_PATH_PREFIX);
-            xpathRegexBuilder.append(escapeXpath(cpsPathQuery.getDescendantName()));
-        }
-        xpathRegexBuilder.append(REGEX_OPTIONAL_LIST_INDEX_POSTFIX);
-        return xpathRegexBuilder.toString();
-    }
-
-    private static String escapeXpath(final String xpath) {
-        // See https://jira.onap.org/browse/CPS-500 for limitations of this basic escape mechanism
-        return xpath.replace("[@", "\\[@");
-    }
-
-    private static Integer getTextValueAsInt(final CpsPathQuery cpsPathQuery) {
-        try {
-            return Integer.parseInt(cpsPathQuery.getTextFunctionConditionValue());
-        } catch (final NumberFormatException e) {
-            return null;
-        }
-    }
-
-    private static void addTextFunctionCondition(final CpsPathQuery cpsPathQuery, final StringBuilder sqlStringBuilder,
-                                                 final Map<String, Object> queryParameters) {
-        if (cpsPathQuery.hasTextFunctionCondition()) {
-            sqlStringBuilder.append(" AND (");
-            sqlStringBuilder.append("attributes @> jsonb_build_object(:textLeafName, :textValue)");
-            sqlStringBuilder
-                .append(" OR attributes @> jsonb_build_object(:textLeafName, json_build_array(:textValue))");
-            queryParameters.put("textLeafName", cpsPathQuery.getTextFunctionConditionLeafName());
-            queryParameters.put("textValue", cpsPathQuery.getTextFunctionConditionValue());
-            final Integer textValueAsInt = getTextValueAsInt(cpsPathQuery);
-            if (textValueAsInt != null) {
-                sqlStringBuilder.append(" OR attributes @> jsonb_build_object(:textLeafName, :textValueAsInt)");
-                sqlStringBuilder
-                    .append(" OR attributes @> jsonb_build_object(:textLeafName, json_build_array(:textValueAsInt))");
-                queryParameters.put("textValueAsInt", textValueAsInt);
-            }
-            sqlStringBuilder.append(")");
-        }
-    }
-
-    private static void setQueryParameters(final Query query, final Map<String, Object> queryParameters) {
-        for (final Map.Entry<String, Object> queryParameter : queryParameters.entrySet()) {
-            query.setParameter(queryParameter.getKey(), queryParameter.getValue());
-        }
-    }
-
 }