blob: cd49110f9e776e570b1ecc0c9c3466bdab13caf3 [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;
import java.util.Collections;
import java.util.List;
import org.eclipse.persistence.jpa.jpql.ExpressionTools;
import org.eclipse.persistence.jpa.jpql.parser.TrimExpression.Specification;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AllOrAnyExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.AndExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.BetweenExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.CollectionMemberExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.ComparisonExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.EmptyCollectionComparisonExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.ExistsExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.InExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.KeywordExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.LikeExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.LowerExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.NullComparisonExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.OrExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.SimpleSelectStatementStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.StateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.SubExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.SubstringExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.TrimExpressionStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.UpperExpressionStateObject;
import static org.eclipse.persistence.jpa.jpql.parser.Expression.*;
/**
* The abstract implementation of {@link IConditionalExpressionStateObjectBuilder} that supports the
* creation of the conditional expression based on the JPQL grammar defined in JPA 2.0.
*
* @version 2.4
* @since 2.4
* @author Pascal Filion
*/
@SuppressWarnings("unchecked")
public abstract class AbstractConditionalExpressionStateObjectBuilder<T extends IAbstractConditionalExpressionStateObjectBuilder<T>>
extends AbstractScalarExpressionStateObjectBuilder<T>
implements IAbstractConditionalExpressionStateObjectBuilder<T> {
/**
* Creates a new <code>AbstractStateObjectBuilder</code>.
*
* @param parent The parent of the expression to build, which is only required when a JPQL
* fragment needs to be parsed
*/
public AbstractConditionalExpressionStateObjectBuilder(StateObject parent) {
super(parent);
}
@Override
public T all(SimpleSelectStatementStateObject subquery) {
allOrAny(ALL, subquery);
return (T) this;
}
protected void allOrAny(String identifier, SimpleSelectStatementStateObject subquery) {
StateObject stateObject = new AllOrAnyExpressionStateObject(getParent(), identifier, subquery);
add(stateObject);
}
@Override
public T and(T builder) {
checkBuilder(builder);
StateObject rightStateObject = pop();
StateObject leftStateObject = pop();
StateObject stateObject = new AndExpressionStateObject(
getParent(),
leftStateObject,
rightStateObject
);
add(stateObject);
return (T) this;
}
@Override
public T any(SimpleSelectStatementStateObject subquery) {
allOrAny(ANY, subquery);
return (T) this;
}
protected void between(boolean not) {
StateObject upperBoundStateObject = pop();
StateObject lowerBoundStateObject = pop();
StateObject firstStateObject = pop();
StateObject stateObject = new BetweenExpressionStateObject(
getParent(),
firstStateObject,
not,
lowerBoundStateObject,
upperBoundStateObject
);
add(stateObject);
}
@Override
public T between(T lowerBoundExpression, T upperBoundExpression) {
checkBuilders(lowerBoundExpression, upperBoundExpression);
between(false);
return (T) this;
}
@Override
public T collectionPath(String path) {
StateObject stateObject = buildCollectionPath(path);
add(stateObject);
return (T) this;
}
protected void comparison(String identifier) {
comparison(identifier, pop());
}
protected void comparison(String identifier, StateObject rightStateObject) {
StateObject leftStateObject = pop();
StateObject stateObject = new ComparisonExpressionStateObject(
getParent(),
leftStateObject,
identifier,
rightStateObject
);
add(stateObject);
}
@Override
public T different(Number number) {
comparison(DIFFERENT, buildNumeric(number));
return (T) this;
}
@Override
public T different(String literal) {
comparison(DIFFERENT, literal(literal));
return (T) this;
}
@Override
public T different(T builder) {
checkBuilder(builder);
comparison(DIFFERENT);
return (T) this;
}
@Override
public T equal(Number number) {
comparison(EQUAL, buildNumeric(number));
return (T) this;
}
@Override
public T equal(String literal) {
comparison(EQUAL, literal(literal));
return (T) this;
}
@Override
public T equal(T builder) {
checkBuilder(builder);
comparison(EQUAL);
return (T) this;
}
protected void exists(boolean not, SimpleSelectStatementStateObject subquery) {
StateObject stateObject = new ExistsExpressionStateObject(getParent(), not, subquery);
add(stateObject);
}
@Override
public T exists(SimpleSelectStatementStateObject subquery) {
exists(false, subquery);
return (T) this;
}
@Override
public T FALSE() {
keyword(FALSE);
return (T) this;
}
@Override
public T greaterThan(Number number) {
comparison(GREATER_THAN, buildNumeric(number));
return (T) this;
}
@Override
public T greaterThan(String literal) {
comparison(GREATER_THAN, literal(literal));
return (T) this;
}
@Override
public T greaterThan(T builder) {
checkBuilder(builder);
comparison(GREATER_THAN);
return (T) this;
}
@Override
public T greaterThanOrEqual(Number number) {
comparison(GREATER_THAN_OR_EQUAL, buildNumeric(number));
return (T) this;
}
@Override
public T greaterThanOrEqual(String literal) {
comparison(GREATER_THAN_OR_EQUAL, literal(literal));
return (T) this;
}
@Override
public T greaterThanOrEqual(T builder) {
checkBuilder(builder);
comparison(GREATER_THAN_OR_EQUAL);
return (T) this;
}
protected void in(boolean not, List<StateObject> inItems) {
StateObject stateFieldPath = pop();
StateObject stateObject = new InExpressionStateObject(
getParent(),
stateFieldPath,
not,
inItems
);
add(stateObject);
}
protected void in(boolean not, String... inItems) {
in(not, literals(inItems));
}
protected void in(boolean not, T... inItems) {
in(false, stateObjects(inItems));
}
@Override
public T in(SimpleSelectStatementStateObject subquery) {
in(false, Collections.<StateObject>singletonList(subquery));
return (T) this;
}
@Override
public T in(String... inItems) {
in(false, inItems);
return (T) this;
}
@Override
public T in(T builder) {
checkBuilders(builder);
in(false, builder);
return (T) this;
}
@Override
public T in(T builder1, T builder2) {
checkBuilders(builder1, builder2);
in(false, builder1, builder2);
return (T) this;
}
protected void isEmpty(boolean not, String path) {
StateObject stateObject = new EmptyCollectionComparisonExpressionStateObject(
getParent(),
not,
path
);
add(stateObject);
}
@Override
public T isEmpty(String path) {
isEmpty(false, path);
return (T) this;
}
@Override
public T isNotEmpty(String path) {
isEmpty(true, path);
return (T) this;
}
@Override
public T isNotNull(String path) {
isNull(true, path);
return (T) this;
}
protected void isNull(boolean not, String path) {
StateObject stateObject;
if (ExpressionTools.isParameter(path.charAt(0))) {
stateObject = buildInputParameter(path);
}
else {
stateObject = buildStateFieldPath(path);
}
stateObject = new NullComparisonExpressionStateObject(
getParent(),
not,
stateObject
);
add(stateObject);
}
@Override
public T isNull(String path) {
isNull(false, path);
return (T) this;
}
protected void keyword(String identifier) {
StateObject stateObject = new KeywordExpressionStateObject(getParent(), identifier);
add(stateObject);
}
protected void like(boolean not, String escapeCharacter) {
StateObject patternValue = pop();
StateObject string = pop();
StateObject stateObject = new LikeExpressionStateObject(
getParent(),
string,
not,
patternValue,
escapeCharacter
);
add(stateObject);
}
@Override
public T like(String patternValue) {
like(string(patternValue));
return (T) this;
}
@Override
public T like(T patternValue) {
checkBuilder(patternValue);
like(false, null);
return (T) this;
}
@Override
public T like(T patternValue, String escapeCharacter) {
checkBuilder(patternValue);
like(false, escapeCharacter);
return (T) this;
}
@Override
public T lower(T builder) {
checkBuilder(builder);
StateObject stateObject = new LowerExpressionStateObject(getParent(), pop());
add(stateObject);
return (T) this;
}
@Override
public T lowerThan(Number number) {
comparison(LOWER_THAN, buildNumeric(number));
return (T) this;
}
@Override
public T lowerThan(String literal) {
comparison(LOWER_THAN, literal(literal));
return (T) this;
}
@Override
public T lowerThan(T builder) {
checkBuilder(builder);
comparison(LOWER_THAN);
return (T) this;
}
@Override
public T lowerThanOrEqual(Number number) {
comparison(LOWER_THAN_OR_EQUAL, buildNumeric(number));
return (T) this;
}
@Override
public T lowerThanOrEqual(String literal) {
comparison(LOWER_THAN_OR_EQUAL, literal(literal));
return (T) this;
}
@Override
public T lowerThanOrEqual(T builder) {
checkBuilder(builder);
comparison(LOWER_THAN_OR_EQUAL);
return (T) this;
}
protected void member(boolean not, boolean of, String collectionValuedPathExpression) {
StateObject entity = pop();
StateObject stateObject = new CollectionMemberExpressionStateObject(
getParent(),
entity,
not,
of,
collectionValuedPathExpression
);
add(stateObject);
}
@Override
public T member(String path) {
member(false, false, path);
return (T) this;
}
@Override
public T memberOf(String path) {
member(false, true, path);
return (T) this;
}
@Override
public T notBetween(T lowerBoundExpression, T upperBoundExpression) {
checkBuilders(lowerBoundExpression, upperBoundExpression);
between(true);
return (T) this;
}
@Override
public T notExists(SimpleSelectStatementStateObject subquery) {
exists(true, subquery);
return (T) this;
}
@Override
public T notIn(SimpleSelectStatementStateObject subquery) {
in(true, Collections.<StateObject>singletonList(subquery));
return (T) this;
}
@Override
public T notIn(String... inItems) {
in(true, inItems);
return (T) this;
}
@Override
public T notIn(T builder) {
checkBuilders(builder);
in(true, builder);
return (T) this;
}
@Override
public T notIn(T builder1, T builder2) {
checkBuilders(builder1, builder2);
in(true, builder1, builder2);
return (T) this;
}
@Override
public T notLike(String patternValue) {
notLike(string(patternValue));
return (T) this;
}
@Override
public T notLike(T builder) {
checkBuilder(builder);
like(true, null);
return (T) this;
}
@Override
public T notLike(T builder, String escapeCharacter) {
checkBuilder(builder);
like(true, escapeCharacter);
return (T) this;
}
@Override
public T notMember(String path) {
member(true, false, path);
return (T) this;
}
@Override
public T notMemberOf(String path) {
member(true, true, path);
return (T) this;
}
@Override
public T NULL() {
keyword(NULL);
return (T) this;
}
@Override
public T or(T builder) {
checkBuilder(builder);
StateObject rightStateObject = pop();
StateObject leftStateObject = pop();
StateObject stateObject = new OrExpressionStateObject(
getParent(),
leftStateObject,
rightStateObject
);
add(stateObject);
return (T) this;
}
@Override
public T some(SimpleSelectStatementStateObject subquery) {
allOrAny(SOME, subquery);
return (T) this;
}
@Override
public T sub(StateObject stateObject) {
stateObject = new SubExpressionStateObject(getParent(), stateObject);
add(stateObject);
return (T) this;
}
@Override
public T substring(T parameter1, T parameter2, T parameter3) {
checkBuilders(parameter1, parameter2, parameter3);
StateObject thirdStateObject = pop();
StateObject secondStateObject = pop();
StateObject firstStateObject = pop();
StateObject stateObject = new SubstringExpressionStateObject(
getParent(),
firstStateObject,
secondStateObject,
thirdStateObject
);
add(stateObject);
return (T) this;
}
@Override
public T trim(Specification specification, String trimCharacter, T builder) {
checkBuilder(builder);
StateObject stateObject = pop();
stateObject = new TrimExpressionStateObject(
getParent(),
specification,
ExpressionTools.stringIsNotEmpty(trimCharacter) ? literal(trimCharacter) : null,
stateObject
);
add(stateObject);
return (T) this;
}
@Override
public T trim(Specification specification, T builder) {
return trim(specification, null, builder);
}
@Override
public T TRUE() {
keyword(TRUE);
return (T) this;
}
@Override
public T upper(T builder) {
checkBuilder(builder);
StateObject stateObject = new UpperExpressionStateObject(getParent(), pop());
add(stateObject);
return (T) this;
}
@Override
public T variable(String variable) {
StateObject stateObject = buildIdentificationVariable(variable);
add(stateObject);
return (T) this;
}
}