org.eclipse.persistence.jpa.jpql.parser.CaseExpression 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) 2006, 2018 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;
/**
* BNF: general_case_expression ::= CASE when_clause {when_clause}* ELSE scalar_expression END
* or
* BNF: simple_case_expression ::= CASE case_operand simple_when_clause {simple_when_clause}* ELSE scalar_expression END
*
* @version 2.5
* @since 2.3
* @author Pascal Filion
*/
public final class CaseExpression extends AbstractExpression {
/**
* The actual CASE identifier found in the string representation of the JPQL query.
*/
private String caseIdentifier;
/**
* The {@link Expression} representing the case operand.
*/
private AbstractExpression caseOperand;
/**
* The {@link Expression} representing the ELSE expression.
*/
private AbstractExpression elseExpression;
/**
* The actual ELSE identifier found in the string representation of the JPQL query.
*/
private String elseIdentifier;
/**
* The actual END identifier found in the string representation of the JPQL query.
*/
private String endIdentifier;
/**
* Determines whether a whitespace was parsed after CASE.
*/
private boolean hasSpaceAfterCase;
/**
* Determines whether a whitespace was parsed after the case operand.
*/
private boolean hasSpaceAfterCaseOperand;
/**
* Determines whether a whitespace was parsed after ELSE.
*/
private boolean hasSpaceAfterElse;
/**
* Determines whether a whitespace was parsed after the BETWEEN expression.
*/
private boolean hasSpaceAfterElseExpression;
/**
* Determines whether a whitespace was parsed after WHEN clause.
*/
private boolean hasSpaceAfterWhenClauses;
/**
* Used to determine how to check if the parsing is complete.
*/
private ParsingType parsingType;
/**
* The {@link Expression} representing the WHEN clauses.
*/
private AbstractExpression whenClauses;
/**
* Creates a new CaseExpression
.
*
* @param parent The parent of this expression
*/
public CaseExpression(AbstractExpression parent) {
super(parent, CASE);
}
/**
* {@inheritDoc}
*/
public void accept(ExpressionVisitor visitor) {
visitor.visit(this);
}
/**
* {@inheritDoc}
*/
public void acceptChildren(ExpressionVisitor visitor) {
getCaseOperand().accept(visitor);
getWhenClauses().accept(visitor);
getElseExpression().accept(visitor);
}
/**
* {@inheritDoc}
*/
@Override
protected void addChildrenTo(Collection children) {
children.add(getCaseOperand());
children.add(getWhenClauses());
children.add(getElseExpression());
}
/**
* {@inheritDoc}
*/
@Override
protected void addOrderedChildrenTo(List children) {
// 'CASE'
children.add(buildStringExpression(CASE));
if (hasSpaceAfterCase) {
children.add(buildStringExpression(SPACE));
}
// Case operand
if (caseOperand != null) {
children.add(caseOperand);
}
if (hasSpaceAfterCaseOperand) {
children.add(buildStringExpression(SPACE));
}
// WHEN clauses
if (whenClauses != null) {
children.add(whenClauses);
}
if (hasSpaceAfterWhenClauses) {
children.add(buildStringExpression(SPACE));
}
// 'ELSE'
if (elseIdentifier != null) {
children.add(buildStringExpression(ELSE));
}
if (hasSpaceAfterElse) {
children.add(buildStringExpression(SPACE));
}
// Else expression
if (elseExpression != null) {
children.add(elseExpression);
}
if (hasSpaceAfterElseExpression) {
children.add(buildStringExpression(SPACE));
}
// 'END'
if (endIdentifier != null) {
children.add(buildStringExpression(END));
}
}
/**
* {@inheritDoc}
*/
@Override
public JPQLQueryBNF findQueryBNF(Expression expression) {
if ((caseOperand != null) && caseOperand.isAncestor(expression)) {
return getQueryBNF(CaseOperandBNF.ID);
}
if ((whenClauses != null) && whenClauses.isAncestor(expression)) {
return getQueryBNF(WhenClauseBNF.ID);
}
if ((elseExpression != null) && elseExpression.isAncestor(expression)) {
return getQueryBNF(ElseExpressionBNF.ID);
}
return super.findQueryBNF(expression);
}
/**
* Returns the actual CASE identifier found in the string representation of the JPQL
* query, which has the actual case that was used.
*
* @return The CASE identifier that was actually parsed
*/
public String getActualCaseIdentifier() {
return caseIdentifier;
}
/**
* Returns the actual ELSE identifier found in the string representation of the JPQL
* query, which has the actual case that was used.
*
* @return The ELSE identifier that was actually parsed, or an empty string if it was not
* parsed
*/
public String getActualElseIdentifier() {
return (elseIdentifier != null) ? elseIdentifier : ExpressionTools.EMPTY_STRING;
}
/**
* Returns the actual END identifier found in the string representation of the JPQL query,
* which has the actual case that was used.
*
* @return The END identifier that was actually parsed, or an empty string if it was not
* parsed
*/
public String getActualEndIdentifier() {
return (endIdentifier != null) ? endIdentifier : ExpressionTools.EMPTY_STRING;
}
/**
* Returns the {@link Expression} that represents the CASE operand.
*
* @return The expression that was parsed representing the CASE operand
*/
public Expression getCaseOperand() {
if (caseOperand == null) {
caseOperand = buildNullExpression();
}
return caseOperand;
}
/**
* Returns the {@link Expression} that represents the ELSE operand.
*
* @return The expression that was parsed representing the ELSE operand
*/
public AbstractExpression getElseExpression() {
if (elseExpression == null) {
elseExpression = buildNullExpression();
}
return elseExpression;
}
/**
* {@inheritDoc}
*/
public JPQLQueryBNF getQueryBNF() {
return getQueryBNF(GeneralCaseExpressionBNF.ID);
}
/**
* Returns the {@link Expression} that represents the WHEN clauses.
*
* @return The expression that was parsed representing the WHEN clauses
*/
public AbstractExpression getWhenClauses() {
if (whenClauses == null) {
whenClauses = buildNullExpression();
}
return whenClauses;
}
/**
* Determines whether the CASE operand was parsed.
*
* @return true
if the CASE operand was parsed; false
otherwise
*/
public boolean hasCaseOperand() {
return caseOperand != null &&
!caseOperand.isNull();
}
/**
* Determines whether the identifier ELSE was parsed.
*
* @return true
if the identifier ELSE was parsed; false
* otherwise
*/
public boolean hasElse() {
return elseIdentifier != null;
}
/**
* Determines whether the ELSE expression was parsed.
*
* @return true
if the ELSE expression was parsed; false
* otherwise
*/
public boolean hasElseExpression() {
return elseExpression != null &&
!elseExpression.isNull();
}
/**
* Determines whether the identifier END was parsed.
*
* @return true
if the identifier END was parsed; false
otherwise
*/
public boolean hasEnd() {
return endIdentifier != null;
}
/**
* Determines whether a whitespace was parsed after CASE.
*
* @return true
if there was a whitespace after CASE; false
* otherwise
*/
public boolean hasSpaceAfterCase() {
return hasSpaceAfterCase;
}
/**
* Determines whether a whitespace was parsed after the case operand.
*
* @return true
if there was a whitespace after the case operand; false
* otherwise
*/
public boolean hasSpaceAfterCaseOperand() {
return hasSpaceAfterCaseOperand;
}
/**
* Determines whether a whitespace was parsed after ELSE.
*
* @return true
if there was a whitespace after ELSE; false
* otherwise
*/
public boolean hasSpaceAfterElse() {
return hasSpaceAfterElse;
}
/**
* Determines whether a whitespace was parsed after the else expression.
*
* @return true
if there was a whitespace after the else expression;
* false
otherwise
*/
public boolean hasSpaceAfterElseExpression() {
return hasSpaceAfterElseExpression;
}
/**
* Determines whether a whitespace was parsed after the WHEN clause.
*
* @return true
if there was a whitespace after the WHEN
* clause; false
otherwise
*/
public boolean hasSpaceAfterWhenClauses() {
return hasSpaceAfterWhenClauses;
}
/**
* Determines whether the WHEN clauses were parsed.
*
* @return true
if the WHEN clauses were parsed;
* false
otherwise
*/
public boolean hasWhenClauses() {
return whenClauses != null &&
!whenClauses.isNull();
}
/**
* {@inheritDoc}
*/
@Override
protected boolean isParsingComplete(WordParser wordParser, String word, Expression expression) {
// 'CASE'
if (parsingType == ParsingType.CASE) {
return word.equalsIgnoreCase(WHEN) ||
word.equalsIgnoreCase(ELSE) ||
word.equalsIgnoreCase(END) ||
super.isParsingComplete(wordParser, word, expression);
}
// 'WHEN'
if (parsingType == ParsingType.WHEN) {
return word.equalsIgnoreCase(ELSE) ||
word.equalsIgnoreCase(END) ||
super.isParsingComplete(wordParser, word, expression);
}
// 'ELSE'
return word.equalsIgnoreCase(END) ||
super.isParsingComplete(wordParser, word, expression);
}
/**
* {@inheritDoc}
*/
@Override
protected void parse(WordParser wordParser, boolean tolerant) {
// Parse 'CASE'
caseIdentifier = wordParser.moveForward(CASE);
hasSpaceAfterCase = wordParser.skipLeadingWhitespace() > 0;
// Parse case operand
parsingType = ParsingType.CASE;
if (!wordParser.startsWithIdentifier(WHEN)) {
caseOperand = parse(wordParser, CaseOperandBNF.ID, tolerant);
hasSpaceAfterCaseOperand = wordParser.skipLeadingWhitespace() > 0;
}
// Parse the WHEN clauses
parsingType = ParsingType.WHEN;
whenClauses = parse(wordParser, WhenClauseBNF.ID, tolerant);
hasSpaceAfterWhenClauses = wordParser.skipLeadingWhitespace() > 0;
// Parse 'ELSE'
if (!tolerant || wordParser.startsWithIdentifier(ELSE)) {
elseIdentifier = wordParser.moveForward(ELSE);
hasSpaceAfterElse = wordParser.skipLeadingWhitespace() > 0;
}
// Parse the ELSE expression
parsingType = ParsingType.ELSE;
elseExpression = parse(wordParser, ElseExpressionBNF.ID, tolerant);
hasSpaceAfterElseExpression = wordParser.skipLeadingWhitespace() > 0;
// Parse 'END'
if (!tolerant || wordParser.startsWithIdentifier(END)) {
endIdentifier = wordParser.moveForward(END);
}
}
/**
* {@inheritDoc}
*/
@Override
protected void toParsedText(StringBuilder writer, boolean actual) {
// 'CASE'
writer.append(actual ? caseIdentifier : CASE);
if (hasSpaceAfterCase) {
writer.append(SPACE);
}
// Case Operand
if (caseOperand != null) {
caseOperand.toParsedText(writer, actual);
}
if (hasSpaceAfterCaseOperand) {
writer.append(SPACE);
}
// When clauses
if (whenClauses != null) {
whenClauses.toParsedText(writer, actual);
}
if (hasSpaceAfterWhenClauses) {
writer.append(SPACE);
}
// 'ELSE'
if (elseIdentifier != null) {
writer.append(actual ? elseIdentifier : ELSE);
}
if (hasSpaceAfterElse) {
writer.append(SPACE);
}
// Else expression
if (elseExpression != null) {
elseExpression.toParsedText(writer, actual);
}
if (hasSpaceAfterElseExpression) {
writer.append(SPACE);
}
// 'END'
if (endIdentifier != null) {
writer.append(actual ? endIdentifier : END);
}
}
/**
* A enumeration used to determine how {@link CaseExpression#isParsingComplete(WordParser, String)}
* should behaves.
*/
private enum ParsingType {
CASE,
ELSE,
WHEN
}
}