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

org.eclipse.persistence.jpa.jpql.parser.TrimExpression 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.List;
import org.eclipse.persistence.jpa.jpql.ExpressionTools;
import org.eclipse.persistence.jpa.jpql.WordParser;

/**
 * The TRIM function trims the specified character from a string. If the character to be
 * trimmed is not specified, it is assumed to be space (or blank). The optional trim_character
 * is a single-character string literal or a character-valued input parameter (i.e., char or
 * Character). If a trim specification is not provided, BOTH is assumed. The TRIM
 * function returns the trimmed string.
 * 

* JPA 1.0, 2.0: *

BNF: expression ::= TRIM([[trim_specification] [trim_character] FROM] string_primary)
* *
BNF: trim_character ::= string_literal | input_parameter
*
* JPA 2.1: *
BNF: expression ::= TRIM([[trim_specification] [trim_character] FROM] string_expression)
* *
BNF: trim_character ::= string_literal | input_parameter
* *
Example: UPDATE Student st SET st.sname=TRIM(st.sname)
* * @version 2.5 * @since 2.3 * @author Pascal Filion */ public final class TrimExpression extends AbstractSingleEncapsulatedExpression { /** * The actual FROM identifier found in the string representation of the JPQL query. */ private String fromIdentifier; /** * Determines whether the identifier FROM was part of the query. */ private boolean hasFrom; /** * Determines whether a space was parsed after the identifier FROM. */ private boolean hasSpaceAfterFrom; /** * Determines whether a space was parsed after the trim specification. */ private boolean hasSpaceAfterSpecification; /** * Determines whether a space was parsed after the trim character. */ private boolean hasSpaceAfterTrimCharacter; /** * The specification specifies how to trim the string. */ private Specification specification; /** * The actual trim specification identifier found in the string representation of the JPQL query. */ private String specificationIdentifier; /** * The character used for trimming the string. */ private AbstractExpression trimCharacter; /** * Creates a new TrimExpression. * * @param parent The parent of this expression */ public TrimExpression(AbstractExpression parent) { super(parent, TRIM); } @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); } @Override public void acceptChildren(ExpressionVisitor visitor) { getTrimCharacter().accept(visitor); super.acceptChildren(visitor); } @Override protected void addOrderedEncapsulatedExpressionTo(List children) { // Trim specification if (hasSpecification()) { children.add(buildStringExpression(specification.name())); } if (hasSpaceAfterSpecification) { children.add(buildStringExpression(SPACE)); } // Trim character if (hasTrimCharacter()) { children.add(trimCharacter); } if (hasSpaceAfterTrimCharacter) { children.add(buildStringExpression(SPACE)); } // 'FROM' if (hasFrom) { children.add(buildStringExpression(FROM)); } if (hasSpaceAfterFrom) { children.add(buildStringExpression(SPACE)); } // String primary super.addOrderedEncapsulatedExpressionTo(children); } @Override public String getEncapsulatedExpressionQueryBNFId() { return StringPrimaryBNF.ID; } /** * Returns the actual FROM identifier found in the string representation of the JPQL * query, which has the actual case that was used. * * @return The FROM identifier that was actually parsed, or an empty string if it was not * parsed */ public String getActualFromIdentifier() { return (fromIdentifier != null) ? fromIdentifier : ExpressionTools.EMPTY_STRING; } /** * Returns the actual specification identifier found in the string representation of the JPQL * query, which has the actual case that was used. * * @return The specification identifier that was actually parsed, or an empty string if it was * not parsed */ public String getActualSpecificationIdentifier() { return (specificationIdentifier != null) ? specificationIdentifier : ExpressionTools.EMPTY_STRING; } @Override public JPQLQueryBNF getQueryBNF() { return getQueryBNF(FunctionsReturningStringsBNF.ID); } /** * Returns the specification which specifies how to trim the string. * * @return One of the available choices for trimming the string */ public Specification getSpecification() { return specification; } /** * Returns the character used for trimming the string. * * @return The character, if one was parsed, that will be used to trim the string. If the * character was not specified, then '\0' is the character */ public Expression getTrimCharacter() { if (trimCharacter == null) { trimCharacter = buildNullExpression(); } return trimCharacter; } @Override public boolean hasEncapsulatedExpression() { return hasSpecification() || hasTrimCharacter() || hasFrom || hasExpression(); } /** * Determines whether the identifier FROM was part of the query. * * @return true if the identifier FROM was parsed; false otherwise */ public boolean hasFrom() { return hasFrom; } /** * Determines whether a whitespace was found after FROM. * * @return true if there was a whitespace after FROM; false otherwise */ public boolean hasSpaceAfterFrom() { return hasSpaceAfterFrom; } /** * Determines whether a whitespace was found after the way the string is trimmed. * * @return true if there was a whitespace after the trim specification; * false otherwise */ public boolean hasSpaceAfterSpecification() { return hasSpaceAfterSpecification; } /** * Determines whether a whitespace was found after the character used to trim the string. * * @return true if there was a whitespace after the trim character; * false otherwise */ public boolean hasSpaceAfterTrimCharacter() { return hasSpaceAfterTrimCharacter; } /** * Determines whether the way the trim is trimmed was parsed. * * @return true if the query contained the way the trim needs to * be trimmed; false otherwise */ public boolean hasSpecification() { return (specification != Specification.DEFAULT); } /** * Determines whether the character used to trim the string was specified. * * @return true if the character used for trimming was specified; false * otherwise */ public boolean hasTrimCharacter() { return trimCharacter != null && !trimCharacter.isNull(); } @Override protected void parseEncapsulatedExpression(WordParser wordParser, int whitespaceCount, boolean tolerant) { // Parse the trim specification specification = parseTrimSpecification(wordParser); if (specification != Specification.DEFAULT) { specificationIdentifier = wordParser.moveForward(specification.name().length()); hasSpaceAfterSpecification = wordParser.skipLeadingWhitespace() > 0; } // Parse the trim character if (!wordParser.startsWithIdentifier(FROM)) { // Make sure to parse with the encapsulated expression because if it is not // the trim character but the string primary, then it has to be parsed correctly trimCharacter = parse(wordParser, getEncapsulatedExpressionQueryBNFId(), tolerant); } if (hasTrimCharacter()) { hasSpaceAfterTrimCharacter = wordParser.skipLeadingWhitespace() > 0; } // Parse 'FROM' hasFrom = wordParser.startsWithIdentifier(FROM); if (hasFrom) { fromIdentifier = wordParser.moveForward(FROM); hasSpaceAfterFrom = wordParser.skipLeadingWhitespace() > 0; } // Parse the string primary super.parseEncapsulatedExpression(wordParser, whitespaceCount, tolerant); // The trim character is actually the string primary if (!hasFrom && !hasExpression() && hasTrimCharacter()) { setExpression(trimCharacter); trimCharacter = null; if (hasSpaceAfterTrimCharacter) { hasSpaceAfterTrimCharacter = false; wordParser.moveBackward(1); } } } private Specification parseTrimSpecification(WordParser wordParser) { if (wordParser.startsWithIdentifier(BOTH)) { return Specification.BOTH; } if (wordParser.startsWithIdentifier(LEADING)) { return Specification.LEADING; } if (wordParser.startsWithIdentifier(TRAILING)) { return Specification.TRAILING; } return Specification.DEFAULT; } @Override protected void toParsedTextEncapsulatedExpression(StringBuilder writer, boolean actual) { // Trim specification if (hasSpecification()) { writer.append(specification); } if (hasSpaceAfterSpecification) { writer.append(SPACE); } // Trim character if (hasTrimCharacter()) { trimCharacter.toParsedText(writer, actual); } if (hasSpaceAfterTrimCharacter) { writer.append(SPACE); } // 'FROM' if (hasFrom) { writer.append(actual ? fromIdentifier : FROM); } if (hasSpaceAfterFrom) { writer.append(SPACE); } // String primary super.toParsedTextEncapsulatedExpression(writer, actual); } /** * The possible ways to trim the string. */ public enum Specification { /** * The leading and trailing parts of the string will be trimmed. */ BOTH(Expression.BOTH), /** * Used when the trim specification is not specified, by default it means the leading and * trailing parts of the string will be trimmed. */ DEFAULT(ExpressionTools.EMPTY_STRING), /** * Only the leading part of the string will be trimmed. */ LEADING(Expression.LEADING), /** * Only the trailing part of the string will be trimmed. */ TRAILING(Expression.TRAILING); /** * The actual constant associated with the constant. */ private String value; Specification(String value) { this.value = value; } /** * Returns the actual identifier associated with the constant. * * @return The identifier associated with the constant or an empty string for {@link #DEFAULT} */ public String getValue() { return value; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy