org.apache.openjpa.persistence.criteria.SubqueryImpl Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.persistence.criteria;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.persistence.criteria.AbstractQuery;
import javax.persistence.criteria.CollectionJoin;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.ListJoin;
import javax.persistence.criteria.MapJoin;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.SetJoin;
import javax.persistence.criteria.Subquery;
import javax.persistence.metamodel.EntityType;
import org.apache.openjpa.kernel.exps.Context;
import org.apache.openjpa.kernel.exps.ExpressionFactory;
import org.apache.openjpa.kernel.exps.QueryExpressions;
import org.apache.openjpa.kernel.exps.Value;
import org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.ValueMetaData;
import org.apache.openjpa.persistence.meta.AbstractManagedType;
import org.apache.openjpa.persistence.meta.MetamodelImpl;
import org.apache.openjpa.persistence.meta.Types;
/**
* Subquery is an expression which itself is a query and always appears in the
* context of a parent query. A subquery delegates to a captive query for most
* of the operations but also maintains its own joins and correlated joins.
*
* @param the type selected by this subquery.
*
* @author Pinaki Poddar
* @author Fay Wang
*
* @since 2.0.0
*/
class SubqueryImpl extends ExpressionImpl implements Subquery {
private final AbstractQuery> _parent;
private final CriteriaQueryImpl _delegate;
private final MetamodelImpl _model;
private org.apache.openjpa.kernel.exps.Subquery _subq;
private List> _corrJoins = null;
/**
* Construct a subquery always in the context of a parent query.
*
* @param cls the result type of this subquery
* @param parent the non-null parent query which itself can be a subquery.
*/
SubqueryImpl(Class cls, AbstractQuery> parent) {
super(cls);
_parent = parent;
if (parent instanceof CriteriaQueryImpl) {
_model = ((CriteriaQueryImpl>)parent).getMetamodel();
} else if (parent instanceof SubqueryImpl) {
_model = ((SubqueryImpl>)parent).getMetamodel();
} else {
_model = null;
}
_delegate = new CriteriaQueryImpl(_model, this);
}
/**
* Gets the parent query of this subquery.
* Can be a query or another subquery.
*/
public AbstractQuery> getParent() {
return _parent;
}
/**
* Gets the captive query to which this subquery delegates.
*/
CriteriaQueryImpl getDelegate() {
return _delegate;
}
public MetamodelImpl getMetamodel() {
return _model;
}
Stack getContexts() {
return getInnermostParent().getContexts();
}
/**
* Gets the 'root' query for this subquery.
*/
public CriteriaQueryImpl> getInnermostParent() {
return (CriteriaQueryImpl>)(((_parent instanceof CriteriaQueryImpl)) ?
_parent : ((SubqueryImpl>)_parent).getInnermostParent());
}
public Subquery select(Expression expression) {
_delegate.select(expression);
return this;
}
public Expression getSelection() {
return (Expression)_delegate.getSelection();
}
public Root from(EntityType entity) {
return _delegate.from(entity);
}
public Root from(Class entityClass) {
return _delegate.from(entityClass);
}
public Set> getRoots() {
return _delegate.getRoots();
}
public Root> getRoot() {
return _delegate.getRoot(false);
}
public Subquery where(Expression restriction) {
_delegate.where(restriction);
return this;
}
public Subquery where(Predicate... restrictions) {
_delegate.where(restrictions);
return this;
}
public Subquery groupBy(Expression>... grouping) {
_delegate.groupBy(grouping);
return this;
}
public Subquery groupBy(List> grouping) {
_delegate.groupBy(grouping);
return this;
}
public Subquery having(Expression restriction) {
_delegate.having(restriction);
return this;
}
public Subquery having(Predicate... restrictions) {
_delegate.having(restrictions);
return this;
}
public Subquery distinct(boolean distinct) {
_delegate.distinct(distinct);
return this;
}
public List> getGroupList() {
return _delegate.getGroupList();
}
public Predicate getRestriction() {
return _delegate.getRestriction();
}
public Predicate getGroupRestriction() {
return _delegate.getGroupRestriction();
}
public boolean isDistinct() {
return _delegate.isDistinct();
}
public Subquery subquery(Class type) {
return new SubqueryImpl(type, this);
}
/**
* Correlate this subquery with the given root.
*/
public Root correlate(Root root) {
Types.Entity entity = (Types.Entity)root.getModel();
RootImpl corrRoot = new RootImpl(entity);
corrRoot.setCorrelatedPath((RootImpl)root);
_delegate.addRoot(corrRoot);
return corrRoot;
}
public Set> getCorrelatedJoins() {
return _corrJoins == null ? Collections.emptySet() : new CopyOnWriteArraySet(_corrJoins);
}
/**
* Correlate this subquery with the given join.
*/
public Join correlate(Join parentJoin) {
Join,?> corrJoin = Joins.clone(parentJoin);
((PathImpl,?>)corrJoin).setCorrelatedPath((PathImpl,?>)parentJoin);
if (_corrJoins == null)
_corrJoins = new ArrayList>();
_corrJoins.add(corrJoin);
return (Join)corrJoin;
}
/**
* Affirms if this is a correlated subquery.
*/
public boolean isCorrelated() {
return _corrJoins != null;
}
public CollectionJoin correlate(CollectionJoin parentJoin) {
Join corrJoin = Joins.clone((Joins.Collection)parentJoin);
((PathImpl,?>)corrJoin).setCorrelatedPath((PathImpl,?>)parentJoin);
if (_corrJoins == null)
_corrJoins = new ArrayList>();
_corrJoins.add(corrJoin);
return (CollectionJoin)corrJoin;
}
public SetJoin correlate(SetJoin parentJoin) {
Join corrJoin = Joins.clone((Joins.Set)parentJoin);
((PathImpl,?>)corrJoin).setCorrelatedPath((PathImpl,?>)parentJoin);
if (_corrJoins == null)
_corrJoins = new ArrayList>();
_corrJoins.add(corrJoin);
return (SetJoin)corrJoin;
}
public ListJoin correlate(ListJoin parentJoin) {
Join corrJoin = Joins.clone((Joins.List)parentJoin);
((PathImpl,?>)corrJoin).setCorrelatedPath((PathImpl,?>)parentJoin);
if (_corrJoins == null)
_corrJoins = new ArrayList>();
_corrJoins.add(corrJoin);
return (ListJoin)corrJoin;
}
public MapJoin correlate(MapJoin parentJoin) {
Join corrJoin = Joins.clone((Joins.Map)parentJoin);
((PathImpl,?>)corrJoin).setCorrelatedPath((PathImpl,?>)parentJoin);
if (_corrJoins == null)
_corrJoins = new ArrayList>();
_corrJoins.add(corrJoin);
return (MapJoin)corrJoin;
}
org.apache.openjpa.kernel.exps.Subquery getSubQ() {
return _subq;
}
/**
* Convert this path to a kernel path value.
*/
@Override
public Value toValue(ExpressionFactory factory, CriteriaQueryImpl> q) {
final boolean subclasses = true;
CriteriaExpressionBuilder exprBuilder = new CriteriaExpressionBuilder();
String alias = q.getAlias(this);
ClassMetaData candidate = getCandidate();
_subq = factory.newSubquery(candidate, subclasses, alias);
_subq.setMetaData(candidate);
Stack contexts = getContexts();
Context context = new Context(null, _subq, contexts.peek());
contexts.push(context);
_delegate.setContexts(contexts);
QueryExpressions subexp = exprBuilder.getQueryExpressions(factory, _delegate);
_subq.setQueryExpressions(subexp);
if (subexp.projections.length > 0)
JPQLExpressionBuilder.checkEmbeddable(subexp.projections[0], null);
contexts.pop();
return _subq;
}
// if we are in a subquery against a collection from a
// correlated parent, the candidate of the subquery
// should be the class metadata of the collection element
private ClassMetaData getCandidate() {
if (getRoots().isEmpty() && _corrJoins != null) {
FromImpl,?> corrJoin = (FromImpl,?>) _corrJoins.get(0);
if (corrJoin.getJoins() != null) {
FromImpl,?> join = (FromImpl,?>)corrJoin.getJoins().iterator().next();
return getInnermostCandidate(join);
}
}
RootImpl> root = (RootImpl>)getRoot();
if (root != null && root.getCorrelatedPath() != null && !root.getJoins().isEmpty()) {
FromImpl,?> join = (FromImpl,?>) root.getJoins().iterator().next();
return getInnermostCandidate(join);
}
return ((AbstractManagedType>)root.getModel()).meta;
}
private ClassMetaData getInnermostCandidate(FromImpl,?> from) {
if (!from.getJoins().isEmpty()) {
from = (FromImpl,?>) from.getJoins().iterator().next();
return getInnermostCandidate(from);
}
return getCandidate(from);
}
private ClassMetaData getCandidate(FromImpl,?> from) {
return getFieldType(from._member.fmd);
}
private static ClassMetaData getFieldType(FieldMetaData fmd) {
if (fmd == null)
return null;
ClassMetaData cmd = null;
ValueMetaData vmd;
if ((vmd = fmd.getElement()) != null)
cmd = vmd.getDeclaredTypeMetaData();
else if ((vmd = fmd.getKey()) != null)
cmd = vmd.getDeclaredTypeMetaData();
else if ((vmd = fmd.getValue()) != null)
cmd = vmd.getDeclaredTypeMetaData();
if (cmd == null || cmd.getDescribedType() == Object.class)
cmd = fmd.getDeclaredTypeMetaData();
if (cmd == null && fmd.isElementCollection())
cmd = fmd.getDefiningMetaData();
return cmd;
}
public Class getResultType() {
return getJavaType();
}
public StringBuilder asValue(AliasContext q) {
StringBuilder buffer = new StringBuilder();
_delegate.render(buffer, _delegate.getRoots(), _corrJoins);
return buffer;
}
public StringBuilder asVariable(AliasContext q) {
return asValue(q);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy