All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.jpa.jpql.parser.LikeExpression Maven / Gradle / Ivy

There is a newer version: 5.0.0-B03
Show newest version
/*
 * Copyright (c) 2006, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Oracle - initial API and implementation
//
package org.eclipse.persistence.jpa.jpql.parser;

import java.util.Collection;
import java.util.List;
import org.eclipse.persistence.jpa.jpql.ExpressionTools;
import org.eclipse.persistence.jpa.jpql.WordParser;

/**
 * The LIKE condition is used to specify a search for a pattern.
 * 

* The string_expression must have a string value. The pattern_value is a * string literal or a string-valued input parameter in which an underscore (_) stands for any * single character, a percent (%) character stands for any sequence of characters (including the * empty sequence), and all other characters stand for themselves. The optional escape_character * is a single-character string literal or a character-valued input parameter (i.e., char or * Character) and is used to escape the special meaning of the underscore and percent characters in * pattern_value. * *

BNF: like_expression ::= string_expression [NOT] LIKE pattern_value [ESCAPE escape_character]

* * @version 2.5 * @since 2.3 * @author Pascal Filion */ public final class LikeExpression extends AbstractExpression { /** * The {@link Expression} representing the escape character, which is either a single character * or an input parameter. */ private AbstractExpression escapeCharacter; /** * The actual escape identifier found in the string representation of the JPQL query. */ private String escapeIdentifier; /** * Determines whether a whitespace was parsed after ESCAPE. */ private boolean hasSpaceAfterEscape; /** * Determines whether a whitespace was parsed after LIKE. */ private boolean hasSpaceAfterLike; /** * Determines whether a whitespace was parsed after the pattern value. */ private boolean hasSpaceAfterPatternValue; /** * The actual LIKE identifier found in the string representation of the JPQL query. */ private String likeIdentifier; /** * The actual NOT identifier found in the string representation of the JPQL query. */ private String notIdentifier; /** * The {@link Expression} representing the pattern value. */ private AbstractExpression patternValue; /** * The {@link Expression} representing the string expression. */ private AbstractExpression stringExpression; /** * Creates a new LikeExpression. * * @param parent The parent of this expression * @param stringExpression The first part of this expression, which is the string expression */ public LikeExpression(AbstractExpression parent, AbstractExpression stringExpression) { super(parent, LIKE); if (stringExpression != null) { this.stringExpression = stringExpression; this.stringExpression.setParent(this); } } @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); } @Override public void acceptChildren(ExpressionVisitor visitor) { getStringExpression().accept(visitor); getPatternValue().accept(visitor); getEscapeCharacter().accept(visitor); } @Override protected void addChildrenTo(Collection children) { children.add(getStringExpression()); children.add(getPatternValue()); children.add(getEscapeCharacter()); } @Override protected void addOrderedChildrenTo(List children) { // String expression if (stringExpression != null) { children.add(stringExpression); } // 'NOT' if (notIdentifier != null) { children.add(buildStringExpression(SPACE)); children.add(buildStringExpression(NOT)); } children.add(buildStringExpression(SPACE)); // 'LIKE' children.add(buildStringExpression(LIKE)); if (hasSpaceAfterLike) { children.add(buildStringExpression(SPACE)); } // Pattern value if (patternValue != null) { children.add(patternValue); } if (hasSpaceAfterPatternValue) { children.add(buildStringExpression(SPACE)); } // 'ESCAPE' if (escapeIdentifier != null) { children.add(buildStringExpression(ESCAPE)); } if (hasSpaceAfterEscape) { children.add(buildStringExpression(SPACE)); } // Escape character if (escapeCharacter != null) { children.add(escapeCharacter); } } @Override public JPQLQueryBNF findQueryBNF(Expression expression) { if ((patternValue != null) && patternValue.isAncestor(expression)) { return getQueryBNF(PatternValueBNF.ID); } if ((escapeCharacter != null) && escapeCharacter.isAncestor(expression)) { return getQueryBNF(LikeExpressionEscapeCharacterBNF.ID); } return super.findQueryBNF(expression); } /** * Returns the actual ESCAPE found in the string representation of the JPQL query, which * has the actual case that was used. * * @return The ESCAPE identifier that was actually parsed, or an empty string if it was * not parsed */ public String getActualEscapeIdentifier() { return (escapeIdentifier != null) ? escapeIdentifier : ExpressionTools.EMPTY_STRING; } /** * Returns the actual LIKE found in the string representation of the JPQL query, which * has the actual case that was used. * * @return The LIKE identifier that was actually parsed */ public String getActualLikeIdentifier() { return likeIdentifier; } /** * Returns the actual NOT found in the string representation of the JPQL query, which has * the actual case that was used. * * @return The NOT identifier that was actually parsed, or an empty string if it was not * parsed */ public String getActualNotIdentifier() { return (notIdentifier != null) ? notIdentifier : ExpressionTools.EMPTY_STRING; } /** * Returns the {@link Expression} that represents the escape character, which is either a single * character or an input parameter. * * @return The expression that was parsed representing the escape character */ public Expression getEscapeCharacter() { if (escapeCharacter == null) { escapeCharacter = buildNullExpression(); } return escapeCharacter; } /** * Returns the enum constant that represents the identifier. * * @return Either LIKE or NOT LIKE */ public String getIdentifier() { return (notIdentifier != null) ? NOT_LIKE : LIKE; } /** * Returns the {@link Expression} that represents the pattern value. * * @return The expression that was parsed representing the pattern value */ public Expression getPatternValue() { if (patternValue == null) { patternValue = buildNullExpression(); } return patternValue; } @Override public JPQLQueryBNF getQueryBNF() { return getQueryBNF(LikeExpressionBNF.ID); } /** * Returns the {@link Expression} that represents the string expression. * * @return The expression that was parsed representing the string expression */ public Expression getStringExpression() { if (stringExpression == null) { stringExpression = buildNullExpression(); } return stringExpression; } /** * Determines whether the identifier ESCAPE was parsed. * * @return true if the identifier ESCAPE was parsed; false otherwise */ public boolean hasEscape() { return escapeIdentifier != null; } /** * Determines whether the escape character was parsed, which is either a single character or an * input parameter. * * @return true if the escape character was parsed; false otherwise */ public boolean hasEscapeCharacter() { return escapeCharacter != null && !escapeCharacter.isNull(); } /** * Determines whether the identifier NOT was parsed. * * @return true if the identifier NOT was parsed; false otherwise */ public boolean hasNot() { return notIdentifier != null; } /** * Determines whether the pattern value was parsed. * * @return true if the pattern value was parsed; false otherwise */ public boolean hasPatternValue() { return patternValue != null && !patternValue.isNull(); } /** * Determines whether a whitespace was parsed after ESCAPE. * * @return true if there was a whitespace after ESCAPE; false otherwise */ public boolean hasSpaceAfterEscape() { return hasSpaceAfterEscape; } /** * Determines whether a whitespace was parsed after LIKE. * * @return true if there was a whitespace after LIKE; false otherwise */ public boolean hasSpaceAfterLike() { return hasSpaceAfterLike; } /** * Determines whether a whitespace was parsed after the pattern value. * * @return true if there was a whitespace after the pattern value; false otherwise */ public boolean hasSpaceAfterPatternValue() { return hasSpaceAfterPatternValue; } /** * Determines whether a whitespace was parsed after the string expression. * * @return true if there was a whitespace after the string expression; * false otherwise */ public boolean hasSpaceAfterStringExpression() { return hasStringExpression(); } /** * Determines whether the string expression was parsed. * * @return true if the string expression was parsed; false otherwise */ public boolean hasStringExpression() { return stringExpression != null && !stringExpression.isNull(); } @Override protected boolean isParsingComplete(WordParser wordParser, String word, Expression expression) { char character = word.charAt(0); if (getQueryBNF(PatternValueBNF.ID).handleAggregate() && (character == '+' || character == '-' || character == '*' || character == '/')) { return false; } return super.isParsingComplete(wordParser, word, expression) || word.equalsIgnoreCase(ESCAPE) || word.equalsIgnoreCase(AND) || word.equalsIgnoreCase(OR) || expression != null; } @Override protected void parse(WordParser wordParser, boolean tolerant) { // Parse 'NOT if (wordParser.startsWithIgnoreCase('N')) { notIdentifier = wordParser.moveForward(NOT); wordParser.skipLeadingWhitespace(); } // Parse 'LIKE' likeIdentifier = wordParser.moveForward(LIKE); hasSpaceAfterLike = wordParser.skipLeadingWhitespace() > 0; // Parse the pattern value patternValue = parse(wordParser, PatternValueBNF.ID, tolerant); int count = wordParser.skipLeadingWhitespace(); // Parse 'ESCAPE' if (wordParser.startsWithIdentifier(ESCAPE)) { hasSpaceAfterPatternValue = (count > 0); count = 0; escapeIdentifier = wordParser.moveForward(ESCAPE); hasSpaceAfterEscape = wordParser.skipLeadingWhitespace() > 0; } else if (tolerant) { hasSpaceAfterPatternValue = (count > 0); } else { wordParser.moveBackward(count); return; } // Parse escape character char character = wordParser.character(); // Single escape character if (character == SINGLE_QUOTE) { escapeCharacter = new StringLiteral(this, wordParser.word()); escapeCharacter.parse(wordParser, tolerant); count = 0; } // Parse input parameter else if (ExpressionTools.isParameter(character)) { escapeCharacter = new InputParameter(this, wordParser.word()); escapeCharacter.parse(wordParser, tolerant); count = 0; } // Parse with the BNF else { escapeCharacter = parse(wordParser, LikeExpressionEscapeCharacterBNF.ID, tolerant); if ((escapeIdentifier == null) && (escapeCharacter == null) && !wordParser.isTail()) { hasSpaceAfterPatternValue = false; wordParser.moveBackward(count); } } } @Override protected void toParsedText(StringBuilder writer, boolean actual) { // String expression if (stringExpression != null) { stringExpression.toParsedText(writer, actual); writer.append(SPACE); } // 'NOT LIKE' or 'LIKE' if (actual) { if (notIdentifier != null) { writer.append(notIdentifier); writer.append(SPACE); } writer.append(likeIdentifier); } else { writer.append((notIdentifier != null) ? NOT_LIKE : LIKE); } if (hasSpaceAfterLike) { writer.append(SPACE); } // Pattern value if (patternValue != null) { patternValue.toParsedText(writer, actual); } if (hasSpaceAfterPatternValue) { writer.append(SPACE); } // 'ESCAPE' if (escapeIdentifier != null) { writer.append(actual ? escapeIdentifier : ESCAPE); } if (hasSpaceAfterEscape) { writer.append(SPACE); } // Escape character if (escapeCharacter != null) { escapeCharacter.toParsedText(writer, actual); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy