org.hibernate.envers.function.OrderByFragmentFunction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-envers Show documentation
Show all versions of hibernate-envers Show documentation
Hibernate's entity version (audit/history) support
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or .
*/
package org.hibernate.envers.function;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.ValuedModelPart;
import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.ReturnableType;
import org.hibernate.query.sqm.function.FunctionRenderer;
import org.hibernate.spi.NavigablePath;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingSqmFunction;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.sql.FromClauseIndex;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
import org.hibernate.sql.ast.spi.SqlAstQueryPartProcessingState;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.DelegatingTableGroup;
import org.hibernate.sql.ast.tree.from.NamedTableReference;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.select.QuerySpec;
/**
* Envers specific FunctionContributor
*
* @author Christian Beikov
*/
public class OrderByFragmentFunction extends AbstractSqmFunctionDescriptor {
public static final String FUNCTION_NAME = "_order_by_frag";
public static final OrderByFragmentFunction INSTANCE = new OrderByFragmentFunction();
public OrderByFragmentFunction() {
super(
FUNCTION_NAME,
StandardArgumentsValidators.exactly( 2 ),
StandardFunctionReturnTypeResolvers.useArgType( 1 ),
null
);
}
@Override
protected SelfRenderingSqmFunction generateSqmFunctionExpression(
List extends SqmTypedNode>> arguments,
ReturnableType impliedResultType,
QueryEngine queryEngine) {
return new OrderByFragmentSelfRenderingSqmFunction<>( this, arguments, impliedResultType, queryEngine );
}
private static class AuditingTableGroup extends DelegatingTableGroup {
private final TableGroup delegate;
private final String auditTableExpression;
private final String normalTableExpression;
public AuditingTableGroup(TableGroup delegate, String normalTableExpression) {
this.delegate = delegate;
this.auditTableExpression = ( (NamedTableReference) delegate.getPrimaryTableReference() ).getTableExpression();
this.normalTableExpression = normalTableExpression;
}
@Override
protected TableGroup getTableGroup() {
return delegate;
}
@Override
public TableReference resolveTableReference(
NavigablePath navigablePath,
String tableExpression) {
if ( tableExpression.equals( normalTableExpression ) ) {
tableExpression = auditTableExpression;
}
return super.resolveTableReference( navigablePath, tableExpression );
}
@Override
public TableReference resolveTableReference(
NavigablePath navigablePath,
ValuedModelPart modelPart,
String tableExpression) {
if ( tableExpression.equals( normalTableExpression ) ) {
return resolveTableReference( navigablePath, modelPart, auditTableExpression );
}
return super.resolveTableReference( navigablePath, modelPart, tableExpression );
}
@Override
public TableReference getTableReference(
NavigablePath navigablePath,
String tableExpression,
boolean resolve) {
if ( tableExpression.equals( normalTableExpression ) ) {
tableExpression = auditTableExpression;
}
return super.getTableReference( navigablePath, tableExpression, resolve );
}
@Override
public TableReference getTableReference(
NavigablePath navigablePath,
ValuedModelPart modelPart,
String tableExpression,
boolean resolve) {
if ( tableExpression.equals( normalTableExpression ) ) {
return getTableReference( navigablePath, modelPart, auditTableExpression, resolve );
}
return super.getTableReference( navigablePath, modelPart, tableExpression, resolve );
}
}
private static class OrderByFragmentSelfRenderingSqmFunction extends SelfRenderingSqmFunction {
public OrderByFragmentSelfRenderingSqmFunction(
OrderByFragmentFunction orderByFragmentFunction,
List extends SqmTypedNode>> arguments,
ReturnableType impliedResultType,
QueryEngine queryEngine) {
super(
orderByFragmentFunction,
(sqlAppender, sqlAstArguments, returnType, walker) -> {},
arguments,
impliedResultType,
orderByFragmentFunction.getArgumentsValidator(),
orderByFragmentFunction.getReturnTypeResolver(),
queryEngine.getCriteriaBuilder(),
orderByFragmentFunction.getName()
);
}
private OrderByFragmentSelfRenderingSqmFunction(
SqmFunctionDescriptor descriptor,
FunctionRenderer renderer,
List extends SqmTypedNode>> arguments,
ReturnableType impliedResultType,
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver,
NodeBuilder nodeBuilder,
String name) {
super(
descriptor,
renderer,
arguments,
impliedResultType,
argumentsValidator,
returnTypeResolver,
nodeBuilder,
name
);
}
@Override
public OrderByFragmentSelfRenderingSqmFunction copy(SqmCopyContext context) {
final OrderByFragmentSelfRenderingSqmFunction existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final List> arguments = new ArrayList<>( getArguments().size() );
for ( SqmTypedNode> argument : getArguments() ) {
arguments.add( argument.copy( context ) );
}
return context.registerCopy(
this,
new OrderByFragmentSelfRenderingSqmFunction<>(
getFunctionDescriptor(),
getFunctionRenderer(),
arguments,
getImpliedResultType(),
getArgumentsValidator(),
getReturnTypeResolver(),
nodeBuilder(),
getFunctionName()
)
);
}
@Override
public Expression convertToSqlAst(SqmToSqlAstConverter walker) {
final String sqmAlias = ( (SqmLiteral) getArguments().get( 0 ) ).getLiteralValue();
final String attributeRole = ( (SqmLiteral) getArguments().get( 1 ) ).getLiteralValue();
final TableGroup tableGroup = ( (FromClauseIndex) walker.getFromClauseAccess() ).findTableGroup(
sqmAlias
);
final CollectionPersister collectionDescriptor = walker.getCreationContext()
.getSessionFactory()
.getRuntimeMetamodels()
.getMappingMetamodel()
.findCollectionDescriptor( attributeRole );
final PluralAttributeMapping pluralAttribute = collectionDescriptor.getAttributeMapping();
final QuerySpec queryPart = (QuerySpec) ( (SqlAstQueryPartProcessingState) walker.getCurrentProcessingState() ).getInflightQueryPart();
final OrderByFragment fragment;
if ( pluralAttribute.getOrderByFragment() != null ) {
fragment = pluralAttribute.getOrderByFragment();
}
else {
fragment = pluralAttribute.getManyToManyOrderByFragment();
}
final String targetTableExpression;
if ( collectionDescriptor.getElementPersister() == null ) {
targetTableExpression = collectionDescriptor.getTableName();
}
else {
targetTableExpression = collectionDescriptor.getElementPersister().getTableName();
}
// We apply the fragment here and return null to signal that this is a no-op
fragment.apply(
queryPart,
new AuditingTableGroup( tableGroup, targetTableExpression ),
walker
);
return null;
}
}
}