blob: 429d548bab303100c544002565e01b84bb2e0108 [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:
// 10/26/2012-2.5 Chris Delahunt
// - 350469: JPA 2.1 Criteria Query framework Bulk Update/Delete support
package org.eclipse.persistence.internal.jpa.querydef;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import jakarta.persistence.criteria.CommonAbstractCriteria;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.ParameterExpression;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;
import jakarta.persistence.metamodel.EntityType;
import jakarta.persistence.metamodel.Metamodel;
import org.eclipse.persistence.expressions.ExpressionBuilder;
import org.eclipse.persistence.internal.expressions.ConstantExpression;
import org.eclipse.persistence.queries.DatabaseQuery;
/**
* <p>
* <b>Purpose</b>: Contains the implementation of the CommonAbstractCriteria interface of
* the JPA criteria API.
* <p>
* <b>Description</b>: This is the container class for the components that
* define a query. This is the superclass of CriteriaQuery, SubQuery, CriteriaDelete
* and CriteriaUpdate.
*
* @see jakarta.persistence.criteria CommonAbstractCriteria
*
* @author Chris Delahunt
* @since EclipseLink 2.5
*/
public abstract class CommonAbstractCriteriaImpl<T> implements CommonAbstractCriteria, Serializable {
private static final long serialVersionUID = -2729946665208116620L;
protected Metamodel metamodel;
protected Expression<Boolean> where;
protected CriteriaBuilderImpl queryBuilder;
protected Class queryType;
protected Set<ParameterExpression<?>> parameters;
public CommonAbstractCriteriaImpl(Metamodel metamodel, CriteriaBuilderImpl queryBuilder, Class<T> resultType){
this.metamodel = metamodel;
this.queryBuilder = queryBuilder;
this.queryType = resultType;
}
/**
* Return the predicate that corresponds to the where clause restriction(s).
*
* @return where clause predicate
*/
@Override
public Predicate getRestriction(){
if (this.where == null) {
return null;
}
if (((ExpressionImpl)this.where).isPredicate()) {
return (Predicate)this.where;
}
return this.queryBuilder.isTrue(this.where);
}
/**
* Return the result type of the query.
* If a result type was specified as an argument to the
* createQuery method, that type will be returned.
* If the query was created using the createTupleQuery
* method, the result type is Tuple.
* Otherwise, the result type is Object.
* @return result type
*/
public Class<T> getResultType(){
return this.queryType;
}
/**
* Add a query root corresponding to the given entity, forming a Cartesian
* product with any existing roots.
*
* @param entity
* metamodel entity representing the entity of type X
* @return query root corresponding to the given entity
*/
public Root internalFrom(EntityType entity) {
RootImpl root = new RootImpl(entity, this.metamodel, entity.getBindableJavaType(), new ExpressionBuilder(entity.getBindableJavaType()), entity);
integrateRoot(root);
return root;
}
/**
* Add a query root corresponding to the given entity, forming a Cartesian
* product with any existing roots.
*
* @param entityClass
* the entity class
* @return query root corresponding to the given entity
*/
public Root internalFrom(Class entityClass) {
EntityType entity = this.metamodel.entity(entityClass);
return this.internalFrom(entity);
}
/**
* Modify the query to restrict the query results according to the specified
* boolean expression. Replaces the previously added restriction(s), if any.
*
* @param restriction
* a simple or compound boolean expression
* @return the modified query
*/
public CommonAbstractCriteria where(Expression<Boolean> restriction) {
findRootAndParameters(restriction);
this.where = restriction;
return this;
}
/**
* Modify the query to restrict the query results according to the
* conjunction of the specified restriction predicates. Replaces the
* previously added restriction(s), if any. If no restrictions are
* specified, any previously added restrictions are simply removed.
*
* @param restrictions
* zero or more restriction predicates
* @return the modified query
*/
public CommonAbstractCriteria where(Predicate... restrictions) {
if (restrictions == null || restrictions.length == 0){
this.where = null;
}
Predicate predicate = this.queryBuilder.and(restrictions);
findRootAndParameters(predicate);
this.where = predicate;
return this;
}
/**
* Specify that the query is to be used as a subquery having the specified
* return type.
*
* @return subquery corresponding to the query
*/
@Override
public <U> Subquery<U> subquery(Class<U> type) {
return new SubQueryImpl<U>(metamodel, type, queryBuilder, this);
}
/**
* Used to use a root from a different query.
*/
protected abstract void integrateRoot(RootImpl root);
protected void findRootAndParameters(Expression<?> predicate) {
((InternalSelection) predicate).findRootAndParameters(this);
}
protected abstract org.eclipse.persistence.expressions.Expression getBaseExpression();
public void addParameter(ParameterExpression<?> parameter) {
if (this.parameters == null) {
this.parameters = new HashSet<ParameterExpression<?>>();
}
this.parameters.add(parameter);
}
protected abstract DatabaseQuery getDatabaseQuery();
/**
* Return the parameters of the query
*
* @return the query parameters
*/
public Set<ParameterExpression<?>> getParameters() {
if (this.parameters == null) {
this.parameters = new HashSet<ParameterExpression<?>>();
}
return this.parameters;
}
/**
* Translates from the criteria query to a EclipseLink Database Query.
*/
public DatabaseQuery translate() {
DatabaseQuery query = getDatabaseQuery();
for (ParameterExpression<?> parameter : getParameters()) {
query.addArgument(((ParameterExpressionImpl)parameter).getInternalName(), parameter.getJavaType());
}
if (this.where != null) {
if (((InternalExpression) this.where).isJunction()) {
if (!((PredicateImpl) this.where).getJunctionValue()) {
query.setSelectionCriteria(new ConstantExpression(1, getBaseExpression()).equal(0));
}
} else {
query.setSelectionCriteria(((InternalSelection) this.where).getCurrentNode());
}
}
return query;
}
}