| /* |
| * Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved. |
| * Copyright (c) 2011, 2021 IBM Corporation. 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: |
| // Gordon Yorke - Initial development |
| // 02/03/2017 - Dalia Abo Sheasha |
| // - 509693 : EclipseLink generates inconsistent SQL statements for SubQuery |
| package org.eclipse.persistence.internal.jpa.querydef; |
| |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import jakarta.persistence.criteria.AbstractQuery; |
| import jakarta.persistence.criteria.Expression; |
| import jakarta.persistence.criteria.Predicate; |
| import jakarta.persistence.criteria.Root; |
| import jakarta.persistence.metamodel.EntityType; |
| import jakarta.persistence.metamodel.Metamodel; |
| |
| import org.eclipse.persistence.expressions.ExpressionBuilder; |
| |
| /** |
| * <p> |
| * <b>Purpose</b>: Contains the implementation of the AbstractQuery 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 both the CriteriaQuery and the |
| * SubQuery. |
| * |
| * @see jakarta.persistence.criteria CriteriaQuery |
| * |
| * @author gyorke |
| * @since EclipseLink 1.2 |
| */ |
| public abstract class AbstractQueryImpl<T> extends CommonAbstractCriteriaImpl<T> implements AbstractQuery<T> { |
| |
| private static final long serialVersionUID = -5270020290752637882L; |
| |
| protected ResultType queryResult; |
| protected boolean distinct; |
| protected Predicate havingClause; |
| protected List<Expression<?>> groupBy; |
| protected Set<Root<?>> roots; |
| protected org.eclipse.persistence.expressions.Expression baseExpression; |
| |
| protected enum ResultType{ |
| UNKNOWN, OBJECT_ARRAY, PARTIAL, TUPLE, ENTITY, CONSTRUCTOR, OTHER |
| } |
| |
| public AbstractQueryImpl(Metamodel metamodel, ResultType queryResult, CriteriaBuilderImpl queryBuilder, Class<T> resultType){ |
| super(metamodel, queryBuilder, resultType); |
| this.roots = new HashSet<Root<?>>(); |
| this.queryResult = queryResult; |
| this.baseExpression = new ExpressionBuilder(); |
| } |
| |
| /** |
| * Specify the expressions that are used to form groups over |
| * the query results. |
| * Replaces the previous specified grouping expressions, if any. |
| * If no grouping expressions are specified, any previously |
| * added grouping expressions are simply removed. |
| * @param grouping list of zero or more grouping expressions |
| * @return the modified query |
| */ |
| @Override |
| public AbstractQuery<T> groupBy(List<Expression<?>> grouping){ |
| this.groupBy = grouping; |
| return this; |
| } |
| |
| |
| /** |
| * Specify the expressions that are used to form groups over the query |
| * results. Replaces the previous specified grouping expressions, if any. If |
| * no grouping expressions are specified, any previously added grouping |
| * expressions are simply removed. |
| * |
| * @param grouping |
| * zero or more grouping expressions |
| * @return the modified query |
| */ |
| @Override |
| public AbstractQuery<T> groupBy(Expression<?>... grouping){ |
| this.groupBy = new ArrayList<Expression<?>>(); |
| for (Expression<?> exp : grouping){ |
| this.groupBy.add(exp); |
| } |
| return this; |
| } |
| |
| /** |
| * Specify a restriction over the groups of the query. Replaces the previous |
| * having restriction(s), if any. |
| * |
| * @param restriction |
| * a simple or compound boolean expression |
| * @return the modified query |
| */ |
| @Override |
| public AbstractQuery<T> having(Expression<Boolean> restriction) { |
| findRootAndParameters(restriction); |
| if (((InternalExpression)restriction).isCompoundExpression() || ((InternalExpression)restriction).isPredicate()) { |
| this.havingClause = (Predicate) restriction; |
| } else { |
| this.havingClause = queryBuilder.isTrue(restriction); |
| } |
| return this; |
| } |
| |
| /** |
| * Specify restrictions over the groups of the query according 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 |
| */ |
| @Override |
| public AbstractQuery<T> having(Predicate... restrictions){ |
| if (restrictions != null && restrictions.length > 0) { |
| Predicate conjunction = this.queryBuilder.conjunction(); |
| for (Predicate predicate : restrictions) { |
| conjunction = this.queryBuilder.and(conjunction, predicate); |
| } |
| findRootAndParameters(conjunction); |
| this.havingClause = conjunction; |
| } |
| return this; |
| } |
| |
| public abstract void addJoin(FromImpl join); |
| |
| /** |
| * Specify whether duplicate query results will be eliminated. A true value |
| * will cause duplicates to be eliminated. A false value will cause |
| * duplicates to be retained. If distinct has not been specified, duplicate |
| * results must be retained. This method only overrides the return type of |
| * the corresponding AbstractQuery method. |
| * |
| * @param distinct |
| * boolean value specifying whether duplicate results must be |
| * eliminated from the query result or whether they must be |
| * retained |
| * @return the modified query. |
| */ |
| @Override |
| public AbstractQuery<T> distinct(boolean distinct){ |
| this.distinct= distinct; |
| return this; |
| } |
| |
| @Override |
| protected org.eclipse.persistence.expressions.Expression getBaseExpression() { |
| return getBaseExpression(null); |
| } |
| |
| protected org.eclipse.persistence.expressions.Expression getBaseExpression(Root root) { |
| if (this.roots.isEmpty()) { |
| baseExpression = new ExpressionBuilder(); |
| } else if (this.roots.size() == 1) { |
| baseExpression = ((RootImpl) this.roots.iterator().next()).getCurrentNode(); |
| } else if (root != null) { |
| for (Root r : this.roots) { |
| if (r == root) { |
| baseExpression = ((RootImpl) r).getCurrentNode(); |
| } |
| } |
| } |
| return baseExpression; |
| } |
| |
| /** |
| * Return a list of the grouping expressions |
| * @return the list of grouping expressions |
| */ |
| @Override |
| public List<Expression<?>> getGroupList(){ |
| if (this.groupBy == null){ |
| this.groupBy = new ArrayList<Expression<?>>(); |
| } |
| return this.groupBy; |
| } |
| |
| /** |
| * Return the predicate that corresponds to the restriction(s) over the |
| * grouping items. |
| * |
| * @return having clause predicate |
| */ |
| @Override |
| public Predicate getGroupRestriction(){ |
| return this.havingClause; |
| } |
| |
| /** |
| * Return the query roots. |
| * |
| * @return the set of query roots |
| */ |
| @Override |
| public Set<Root<?>> getRoots(){ |
| return this.roots; |
| } |
| |
| @Override |
| protected void integrateRoot(RootImpl root) { |
| if (!this.roots.contains(root)) { |
| this.roots.add(root); |
| } |
| } |
| |
| /** |
| * Return whether duplicate query results must be eliminated or retained. |
| * |
| * @return boolean indicating whether duplicate query results must be |
| * eliminated |
| */ |
| @Override |
| public boolean isDistinct(){ |
| return this.distinct; |
| } |
| |
| protected void findJoins(FromImpl root) { |
| root.findJoins(this); |
| } |
| |
| /** |
| * 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 |
| */ |
| @Override |
| public <X> Root<X> from(EntityType<X> entity) { |
| return this.internalFrom(entity); |
| } |
| |
| /** |
| * 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 |
| */ |
| @Override |
| public <X> Root<X> from(Class<X> entityClass) { |
| return this.internalFrom(entityClass); |
| } |
| |
| // override the return type only: |
| /** |
| * Modify the query to restrict the query result according to the specified |
| * boolean expression. Replaces the previously added restriction(s), if any. |
| * This method only overrides the return type of the corresponding |
| * AbstractQuery method. |
| * |
| * @param restriction |
| * a simple or compound boolean expression |
| * @return the modified query |
| */ |
| @Override |
| public AbstractQuery<T> where(Expression<Boolean> restriction){ |
| return (AbstractQuery<T>)super.where(restriction); |
| } |
| |
| /** |
| * Modify the query to restrict the query result 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. This |
| * method only overrides the return type of the corresponding AbstractQuery |
| * method. |
| * |
| * @param restrictions |
| * zero or more restriction predicates |
| * @return the modified query |
| */ |
| @Override |
| public AbstractQuery<T> where(Predicate... restrictions) { |
| return (AbstractQuery<T>) super.where(restrictions); |
| } |
| |
| } |