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

com.blazebit.persistence.spi.JpaProvider Maven / Gradle / Ivy

/*
 * Copyright 2014 - 2020 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.spi;

import com.blazebit.persistence.JoinType;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.ManagedType;
import java.util.List;
import java.util.Map;

/**
 * A JPA provider implementation provides information about which features are supported by a JPA implementation.
 *
 * @author Christian Beikov
 * @since 1.2.0
 */
public interface JpaProvider {

    /**
     * Whether JPA 2.1 specification is supported.
     *
     * @return True if JPA 2.1 is supported, false otherwise
     */
    public boolean supportsJpa21();

    /**
     * Whether Entity Joins are supported.
     *
     * @return True if Entity Joins are supported, false otherwise
     */
    public boolean supportsEntityJoin();

    /**
     * Whether Insert statements are supported.
     *
     * @return True if Insert statements are supported, false otherwise
     */
    public boolean supportsInsertStatement();

    /**
     * Whether brackets are needed around a list parameter.
     *
     * @return True if brackets are needed, false otherwise
     */
    public boolean needsBracketsForListParameter();

    /**
     * Returns whether key restricted left joins should be rewritten to subquery joins.
     * This is part of the workaround for https://hibernate.atlassian.net/browse/HHH-9329 which makes key restricted left joins wrong.
     *
     * @return true if joins should be rewritten to subquery joins, false otherwise
     */
    public boolean needsJoinSubqueryRewrite();

    /**
     * The JPQL expression to use for the given literal boolean value.
     * This expression is used in contexts where an expression is assumed.
     *
     * @param value The boolean value
     * @return The JPQL expression to use to reflect the boolean value
     */
    public String getBooleanExpression(boolean value);

    /**
     * The JPQL conditional expression to use for the given literal boolean value.
     * This expression is used in contexts where a predicate is assumed.
     *
     * @param value The boolean value
     * @return The JPQL conditional expression to use to reflect the boolean value
     */
    public String getBooleanConditionalExpression(boolean value);

    /**
     * The JPQL expression to use for the NULL literal.
     *
     * @return The JPQL expression to use to reflect the NULL value
     */
    public String getNullExpression();

    /**
     * The name of the clause that has the same semantics as the ON clause which was introduced in JPA 2.1.
     *
     * @return The name of the ON clause
     */
    public String getOnClause();

    /**
     * Normally returns VALUE, but since Hibernate does weird things when using that, it returns null.
     * Returning null results in omitting VALUE in the final query that is passed to the JPA provider.
     *
     * @return The value function
     */
    public String getCollectionValueFunction();

    /**
     * Whether dereferencing a VALUE function expression is supported by the JPA provider.
     *
     * @return True if dereferencing is supported, false otherwise
     */
    public boolean supportsCollectionValueDereference();

    /**
     * The default result type of a scalar query.
     *
     * @return The default result type
     */
    public Class getDefaultQueryResultType();

    /**
     * Returns the start of a JPQL representation of a function invocation for the given function name and argument count.
     * Normally this returns FUNCTION('functionName', but implementations may also allow to render the function name directly.
     *
     * @param functionName The function name
     * @param argumentCount The number of the arguments that the function is invoked with
     * @return The start of the JPQL represenation for the function invocation
     */
    public String getCustomFunctionInvocation(String functionName, int argumentCount);

    /**
     * The given escape character for a LIKE predicate as string.
     *
     * @param character The escape character
     * @return The string representation
     */
    public String escapeCharacter(char character);

    /**
     * Whether the query language supports the null precedence clause.
     *
     * @return True if the null precedence clause is supported, false otherwise
     */
    public boolean supportsNullPrecedenceExpression();

    /**
     * Renders the null precedence into the given string builder.
     *
     * @param sb The builder to which the null precedence should be appended to
     * @param expression The order by expression which might be a select alias
     * @param resolvedExpression The resolved expression for a possible select alias or the expression
     * @param order The order as string (ASC or DESC)
     * @param nulls The null precedence as string (NULLS FIRST or NULLS LAST)
     */
    public void renderNullPrecedence(StringBuilder sb, String expression, String resolvedExpression, String order, String nulls);

