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

com.blazebit.persistence.impl.EntitySelectResolveVisitor Maven / Gradle / Ivy

There is a newer version: 1.6.12
Show newest version
/*
 * Copyright 2014 - 2019 Blazebit.
 *
 * Licensed 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 com.blazebit.persistence.impl;

import com.blazebit.persistence.parser.EntityMetamodel;
import com.blazebit.persistence.parser.expression.FunctionExpression;
import com.blazebit.persistence.parser.expression.ListIndexExpression;
import com.blazebit.persistence.parser.expression.MapEntryExpression;
import com.blazebit.persistence.parser.expression.MapKeyExpression;
import com.blazebit.persistence.parser.expression.MapValueExpression;
import com.blazebit.persistence.parser.expression.PathElementExpression;
import com.blazebit.persistence.parser.expression.PathExpression;
import com.blazebit.persistence.parser.expression.PropertyExpression;
import com.blazebit.persistence.parser.expression.VisitorAdapter;
import com.blazebit.persistence.spi.ExtendedAttribute;
import com.blazebit.persistence.spi.ExtendedManagedType;
import com.blazebit.persistence.spi.JpaProvider;

import javax.persistence.FetchType;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * This visitor resolves entity references to their attributes. This is needed for entity references
 * in the select clause when used in combination with aggregate functions. We have to decompose the
 * entity and add the components to the group by because all components will end up in the select clause.
 * Only until grouping by entities is resolved: https://hibernate.atlassian.net/browse/HHH-1615
 * 
 * @author Christian Beikov
 * @since 1.0.5
 */
public class EntitySelectResolveVisitor extends VisitorAdapter {

    private final EntityMetamodel m;
    private final JpaProvider jpaProvider;
    private final Set pathExpressions;

    private JoinNode rootNode;

    public EntitySelectResolveVisitor(EntityMetamodel m, JpaProvider jpaProvider, Set pathExpressions) {
        this.m = m;
        this.jpaProvider = jpaProvider;
        this.pathExpressions = pathExpressions;
    }

    public JoinNode getRootNode() {
        return rootNode;
    }

    @Override
    public void visit(FunctionExpression expression) {
        // Skip all functions in here
    }

    @Override
    public void visit(PathExpression expression) {
        if (expression.getField() == null) {
            /**
             * We need to resolve entity selects because hibernate will
             * select every entity attribute. Since we need every select in
             * the group by (because of DB2) we need to resolve such entity
             * selects here
             */
            rootNode = ((JoinNode) expression.getBaseNode());
            if (rootNode == null) {
                // This is an alias expression to a complex expression
                return;
            }
            EntityType entityType = m.getEntity(rootNode.getJavaType());
            if (entityType == null) {
                // ignore if the expression is not an entity
                return;
            }

            // TODO: a polymorphic query will fail because we don't collect subtype properties
            ExtendedManagedType extendedManagedType = m.getManagedType(ExtendedManagedType.class, entityType);
            Set attributePaths;
            if (rootNode.getValuesIdNames() != null && !rootNode.getValuesIdNames().isEmpty()) {
                attributePaths = rootNode.getValuesIdNames();
            } else {
                attributePaths = Collections.emptySet();
            }
            Map> ownedSingularAttributes = (Map>) (Map) extendedManagedType.getOwnedSingularAttributes();
            Collection propertyPaths = JpaUtils.getEmbeddedPropertyPaths(ownedSingularAttributes, null, jpaProvider.needsElementCollectionIdCutoff(), true);
            for (String propertyPath : propertyPaths) {
                // Skip if the attribute is not in the desired attribute paths
                if (!attributePaths.isEmpty() && !attributePaths.contains(propertyPath)) {
                    continue;
                }
                ExtendedAttribute extendedAttribute = ownedSingularAttributes.get(propertyPath);
                Attribute attr = extendedAttribute.getAttribute();
                boolean resolve = false;
                if (ExpressionUtils.isAssociation(attr) && !attr.isCollection()) {
                    resolve = true;
                } else if (ExpressionUtils.getFetchType(attr) == FetchType.EAGER) {
                    if (attr.getPersistentAttributeType() == Attribute.PersistentAttributeType.ELEMENT_COLLECTION) {
                        throw new UnsupportedOperationException("Eager element collections are not supported");
                    }
                    resolve = true;
                }

                if (resolve) {
                    List paths = new ArrayList<>(expression.getExpressions().size() + 1);
                    paths.addAll(expression.getExpressions());
                    for (Attribute attribute : extendedAttribute.getAttributePath()) {
                        paths.add(new PropertyExpression(attribute.getName()));
                    }
                    PathExpression attrPath = new PathExpression(paths);
                    attrPath.setPathReference(new SimplePathReference(rootNode, propertyPath, m.type(extendedAttribute.getElementClass())));
                    pathExpressions.add(attrPath);
                }
            }
        }
    }

    /* Skip the expressions that are not really entity expressions */

    @Override
    public void visit(ListIndexExpression expression) {
    }

    @Override
    public void visit(MapEntryExpression expression) {
    }

    @Override
    public void visit(MapKeyExpression expression) {
    }

    @Override
    public void visit(MapValueExpression expression) {
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy