| /* |
| * 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); |
| } |
| } |
| } |