    /**
     * Whether treating a from/root alias is supported.
     * For example SELECT TREAT(alias AS Subtype).property FROM ..
     *
     * @return True if treating a from alias is supported, false otherwise
     */
    public boolean supportsRootTreat();

    /**
     * Whether a treat join is supported.
     * For example SELECT ... FROM .. JOIN TREAT(alias.relation AS Subtype)
     *
     * @return True if a treat join is supported, false otherwise
     */
    public boolean supportsTreatJoin();

    /**
     * Whether a correlation path with a treat expression is supported.
     * For example SELECT (SELECT .. FROM TREAT(parent AS Subtype).relation) FROM ..
     *
     * @return True if a treat in correlation expressions is supported, false otherwise
     */
    public boolean supportsTreatCorrelation();

    /**
     * Whether a root treat in a join is supported.
     * For example SELECT ... FROM .. JOIN TREAT(alias AS Subtype).relation
     *
     * @return True if a root treat in a join is supported, false otherwise
     */
    public boolean supportsRootTreatJoin();

    /**
     * Whether a root treat in a treat join is supported.
     * For example SELECT ... FROM .. JOIN TREAT(TREAT(alias AS Subtype).relation AS Subtype)
     *
     * @return True if a root treat in a treat join is supported, false otherwise
     */
    public boolean supportsRootTreatTreatJoin();

    /**
     * Whether properties accessed of a from node are implicitly resolved to properties of a subtype of the from node.
     *
     * @return True if subtype property resolving is supported, false otherwise
     */
    public boolean supportsSubtypePropertyResolving();

    /**
     * Whether relations of a from node in joins are implicitly resolved to the relations of a subtype of the from node.
     *
     * @return True if subtype relation resolving is supported, false otherwise
     */
    public boolean supportsSubtypeRelationResolving();

    /**
     * Whether the COUNT(*) syntax is supported.
     *
     * @return True if COUNT(*) syntax is supported, false otherwise
     */
    public boolean supportsCountStar();

    /**
     * Whether the custom functions are supported.
     *
     * @return True if custom functions are supported, false otherwise
     * @since 1.4.0
     */
    public boolean supportsCustomFunctions();

    /**
     * Whether the non scalar subqueries are supported.
     *
     * @return True if non scalar subqueries are supported, false otherwise
     * @since 1.4.1
     */
    public boolean supportsNonScalarSubquery();

    /**
     * Whether the subqueries in functions are supported.
     *
     * @return True if subqueries in functions are supported, false otherwise
     * @since 1.4.1
     */
    public boolean supportsSubqueryInFunction();

    /**
     * Whether the subqueries alias shadowing is supported.
     *
     * @return True if subqueries alias shadowing is supported, false otherwise
     * @since 1.4.1
     */
    public boolean supportsSubqueryAliasShadowing();

    /**
     * Returns an array with the column name of the discriminator of the given entity type and the discriminator value, or null.
     *
     * @param entityType The entity type
     * @return The column name of the discriminator and the discriminator value, or null
     * @since 1.3.0
     */
    public String[] getDiscriminatorColumnCheck(EntityType entityType);

    /**
     * Whether the join columns for the given attribute are in a foreign table.
     *
     * @param ownerType The owner of the attribute
     * @param attributeName The attribute name to check
     * @return True if join columns are in a foreign table, false otherwise
     */
    public boolean isForeignJoinColumn(EntityType ownerType, String attributeName);

    /**
     * Whether columns for the given attribute are shared between multiple subtypes
     * or shared by occupying the same slot in the resulting SQL.
     *
     * @param ownerType The owner of the attribute
     * @param attributeName The attribute name to check
     * @return True if columns of the attribute are shared, false otherwise
     */
    public boolean isColumnShared(EntityType ownerType, String attributeName);

    /**
     * Returns the column names of the attribute of the given entity type.
     *
     * @param ownerType The owner of the attribute
     * @param attributeName The attribute name
     * @return The column names of the attribute
     */
    public String[] getColumnNames(EntityType ownerType, String attributeName);

    /**
     * Returns the column names of the attribute of the given entity type within the element collection.
     *
     * @param ownerType The owner of the attribute
     * @param elementCollectionPath The path to the element collection within which the attribute is contained
     * @param attributeName The attribute name
     * @return The column names of the attribute
     * @since 1.3.0
     */
    public String[] getColumnNames(EntityType ownerType, String elementCollectionPath, String attributeName);

