All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.jpa.jpql.tools.resolver.FromSubqueryResolver Maven / Gradle / Ivy

There is a newer version: 4.0.3
Show newest version
/*******************************************************************************
 * Copyright (c) 2012, 2014 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 v1.0 and Eclipse Distribution License v. 1.0
 * which accompanies this distribution.
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 *     Oracle - initial API and implementation
 *
 ******************************************************************************/
package org.eclipse.persistence.jpa.jpql.tools.resolver;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.persistence.jpa.jpql.ExpressionTools;
import org.eclipse.persistence.jpa.jpql.parser.AbsExpression;
import org.eclipse.persistence.jpa.jpql.parser.AbstractEclipseLinkExpressionVisitor;
import org.eclipse.persistence.jpa.jpql.parser.AdditionExpression;
import org.eclipse.persistence.jpa.jpql.parser.AvgFunction;
import org.eclipse.persistence.jpa.jpql.parser.CollectionExpression;
import org.eclipse.persistence.jpa.jpql.parser.ConcatExpression;
import org.eclipse.persistence.jpa.jpql.parser.CountFunction;
import org.eclipse.persistence.jpa.jpql.parser.DivisionExpression;
import org.eclipse.persistence.jpa.jpql.parser.Expression;
import org.eclipse.persistence.jpa.jpql.parser.IndexExpression;
import org.eclipse.persistence.jpa.jpql.parser.LengthExpression;
import org.eclipse.persistence.jpa.jpql.parser.LocateExpression;
import org.eclipse.persistence.jpa.jpql.parser.LowerExpression;
import org.eclipse.persistence.jpa.jpql.parser.MaxFunction;
import org.eclipse.persistence.jpa.jpql.parser.MinFunction;
import org.eclipse.persistence.jpa.jpql.parser.ResultVariable;
import org.eclipse.persistence.jpa.jpql.parser.SimpleSelectClause;
import org.eclipse.persistence.jpa.jpql.parser.SimpleSelectStatement;
import org.eclipse.persistence.jpa.jpql.parser.SizeExpression;
import org.eclipse.persistence.jpa.jpql.parser.SqrtExpression;
import org.eclipse.persistence.jpa.jpql.parser.StateFieldPathExpression;
import org.eclipse.persistence.jpa.jpql.parser.SubstringExpression;
import org.eclipse.persistence.jpa.jpql.parser.SubtractionExpression;
import org.eclipse.persistence.jpa.jpql.parser.SumFunction;
import org.eclipse.persistence.jpa.jpql.parser.TrimExpression;
import org.eclipse.persistence.jpa.jpql.parser.UpperExpression;
import org.eclipse.persistence.jpa.jpql.tools.JPQLQueryContext;
import org.eclipse.persistence.jpa.jpql.tools.spi.IManagedType;
import org.eclipse.persistence.jpa.jpql.tools.spi.IManagedTypeProvider;
import org.eclipse.persistence.jpa.jpql.tools.spi.IManagedTypeVisitor;
import org.eclipse.persistence.jpa.jpql.tools.spi.IMapping;
import org.eclipse.persistence.jpa.jpql.tools.spi.IMappingType;
import org.eclipse.persistence.jpa.jpql.tools.spi.IType;
import org.eclipse.persistence.jpa.jpql.tools.spi.ITypeDeclaration;
import org.eclipse.persistence.jpa.jpql.tools.utility.iterable.SnapshotCloneIterable;
import static org.eclipse.persistence.jpa.jpql.LiteralType.*;

/**
 * This {@link Resolver} wraps a subquery that is used as the "root" object in a query's declaration.
 * 

* Example: * *

   SELECT e.firstName
 * FROM Employee e, (SELECT count(e2), e2.firstName FROM Employee e2) e3
 * WHERE e.firstName = e3.firstName
* * @version 2.5 * @since 2.4 * @author Pascal Filion */ public class FromSubqueryResolver extends Resolver { /** * The virtual {@link IManagedType} representing the subquery. */ private IManagedType managedType; /** * The {@link JPQLQueryContext} is used to query information about the application metadata and * cached information. */ private JPQLQueryContext queryContext; /** * The subquery being defined as a "root" object. */ private SimpleSelectStatement subquery; /** * Creates a new FromSubqueryResolver. * * @param parent The parent of this resolver, which is never null * @param queryContext The context used to query information about the application metadata and * cached information * @param subquery * @exception NullPointerException If the parent is null */ public FromSubqueryResolver(Resolver parent, JPQLQueryContext queryContext, SimpleSelectStatement subquery) { super(parent); this.subquery = subquery; this.queryContext = queryContext; } /** * {@inheritDoc} */ @Override protected IType buildType() { return getManagedType().getType(); } /** * {@inheritDoc} */ @Override protected ITypeDeclaration buildTypeDeclaration() { return getType().getTypeDeclaration(); } /** * {@inheritDoc} */ @Override public IManagedType getManagedType() { if (managedType == null) { managedType = new VirtualManagedType(); } return managedType; } private enum MappingType { PROPERTY, RELATIONSHIP, UNKNOWN } /** * This {@link IManagedType} represents a virtual managed type where its content will be derived * from the subquery. */ protected class VirtualManagedType implements IManagedType { /** * The virtual {@link IMapping mappings} representing what is selected. */ private Map mappings; /** * {@inheritDoc} */ public void accept(IManagedTypeVisitor visitor) { } /** * {@inheritDoc} */ public int compareTo(IManagedType managedType) { return getType().getName().compareTo(managedType.getType().getName()); } /** * {@inheritDoc} */ public IMapping getMappingNamed(String name) { initializeMappings(); return mappings.get(name); } /** * {@inheritDoc} */ public IManagedTypeProvider getProvider() { return FromSubqueryResolver.this.getProvider(); } /** * {@inheritDoc} */ public IType getType() { return getProvider().getTypeRepository().getType(IType.UNRESOLVABLE_TYPE); } private void initializeMappings() { if (mappings == null) { mappings = new HashMap(); // Create virtual mappings that wraps the select items VirtualMappingBuilder builder = new VirtualMappingBuilder(); builder.parent = this; builder.mappings = mappings; subquery.accept(builder); } } /** * {@inheritDoc} */ public Iterable mappings() { initializeMappings(); return new SnapshotCloneIterable(mappings.values()); } } /** * This virtual {@link IMapping} wraps one of the select items. */ protected class VirtualMapping implements IMapping { private MappingType mappingType; private String name; private IManagedType parent; private Resolver resolver; protected VirtualMapping(IManagedType parent, String name, Resolver resolver, MappingType mappingType) { super(); this.name = name; this.parent = parent; this.resolver = resolver; this.mappingType = mappingType; } /** * {@inheritDoc} */ public int compareTo(IMapping mapping) { return getName().compareTo(mapping.getName()); } /** * {@inheritDoc} */ public int getMappingType() { IMapping mapping = resolver.getMapping(); return (mapping != null) ? mapping.getMappingType() : IMappingType.TRANSIENT; } /** * {@inheritDoc} */ public String getName() { return name; } /** * {@inheritDoc} */ public IManagedType getParent() { return parent; } /** * {@inheritDoc} */ public IType getType() { return resolver.getType(); } /** * {@inheritDoc} */ public ITypeDeclaration getTypeDeclaration() { return resolver.getTypeDeclaration(); } /** * {@inheritDoc} */ public boolean hasAnnotation(Class annotationType) { // TODO: Can we do this??? return getType().hasAnnotation(annotationType); } /** * {@inheritDoc} */ public boolean isCollection() { IMapping mapping = resolver.getMapping(); return (mapping != null) ? mapping.isCollection() : false; } /** * {@inheritDoc} */ public boolean isProperty() { IMapping mapping = resolver.getMapping(); return (mapping != null) ? mapping.isProperty() : (mappingType == MappingType.PROPERTY); } /** * {@inheritDoc} */ public boolean isRelationship() { IMapping mapping = resolver.getMapping(); return (mapping != null) ? mapping.isRelationship() : (mappingType == MappingType.RELATIONSHIP); } /** * {@inheritDoc} */ public boolean isTransient() { IMapping mapping = resolver.getMapping(); return (mapping != null) ? mapping.isTransient() : false; } /** * {@inheritDoc} */ @Override public String toString() { return name; } } /** * This visitor will traverse the SELECT clause and create virtual mappings * for the state field path expressions and any expression aliased with a result variable. */ protected class VirtualMappingBuilder extends AbstractEclipseLinkExpressionVisitor { /** * The virtual {@link IMapping} that wraps a select item mapped with the result variable if * one was defined otherwise the name will be generated based on the type of select item. */ private Map mappings; /** * */ private MappingType mappingType; /** * The virtual {@link IManagedType}. */ protected IManagedType parent; /** * Creates a new VirtualMappingBuilder. */ public VirtualMappingBuilder() { super(); mappingType = MappingType.UNKNOWN; } /** * Creates * * @param name * @param resolver * @return */ protected IMapping buildMapping(String name, Resolver resolver) { return new VirtualMapping(parent, name, resolver, mappingType); } /** * {@inheritDoc} */ @Override public void visit(AbsExpression expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(AdditionExpression expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(AvgFunction expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(CollectionExpression expression) { expression.acceptChildren(this); } /** * {@inheritDoc} */ @Override public void visit(ConcatExpression expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(CountFunction expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(DivisionExpression expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(IndexExpression expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(LengthExpression expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(LocateExpression expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(LowerExpression expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(MaxFunction expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(MinFunction expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(ResultVariable expression) { String name = queryContext.literal(expression, RESULT_VARIABLE); if (ExpressionTools.stringIsNotEmpty(name)) { // Visit the select expression in order to get a mapping type that could // help determine the mapping type Expression selectExpression = expression.getSelectExpression(); selectExpression.accept(this); // Retrieve the select expression's Resolver and wrap it with a virtual mapping Resolver resolver = queryContext.getResolver(selectExpression); mappings.put(name, buildMapping(name, resolver)); } } /** * {@inheritDoc} */ @Override public void visit(SimpleSelectClause expression) { expression.getSelectExpression().accept(this); } /** * {@inheritDoc} */ @Override public void visit(SimpleSelectStatement expression) { expression.getSelectClause().accept(this); } /** * {@inheritDoc} */ @Override public void visit(SizeExpression expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(SqrtExpression expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(StateFieldPathExpression expression) { if (!expression.startsWithDot()) { String name = queryContext.literal(expression, PATH_EXPRESSION_LAST_PATH); if (ExpressionTools.stringIsNotEmpty(name)) { mappingType = MappingType.UNKNOWN; Resolver resolver = queryContext.getResolver(expression); mappings.put(name, buildMapping(name, resolver)); } } } /** * {@inheritDoc} */ @Override public void visit(SubstringExpression expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(SubtractionExpression expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(SumFunction expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(TrimExpression expression) { mappingType = MappingType.PROPERTY; } /** * {@inheritDoc} */ @Override public void visit(UpperExpression expression) { mappingType = MappingType.PROPERTY; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy