| /* |
| * 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; |
| |
| import java.lang.reflect.Array; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| import org.eclipse.persistence.jpa.jpql.Assert; |
| import org.eclipse.persistence.jpa.jpql.ExpressionTools; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.AbsExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.AdditionExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.ArithmeticFactorStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.AvgFunctionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.CoalesceExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.CollectionValuedPathExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.ConcatExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.CountFunctionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.DateTimeStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.DivisionExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.EntityTypeLiteralStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.EnumTypeStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.FunctionExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.IdentificationVariableStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.IndexExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.InputParameterStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.LengthExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.LocateExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.MaxFunctionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.ModExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.MultiplicationExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.NullIfExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.NumericLiteralStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.SizeExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.SqrtExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.StateFieldPathExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.StateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.StringLiteralStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.SubExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.SubtractionExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.SumFunctionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.TypeExpressionStateObject; |
| import static org.eclipse.persistence.jpa.jpql.parser.Expression.*; |
| |
| /** |
| * This abstract definition of a builder provides the support for creating expressions defined by a |
| * <code>scalar expression</code>. |
| * |
| * @version 2.4 |
| * @since 2.4 |
| * @author Pascal Filion |
| */ |
| @SuppressWarnings({"unchecked", "nls"}) |
| public abstract class AbstractScalarExpressionStateObjectBuilder<T extends IScalarExpressionStateObjectBuilder<T>> extends AbstractStateObjectBuilder |
| implements IScalarExpressionStateObjectBuilder<T> { |
| |
| /** |
| * Caches the {@link ICaseExpressionStateObjectBuilder} while it's been used. |
| */ |
| private ICaseExpressionStateObjectBuilder caseBuilder; |
| |
| /** |
| * The parent of the expression to build, which is only required when a JPQL fragment needs to |
| * be parsed. |
| */ |
| private StateObject parent; |
| |
| /** |
| * Creates a new <code>AbstractScalarExpressionStateObjectBuilder</code>. |
| * |
| * @param parent The parent of the expression to build, which is only required when a JPQL |
| * fragment needs to be parsed |
| */ |
| protected AbstractScalarExpressionStateObjectBuilder(StateObject parent) { |
| super(); |
| this.parent = parent; |
| } |
| |
| @Override |
| public T abs(T builder) { |
| |
| checkBuilder(builder); |
| |
| StateObject stateObject = new AbsExpressionStateObject(parent, pop()); |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T add(T builder) { |
| |
| checkBuilder(builder); |
| |
| StateObject rightStateObject = pop(); |
| StateObject leftStateObject = pop(); |
| |
| StateObject stateObject = new AdditionExpressionStateObject( |
| parent, |
| leftStateObject, |
| rightStateObject |
| ); |
| |
| add(stateObject); |
| return (T) this; |
| } |
| |
| protected void arithmetic(boolean plusSign) { |
| StateObject stateObject = new ArithmeticFactorStateObject(parent, plusSign, pop()); |
| add(stateObject); |
| } |
| |
| protected void avg(boolean distinct, String path) { |
| StateObject stateObject = new AvgFunctionStateObject(parent, distinct, literal(path)); |
| add(stateObject); |
| } |
| |
| @Override |
| public T avg(String path) { |
| avg(false, path); |
| return (T) this; |
| } |
| |
| @Override |
| public T avgDistinct(String path) { |
| avg(true, path); |
| return (T) this; |
| } |
| |
| protected StateObject buildCollectionPath(String path) { |
| return new CollectionValuedPathExpressionStateObject(parent, path); |
| } |
| |
| protected StateObject buildIdentificationVariable(String literal) { |
| return new IdentificationVariableStateObject(parent, literal); |
| } |
| |
| protected StateObject buildInputParameter(String parameter) { |
| return new InputParameterStateObject(parent, parameter); |
| } |
| |
| protected StateObject buildNumeric(Number number) { |
| return new NumericLiteralStateObject(parent, number); |
| } |
| |
| protected StateObject buildNumeric(String number) { |
| return new NumericLiteralStateObject(parent, number); |
| } |
| |
| protected StateObject buildStateFieldPath(String path) { |
| return new StateFieldPathExpressionStateObject(parent, path); |
| } |
| |
| protected StateObject buildStringLiteral(String literal) { |
| return new StringLiteralStateObject(parent, literal); |
| } |
| |
| @Override |
| public T case_(ICaseExpressionStateObjectBuilder builder) { |
| Assert.isEqual(caseBuilder, builder, "The Case expression builder is not the same as the current one"); |
| add(builder.buildStateObject()); |
| builder = null; |
| return (T) this; |
| } |
| |
| @Override |
| public T coalesce(T builder1, T builder2) { |
| return coalesce(builder1, builder2, (T[]) Array.newInstance(builder1.getClass(), 0)); |
| } |
| |
| @Override |
| public T coalesce(T builder1, T builder2, T[] builders) { |
| |
| checkBuilders(builder1, builder2); |
| checkBuilders(builders); |
| |
| List<StateObject> stateObjects = new ArrayList<StateObject>(); |
| stateObjects.addAll(stateObjects(builders)); |
| stateObjects.add(0, pop()); |
| stateObjects.add(0, pop()); |
| |
| StateObject stateObject = new CoalesceExpressionStateObject(parent, stateObjects); |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T concat(T builder1, T builder2) { |
| return concat(builder1, builder2, (T[]) Array.newInstance(builder1.getClass(), 0)); |
| } |
| |
| @Override |
| public T concat(T builder1, T builder2, T[] builders) { |
| |
| checkBuilders(builder1, builder2); |
| checkBuilders(builders); |
| |
| List<StateObject> stateObjects = new ArrayList<StateObject>(); |
| stateObjects.addAll(stateObjects(builders)); |
| stateObjects.add(0, pop()); |
| stateObjects.add(0, pop()); |
| |
| StateObject stateObject = new ConcatExpressionStateObject(parent, stateObjects); |
| add(stateObject); |
| return (T) this; |
| } |
| |
| protected void count(boolean distinct, String path) { |
| StateObject stateObject = new CountFunctionStateObject(parent, distinct, literal(path)); |
| add(stateObject); |
| } |
| |
| @Override |
| public T count(String path) { |
| count(false, path); |
| return (T) this; |
| } |
| |
| @Override |
| public T countDistinct(String path) { |
| count(true, path); |
| return (T) this; |
| } |
| |
| @Override |
| public T currentDate() { |
| return date(CURRENT_DATE); |
| } |
| |
| @Override |
| public T currentTime() { |
| return date(CURRENT_TIME); |
| } |
| |
| @Override |
| public T currentTimestamp() { |
| return date(CURRENT_TIMESTAMP); |
| } |
| |
| @Override |
| public T date(String jdbcDate) { |
| StateObject stateObject = new DateTimeStateObject(parent, jdbcDate); |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T divide(T builder) { |
| |
| checkBuilder(builder); |
| |
| StateObject rightStateObject = pop(); |
| StateObject leftStateObject = pop(); |
| |
| StateObject stateObject = new DivisionExpressionStateObject( |
| parent, |
| leftStateObject, |
| rightStateObject |
| ); |
| |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T entityType(String entityTypeName) { |
| StateObject stateObject = new EntityTypeLiteralStateObject(parent,entityTypeName); |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T enumLiteral(Enum<? extends Enum<?>> enumConstant) { |
| StateObject stateObject = new EnumTypeStateObject(parent, enumConstant); |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T function(String identifier, String functionName, String... arguments) { |
| |
| StateObject stateObject = new FunctionExpressionStateObject( |
| getParent(), |
| identifier, |
| functionName, |
| literals(arguments) |
| ); |
| |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T function(String identifier, String functionName) { |
| StateObject stateObject = new FunctionExpressionStateObject( |
| getParent(), |
| identifier, |
| functionName, |
| stateObjects(0) |
| ); |
| |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T function(String identifier, String functionName, T[] arguments) { |
| |
| checkBuilders(arguments); |
| |
| StateObject stateObject = new FunctionExpressionStateObject( |
| getParent(), |
| identifier, |
| functionName, |
| stateObjects(arguments) |
| ); |
| |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public ICaseExpressionStateObjectBuilder getCaseBuilder() { |
| if (caseBuilder == null) { |
| caseBuilder = getParent().getQueryBuilder().buildCaseExpressionStateObjectBuilder(parent); |
| } |
| return caseBuilder; |
| } |
| |
| /** |
| * Returns the parent of the expression to build, which is only required when a JPQL fragment |
| * needs to be parsed. |
| * |
| * @return The parent |
| */ |
| protected StateObject getParent() { |
| return parent; |
| } |
| |
| @Override |
| public T index(String variable) { |
| StateObject stateObject = new IndexExpressionStateObject(parent, variable); |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T length(T builder) { |
| |
| checkBuilder(builder); |
| |
| StateObject stateObject = new LengthExpressionStateObject(parent, pop()); |
| add(stateObject); |
| return (T) this; |
| } |
| |
| protected StateObject literal(String literal) { |
| |
| if ((literal != null) && (literal.length() > 0)) { |
| |
| char character = literal.charAt(0); |
| |
| // String literal |
| if (ExpressionTools.isQuote(character)) { |
| return buildStringLiteral(literal); |
| } |
| |
| // Input parameter |
| if (ExpressionTools.isParameter(character)) { |
| return buildInputParameter(literal); |
| } |
| |
| // State-field path expression |
| if (literal.indexOf('.') > 0) { |
| return buildStateFieldPath(literal); |
| } |
| |
| // Identification variable |
| return buildIdentificationVariable(literal); |
| } |
| |
| // String literal |
| return buildStringLiteral(literal); |
| } |
| |
| protected List<StateObject> literals(String... literals) { |
| List<StateObject> stateObjects = new ArrayList<StateObject>(); |
| for (String literal : literals) { |
| stateObjects.add(literal(literal)); |
| } |
| return stateObjects; |
| } |
| |
| @Override |
| public T locate(T parameter1, T parameter2) { |
| return locate(parameter1, parameter2, null); |
| } |
| |
| @Override |
| public T locate(T parameter1, T parameter2, T parameter3) { |
| |
| checkBuilders(parameter1, parameter2); |
| |
| if (parameter3 != null) { |
| checkBuilder(parameter3); |
| } |
| |
| StateObject thirdStateObject = (parameter3 != null) ? pop() : null; |
| StateObject secondStateObject = pop(); |
| StateObject firstStateObject = pop(); |
| |
| StateObject stateObject = new LocateExpressionStateObject( |
| parent, |
| firstStateObject, |
| secondStateObject, |
| thirdStateObject |
| ); |
| |
| add(stateObject); |
| return (T) this; |
| } |
| |
| protected void max(boolean distinct, String path) { |
| StateObject stateObject = new MaxFunctionStateObject(parent, distinct, literal(path)); |
| add(stateObject); |
| } |
| |
| @Override |
| public T max(String path) { |
| max(false, path); |
| return (T) this; |
| } |
| |
| @Override |
| public T maxDistinct(String path) { |
| max(true, path); |
| return (T) this; |
| } |
| |
| protected void min(boolean distinct, String path) { |
| StateObject stateObject = new MaxFunctionStateObject(parent, distinct, literal(path)); |
| add(stateObject); |
| } |
| |
| @Override |
| public T min(String path) { |
| min(false, path); |
| return (T) this; |
| } |
| |
| @Override |
| public T minDistinct(String path) { |
| min(true, path); |
| return (T) this; |
| } |
| |
| @Override |
| public T minus(T builder) { |
| checkBuilders(builder); |
| arithmetic(false); |
| return (T) this; |
| } |
| |
| @Override |
| public T mod(T parameter1, T parameter2) { |
| |
| checkBuilders(parameter1, parameter2); |
| |
| StateObject secondStateObject = pop(); |
| StateObject firstStateObject = pop(); |
| |
| StateObject stateObject = new ModExpressionStateObject( |
| parent, |
| firstStateObject, |
| secondStateObject |
| ); |
| |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T multiply(T builder) { |
| |
| checkBuilders(builder); |
| |
| StateObject rightStateObject = pop(); |
| StateObject leftStateObject = pop(); |
| |
| StateObject stateObject = new MultiplicationExpressionStateObject( |
| parent, |
| leftStateObject, |
| rightStateObject |
| ); |
| |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T nullIf(T builder1, T builder2) { |
| |
| checkBuilders(builder1, builder2); |
| |
| StateObject rightStateObject = pop(); |
| StateObject leftStateObject = pop(); |
| |
| StateObject stateObject = new NullIfExpressionStateObject( |
| parent, |
| leftStateObject, |
| rightStateObject |
| ); |
| |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T numeric(Number number) { |
| StateObject stateObject = buildNumeric(number); |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T numeric(String number) { |
| StateObject stateObject = buildNumeric(number); |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T parameter(String parameter) { |
| StateObject stateObject = buildInputParameter(parameter); |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T path(String path) { |
| StateObject stateObject = buildStateFieldPath(path); |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T plus(T builder) { |
| checkBuilders(builder); |
| arithmetic(true); |
| return (T) this; |
| } |
| |
| @Override |
| public T size(String path) { |
| StateObject stateObject = new SizeExpressionStateObject(parent, buildCollectionPath(path)); |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T sqrt(T builder) { |
| |
| checkBuilders(builder); |
| |
| StateObject stateObject = new SqrtExpressionStateObject(parent, pop()); |
| add(stateObject); |
| return (T) this; |
| } |
| |
| /** |
| * Returns a list of the {@link StateObject StateObjects} that were previously created. |
| * |
| * @param count The number of {@link StateObject StateObjects} to move to the list |
| * @return The list of {@link StateObject StateObjects} that were added to the stack |
| */ |
| protected List<StateObject> stateObjects(int count) { |
| |
| if (count == 0) { |
| return Collections.emptyList(); |
| } |
| |
| List<StateObject> items = new ArrayList<StateObject>(count); |
| |
| while (count-- > 0) { |
| items.add(0, pop()); |
| } |
| |
| return items; |
| } |
| |
| /** |
| * Returns a list of the {@link StateObject StateObjects} that were previously created. |
| * |
| * @param builders The list of {@link IScalarExpressionStateObjectBuilder builders} is used to |
| * determine how many {@link StateObject StateObjects} needs to be pulled out of the stack |
| * @return The list of {@link StateObject StateObjects} that were added to the stack |
| */ |
| protected List<StateObject> stateObjects(T... builders) { |
| return stateObjects(builders.length); |
| } |
| |
| @Override |
| public T string(String literal) { |
| StateObject stateObject = buildStringLiteral(literal); |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T sub(T builder) { |
| |
| checkBuilders(builder); |
| |
| StateObject stateObject = new SubExpressionStateObject(parent, pop()); |
| add(stateObject); |
| return (T) this; |
| } |
| |
| @Override |
| public T subtract(T builder) { |
| |
| checkBuilders(builder); |
| |
| StateObject rightStateObject = pop(); |
| StateObject leftStateObject = pop(); |
| |
| StateObject stateObject = new SubtractionExpressionStateObject( |
| parent, |
| leftStateObject, |
| rightStateObject |
| ); |
| |
| add(stateObject); |
| return (T) this; |
| } |
| |
| protected void sum(boolean distinct, String path) { |
| StateObject stateObject = new SumFunctionStateObject(parent, distinct, literal(path)); |
| add(stateObject); |
| } |
| |
| @Override |
| public T sum(String path) { |
| sum(false, path); |
| return (T) this; |
| } |
| |
| @Override |
| public T sumDistinct(String path) { |
| sum(true, path); |
| return (T) this; |
| } |
| |
| @Override |
| public T type(String path) { |
| StateObject stateObject = new TypeExpressionStateObject(parent, path); |
| add(stateObject); |
| return (T) this; |
| } |
| } |