    /**
     * Returns the SQL column type names of the given attribute of the given entity type.
     *
     * @param ownerType The owner of the attribute
     * @param attributeName The attribute name
     * @return The SQL column type names for the attribute
     */
    public String[] getColumnTypes(EntityType ownerType, String attributeName);

    /**
     * Returns the SQL column type names of the given attribute of the given entity type within the element collection.
     *
     * @param ownerType The owner of the attribute
     * @param elementCollectionPath The path to the element collection within which the attribute is contained
     * @param attributeName The attribute name
     * @return The SQL column type names for the attribute
     * @since 1.3.0
     */
    public String[] getColumnTypes(EntityType ownerType, String elementCollectionPath, String attributeName);

    /**
     * Returns where to put treat filters for a treat joined association of this attribute.
     * This is for JPA providers that don't correctly filter the types.
     *
     * Hibernate for example does not automatically add the type constraint to treat joins of a type that uses
     * the table per class inheritance strategy.
     *
     * @param ownerType The declaring type of the attribute to check
     * @param attributeName The attribute name for which to check the treat filter requirement or null
     * @param joinType The join type used for the treat join
     * @return The constraint type for the treat filter
     */
    public ConstraintType requiresTreatFilter(EntityType ownerType, String attributeName, JoinType joinType);

    /**
     * If the given attribute is an inverse collection, the mapped by attribute name is returned.
     * Otherwise returns null.
     *
     * @param ownerType The declaring type of the attribute to check
     * @param attributeName The name of the inverse attribute for which to retrieve the mapped by value
     * @return The mapped by attribute name if the given attribute is an inverse collection, null otherwise
     */
    public String getMappedBy(EntityType ownerType, String attributeName);

    /**
     * If the given attribute is insertable = false and updatable = false it returns the writable mappings for the inverse type.
     * Otherwise returns null.
     *
     * @param inverseType The type containing the inverse relation
     * @param ownerType The declaring type of the attribute to check
     * @param attributeName The name of the attribute for which to retrieve the writable mapped by mapping
     * @param inverseAttribute The name of the inverse attribute for which to retrieve the writable mapped by mapping
     * @return The writable mappings for the inverse type if the attribute is not insertable or updatable, null otherwise
     */
    public Map getWritableMappedByMappings(EntityType inverseType, EntityType ownerType, String attributeName, String inverseAttribute);

    /**
     * If the given attribute is a collection that uses a join table, returns it's descriptor.
     * Otherwise returns null.
     *
     * @param ownerType The declaring type of the attribute to check
     * @param attributeName The name of the attribute for which to retrieve the join table name
     * @return The join table information if the attribute has one, null otherwise
     */
    public JoinTable getJoinTable(EntityType ownerType, String attributeName);

    /**
     * Whether the given attribute is a non-indexed and non-ordered collection a.k.a. a bag.
     *
     * @param ownerType The declaring type of the attribute to check
     * @param attributeName The name of the attribute to check
     * @return True if it is a bag, false otherwise
     */
    public boolean isBag(EntityType ownerType, String attributeName);

    /**
     * Whether orphan removal is activated for the given attribute.
     *
     * @param ownerType The declaring type of the attribute to check
     * @param attributeName The name of the attribute to check
     * @return True if orphan removal is activated, else false
     */
    public boolean isOrphanRemoval(ManagedType ownerType, String attributeName);

    /**
     * Whether orphan removal is activated for the given attribute within the element collection.
     *
     * @param ownerType The declaring type of the attribute to check
     * @param elementCollectionPath The path to the element collection within which the attribute is contained
     * @param attributeName The name of the attribute to check
     * @return True if orphan removal is activated, else false
     * @since 1.3.0
     */
    public boolean isOrphanRemoval(ManagedType ownerType, String elementCollectionPath, String attributeName);

    /**
     * Whether delete cascading is activated for the given attribute.
     *
     * @param ownerType The declaring type of the attribute to check
     * @param attributeName The name of the attribute to check
     * @return True if delete cascading is activated, else false
     */
    public boolean isDeleteCascaded(ManagedType ownerType, String attributeName);

    /**
     * Whether delete cascading is activated for the given attribute within the element collection.
     *
     * @param ownerType The declaring type of the attribute to check
     * @param elementCollectionPath The path to the element collection within which the attribute is contained
     * @param attributeName The name of the attribute to check
     * @return True if delete cascading is activated, else false
     * @since 1.3.0
     */
    public boolean isDeleteCascaded(ManagedType ownerType, String elementCollectionPath, String attributeName);

    /**
     * Whether the given attribute has a join condition.
     *
     * @param ownerType The declaring type of the attribute to check
     * @param elementCollectionPath The nullable path to the element collection within which the attribute is contained
     * @param attributeName The name of the attribute to check
     * @return True if it has a join condition, else false
     */
    public boolean hasJoinCondition(ManagedType ownerType, String elementCollectionPath, String attributeName);

    /**
     * Returns whether the entity with the id is contained in the entity managers persistence context.
     *
     * @param em The entity manager
     * @param entityClass The entity class
     * @param id The entity id
     * @return True if it is contained, false otherwise
     */
    public boolean containsEntity(EntityManager em, Class entityClass, Object id);

    /**
     * Indicates if the provider supports expressions like
     *
     *    doc.owner.id
     *
     * without generating an extra join.
     *
     * @return true if supported, else false
     */
    public boolean supportsSingleValuedAssociationIdExpressions();

    /**
     * Indicates if the provider supports the use of foreign associations in the ON clause.
     * This is the case when implicit joins in the ON clause are specially treated regarding SQL rendering.
     * If an expression like alias.association.property results in a subquery or table group join
     * when used in the ON clause, the JPA provider supports this feature. Normally this silently fails with invalid SQL.
     * By returning false, subqueries will be generated for such associations instead.
     *
     * The value is not yet used but will be in a future version. Also see: https://github.com/Blazebit/blaze-persistence/issues/402
     *
     * @return true if supported, else false
     */
    public boolean supportsForeignAssociationInOnClause();

    /**
     * Indicates whether an embeddable can be set via an update queries SET clause.
     * Although the JPA spec mandates this, it doesn't seem to be asserted so some providers don't support it.
     *
     * @return true if supported, else false
     */
    public boolean supportsUpdateSetEmbeddable();

    /**
     * Indicates whether an association id can be set via an update queries SET clause or if the association has to be set as a whole.
     *
     * @return true if supported, else false
     * @since 1.5.0
     */
    public boolean supportsUpdateSetAssociationId();


    /**
     * Indicates if the provider supports the use of transient entity objects as parameters.
     *
     * @return true if supported, else false
     */
    public boolean supportsTransientEntityAsParameter();

    /**
     * Indicates if the provider needs associations in the ON clause to use their id.
     * If needed, an expression like alias.association in the ON clause is rewritten to
     * alias.association.id.
     *
     * @return true if required, else false
     */
    public boolean needsAssociationToIdRewriteInOnClause();

    /**
     * Indicates if the provider needs associations in the ON clause to use their id.
     * If needed, an expression like alias.association in the ON clause is rewritten to
     * alias.association.id which relies on a broken type check in older Hibernate versions.
     *
     * @return true if required, else false
     */
    public boolean needsBrokenAssociationToIdRewriteInOnClause();

    /**
     * Indicates if the provider does column sharing for same named columns in inheritance mappings
     * and thus requires the use of a CASE WHEN expression for restricting casted accesses like e.g. TREAT(alias AS Subtype).property
     * to retain cast semantics.
     *
     * @return true if required, else false
     */
    public boolean needsTypeConstraintForColumnSharing();

    /**
     * Indicates whether the provider clears collection table entries on bulk delete operations.
     *
     * @return true if supported, else false
     */
    public boolean supportsCollectionTableCleanupOnDelete();

    /**
     * Indicates whether the provider clears join table entries on bulk delete operations.
     *
     * @return true if supported, else false
     */
    public boolean supportsJoinTableCleanupOnDelete();

    /**
     * Indicates whether the provider supports correlating inverse associations.
     *
     * @return true if needed, else false
     * @since 1.3.0
     */
    public boolean needsCorrelationPredicateWhenCorrelatingWithWhereClause();

    /**
     * Indicates whether the provider supports optimized natural id access.
     *
     * @return true if supported, else false
     * @since 1.3.0
     */
    public boolean supportsSingleValuedAssociationNaturalIdExpressions();

    /**
     * Indicates whether the provider supports group by entity alias properly.
     *
     * @return true if supported, else false
     * @since 1.3.0
     */
    public boolean supportsGroupByEntityAlias();

    /**
     * Indicates whether the provider needs to cutoff id properties when used as subpath of element collections.
     * This is to be able to workaround https://hibernate.atlassian.net/browse/HHH-13045 .
     *
     * @return true if needed, else false
     * @since 1.3.0
     */
    public boolean needsElementCollectionIdCutoff();

    /**
     * Indicates whether the provider requires an unproxied entity for field access to work.
     *
     * @return true if needed, else false
     * @since 1.4.1
     */
    public boolean needsUnproxyForFieldAccess();

    /**
     * Enables query result caching for the given query.
     *
     * @param query Enables query result caching for the query
     * @since 1.2.0
     */
    public void setCacheable(Query query);

    /**
     * Get the identifier or unique key inverse properties of an association attribute.
     *
     * @param owner The owning entity type
     * @param attributeName The association attribute
     * @return the identifier or unique key inverse properties of the association attribute
     * @since 1.2.1
     * @deprecated Use {@link #getJoinMappingPropertyNames(EntityType, String, String)} instead
     */
    public List getIdentifierOrUniqueKeyEmbeddedPropertyNames(EntityType owner, String attributeName);

    /**
     * Get the identifier or unique key inverse properties of an association attribute within an element collection.
     *
     * @param owner The owning entity type
     * @param elementCollectionPath The path to the element collection within which the attribute is contained
     * @param attributeName The association attribute
     * @return the identifier or unique key inverse properties of the association attribute
     * @since 1.3.0
     * @deprecated Use {@link #getJoinMappingPropertyNames(EntityType, String, String)} instead
     */
    public List getIdentifierOrUniqueKeyEmbeddedPropertyNames(EntityType owner, String elementCollectionPath, String attributeName);

    /**
     * Returns the join mapping property names of an association attribute. This is a mapping from target to source property names.
     *
     * @param owner The owning entity type
     * @param elementCollectionPath The nullable path to the element collection within which the attribute is contained
     * @param attributeName The association attribute
     * @return the property names from target type to the source type
     * @since 1.4.0
     */
    public Map getJoinMappingPropertyNames(EntityType owner, String elementCollectionPath, String attributeName);

    /**
     * Whether the enum type of the given attribute supports being used as literal by it's FQN.
     *
     * @param ownerType The declaring type of the attribute to check
     * @param attributeName The name of the attribute to check
     * @param key Whether the key part of a map attribute should be checked or the attribute element type
     * @return true if supported, false otherwise
     * @since 1.5.0
     */
    public boolean supportsEnumLiteral(ManagedType ownerType, String attributeName, boolean key);

    /**
     * Whether the JPA provider supports the temporal literal.
     *
     * @return true if supported, false otherwise
     * @since 1.5.0
     */
    public boolean supportsTemporalLiteral();

    /**
     * Returns the identifier of the entity object.
     *
     * @param entity The entity
     * @return the primary identifier of the entity
     * @since 1.3.0
     */
    public Object getIdentifier(Object entity);

    /**
     * Returns the unproxied i.e. the real entity object.
     *
     * @param entity The entity, maybe a proxy
     * @param  The entity type
     * @return the real entity object
     * @since 1.3.0
     */
    public  T unproxy(T entity);

    /**
     * Returns the JpaMetamodelAccessor for this JPA vendor.
     * @return the JpaMetamodelAccessor for this JPA vendor
     * @since 1.3.0
     */
    public JpaMetamodelAccessor getJpaMetamodelAccessor();

    /**
     * The possible locations of a constraint.
     *
     * @author Christian Beikov
     */
    public static enum ConstraintType {
        /**
         * No constraint.
         */
        NONE,
        /**
         * Constraint in the ON clause.
         */
        ON,
        /**
         * Constraint in the WHERE clause.
         */
        WHERE;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy