diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/RsqlValidationOracle.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/RsqlValidationOracle.java deleted file mode 100644 index 235b54529..000000000 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/RsqlValidationOracle.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.eclipse.hawkbit.repository.rsql; - -/** - * An interface declaration which validates an RSQL based query syntax and - * allows providing suggestions e.g. in case of syntax errors or current cursor - * position. - */ -@FunctionalInterface -public interface RsqlValidationOracle { - - /** - * Parses and validates an given RSQL based query syntax and provides - * suggestion based on syntax error and cursor positioning. - * - * @param rsqlQuery an RSQL based query string to parse. - * @param cursorPosition the position of the cursor to retrieve suggestions at the - * position. {@code -1} indicates for no cursor suggestion - * @return a validation oracle context providing information about syntax - * errors and possible suggestions for fixing the syntax error or at - * the cursor position to replace tokens - */ - ValidationOracleContext suggest(final String rsqlQuery, final int cursorPosition); - -} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/SuggestToken.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/SuggestToken.java deleted file mode 100644 index 7c9037557..000000000 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/SuggestToken.java +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.eclipse.hawkbit.repository.rsql; - -/** - * A suggestion which contains the start and the end character position of the - * suggested token of the suggestion of the token and the actual suggestion. - */ -public class SuggestToken { - - private final int start; - private final int end; - private final String suggestion; - private final String tokenImageName; - - /** - * Constructor. - * - * @param start the character position of the start of the token - * @param end the character position of the end of the token - * @param tokenImageName the entered name of the token, e.g. could be the beginning of - * the suggestion like 'na' or 'name' - * @param suggestion the token suggestion - */ - public SuggestToken(final int start, final int end, final String tokenImageName, final String suggestion) { - this.start = start; - this.end = end; - this.tokenImageName = tokenImageName; - this.suggestion = suggestion; - } - - public int getStart() { - return start; - } - - public int getEnd() { - return end; - } - - public String getSuggestion() { - return suggestion; - } - - public String getTokenImageName() { - return tokenImageName; - } - - @Override - public String toString() { - return "SuggestToken [start=" + start + ", end=" + end + ", suggestion=" + suggestion + ", tokenImageName=" - + tokenImageName + "]"; - } -} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/SuggestionContext.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/SuggestionContext.java deleted file mode 100644 index cbc026e8d..000000000 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/SuggestionContext.java +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.eclipse.hawkbit.repository.rsql; - -import java.util.ArrayList; -import java.util.List; - -/** - * The context which holds suggestions for the current cursor position. - */ -public class SuggestionContext { - - private String rsqlQuery; - private int cursorPosition; - private List suggestions = new ArrayList<>(); - - /** - * Default constructor. - */ - public SuggestionContext() { - // nothing to initialize - } - - /** - * Constructor. - * - * @param rsqlQuery the original RSQL based query the suggestions based on - * @param cursorPosition the current cursor position - * @param suggestions the suggestions for the current cursor position - */ - public SuggestionContext(final String rsqlQuery, final int cursorPosition, final List suggestions) { - this.rsqlQuery = rsqlQuery; - this.cursorPosition = cursorPosition; - this.suggestions = suggestions; - } - - public List getSuggestions() { - return suggestions; - } - - public void setSuggestions(final List suggestions) { - this.suggestions = suggestions; - } - - public int getCursorPosition() { - return cursorPosition; - } - - public void setCursorPosition(final int cursorPosition) { - this.cursorPosition = cursorPosition; - } - - public String getRsqlQuery() { - return rsqlQuery; - } - - public void setRsqlQuery(final String rsqlQuery) { - this.rsqlQuery = rsqlQuery; - } -} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/SyntaxErrorContext.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/SyntaxErrorContext.java deleted file mode 100644 index dfedfa342..000000000 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/SyntaxErrorContext.java +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.eclipse.hawkbit.repository.rsql; - -/** - * An syntax error context object which holds the character position of the - * syntax error and message. - */ -public class SyntaxErrorContext { - - private int characterPosition = -1; - private String errorMessage; - - /** - * Default constructor. - */ - public SyntaxErrorContext() { - // nothing to initialize - } - - /** - * Constructor. - * - * @param characterPosition the position of the character within the RSQL query string the - * error occurs. - * @param errorMessage the error message with further information - */ - public SyntaxErrorContext(final int characterPosition, final String errorMessage) { - this.characterPosition = characterPosition; - this.errorMessage = errorMessage; - } - - public int getCharacterPosition() { - return characterPosition; - } - - public void setCharacterPosition(final int characterPosition) { - this.characterPosition = characterPosition; - } - - public String getErrorMessage() { - return errorMessage; - } - - public void setErrorMessage(final String errorMessage) { - this.errorMessage = errorMessage; - } -} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/ValidationOracleContext.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/ValidationOracleContext.java deleted file mode 100644 index 196b1869f..000000000 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/rsql/ValidationOracleContext.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.eclipse.hawkbit.repository.rsql; - -/** - * A context object which contains information about validation and suggestions - * of a parsed RSQL query. - */ -public class ValidationOracleContext { - - private boolean syntaxError; - - private SuggestionContext suggestionContext; - - private SyntaxErrorContext syntaxErrorContext; - - public boolean isSyntaxError() { - return syntaxError; - } - - public void setSyntaxError(final boolean syntaxError) { - this.syntaxError = syntaxError; - } - - public SuggestionContext getSuggestionContext() { - return suggestionContext; - } - - public void setSuggestionContext(final SuggestionContext suggestionContext) { - this.suggestionContext = suggestionContext; - } - - public SyntaxErrorContext getSyntaxErrorContext() { - return syntaxErrorContext; - } - - public void setSyntaxErrorContext(final SyntaxErrorContext syntaxErrorContext) { - this.syntaxErrorContext = syntaxErrorContext; - } -} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/RepositoryApplicationConfiguration.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/RepositoryApplicationConfiguration.java index cc5c386d8..3d008ca41 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/RepositoryApplicationConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/RepositoryApplicationConfiguration.java @@ -147,7 +147,6 @@ import org.eclipse.hawkbit.repository.jpa.rollout.condition.StartNextGroupRollou import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupErrorCondition; import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupSuccessCondition; import org.eclipse.hawkbit.repository.jpa.rsql.DefaultRsqlVisitorFactory; -import org.eclipse.hawkbit.repository.jpa.rsql.RsqlParserValidationOracle; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.Rollout; @@ -160,7 +159,6 @@ import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder; import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder; import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder; import org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder; -import org.eclipse.hawkbit.repository.rsql.RsqlValidationOracle; import org.eclipse.hawkbit.repository.rsql.RsqlVisitorFactory; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.security.HawkbitSecurityProperties; @@ -340,12 +338,6 @@ public class RepositoryApplicationConfiguration { return new AfterTransactionCommitDefaultServiceExecutor(); } - @Bean - @ConditionalOnMissingBean - RsqlValidationOracle rsqlValidationOracle() { - return new RsqlParserValidationOracle(); - } - @Bean @ConditionalOnMissingBean QuotaManagement staticQuotaManagement(final HawkbitSecurityProperties securityProperties) { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RsqlParserValidationOracle.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RsqlParserValidationOracle.java deleted file mode 100644 index 2e2b08acd..000000000 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rsql/RsqlParserValidationOracle.java +++ /dev/null @@ -1,333 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.eclipse.hawkbit.repository.jpa.rsql; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import cz.jirutka.rsql.parser.ParseException; -import cz.jirutka.rsql.parser.RSQLParserException; -import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.repository.TargetFields; -import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; -import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; -import org.eclipse.hawkbit.repository.jpa.rsql.ParseExceptionWrapper.TokenWrapper; -import org.eclipse.hawkbit.repository.rsql.RsqlValidationOracle; -import org.eclipse.hawkbit.repository.rsql.SuggestToken; -import org.eclipse.hawkbit.repository.rsql.SuggestionContext; -import org.eclipse.hawkbit.repository.rsql.SyntaxErrorContext; -import org.eclipse.hawkbit.repository.rsql.ValidationOracleContext; -import org.springframework.orm.jpa.JpaSystemException; -import org.springframework.util.CollectionUtils; - -/** - * An implementation of {@link RsqlValidationOracle} which retrieves the - * exception using the {@link ParseException} to retrieve the suggestions. - * - * The suggestion only works when there are syntax errors existing because the - * information about current and next tokens in the RSQL syntax are from the - * {@link ParseException}. - * - * There is a feature request on the GitHub project - * https://github.com - * /jirutka/rsql-parser/issues/22 - */ -@Slf4j -public class RsqlParserValidationOracle implements RsqlValidationOracle { - - @SuppressWarnings("java:S1872") // intentionally don't use class but name - class could be unavailable - @Override - public ValidationOracleContext suggest(final String rsqlQuery, final int cursorPosition) { - final List expectedTokens = new ArrayList<>(); - final ValidationOracleContext context = new ValidationOracleContext(); - context.setSyntaxError(true); - final SuggestionContext suggestionContext = new SuggestionContext(); - context.setSuggestionContext(suggestionContext); - final SyntaxErrorContext errorContext = new SyntaxErrorContext(); - context.setSyntaxErrorContext(errorContext); - - try { - RSQLUtility.validateRsqlFor(rsqlQuery, TargetFields.class); - context.setSyntaxError(false); - suggestionContext.getSuggestions().addAll(getLogicalOperatorSuggestion(rsqlQuery)); - } catch (final RSQLParameterSyntaxException | RSQLParserException ex) { - setExceptionDetails(rsqlQuery, new Exception(ex.getCause().getCause()), expectedTokens); - errorContext.setErrorMessage(getCustomMessage(ex.getCause().getMessage(), expectedTokens)); - suggestionContext.setSuggestions(expectedTokens); - log.trace("Syntax exception on parsing :", ex); - } catch (final RSQLParameterUnsupportedFieldException | IllegalArgumentException ex) { - errorContext.setErrorMessage(getCustomMessage(ex.getMessage(), null)); - log.trace("Illegal argument on parsing :", ex); - } catch (final JpaSystemException e) { - // noop - } catch (final RuntimeException e) { - if (!"org.eclipse.persistence.exceptions.ConversionException".equals(e.getClass().getName())) { - throw e; - } - } - return context; - } - - private static Collection getLogicalOperatorSuggestion(final String rsqlQuery) { - if (!rsqlQuery.endsWith(" ")) { - return Collections.emptyList(); - } else { - final int currentQueryLength = rsqlQuery.length(); - // only return and/or suggestion when there is a space at the end - final Collection tokenImages = TokenDescription.getTokenImage(TokenDescription.LOGICAL_OP); - final List logicalOps = new ArrayList<>(tokenImages.size()); - for (final String tokenImage : tokenImages) { - logicalOps.add( - new SuggestToken(currentQueryLength, currentQueryLength + tokenImage.length(), null, tokenImage)); - } - return logicalOps; - } - } - - private static void setExceptionDetails(final String rsqlQuery, final Exception ex, - final List expectedTokens) { - final ParseException parseException = findParseException(ex); - if (parseException == null) { - expectedTokens.addAll(getComparatorOperatorSuggestions(rsqlQuery)); - } else { - expectedTokens.addAll(getNextTokens(parseException)); - } - } - - private static List getNextTokens(final ParseException parseException) { - final List listTokens = new ArrayList<>(); - final ParseExceptionWrapper parseExceptionWrapper = new ParseExceptionWrapper(parseException); - final int[][] expectedTokenSequence = parseException.expectedTokenSequences; - final TokenWrapper currentToken = parseExceptionWrapper.getCurrentToken(); - if (currentToken == null) { - return Collections.emptyList(); - } - final TokenWrapper nextToken = currentToken.getNext(); - final int currentTokenKind = currentToken.getKind(); - final String currentTokenImageName = currentToken.getImage(); - final int nextTokenBeginColumn = nextToken.getBeginColumn(); - final int currentTokenEndColumn = currentToken.getEndColumn(); - - // token == 5 is the field token, reverse engineering. - if (currentTokenKind == 5) { - final Optional> handleFieldTokenSuggestion = handleFieldTokenSuggestion( - currentTokenImageName, nextTokenBeginColumn, currentTokenEndColumn); - if (handleFieldTokenSuggestion.isPresent()) { - return handleFieldTokenSuggestion.get(); - } - } - - for (final int[] is : expectedTokenSequence) { - addSuggestionOnTokenImage(listTokens, nextTokenBeginColumn, currentTokenEndColumn, is); - } - return listTokens; - } - - private static List getComparatorOperatorSuggestions(final String rsqlQuery) { - // only return comparator operators suggestions when there is a '=' or - // '!' symbol at the end - final String mapKeyOperatorPattern = "(\\w+)\\.\\w+[=!]{1}$"; - final Matcher mapKeyOperatorMatcher = Pattern.compile(mapKeyOperatorPattern).matcher(rsqlQuery); - - if (mapKeyOperatorMatcher.find() && FieldNameDescription.isMap(mapKeyOperatorMatcher.group(1))) { - final int currentQueryLength = rsqlQuery.length() - 1; - final Collection tokenImages = TokenDescription.getTokenImage(TokenDescription.COMPARATOR); - return tokenImages.stream().map(tokenImage -> new SuggestToken(currentQueryLength, - currentQueryLength + tokenImage.length(), null, tokenImage)).toList(); - } - - return Collections.emptyList(); - } - - private static void addSuggestionOnTokenImage(final List listTokens, final int nextTokenBeginColumn, - final int currentTokenEndColumn, final int[] is) { - for (final int i : is) { - final Collection tokenImage = TokenDescription.getTokenImage(i); - if (!CollectionUtils.isEmpty(tokenImage)) { - tokenImage.forEach(image -> listTokens.add(new SuggestToken(currentTokenEndColumn + 1, - nextTokenBeginColumn + image.length(), null, image))); - } - } - } - - private static Optional> handleFieldTokenSuggestion(final String currentTokenImageName, - final int nextTokenBeginColumn, final int currentTokenEndColumn) { - final boolean containsDot = currentTokenImageName.indexOf('.') != -1; - if (shouldSuggestTopLevelFieldNames(currentTokenImageName, containsDot)) { - return Optional - .of(FieldNameDescription.toTopSuggestToken(nextTokenBeginColumn - currentTokenImageName.length(), - nextTokenBeginColumn + currentTokenImageName.length(), currentTokenImageName)); - } else if (shouldSuggestDotToken(currentTokenImageName, containsDot)) { - return Optional - .of(Arrays.asList(new SuggestToken(currentTokenEndColumn, nextTokenBeginColumn + 1, null, "."))); - } else if (shouldSuggestSubTokenFieldNames(currentTokenImageName, containsDot)) { - return handleSubtokenSuggestion(currentTokenImageName, nextTokenBeginColumn); - } - return Optional.empty(); - } - - private static boolean shouldSuggestSubTokenFieldNames(final String currentTokenImageName, - final boolean containsDot) { - return containsDot && !FieldNameDescription.containsValue(currentTokenImageName); - } - - private static boolean shouldSuggestDotToken(final String currentTokenImageName, final boolean containsDot) { - return !containsDot && (FieldNameDescription.hasSubEntries(currentTokenImageName) - || FieldNameDescription.isMap(currentTokenImageName)); - } - - private static boolean shouldSuggestTopLevelFieldNames(final String currentTokenImageName, - final boolean containsDot) { - return !containsDot && !FieldNameDescription.containsValue(currentTokenImageName) - && !FieldNameDescription.hasSubEntries(currentTokenImageName); - } - - private static Optional> handleSubtokenSuggestion(final String currentTokenImageName, - final int nextTokenBeginColumn) { - final String[] split = currentTokenImageName.split("\\."); - for (final String string : split) { - if (FieldNameDescription.containsValue(string)) { - final String subTokenImage = split.length > 1 ? split[1] : null; - final int subTokenBegin = nextTokenBeginColumn + currentTokenImageName.indexOf('.') + 1; - return Optional.of(FieldNameDescription.toSubSuggestToken(subTokenBegin, subTokenBegin + 1, string, - subTokenImage)); - } - } - return Optional.empty(); - } - - private static ParseException findParseException(final Throwable e) { - if (e instanceof ParseException parseException) { - return parseException; - } else if (e.getCause() != null) { - return findParseException(e.getCause()); - } - return null; - } - - private static String getCustomMessage(final String message, final List expectedTokens) { - String builder = message; - - if (!message.contains(":")) { - return builder; - } - - builder = message.substring(message.indexOf(':') + 1); - if (builder.contains("Was expecting")) { - builder = builder.substring(0, builder.lastIndexOf("Was expecting")); - } - - if (!CollectionUtils.isEmpty(expectedTokens)) { - final StringBuilder tokens = new StringBuilder(); - expectedTokens.stream().forEach(value -> tokens.append(value.getSuggestion()).append(",")); - builder = builder.concat("Was expecting :" + tokens.substring(0, tokens.length() - 1)); - } - builder = builder.replace('\r', ' '); - builder = builder.replace('\n', ' '); - builder = builder.replace(">", " "); - builder = builder.replace("<", " "); - - return builder; - } - - // Token map with logical and comparator operator that are used for context - // sensitive help on search query. - private static final class TokenDescription { - - private static final Map> TOKEN_MAP = new HashMap<>(); - - private static final int LOGICAL_OP = 8; - private static final int COMPARATOR = 12; - - static { - TOKEN_MAP.put(LOGICAL_OP, List.of("and", "or")); - TOKEN_MAP.put(COMPARATOR, List.of("==", "!=", "=ge=", "=le=", "=gt=", "=lt=", "=in=", "=out=")); - } - - private TokenDescription() { - - } - - private static Collection getTokenImage(final int tokenIndex) { - return TOKEN_MAP.get(tokenIndex); - } - } - - private static final class FieldNameDescription { - - private static final Set FIELD_NAMES = Arrays.stream(TargetFields.values()) - .map(field -> field.toString().toLowerCase()).collect(Collectors.toSet()); - - private static final Map> SUB_NAMES = Arrays.stream(TargetFields.values()).collect( - Collectors.toMap(field -> field.toString().toLowerCase(), TargetFields::getSubEntityAttributes)); - - private FieldNameDescription() { - - } - - private static boolean hasSubEntries(final String tokenImageName) { - String tmpTokenName = tokenImageName; - if (tokenImageName.contains(".")) { - final String[] split = tokenImageName.split("\\."); - if (split.length <= 0) { - return false; - } - tmpTokenName = split[0]; - } - final String finalTmpTokenName = tmpTokenName; - return Arrays.stream(TargetFields.values()) - .filter(field -> field.toString().equalsIgnoreCase(finalTmpTokenName)) - .map(TargetFields::getSubEntityAttributes).mapToLong(List::size).sum() > 0; - } - - private static boolean isMap(final String tokenImageName) { - return Arrays.stream(TargetFields.values()) - .filter(field -> field.toString().equalsIgnoreCase(tokenImageName)).findFirst() - .map(TargetFields::isMap).orElse(false); - } - - private static List toTopSuggestToken(final int beginToken, final int endToken, - final String tokenImageName) { - return FIELD_NAMES.stream() - .map(field -> new SuggestToken(beginToken, endToken, tokenImageName, field.toLowerCase())) - .toList(); - } - - private static List toSubSuggestToken(final int beginToken, final int endToken, - final String topToken, final String tokenImageName) { - return Arrays.stream(TargetFields.values()).filter(field -> field.toString().equalsIgnoreCase(topToken)) - .map(TargetFields::getSubEntityAttributes).flatMap(List::stream) - .map(subEntity -> new SuggestToken(beginToken, endToken, tokenImageName, subEntity)) - .toList(); - } - - private static boolean containsValue(final String imageName) { - if (!imageName.contains(".")) { - return FIELD_NAMES.stream().anyMatch(value -> value.equalsIgnoreCase(imageName)); - } - final String[] split = imageName.split("\\."); - if (split.length > 1 && FIELD_NAMES.contains(split[0].toLowerCase())) { - return SUB_NAMES.get(split[0].toLowerCase()).stream() - .anyMatch(subname -> (split[0] + "." + subname).equalsIgnoreCase(imageName)); - } - return FIELD_NAMES.stream().anyMatch(value -> value.equalsIgnoreCase(imageName)); - } - } -} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLParserValidationOracleTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLParserValidationOracleTest.java deleted file mode 100644 index dd25db974..000000000 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLParserValidationOracleTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.eclipse.hawkbit.repository.jpa.rsql; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.Arrays; -import java.util.List; - -import io.qameta.allure.Description; -import io.qameta.allure.Feature; -import io.qameta.allure.Story; -import org.eclipse.hawkbit.repository.TargetFields; -import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; -import org.eclipse.hawkbit.repository.rsql.RsqlValidationOracle; -import org.eclipse.hawkbit.repository.rsql.SuggestToken; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; - -@Feature("Component Tests - Repository") -@Story("RSQL filter suggestion") -@SuppressWarnings("java:S6813") // constructor injects are not possible for test classes -class RSQLParserValidationOracleTest extends AbstractJpaIntegrationTest { - - private static final String[] OP_SUGGESTIONS = new String[] { "==", "!=", "=ge=", "=le=", "=gt=", "=lt=", "=in=", - "=out=" }; - private static final String[] FIELD_SUGGESTIONS = Arrays.stream(TargetFields.values()) - .map(field -> field.name().toLowerCase()).toArray(String[]::new); - private static final String[] AND_OR_SUGGESTIONS = new String[] { "and", "or" }; - private static final String[] NAME_VERSION_SUGGESTIONS = new String[] { "name", "version" }; - - @Autowired - private RsqlValidationOracle rsqlValidationOracle; - - @Test - @Description("Verifies that suggestions contains all possible field names") - void suggestionContainsAllFieldNames() { - final String rsqlQuery = "na"; - final List currentSuggestions = getSuggestions(rsqlQuery); - assertThat(currentSuggestions).containsOnly(FIELD_SUGGESTIONS); - } - - @Test - @Description("Verifies that suggestions only contains the allowed operators") - void suggestionContainsOnlyOperators() { - final String rsqlQuery = "name"; - final List currentSuggestions = getSuggestions(rsqlQuery); - assertThat(currentSuggestions).containsOnly(OP_SUGGESTIONS); - } - - @Test - @Description("Verifies that suggestions only contains operator to combine RSQL filters (and, or)") - void suggestionContainsOnlyAndOrOperator() { - final String rsqlQuery = "name==a "; - final List currentSuggestions = getSuggestions(rsqlQuery); - assertThat(currentSuggestions).containsOnly(AND_OR_SUGGESTIONS); - } - - @Test - @Description("Verifies that sub suggestions are shown") - void suggestionContainsSubFieldSuggestions() { - final String rsqlQuery = "assignedds."; - final List currentSuggestions = getSuggestions(rsqlQuery); - assertThat(currentSuggestions).containsOnly(NAME_VERSION_SUGGESTIONS); - } - - private List getSuggestions(final String rsqlQuery) { - return rsqlValidationOracle - .suggest(rsqlQuery, -1).getSuggestionContext().getSuggestions().stream() - .map(SuggestToken::getSuggestion) - .toList(); - } -} \ No newline at end of file