blob: 8cd61542d01b6313bcbce158746a5570d2720b89 [file] [log] [blame]
/*
* Copyright (c) 2006, 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.ExpressionTools;
import org.eclipse.persistence.jpa.jpql.WordParser;
/**
* A null comparison tests whether or not the single-valued path expression or input parameter is a
* <b>NULL</b> value.
*
* <div><b>BNF:</b> <code>null_comparison_expression ::= {single_valued_path_expression | input_parameter} IS [NOT] NULL</code><p></p></div>
*
* @version 2.5
* @since 2.3
* @author Pascal Filion
*/
public final class NullComparisonExpression extends AbstractExpression {
/**
* The expression tested for being <code>null</code> or not.
*/
private AbstractExpression expression;
/**
* The actual <b>IS</b> identifier found in the string representation of the JPQL query.
*/
private String isIdentifier;
/**
* The actual <b>IS</b> identifier found in the string representation of the JPQL query.
*/
private String notIdentifier;
/**
* The actual <b>NULL</b> identifier found in the string representation of the JPQL query.
*/
private String nullIdentifier;
/**
* Creates a new <code>NullComparisonExpression</code>.
*
* @param parent The parent of this expression
* @param expression The expression before the identifier
*/
public NullComparisonExpression(AbstractExpression parent,
String identifier,
AbstractExpression expression) {
super(parent, identifier);
this.expression = expression;
if (expression != null) {
expression.setParent(this);
}
}
@Override
public void accept(ExpressionVisitor visitor) {
visitor.visit(this);
}
@Override
public void acceptChildren(ExpressionVisitor visitor) {
getExpression().accept(visitor);
}
@Override
protected void addChildrenTo(Collection<Expression> children) {
children.add(getExpression());
}
@Override
protected void addOrderedChildrenTo(List<Expression> children) {
// Expression
if (hasExpression()) {
children.add(expression);
children.add(buildStringExpression(SPACE));
}
// Identifier
children.add(buildStringExpression(getIdentifier()));
}
@Override
public JPQLQueryBNF findQueryBNF(Expression expression) {
if (this.expression == expression) {
return expression.getQueryBNF();
}
return super.findQueryBNF(expression);
}
/**
* Returns the actual <b>IS</b> found in the string representation of the JPQL query, which has
* the actual case that was used.
*
* @return The <b>IS</b> identifier that was actually parsed, or an empty string if it was not
* parsed
*/
public String getActualIsIdentifier() {
return (isIdentifier != null) ? isIdentifier : ExpressionTools.EMPTY_STRING;
}
/**
* Returns the actual <b>Not</b> found in the string representation of the JPQL query, which has
* the actual case that was used.
*
* @return The <b>NOT</b> 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 actual <b>NULL</b> found in the string representation of the JPQL query, which has
* the actual case that was used.
*
* @return The <b>NULL</b> identifier that was actually parsed
*/
public String getActualNullIdentifier() {
return nullIdentifier;
}
/**
* Returns the expression being tested for being <code>null</code>.
*
* @return Either the parsed expression or the <code>null</code>-expression
*/
public Expression getExpression() {
if (expression == null) {
expression = buildNullExpression();
}
return expression;
}
/**
* Returns the identifier for this expression that may include <b>NOT</b> if it was parsed.
*
* @return Either <b>IS NULL</b> or <b>IS NOT NULL</b>
*/
public String getIdentifier() {
return (notIdentifier != null) ? IS_NOT_NULL : IS_NULL;
}
@Override
public JPQLQueryBNF getQueryBNF() {
return getQueryBNF(NullComparisonExpressionBNF.ID);
}
/**
* Determines whether the expression preceding the identifier was parsed.
*
* @return <code>true</code> the expression preceding the identifier was parsed;
* <code>false</code> otherwise
*/
public boolean hasExpression() {
return expression != null &&
!expression.isNull();
}
/**
* Determines whether <b>NOT</b> is used in the query.
*
* @return <code>true</code> if <b>NOT</b> is present in the query; <code>false</code> otherwise
*/
public boolean hasNot() {
return notIdentifier != null;
}
@Override
protected void parse(WordParser wordParser, boolean tolerant) {
// 'IS'
isIdentifier = wordParser.moveForward(IS);
wordParser.skipLeadingWhitespace();
// 'NOT'
if (wordParser.startsWithIdentifier(NOT)) {
notIdentifier = wordParser.moveForward(NOT);
wordParser.skipLeadingWhitespace();
setText(IS_NOT_NULL);
}
else {
setText(IS_NULL);
}
// 'NULL'
nullIdentifier = wordParser.moveForward(NULL);
}
@Override
protected void toParsedText(StringBuilder writer, boolean actual) {
if (hasExpression()) {
expression.toParsedText(writer, actual);
writer.append(SPACE);
}
if (actual) {
writer.append(isIdentifier);
writer.append(SPACE);
if (notIdentifier != null) {
writer.append(notIdentifier);
writer.append(SPACE);
}
writer.append(nullIdentifier);
}
else {
writer.append(getIdentifier());
}
}
}