org.eclipse.persistence.jpa.jpql.parser.AbstractSelectClause Maven / Gradle / Ivy
Show all versions of eclipselink Show documentation
/*
* 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.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.persistence.jpa.jpql.WordParser;
/**
* The SELECT clause denotes the query result. More than one value may be returned from the
* SELECT clause of a query. The SELECT clause may contain one or more of the
* following elements: a single range variable or identification variable that ranges over an entity
* abstract schema type, a single-valued path expression, an aggregate select expression, a
* constructor expression.
*
* The DISTINCT keyword is used to specify that duplicate values must be eliminated from the
* query result. If DISTINCT is not specified, duplicate values are not eliminated.
* Stand-alone identification variables in the SELECT clause may optionally be qualified by
* the OBJECT operator. The SELECT clause must not use the OBJECT operator to
* qualify path expressions.
*
* @see SelectClause
* @see SimpleSelectClause
*
* @version 2.5
* @since 2.3
* @author Pascal Filion
*/
public abstract class AbstractSelectClause extends AbstractExpression {
/**
* The actual DISTINCT identifier found in the string representation of the JPQL query.
*/
private String distinctIdentifier;
/**
* Determines whether a whitespace was parsed after the DISTINCT.
*/
private boolean hasSpaceAfterDistinct;
/**
* Determines whether a whitespace was parsed after the SELECT.
*/
private boolean hasSpaceAfterSelect;
/**
* The actual identifier found in the string representation of the JPQL query.
*/
private String identifier;
/**
* The actual expression of this select clause.
*/
private AbstractExpression selectExpression;
/**
* Creates a new SelectClause
.
*
* @param parent The parent of this expression
*/
protected AbstractSelectClause(AbstractExpression parent) {
super(parent, SELECT);
}
@Override
public void acceptChildren(ExpressionVisitor visitor) {
getSelectExpression().accept(visitor);
}
@Override
protected void addChildrenTo(Collection children) {
children.add(getSelectExpression());
}
@Override
protected void addOrderedChildrenTo(List children) {
// 'SELECT'
children.add(buildStringExpression(SELECT));
if (hasSpaceAfterSelect) {
children.add(buildStringExpression(SPACE));
}
// 'DISTINCT'
if (distinctIdentifier != null) {
children.add(buildStringExpression(DISTINCT));
}
if (hasSpaceAfterDistinct) {
children.add(buildStringExpression(SPACE));
}
// Select expression
if (selectExpression != null) {
children.add(selectExpression);
}
}
/**
* Creates a new {@link CollectionExpression} that will wrap the single select item.
*
* @return The single select item represented by a temporary collection
*/
public CollectionExpression buildCollectionExpression() {
List children = new ArrayList<>(1);
children.add((AbstractExpression) getSelectExpression());
List commas = new ArrayList<>(1);
commas.add(Boolean.FALSE);
List spaces = new ArrayList<>(1);
spaces.add(Boolean.FALSE);
return new CollectionExpression(this, children, commas, spaces, true);
}
@Override
public JPQLQueryBNF findQueryBNF(Expression expression) {
if ((selectExpression != null) && selectExpression.isAncestor(expression)) {
return getQueryBNF(getSelectItemQueryBNFId());
}
return super.findQueryBNF(expression);
}
/**
* Returns the actual DISTINCT identifier found in the string representation of the JPQL
* query, which has the actual case that was used.
*
* @return The DISTINCT identifier that was actually parsed, or an empty string if it was
* not parsed
* @since 2.4
*/
public final String getActualDistinctIdentifier() {
return distinctIdentifier;
}
/**
* Returns the actual SELECT identifier found in the string representation of the JPQL
* query, which has the actual case that was used.
*
* @return The SELECT identifier that was actually parsed
*/
public final String getActualIdentifier() {
return identifier;
}
/**
* Returns the {@link Expression} representing the select items.
*
* @return The expression representing the select items
*/
public final Expression getSelectExpression() {
if (selectExpression == null) {
selectExpression = buildNullExpression();
}
return selectExpression;
}
/**
* Returns the unique identifier of the {@link JPQLQueryBNF} for the list of select items to parse.
*
* @return The ID of the query BNF for the list of select items to parse
*/
public abstract String getSelectItemQueryBNFId();
/**
* Determines whether the identifier DISTINCT was parsed or not.
*
* @return true
if the identifier DISTINCT was parsed;
* false
otherwise
*/
public final boolean hasDistinct() {
return distinctIdentifier != null;
}
/**
* Determines whether the list of select items was parsed.
*
* @return true
the list of select items was parsed;
* false
otherwise
*/
public final boolean hasSelectExpression() {
return selectExpression != null &&
!selectExpression.isNull();
}
/**
* Determines whether a whitespace was parsed after DISTINCT.
*
* @return true
if there was a whitespace after DISTINCT;
* false
otherwise
*/
public final boolean hasSpaceAfterDistinct() {
return hasSpaceAfterDistinct;
}
/**
* Determines whether a whitespace was parsed after SELECT.
*
* @return true
if there was a whitespace after SELECT;
* false
otherwise
*/
public final boolean hasSpaceAfterSelect() {
return hasSpaceAfterSelect;
}
@Override
protected void parse(WordParser wordParser, boolean tolerant) {
// Parse 'SELECT'
identifier = wordParser.moveForward(SELECT);
hasSpaceAfterSelect = wordParser.skipLeadingWhitespace() > 0;
// Parse 'DISTINCT'
if (wordParser.startsWithIdentifier(DISTINCT)) {
distinctIdentifier = wordParser.moveForward(DISTINCT);
hasSpaceAfterDistinct = wordParser.skipLeadingWhitespace() > 0;
}
// Parse the select expression
selectExpression = parse(wordParser, getSelectItemQueryBNFId(), tolerant);
}
@Override
protected boolean shouldSkipLiteral(AbstractExpression expression) {
return false;
}
@Override
protected void toParsedText(StringBuilder writer, boolean actual) {
// 'SELECT'
writer.append(actual ? identifier : SELECT);
if (hasSpaceAfterSelect) {
writer.append(SPACE);
}
// 'DISTINCT'
if (distinctIdentifier != null) {
writer.append(actual ? distinctIdentifier : DISTINCT);
}
if (hasSpaceAfterDistinct) {
writer.append(SPACE);
}
// Select expression
if (selectExpression != null) {
selectExpression.toParsedText(writer, actual);
}
}
}