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

org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers Maven / Gradle / Ivy

There is a newer version: 7.0.0.Alpha3
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 http://www.gnu.org/licenses/lgpl-2.1.html
 */
package org.hibernate.query.sqm.produce.function;

import java.util.List;
import java.util.Locale;
import java.util.Optional;

import org.hibernate.metamodel.model.domain.spi.AllowableFunctionReturnType;
import org.hibernate.query.sqm.QueryException;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.sql.ast.produce.metamodel.spi.ExpressableType;

/**
 * @author Steve Ebersole
 */
public class StandardFunctionReturnTypeResolvers {
	/**
	 * Disallow instantiation
	 */
	private StandardFunctionReturnTypeResolvers() {
	}

	/**
	 * A resolver that defines an invariant result type.  E.g. `substring` always
	 * returns a String.  Note however that to account for attribute converters and
	 * such, this resolver allows the context-impled expression type to be the
	 * return type so long as the Java types are compatible.
	 */
	public static FunctionReturnTypeResolver invariant(AllowableFunctionReturnType invariantType) {
		if ( invariantType == null ) {
			throw new IllegalArgumentException( "Passed `invariantType` for function return cannot be null" );
		}

		return new FunctionReturnTypeResolver() {
			@Override
			public  AllowableFunctionReturnType resolveFunctionReturnType(
					AllowableFunctionReturnType impliedType,
					List arguments) {
				return useImpliedTypeIfPossible( invariantType, impliedType );
			}
		};
	}

	public static FunctionReturnTypeResolver useArgType(int argPosition) {
		return new FunctionReturnTypeResolver() {
			@Override
			public  AllowableFunctionReturnType resolveFunctionReturnType(
					AllowableFunctionReturnType impliedType,
					List arguments) {
				final AllowableFunctionReturnType specifiedArgType = extractArgumentType( arguments, argPosition );
				return useImpliedTypeIfPossible( specifiedArgType, impliedType );
			}
		};
	}

	public static FunctionReturnTypeResolver useFirstNonNull() {
		return new FunctionReturnTypeResolver() {
			@Override
			public  AllowableFunctionReturnType resolveFunctionReturnType(
					AllowableFunctionReturnType impliedType,
					List arguments) {
				final Optional firstNonNull = arguments.stream()
						.filter(
								sqmExpression -> sqmExpression.getExpressableType() != null
										&& sqmExpression.getExpressableType() instanceof AllowableFunctionReturnType
						)
						.findFirst();
				if ( firstNonNull.isPresent() ) {
					return useImpliedTypeIfPossible( (AllowableFunctionReturnType) firstNonNull.get().getExpressableType(), impliedType );
				}
				else {
					return impliedType;
				}
			}
		};
	}



	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Internal helpers

	@SuppressWarnings("unchecked")
	private static  AllowableFunctionReturnType useImpliedTypeIfPossible(
			AllowableFunctionReturnType found,
			AllowableFunctionReturnType implied) {
		return areCompatible( found, implied )
				? implied
				: found;
	}

	@SuppressWarnings({"unchecked", "SimplifiableIfStatement"})
	private static boolean areCompatible(AllowableFunctionReturnType expected, AllowableFunctionReturnType found) {
		if ( expected == null || found == null ) {
			return false;
		}

		return expected.getJavaType().isAssignableFrom( found.getJavaType() );
	}

	private static AllowableFunctionReturnType extractArgumentType(List arguments, int position) {
		final SqmExpression specifiedArgument = arguments.get( position-1 );
		final ExpressableType specifiedArgType = specifiedArgument.getExpressableType();
		if ( !AllowableFunctionReturnType.class.isInstance( specifiedArgType ) ) {
			throw new QueryException(
					String.format(
							Locale.ROOT,
							"Function argument [%s] at specified position [%d] in call arguments was not typed as an allowable function return type",
							specifiedArgument,
							position
					)
			);
		}

		return (AllowableFunctionReturnType) specifiedArgType;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy