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

org.hibernate.envers.function.OrderByFragmentFunction Maven / Gradle / Ivy

There is a newer version: 7.0.0.Beta2
Show newest version
/*
 * 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> 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> 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> 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;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy