blob: f3b2eb7cbf91a3345882651a962054fe5bcd41fc [file] [log] [blame]
/*
* Copyright (c) 2011, 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.tools.model.query;
import java.io.IOException;
import java.util.List;
import org.eclipse.persistence.jpa.jpql.parser.SelectStatement;
import org.eclipse.persistence.jpa.jpql.tools.model.ISelectExpressionStateObjectBuilder;
import static org.eclipse.persistence.jpa.jpql.parser.AbstractExpression.*;
/**
* This state object represents a select statement, which has at least a <code><b>SELECT</b></code>
* clause and a <code><b>FROM</b></code> clause. The other clauses are optional.
*
* <pre><code>BNF: select_statement ::= select_clause from_clause [where_clause] [groupby_clause] [having_clause] [orderby_clause]</code></pre>
*
* @see FromClauseStateObject
* @see GroupByClauseStateObject
* @see HavingClauseStateObject
* @see OrderByClauseStateObject
* @see SelectClauseStateObject
* @see WhereClauseStateObject
*
* @see SelectStatement
*
* @version 2.4
* @since 2.4
* @author Pascal Filion
*/
@SuppressWarnings("nls")
public class SelectStatementStateObject extends AbstractSelectStatementStateObject {
/**
* The state object representing the <code><b>ORDER BY</b></code> clause.
*/
private OrderByClauseStateObject orderByClause;
/**
* Notify the state object representing the <code><b>ORDER BY</b></code> clause has changed.
*/
public static final String ORDER_BY_CLAUSE_PROPERTY = "orderByClause";
/**
* Creates a new <code>SelectStatementStateObject</code>.
*
* @param parent The parent of this state object, which cannot be <code>null</code>
* @exception NullPointerException The given parent cannot be <code>null</code>
*/
public SelectStatementStateObject(JPQLQueryStateObject parent) {
super(parent);
}
@Override
public void accept(StateObjectVisitor visitor) {
visitor.visit(this);
}
@Override
protected void addChildren(List<StateObject> children) {
super.addChildren(children);
if (orderByClause != null) {
children.add(orderByClause);
}
}
/**
* Adds the <code><b>ORDER BY</b></code> clause. The clause is not added if it's already present.
*
* @return The state object representing the <code><b>ORDER BY</b></code> clause
*/
public OrderByClauseStateObject addOrderByClause() {
if (!hasOrderByClause()) {
setOrderByClause(new OrderByClauseStateObject(this));
}
return orderByClause;
}
/**
* Adds the <code><b>ORDER BY</b></code> clause and parses the given JPQL fragment, which should
* represent one or many ordering items. The clause is not added if it's already present.
*
* @param jpqlFragment The fragment of the JPQL to parse that represents the ordering items, the
* fragment cannot start with <code><b>ORDER BY</b></code>
* @return The {@link OrderByClauseStateObject}
*/
public OrderByClauseStateObject addOrderByClause(String jpqlFragment) {
OrderByClauseStateObject stateObject = addOrderByClause();
stateObject.parse(jpqlFragment);
return stateObject;
}
/**
* Adds the given {@link StateObject} as a select item.
*
* @param stateObject The {@link StateObject} representing a select expression
*/
public void addSelectItem(StateObject stateObject) {
getSelectClause().addItem(stateObject);
}
/**
* Adds the given {@link StateObject} as a select item.
*
* @param stateObject The {@link StateObject} representing the select expression
* @param resultVariable The result variable identifying the select expression
* @return The newly created {@link ResultVariableStateObject}
*/
public ResultVariableStateObject addSelectItem(StateObject stateObject, String resultVariable) {
return getSelectClause().addItem(stateObject, resultVariable);
}
/**
* Adds the given path as a select item, which can either be an identification variable or a
* state-field path expression.
*
* @param path The select expression to parse as a select item
* @return The {@link StateObject} encapsulating the given path
*/
public StateObject addSelectItem(String path) {
return getSelectClause().addItem(path);
}
/**
* Adds the given expression as a select item.
*
* @param jpqlFragment The select expression to parse as a select item
* @param resultVariable The result variable identifying the select expression
* @return The newly created {@link ResultVariableStateObject}
*/
public ResultVariableStateObject addSelectItem(String jpqlFragment, String resultVariable) {
return getSelectClause().addItem(jpqlFragment, resultVariable);
}
/**
* Adds the given {@link StateObject} as a select item.
*
* @param stateObject The {@link StateObject} representing the select expression
* @param resultVariable The result variable identifying the select expression
* @return The newly created {@link ResultVariableStateObject}
*/
public ResultVariableStateObject addSelectItemAs(StateObject stateObject, String resultVariable) {
return getSelectClause().addItemAs(stateObject, resultVariable);
}
/**
* Adds the given expression as a select item.
*
* @param jpqlFragment The portion of a JPQL query that represents a select expression
* @param resultVariable The result variable identifying the select expression
* @return The newly created {@link ResultVariableStateObject}
*/
public ResultVariableStateObject addSelectItemAs(String jpqlFragment, String resultVariable) {
return getSelectClause().addItemAs(jpqlFragment, resultVariable);
}
@Override
protected AbstractFromClauseStateObject buildFromClause() {
return new FromClauseStateObject(this);
}
@Override
protected AbstractSelectClauseStateObject buildSelectClause() {
return new SelectClauseStateObject(this);
}
@Override
public SelectStatement getExpression() {
return (SelectStatement) super.getExpression();
}
@Override
public FromClauseStateObject getFromClause() {
return (FromClauseStateObject) super.getFromClause();
}
/**
* Returns the state object representing the <code><b>ORDER BY</b></code> clause.
*
* @return Either the actual state object representing the <code><b>ORDER BY</b></code> clause or
* <code>null</code> if it's not present
*/
public OrderByClauseStateObject getOrderByClause() {
return orderByClause;
}
@Override
public JPQLQueryStateObject getParent() {
return (JPQLQueryStateObject) super.getParent();
}
/**
* Creates and returns a new {@link ISelectExpressionStateObjectBuilder} that can be used to
* programmatically create a single select expression and once the expression is complete,
* {@link ISelectExpressionStateObjectBuilder#commit()} will push the {@link StateObject}
* representation of that expression as this clause's select expression.
*
* @return A new builder that can be used to quickly create a select expression
*/
public ISelectExpressionStateObjectBuilder getSelectBuilder() {
return getSelectClause().getBuilder();
}
@Override
public SelectClauseStateObject getSelectClause() {
return (SelectClauseStateObject) super.getSelectClause();
}
/**
* Returns the state object representing the <code><b>ORDER BY</b></code> clause.
*
* @return <code>true</code> if the <code><b>ORDER BY</b></code> clause is present;
* <code>false</code> otherwise
*/
public boolean hasOrderByClause() {
return orderByClause != null;
}
@Override
public boolean isEquivalent(StateObject stateObject) {
if (super.isEquivalent(stateObject)) {
SelectStatementStateObject select = (SelectStatementStateObject) stateObject;
return areEquivalent(orderByClause, select.orderByClause);
}
return false;
}
/**
* Removes the <code><b>ORDER BY</b></code> clause.
*/
public void removeOrderByClause() {
setOrderByClause(null);
}
/**
* Keeps a reference of the {@link SelectStatement parsed object} object, which should only be
* done when this object is instantiated during the conversion of a parsed JPQL query into
* {@link StateObject StateObjects}.
*
* @param expression The {@link SelectStatement parsed object} representing a <code><b>SELECT</b></code>
* statement
*/
public void setExpression(SelectStatement expression) {
super.setExpression(expression);
}
private void setOrderByClause(OrderByClauseStateObject orderByClause) {
OrderByClauseStateObject oldOrderByClause = this.orderByClause;
this.orderByClause = orderByClause;
firePropertyChanged(ORDER_BY_CLAUSE_PROPERTY, oldOrderByClause, orderByClause);
}
/**
* Either adds or removes the <code><b>ORDER BY</b></code> clause.
*/
public void toggleOrderByClause() {
if (orderByClause != null) {
removeOrderByClause();
}
else {
addOrderByClause();
}
}
@Override
protected void toTextInternal(Appendable writer) throws IOException {
super.toTextInternal(writer);
if (orderByClause != null) {
writer.append(SPACE);
orderByClause.toString(writer);
}
}
}