All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.jpa.jpql.parser.OrderByItem Maven / Gradle / Ivy

There is a newer version: 5.0.0-B03
Show newest version
/*
 * Copyright (c) 2006, 2024 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;

/**
 * An orderby_item must be one of the following:
 * 
    *
  1. A {@link StateFieldPathExpression state_field_path_expression} that evaluates to an orderable * state field of an entity or embeddable class abstract schema type designated in the SELECT clause * by one of the following: *
      *
    • A general_identification_variable *
    • A single_valued_object_path_expression *
    *
  2. A {@link StateFieldPathExpression state_field_path_expression} that evaluates to the same * state field of the same entity or embeddable abstract schema type as a {@link StateFieldPathExpression * state_field_path_expression} in the SELECT clause *
  3. A {@link ResultVariable result_variable} that refers to an orderable item in the SELECT * clause for which the same {@link ResultVariable result_variable} has been specified. This may be * the result of an aggregate_expression, a scalar_expression, or a {@link * StateFieldPathExpression state_field_path_expression} in the SELECT clause. *
*
* The keyword ASC specifies that ascending ordering be used for the associated orderby_item; * the keyword DESC specifies that descending ordering be used. Ascending ordering is the * default. *
* The keyword NULLS FIRST specifies that nulls first ordering be used for the associated orderby_item; * the keyword NULLS LAST specifies that nulls last ordering be used. Ascending ordering is the * default. *
* JPA 1.0: *
BNF: orderby_item ::= state_field_path_expression [ ASC | DESC ]
*
* JPA 2.0 *
BNF: orderby_item ::= state_field_path_expression | result_variable [ ASC | DESC ]
*
* EclipseLink 2.4: *
BNF: orderby_item ::= state_field_path_expression | result_variable [ ASC | DESC ] [ NULLS FIRST | NULLS LAST ]
* * @version 2.5 * @since 2.3 * @author Pascal Filion */ @SuppressWarnings("nls") public final class OrderByItem extends AbstractExpression { /** * The {@link Expression} representing the order by expression. */ private AbstractExpression expression; /** * The actual 'FIRST' identifier found in the string representation of the JPQL query. */ private String firstIdentifier; /** * Determines whether a whitespace was parsed after the order by expression. */ private boolean hasSpaceAfterExpression; /** * Determines whether a whitespace was parsed after NULLS. */ private boolean hasSpaceAfterNulls; /** * Determines whether a whitespace was parsed after the ordering. */ private boolean hasSpaceAfterOrdering; /** * The actual 'LAST' identifier found in the string representation of the JPQL query. */ private String lastIdentifier; /** * The keyword NULLS FIRST specifies ordering null first; the keyword NULLS LAST * specifies ordering nulls last. */ private NullOrdering nullOrdering; /** * The actual 'NULLS' identifier found in the string representation of the JPQL query. */ private String nullsIdentifier; /** * The keyword ASC specifies that ascending ordering be used; the keyword DESC * specifies that descending ordering be used. Ascending ordering is the default. */ private Ordering ordering; /** * The actual ordering identifier found in the string representation of the JPQL query. */ private String orderingIdentifier; /** * Creates a new OrderByItem. * * @param parent The parent of this expression */ public OrderByItem(AbstractExpression parent) { super(parent); } @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); } @Override public void acceptChildren(ExpressionVisitor visitor) { getExpression().accept(visitor); } @Override protected void addChildrenTo(Collection children) { children.add(getExpression()); } @Override protected void addOrderedChildrenTo(List children) { // Order By expression if (expression != null) { children.add(expression); } if (hasSpaceAfterExpression) { children.add(buildStringExpression(SPACE)); } // Ordering type if (ordering != Ordering.DEFAULT) { children.add(buildStringExpression(ordering.toString())); } if (hasSpaceAfterOrdering) { children.add(buildStringExpression(SPACE)); } // 'NULLS' if (nullsIdentifier != null) { children.add(buildStringExpression(NULLS)); } if (hasSpaceAfterNulls) { children.add(buildStringExpression(SPACE)); } // 'FIRST' if (firstIdentifier != null) { children.add(buildStringExpression(FIRST)); } // 'LAST' else if (lastIdentifier != null) { children.add(buildStringExpression(LAST)); } } @Override public JPQLQueryBNF findQueryBNF(Expression expression) { if ((this.expression != null) && this.expression.isAncestor(expression)) { return getQueryBNF(InternalOrderByItemBNF.ID); } return super.findQueryBNF(expression); } /** * Returns the actual null ordering identifier found in the string representation of * the JPQL query, which has the actual case that was used. * * @return The null ordering identifier that was actually parsed, if one was present, * otherwise an empty string is returned */ public String getActualNullOrdering() { // NULLS FIRST if ((nullsIdentifier != null) && (firstIdentifier != null)) { return nullsIdentifier + SPACE + firstIdentifier; } // NULLS LAST if ((nullsIdentifier != null) && (lastIdentifier != null)) { return nullsIdentifier + SPACE + lastIdentifier; } if (nullsIdentifier != null) { return nullsIdentifier; } if (firstIdentifier != null) { return firstIdentifier; } else if (lastIdentifier != null) { return lastIdentifier; } return ExpressionTools.EMPTY_STRING; } /** * Returns the actual ordering identifier found in the string representation of the JPQL query, * which has the actual case that was used. * * @return The ordering identifier that was actually parsed, if one was present, otherwise an * empty string is returned */ public String getActualOrdering() { return (orderingIdentifier != null) ? orderingIdentifier : ExpressionTools.EMPTY_STRING; } /** * Returns the {@link Expression} that represents the order by expression. * * @return The expression that was parsed representing the order by expression */ public Expression getExpression() { if (expression == null) { expression = buildNullExpression(); } return expression; } /** * Returns the enum constant representing the null ordering type. * * @return The constant representing the null ordering, in the case the ordering was not parsed, * then {@link NullOrdering#DEFAULT} is returned */ public NullOrdering getNullOrdering() { return nullOrdering; } /** * Returns the enum constant representing the ordering type. * * @return The constant representing the ordering, in the case the ordering was not parsed, then * {@link Ordering#DEFAULT} is returned */ public Ordering getOrdering() { return ordering; } @Override public JPQLQueryBNF getQueryBNF() { return getQueryBNF(OrderByItemBNF.ID); } /** * Determines whether the order by expression was parsed. * * @return true if the order by expression was parsed; false otherwise */ public boolean hasExpression() { return expression != null && !expression.isNull(); } /** * Determines whether the NULLS identifier was parsed. * * @return true if the NULLS identifier was parsed; * false otherwise */ public boolean hasNulls() { return nullsIdentifier != null; } /** * Determines whether ASC or DESC was parsed. * * @return true if the ordering status was parsed; false otherwise * @since 2.5 */ public boolean hasOrdering() { return ordering != Ordering.DEFAULT; } /** * Determines whether a whitespace was parsed after the order by expression. * * @return true if there was a whitespace after the order by expression; * false otherwise */ public boolean hasSpaceAfterExpression() { return hasSpaceAfterExpression; } /** * Determines whether a whitespace was parsed after the NULLS identifier. If the * composite identifier was fully parsed - NULLS FIRST or NULLS LAST - * then this is always true, but if only NULLS was parsed, then this * can be useful to determine if there was a space after. * * @return true if there was a whitespace after the NULLS identifier; * false otherwise */ public boolean hasSpaceAfterNulls() { return hasSpaceAfterNulls; } /** * Determines whether a whitespace was parsed after the ordering. * * @return true if there was a whitespace after the ordering; * false otherwise */ public boolean hasSpaceAfterOrdering() { return hasSpaceAfterOrdering; } /** * Determines whether the ordering was specified as being ascendant. * * @return true if ASC was parsed; false otherwise */ public boolean isAscending() { return ordering == Ordering.ASC; } /** * Determines whether the ordering was not specified. * * @return true if no ordering was parsed; false otherwise */ public boolean isDefault() { return ordering == Ordering.DEFAULT; } /** * Determines whether the ordering was specified as being descendant. * * @return true if DESC was parsed; false otherwise */ public boolean isDescending() { return ordering == Ordering.DESC; } /** * Determines whether the ordering was specified as being nulls first. * * @return true if NULLS FIRST was parsed; false otherwise */ public boolean isNullsFirst() { return nullOrdering == NullOrdering.NULLS_FIRST; } /** * Determines whether the ordering was specified as being nulls first. * * @return true if NULLS LAST was parsed; false otherwise */ public boolean isNullsLast() { return nullOrdering == NullOrdering.NULLS_LAST; } @Override protected boolean isParsingComplete(WordParser wordParser, String word, Expression expression) { return word.equalsIgnoreCase(ASC) || word.equalsIgnoreCase(DESC) || word.equalsIgnoreCase("NULLS") || super.isParsingComplete(wordParser, word, expression); } @Override protected void parse(WordParser wordParser, boolean tolerant) { // Parse the state field path expression expression = parse(wordParser, InternalOrderByItemBNF.ID, tolerant); hasSpaceAfterExpression = wordParser.skipLeadingWhitespace() > 0; // Parse ASC/DESC if (!wordParser.isTail()) { String word = wordParser.word(); // Parse 'ASC' if (word.equalsIgnoreCase(ASC)) { ordering = Ordering.ASC; orderingIdentifier = wordParser.moveForward(ASC.length()); } // Parse 'DESC' else if (word.equalsIgnoreCase(DESC)) { ordering = Ordering.DESC; orderingIdentifier = wordParser.moveForward(DESC.length()); } else { ordering = Ordering.DEFAULT; } } else { ordering = Ordering.DEFAULT; } // Parse NULLS FIRST/NULLS LAST if (!wordParser.isTail()) { int count = wordParser.skipLeadingWhitespace(); hasSpaceAfterOrdering = (count > 0); // Parse 'NULLS' if (wordParser.startsWithIdentifier(NULLS)) { nullsIdentifier = wordParser.moveForward(NULLS); hasSpaceAfterNulls = wordParser.skipLeadingWhitespace() > 0; } // Parse 'FIRT' if (wordParser.startsWithIdentifier(FIRST)) { firstIdentifier = wordParser.moveForward(FIRST); } // Parse 'LAST' else if (wordParser.startsWithIdentifier(LAST)) { lastIdentifier = wordParser.moveForward(LAST); } if ((nullsIdentifier != null) && (firstIdentifier != null)) { nullOrdering = NullOrdering.NULLS_FIRST; } else if ((nullsIdentifier != null) && (lastIdentifier != null)) { nullOrdering = NullOrdering.NULLS_LAST; } else { nullOrdering = NullOrdering.DEFAULT; } } else { nullOrdering = NullOrdering.DEFAULT; } } @Override protected void toParsedText(StringBuilder writer, boolean actual) { // Order By expression if (expression != null) { expression.toParsedText(writer, actual); } if (hasSpaceAfterExpression) { writer.append(SPACE); } // Ordering type if (ordering != Ordering.DEFAULT) { writer.append(actual ? orderingIdentifier : ordering.name()); } if (hasSpaceAfterOrdering) { writer.append(SPACE); } // 'NULLS' if (nullsIdentifier != null) { writer.append(actual? nullsIdentifier : NULLS); } if (hasSpaceAfterNulls) { writer.append(SPACE); } // 'FIRST' if (firstIdentifier != null) { writer.append(actual? firstIdentifier : FIRST); } // 'LAST' else if (lastIdentifier != null) { writer.append(actual? lastIdentifier : LAST); } } /** * This enumeration lists all the possible choices for ordering nulls in an item. */ public enum NullOrdering { /** * The constant used when the ordering is not specify. */ DEFAULT(ExpressionTools.EMPTY_STRING), /** * The constant for 'NULLS FIRST', which tells to order nulls first. */ NULLS_FIRST(Expression.NULLS_FIRST), /** * The constant for 'NULLS LAST', which tells to order nulls last. */ NULLS_LAST(Expression.NULLS_LAST); /** * The actual composite identifier. */ private String identifier; /** * Creates a new NullOrdering. * * @param identifier The actual composite identifier */ NullOrdering(String identifier) { this.identifier = identifier; } /** * Returns the actual JPQL composite identifiers identified by this enum constant. * * @return The composite identifiers */ public String getIdentifier() { return identifier; } @Override public String toString() { return identifier; } } /** * This enumeration lists all the possible choices for ordering an item. */ public enum Ordering { /** * The constant for 'ASC', which tells to order the items in ascending ordering. */ ASC, /** * The constant used when the ordering is not specify, the default is ascending ordering. */ DEFAULT, /** * The constant for 'DESC', which tells to order the items in descending ordering. */ DESC } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy