org.eclipse.persistence.jpa.jpql.parser.RegexpExpression Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* Copyright (c) 2012, 2021 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.WordParser;
/**
* The REGEXP condition is used to specify a search for a pattern. It is not part of JPA
* 2.0/2.1, only EclipseLink. It is supported by many databases (Oracle, MySQL, PostgreSQL), I
* think part of SQL 2008, replacing SIMILAR TO.
*
* The string_expression
must have a string value. The pattern_value
is a
* string literal or a string-valued input parameter that is a regular expression.
*
*
BNF: regexp_expression ::= string_expression REGEXP pattern_value
*
* @version 2.5
* @since 2.4
* @author James Sutherland
*/
public final class RegexpExpression extends AbstractExpression {
/**
* Determines whether a whitespace was parsed after REGEXP.
*/
private boolean hasSpaceAfterIdentifier;
/**
* The {@link Expression} representing the pattern value.
*/
private AbstractExpression patternValue;
/**
* The actual REGEXP identifier found in the string representation of the JPQL query.
*/
private String regexpIdentifier;
/**
* 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 RegexpExpression(AbstractExpression parent, AbstractExpression stringExpression) {
super(parent, REGEXP);
if (stringExpression != null) {
this.stringExpression = stringExpression;
this.stringExpression.setParent(this);
}
}
@Override
public void accept(ExpressionVisitor visitor) {
acceptUnknownVisitor(visitor);
}
@Override
public void acceptChildren(ExpressionVisitor visitor) {
getStringExpression().accept(visitor);
getPatternValue().accept(visitor);
}
@Override
protected void addChildrenTo(Collection children) {
children.add(getStringExpression());
children.add(getPatternValue());
}
@Override
protected void addOrderedChildrenTo(List children) {
// String expression
if (stringExpression != null) {
children.add(stringExpression);
children.add(buildStringExpression(SPACE));
}
// 'REGEXP'
children.add(buildStringExpression(REGEXP));
if (hasSpaceAfterIdentifier) {
children.add(buildStringExpression(SPACE));
}
// Pattern value
if (patternValue != null) {
children.add(patternValue);
}
}
@Override
public JPQLQueryBNF findQueryBNF(Expression expression) {
if ((stringExpression != null) && stringExpression.isAncestor(expression)) {
return getQueryBNF(StringExpressionBNF.ID);
}
if ((patternValue != null) && patternValue.isAncestor(expression)) {
return getQueryBNF(PatternValueBNF.ID);
}
return super.findQueryBNF(expression);
}
/**
* Returns the actual REGEXP found in the string representation of the JPQL query, which
* has the actual case that was used.
*
* @return The REGEXP identifier that was actually parsed
*/
public String getActualRegexpIdentifier() {
return regexpIdentifier;
}
/**
* 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(RegexpExpressionBNF.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 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 REGEXP.
*
* @return true
if there was a whitespace after REGEXP; false
* otherwise
*/
public boolean hasSpaceAfterIdentifier() {
return hasSpaceAfterIdentifier;
}
/**
* 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(AND) ||
word.equalsIgnoreCase(OR) ||
expression != null;
}
@Override
protected void parse(WordParser wordParser, boolean tolerant) {
// Parse 'REGEXP'
regexpIdentifier = wordParser.moveForward(REGEXP);
hasSpaceAfterIdentifier = wordParser.skipLeadingWhitespace() > 0;
// Parse the pattern value
patternValue = parse(wordParser, PatternValueBNF.ID, tolerant);
}
@Override
protected void toParsedText(StringBuilder writer, boolean actual) {
// String expression
if (stringExpression != null) {
stringExpression.toParsedText(writer, actual);
writer.append(SPACE);
}
// 'REGEXP'
writer.append(actual ? regexpIdentifier : REGEXP);
if (hasSpaceAfterIdentifier) {
writer.append(SPACE);
}
// Pattern value
if (patternValue != null) {
patternValue.toParsedText(writer, actual);
}
}
}