HHH-15868 Add more non-standard HQL functions to the HibernateCriteriaBuilder interface

This commit is contained in:
Marco Belladelli 2022-12-19 14:44:55 +01:00 committed by Christian Beikov
parent ba985518c7
commit 977587dd67
4 changed files with 1700 additions and 2 deletions

View File

@ -12,6 +12,7 @@ import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.temporal.TemporalAccessor;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@ -894,6 +895,462 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
@Incubating
JpaSearchOrder desc(JpaCteCriteriaAttribute x, boolean nullsFirst);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Non-standard HQL functions
/**
* Embed native {@code pattern} that will be unquoted and embedded in the generated SQL.
* Occurrences of {@code ?} in the pattern are replaced with the remaining {@code arguments}
* of the function.
*
* @param pattern native SQL pattern
* @param type type of this expression
* @param arguments optional arguments to the SQL pattern
* @param <T> type of this expression
*
* @return native SQL expression
*/
<T> JpaExpression<T> sql(String pattern, Class<T> type, Expression<?>... arguments);
/**
* Format a date, time, or datetime according to a pattern.
* The pattern must be written in a subset of the pattern language defined by
* Javas {@link java.time.format.DateTimeFormatter}.
* <p>
* See {@link org.hibernate.dialect.Dialect#appendDatetimeFormat Dialect#appendDatetimeFormat}
* for a full list of pattern elements.
*
* @param datetime the datetime expression to format
* @param pattern the pattern to use for formatting
*
* @return format expression
*/
JpaFunction<String> format(Expression<? extends TemporalAccessor> datetime, String pattern);
/**
* Extracts the {@link org.hibernate.query.sqm.TemporalUnit#YEAR} of a date, time, or datetime expression.
*
* @param datetime the date, time, or datetime to extract the value from
*
* @return the extracted value
*/
JpaFunction<Integer> year(Expression<? extends TemporalAccessor> datetime);
/**
* Extracts the {@link org.hibernate.query.sqm.TemporalUnit#MONTH} of a date, time, or datetime expression.
*
* @param datetime the date, time, or datetime to extract the value from
*
* @return the extracted value
*/
JpaFunction<Integer> month(Expression<? extends TemporalAccessor> datetime);
/**
* Extracts the {@link org.hibernate.query.sqm.TemporalUnit#DAY} of a date, time, or datetime expression.
*
* @param datetime the date, time, or datetime to extract the value from
*
* @return the extracted value
*/
JpaFunction<Integer> day(Expression<? extends TemporalAccessor> datetime);
/**
* Extracts the {@link org.hibernate.query.sqm.TemporalUnit#HOUR} of a date, time, or datetime expression.
*
* @param datetime the date, time, or datetime to extract the value from
*
* @return the extracted value
*/
JpaFunction<Integer> hour(Expression<? extends TemporalAccessor> datetime);
/**
* Extracts the {@link org.hibernate.query.sqm.TemporalUnit#MINUTE} of a date, time, or datetime expression.
*
* @param datetime the date, time, or datetime to extract the value from
*
* @return the extracted value
*/
JpaFunction<Integer> minute(Expression<? extends TemporalAccessor> datetime);
/**
* Extracts the {@link org.hibernate.query.sqm.TemporalUnit#SECOND} of a date, time, or datetime expression.
*
* @param datetime the date, time, or datetime to extract the value from
*
* @return the extracted value
*/
JpaFunction<Float> second(Expression<? extends TemporalAccessor> datetime);
/**
* @see #overlay(Expression, Expression, Expression, Expression)
*/
JpaFunction<String> overlay(Expression<String> string, String replacement, int start);
/**
* @see #overlay(Expression, Expression, Expression, Expression)
*/
JpaFunction<String> overlay(Expression<String> string, Expression<String> replacement, int start);
/**
* @see #overlay(Expression, Expression, Expression, Expression)
*/
JpaFunction<String> overlay(Expression<String> string, String replacement, Expression<Integer> start);
/**
* @see #overlay(Expression, Expression, Expression, Expression)
*/
JpaFunction<String> overlay(Expression<String> string, Expression<String> replacement, Expression<Integer> start);
/**
* @see #overlay(Expression, Expression, Expression, Expression)
*/
JpaFunction<String> overlay(Expression<String> string, String replacement, int start, int length);
/**
* @see #overlay(Expression, Expression, Expression, Expression)
*/
JpaFunction<String> overlay(Expression<String> string, Expression<String> replacement, int start, int length);
/**
* @see #overlay(Expression, Expression, Expression, Expression)
*/
JpaFunction<String> overlay(Expression<String> string, String replacement, Expression<Integer> start, int length);
/**
* @see #overlay(Expression, Expression, Expression, Expression)
*/
JpaFunction<String> overlay(
Expression<String> string,
Expression<String> replacement,
Expression<Integer> start,
int length);
/**
* @see #overlay(Expression, Expression, Expression, Expression)
*/
JpaFunction<String> overlay(Expression<String> string, String replacement, int start, Expression<Integer> length);
/**
* @see #overlay(Expression, Expression, Expression, Expression)
*/
JpaFunction<String> overlay(
Expression<String> string,
Expression<String> replacement,
int start,
Expression<Integer> length);
/**
* @see #overlay(Expression, Expression, Expression, Expression)
*/
JpaFunction<String> overlay(
Expression<String> string,
String replacement,
Expression<Integer> start,
Expression<Integer> length);
/**
* Overlay the {@code string} expression with the {@code replacement} expression,
* starting from index {@code start} and substituting a number of characters
* corresponding to the length of the {@code replacement} expression or the
* {@code length} parameter if specified.
*
* @param string string expression to be manipulated
* @param replacement string expression to replace in original
* @param start start position
* @param length optional, number of characters to substitute
*
* @return overlay expression
*/
JpaFunction<String> overlay(
Expression<String> string,
Expression<String> replacement,
Expression<Integer> start,
Expression<Integer> length);
/**
* @see #pad(Trimspec, Expression, Expression, Expression)
*/
JpaFunction<String> pad(Expression<String> x, int length);
/**
* @see #pad(Trimspec, Expression, Expression, Expression)
*/
JpaFunction<String> pad(Trimspec ts, Expression<String> x, int length);
/**
* @see #pad(Trimspec, Expression, Expression, Expression)
*/
JpaFunction<String> pad(Expression<String> x, Expression<Integer> length);
/**
* @see #pad(Trimspec, Expression, Expression, Expression)
*/
JpaFunction<String> pad(Trimspec ts, Expression<String> x, Expression<Integer> length);
/**
* @see #pad(Trimspec, Expression, Expression, Expression)
*/
JpaFunction<String> pad(Expression<String> x, int length, char padChar);
/**
* @see #pad(Trimspec, Expression, Expression, Expression)
*/
JpaFunction<String> pad(Trimspec ts, Expression<String> x, int length, char padChar);
/**
* @see #pad(Trimspec, Expression, Expression, Expression)
*/
JpaFunction<String> pad(Expression<String> x, Expression<Integer> length, char padChar);
/**
* @see #pad(Trimspec, Expression, Expression, Expression)
*/
JpaFunction<String> pad(Trimspec ts, Expression<String> x, Expression<Integer> length, char padChar);
/**
* @see #pad(Trimspec, Expression, Expression, Expression)
*/
JpaFunction<String> pad(Expression<String> x, int length, Expression<Character> padChar);
/**
* @see #pad(Trimspec, Expression, Expression, Expression)
*/
JpaFunction<String> pad(Trimspec ts, Expression<String> x, int length, Expression<Character> padChar);
/**
* @see #pad(Trimspec, Expression, Expression, Expression)
*/
JpaFunction<String> pad(Expression<String> x, Expression<Integer> length, Expression<Character> padChar);
/**
* Pad the specified string expression with whitespace or with the {@code padChar} character if specified.
* Optionally pass a {@link jakarta.persistence.criteria.CriteriaBuilder.Trimspec} to pad the
* string expression with {@code LEADING} or {@code TRAILING} (default) characters.
*
* @param ts optional {@link jakarta.persistence.criteria.CriteriaBuilder.Trimspec}
* @param x string expression to pad
* @param length length of the result string after padding
* @param padChar optional pad character
*
* @return pad expression
*/
JpaFunction<String> pad(
Trimspec ts,
Expression<String> x,
Expression<Integer> length,
Expression<Character> padChar);
/**
* @see #left(Expression, Expression)
*/
JpaFunction<String> left(Expression<String> x, int length);
/**
* Extract the {@code length} leftmost characters of a string.
*
* @param x original string
* @param length number of characters
*
* @return left expression
*/
JpaFunction<String> left(Expression<String> x, Expression<Integer> length);
/**
* @see #right(Expression, Expression)
*/
JpaFunction<String> right(Expression<String> x, int length);
/**
* Extract the {@code length} rightmost characters of a string.
*
* @param x original string
* @param length number of characters
*
* @return left expression
*/
JpaFunction<String> right(Expression<String> x, Expression<Integer> length);
/**
* @see #replace(Expression, Expression, Expression)
*/
JpaFunction<String> replace(Expression<String> x, String pattern, String replacement);
/**
* @see #replace(Expression, Expression, Expression)
*/
JpaFunction<String> replace(Expression<String> x, String pattern, Expression<String> replacement);
/**
* @see #replace(Expression, Expression, Expression)
*/
JpaFunction<String> replace(Expression<String> x, Expression<String> pattern, String replacement);
/**
* Replace all occurrences of {@code pattern} within the original string with {@code replacement}.
*
* @param x original string
* @param pattern the string to be replaced
* @param replacement the new replacement string
*
* @return replace expression
*/
JpaFunction<String> replace(Expression<String> x, Expression<String> pattern, Expression<String> replacement);
JpaFunction<String> collate(Expression<String> x, String collation);
/**
* Create an expression that returns the base-10 logarithm
* of its argument.
*
* @param x expression
*
* @return base-10 logarithm
*/
JpaExpression<Double> log10(Expression<? extends Number> x);
/**
* @see #log(Expression, Expression)
*/
JpaExpression<Double> log(Number b, Expression<? extends Number> x);
/**
* Create an expression that returns the logarithm of {@code x} to the base {@code b}.
*
* @param b base
* @param x expression
*
* @return arbitrary-base logarithm
*/
JpaExpression<Double> log(Expression<? extends Number> b, Expression<? extends Number> x);
/**
* Literal expression corresponding to the value of pi.
*
* @return pi expression
*/
JpaExpression<Double> pi();
/**
* Create an expression that returns the sine of its argument.
*
* @param x expression
*
* @return sine
*/
JpaExpression<Double> sin(Expression<? extends Number> x);
/**
* Create an expression that returns the cosine of its argument.
*
* @param x expression
*
* @return cosine
*/
JpaExpression<Double> cos(Expression<? extends Number> x);
/**
* Create an expression that returns the tangent of its argument.
*
* @param x expression
*
* @return tangent
*/
JpaExpression<Double> tan(Expression<? extends Number> x);
/**
* Create an expression that returns the inverse sine of its argument.
*
* @param x expression
*
* @return inverse sine
*/
JpaExpression<Double> asin(Expression<? extends Number> x);
/**
* Create an expression that returns the inverse cosine of its argument.
*
* @param x expression
*
* @return inverse cosine
*/
JpaExpression<Double> acos(Expression<? extends Number> x);
/**
* Create an expression that returns the inverse tangent of its argument.
*
* @param x expression
*
* @return inverse tangent
*/
JpaExpression<Double> atan(Expression<? extends Number> x);
/**
* @see #atan2(Expression, Expression)
*/
JpaExpression<Double> atan2(Number y, Expression<? extends Number> x);
/**
* @see #atan2(Expression, Expression)
*/
JpaExpression<Double> atan2(Expression<? extends Number> y, Number x);
/**
* Create an expression that returns the inverse tangent of {@code y} over {@code x}.
*
* @param y y coordinate
* @param x x coordinate
*
* @return 2-argument inverse tangent
*/
JpaExpression<Double> atan2(Expression<? extends Number> y, Expression<? extends Number> x);
/**
* Create an expression that returns the hyperbolic sine of its argument.
*
* @param x expression
*
* @return hyperbolic sine
*/
JpaExpression<Double> sinh(Expression<? extends Number> x);
/**
* Create an expression that returns the hyperbolic cosine of its argument.
*
* @param x expression
*
* @return hyperbolic cosine
*/
JpaExpression<Double> cosh(Expression<? extends Number> x);
/**
* Create an expression that returns the hyperbolic tangent of its argument.
*
* @param x expression
*
* @return hyperbolic tangent
*/
JpaExpression<Double> tanh(Expression<? extends Number> x);
/**
* Create an expression that converts an angle measured in radians
* to an approximately equivalent angle measured in degrees.
*
* @param x expression
*
* @return degrees
*/
JpaExpression<Double> degrees(Expression<? extends Number> x);
/**
* Create an expression that converts an angle measured in degrees
* to an approximately equivalent angle measured in radians.
*
* @param x expression
*
* @return radians
*/
JpaExpression<Double> radians(Expression<? extends Number> x);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Window functions

View File

@ -15,6 +15,7 @@ import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAccessor;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@ -1257,6 +1258,339 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
return criteriaBuilder.desc( x, nullsFirst );
}
@Override
public <T> JpaExpression<T> sql(String pattern, Class<T> type, Expression<?>... arguments) {
return criteriaBuilder.sql( pattern, type, arguments );
}
@Override
public JpaFunction<String> format(Expression<? extends TemporalAccessor> datetime, String pattern) {
return criteriaBuilder.format( datetime, pattern );
}
@Override
public JpaFunction<Integer> year(Expression<? extends TemporalAccessor> datetime) {
return criteriaBuilder.year( datetime );
}
@Override
public JpaFunction<Integer> month(Expression<? extends TemporalAccessor> datetime) {
return criteriaBuilder.month( datetime );
}
@Override
public JpaFunction<Integer> day(Expression<? extends TemporalAccessor> datetime) {
return criteriaBuilder.day( datetime );
}
@Override
public JpaFunction<Integer> hour(Expression<? extends TemporalAccessor> datetime) {
return criteriaBuilder.hour( datetime );
}
@Override
public JpaFunction<Integer> minute(Expression<? extends TemporalAccessor> datetime) {
return criteriaBuilder.minute( datetime );
}
@Override
public JpaFunction<Float> second(Expression<? extends TemporalAccessor> datetime) {
return criteriaBuilder.second( datetime );
}
@Override
public JpaFunction<String> overlay(Expression<String> string, String replacement, int start) {
return criteriaBuilder.overlay( string, replacement, start );
}
@Override
public JpaFunction<String> overlay(Expression<String> string, Expression<String> replacement, int start) {
return criteriaBuilder.overlay( string, replacement, start );
}
@Override
public JpaFunction<String> overlay(Expression<String> string, String replacement, Expression<Integer> start) {
return criteriaBuilder.overlay( string, replacement, start );
}
@Override
public JpaFunction<String> overlay(
Expression<String> string,
Expression<String> replacement,
Expression<Integer> start) {
return criteriaBuilder.overlay( string, replacement, start );
}
@Override
public JpaFunction<String> overlay(Expression<String> string, String replacement, int start, int length) {
return criteriaBuilder.overlay( string, replacement, start, length );
}
@Override
public JpaFunction<String> overlay(
Expression<String> string,
Expression<String> replacement,
int start,
int length) {
return criteriaBuilder.overlay( string, replacement, start, length );
}
@Override
public JpaFunction<String> overlay(
Expression<String> string,
String replacement,
Expression<Integer> start,
int length) {
return criteriaBuilder.overlay( string, replacement, start, length );
}
@Override
public JpaFunction<String> overlay(
Expression<String> string,
Expression<String> replacement,
Expression<Integer> start,
int length) {
return criteriaBuilder.overlay( string, replacement, start, length );
}
@Override
public JpaFunction<String> overlay(
Expression<String> string,
String replacement,
int start,
Expression<Integer> length) {
return criteriaBuilder.overlay( string, replacement, start, length );
}
@Override
public JpaFunction<String> overlay(
Expression<String> string,
Expression<String> replacement,
int start,
Expression<Integer> length) {
return criteriaBuilder.overlay( string, replacement, start, length );
}
@Override
public JpaFunction<String> overlay(
Expression<String> string,
String replacement,
Expression<Integer> start,
Expression<Integer> length) {
return criteriaBuilder.overlay( string, replacement, start, length );
}
@Override
public JpaFunction<String> overlay(
Expression<String> string,
Expression<String> replacement,
Expression<Integer> start,
Expression<Integer> length) {
return criteriaBuilder.overlay( string, replacement, start, length );
}
@Override
public JpaFunction<String> pad(Expression<String> x, int length) {
return criteriaBuilder.pad( x, length );
}
@Override
public JpaFunction<String> pad(Trimspec ts, Expression<String> x, int length) {
return criteriaBuilder.pad( ts, x, length );
}
@Override
public JpaFunction<String> pad(Expression<String> x, Expression<Integer> length) {
return criteriaBuilder.pad( x, length );
}
@Override
public JpaFunction<String> pad(Trimspec ts, Expression<String> x, Expression<Integer> length) {
return criteriaBuilder.pad( ts, x, length );
}
@Override
public JpaFunction<String> pad(Expression<String> x, int length, char padChar) {
return criteriaBuilder.pad( x, length, padChar );
}
@Override
public JpaFunction<String> pad(Trimspec ts, Expression<String> x, int length, char padChar) {
return criteriaBuilder.pad( ts, x, length, padChar );
}
@Override
public JpaFunction<String> pad(Expression<String> x, Expression<Integer> length, char padChar) {
return criteriaBuilder.pad( x, length, padChar );
}
@Override
public JpaFunction<String> pad(Trimspec ts, Expression<String> x, Expression<Integer> length, char padChar) {
return criteriaBuilder.pad( ts, x, length, padChar );
}
@Override
public JpaFunction<String> pad(Expression<String> x, int length, Expression<Character> padChar) {
return criteriaBuilder.pad( x, length, padChar );
}
@Override
public JpaFunction<String> pad(Trimspec ts, Expression<String> x, int length, Expression<Character> padChar) {
return criteriaBuilder.pad( ts, x, length, padChar );
}
@Override
public JpaFunction<String> pad(Expression<String> x, Expression<Integer> length, Expression<Character> padChar) {
return criteriaBuilder.pad( x, length, padChar );
}
@Override
public JpaFunction<String> pad(
Trimspec ts,
Expression<String> x,
Expression<Integer> length,
Expression<Character> padChar) {
return criteriaBuilder.pad( ts, x, length, padChar );
}
@Override
public JpaFunction<String> left(Expression<String> x, int length) {
return criteriaBuilder.left( x, length );
}
@Override
public JpaFunction<String> left(Expression<String> x, Expression<Integer> length) {
return criteriaBuilder.left( x, length );
}
@Override
public JpaFunction<String> right(Expression<String> x, int length) {
return criteriaBuilder.right( x, length );
}
@Override
public JpaFunction<String> right(Expression<String> x, Expression<Integer> length) {
return criteriaBuilder.right( x, length );
}
@Override
public JpaFunction<String> replace(Expression<String> x, String pattern, String replacement) {
return criteriaBuilder.replace( x, pattern, replacement );
}
@Override
public JpaFunction<String> replace(Expression<String> x, String pattern, Expression<String> replacement) {
return criteriaBuilder.replace( x, pattern, replacement );
}
@Override
public JpaFunction<String> replace(Expression<String> x, Expression<String> pattern, String replacement) {
return criteriaBuilder.replace( x, pattern, replacement );
}
@Override
public JpaFunction<String> replace(
Expression<String> x,
Expression<String> pattern,
Expression<String> replacement) {
return criteriaBuilder.replace( x, pattern, replacement );
}
@Override
public JpaFunction<String> collate(Expression<String> x, String collation) {
return criteriaBuilder.collate( x, collation );
}
@Override
public JpaExpression<Double> log10(Expression<? extends Number> x) {
return criteriaBuilder.log10( x );
}
@Override
public JpaExpression<Double> log(Number b, Expression<? extends Number> x) {
return criteriaBuilder.log( b, x );
}
@Override
public JpaExpression<Double> log(Expression<? extends Number> b, Expression<? extends Number> x) {
return criteriaBuilder.log( b, x );
}
@Override
public JpaExpression<Double> pi() {
return criteriaBuilder.pi();
}
@Override
public JpaExpression<Double> sin(Expression<? extends Number> x) {
return criteriaBuilder.sin( x );
}
@Override
public JpaExpression<Double> cos(Expression<? extends Number> x) {
return criteriaBuilder.cos( x );
}
@Override
public JpaExpression<Double> tan(Expression<? extends Number> x) {
return criteriaBuilder.tan( x );
}
@Override
public JpaExpression<Double> asin(Expression<? extends Number> x) {
return criteriaBuilder.asin( x );
}
@Override
public JpaExpression<Double> acos(Expression<? extends Number> x) {
return criteriaBuilder.acos( x );
}
@Override
public JpaExpression<Double> atan(Expression<? extends Number> x) {
return criteriaBuilder.atan( x );
}
@Override
public JpaExpression<Double> atan2(Number y, Expression<? extends Number> x) {
return criteriaBuilder.atan2( y, x );
}
@Override
public JpaExpression<Double> atan2(Expression<? extends Number> y, Number x) {
return criteriaBuilder.atan2( y, x );
}
@Override
public JpaExpression<Double> atan2(Expression<? extends Number> y, Expression<? extends Number> x) {
return criteriaBuilder.atan2( y, x );
}
@Override
public JpaExpression<Double> sinh(Expression<? extends Number> x) {
return criteriaBuilder.sinh( x );
}
@Override
public JpaExpression<Double> cosh(Expression<? extends Number> x) {
return criteriaBuilder.cosh( x );
}
@Override
public JpaExpression<Double> tanh(Expression<? extends Number> x) {
return criteriaBuilder.tanh( x );
}
@Override
public JpaExpression<Double> degrees(Expression<? extends Number> x) {
return criteriaBuilder.degrees( x );
}
@Override
public JpaExpression<Double> radians(Expression<? extends Number> x) {
return criteriaBuilder.radians( x );
}
@Override
public JpaWindow createWindow() {
return criteriaBuilder.createWindow();

View File

@ -17,6 +17,7 @@ import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAccessor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -58,7 +59,6 @@ import org.hibernate.query.criteria.JpaSearchOrder;
import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.criteria.JpaSubQuery;
import org.hibernate.query.criteria.JpaWindow;
import org.hibernate.query.criteria.JpaWindowFrame;
import org.hibernate.query.criteria.ValueHandlingMode;
import org.hibernate.query.criteria.spi.CriteriaBuilderExtension;
import org.hibernate.query.spi.QueryEngine;
@ -71,6 +71,7 @@ import org.hibernate.query.sqm.SetOperator;
import org.hibernate.query.sqm.SortOrder;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.TemporalUnit;
import org.hibernate.query.sqm.TrimSpec;
import org.hibernate.query.sqm.UnaryArithmeticOperator;
import org.hibernate.query.sqm.function.NamedSqmFunctionDescriptor;
@ -98,9 +99,11 @@ import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
import org.hibernate.query.sqm.tree.expression.SqmCoalesce;
import org.hibernate.query.sqm.tree.expression.SqmCollation;
import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
import org.hibernate.query.sqm.tree.expression.SqmLiteralNull;
@ -143,7 +146,6 @@ import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.BasicType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.SmallIntJdbcType;
import org.hibernate.type.spi.TypeConfiguration;
import jakarta.persistence.Tuple;
@ -2569,6 +2571,498 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
throw new InvalidObjectException( "Could not find a SessionFactory [uuid=" + uuid + ",name=" + name + "]" );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Non-standard HQL functions
@Override
public <T> SqmFunction<T> sql(String pattern, Class<T> type, Expression<?>... arguments) {
List<SqmExpression<?>> sqmArguments = new ArrayList<>( expressionList( arguments ) );
sqmArguments.add( 0, literal( pattern ) );
return getFunctionDescriptor( "sql" ).generateSqmExpression(
sqmArguments,
getTypeConfiguration().getBasicTypeForJavaType( type ),
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<String> format(Expression<? extends TemporalAccessor> datetime, String pattern) {
SqmExpression<String> patternLiteral = value( pattern );
return getFunctionDescriptor( "format" ).generateSqmExpression(
asList( (SqmExpression<?>) datetime, patternLiteral ),
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
private <T> SqmFunction<T> extract(
Expression<? extends TemporalAccessor> datetime,
TemporalUnit temporalUnit,
Class<T> type) {
return getFunctionDescriptor( "extract" ).generateSqmExpression(
asList(
new SqmExtractUnit<>(
temporalUnit,
getTypeConfiguration().standardBasicTypeForJavaType( type ),
this
),
(SqmTypedNode<?>) datetime
),
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<Integer> year(Expression<? extends TemporalAccessor> datetime) {
return extract( datetime, TemporalUnit.YEAR, Integer.class );
}
@Override
public SqmFunction<Integer> month(Expression<? extends TemporalAccessor> datetime) {
return extract( datetime, TemporalUnit.MONTH, Integer.class );
}
@Override
public SqmFunction<Integer> day(Expression<? extends TemporalAccessor> datetime) {
return extract( datetime, TemporalUnit.DAY, Integer.class );
}
@Override
public SqmFunction<Integer> hour(Expression<? extends TemporalAccessor> datetime) {
return extract( datetime, TemporalUnit.HOUR, Integer.class );
}
@Override
public SqmFunction<Integer> minute(Expression<? extends TemporalAccessor> datetime) {
return extract( datetime, TemporalUnit.MINUTE, Integer.class );
}
@Override
public SqmFunction<Float> second(Expression<? extends TemporalAccessor> datetime) {
return extract( datetime, TemporalUnit.SECOND, Float.class );
}
@Override
public SqmFunction<String> overlay(Expression<String> string, String replacement, int start) {
return overlay( string, replacement, value( start ), null );
}
@Override
public SqmFunction<String> overlay(Expression<String> string, Expression<String> replacement, int start) {
return overlay( string, replacement, value( start ), null );
}
@Override
public SqmFunction<String> overlay(Expression<String> string, String replacement, Expression<Integer> start) {
return overlay( string, value( replacement ), start, null );
}
@Override
public SqmFunction<String> overlay(
Expression<String> string,
Expression<String> replacement,
Expression<Integer> start) {
return overlay( string, replacement, start, null );
}
@Override
public SqmFunction<String> overlay(Expression<String> string, String replacement, int start, int length) {
return overlay( string, value( replacement ), value( start ), value( length ) );
}
@Override
public SqmFunction<String> overlay(
Expression<String> string,
Expression<String> replacement,
int start,
int length) {
return overlay( string, replacement, value( start ), value( length ) );
}
@Override
public SqmFunction<String> overlay(
Expression<String> string,
String replacement,
Expression<Integer> start,
int length) {
return overlay( string, value( replacement ), start, value( length ) );
}
@Override
public SqmFunction<String> overlay(
Expression<String> string,
Expression<String> replacement,
Expression<Integer> start,
int length) {
return overlay( string, replacement, start, value( length ) );
}
@Override
public SqmFunction<String> overlay(
Expression<String> string,
String replacement,
int start,
Expression<Integer> length) {
return overlay( string, value( replacement ), value( start ), length );
}
@Override
public SqmFunction<String> overlay(
Expression<String> string,
Expression<String> replacement,
int start,
Expression<Integer> length) {
return overlay( string, replacement, value( start ), length );
}
@Override
public SqmFunction<String> overlay(
Expression<String> string,
String replacement,
Expression<Integer> start,
Expression<Integer> length) {
return overlay( string, value( replacement ), start, length );
}
@Override
public SqmFunction<String> overlay(
Expression<String> string,
Expression<String> replacement,
Expression<Integer> start,
Expression<Integer> length) {
SqmExpression<String> sqmString = (SqmExpression<String>) string;
SqmExpression<String> sqmReplacement = (SqmExpression<String>) replacement;
SqmExpression<Integer> sqmStart = (SqmExpression<Integer>) start;
return getFunctionDescriptor( "overlay" ).generateSqmExpression(
( length == null
? asList( sqmString, sqmReplacement, sqmStart )
: asList( sqmString, sqmReplacement, sqmStart, (SqmExpression<Integer>) length ) ),
null,
getQueryEngine(),
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<String> pad(Expression<String> x, int length) {
return pad( null, x, value( length ), null );
}
@Override
public SqmFunction<String> pad(Trimspec ts, Expression<String> x, int length) {
return pad( ts, x, value( length ), null );
}
@Override
public SqmFunction<String> pad(Expression<String> x, Expression<Integer> length) {
return pad( null, x, length, null );
}
@Override
public SqmFunction<String> pad(Trimspec ts, Expression<String> x, Expression<Integer> length) {
return pad( ts, x, length, null );
}
@Override
public SqmFunction<String> pad(Expression<String> x, int length, char padChar) {
return pad( null, x, value( length ), value( padChar ) );
}
@Override
public SqmFunction<String> pad(Trimspec ts, Expression<String> x, int length, char padChar) {
return pad( ts, x, value( length ), value( padChar ) );
}
@Override
public SqmFunction<String> pad(Expression<String> x, int length, Expression<Character> padChar) {
return pad( null, x, value( length ), padChar );
}
@Override
public SqmFunction<String> pad(Trimspec ts, Expression<String> x, int length, Expression<Character> padChar) {
return pad( ts, x, value( length ), padChar );
}
@Override
public SqmFunction<String> pad(Expression<String> x, Expression<Integer> length, char padChar) {
return pad( null, x, length, value( padChar ) );
}
@Override
public SqmFunction<String> pad(Trimspec ts, Expression<String> x, Expression<Integer> length, char padChar) {
return pad( ts, x, length, value( padChar ) );
}
@Override
public SqmFunction<String> pad(Expression<String> x, Expression<Integer> length, Expression<Character> padChar) {
return pad( null, x, length, padChar );
}
@Override
public SqmFunction<String> pad(
Trimspec ts,
Expression<String> x,
Expression<Integer> length,
Expression<Character> padChar) {
SqmExpression<String> source = (SqmExpression<String>) x;
SqmExpression<Integer> sqmLength = (SqmExpression<Integer>) length;
SqmTrimSpecification padSpec = new SqmTrimSpecification(
ts == null ? TrimSpec.TRAILING : convertTrimSpec( ts ),
this
);
return getFunctionDescriptor( "pad" ).generateSqmExpression(
padChar != null
? asList( source, sqmLength, padSpec, (SqmExpression<Character>) padChar )
: asList( source, sqmLength, padSpec ),
null,
getQueryEngine(),
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<String> left(Expression<String> x, int length) {
return left( x, value( length ) );
}
@Override
public SqmFunction<String> left(Expression<String> x, Expression<Integer> length) {
return getFunctionDescriptor( "left" ).generateSqmExpression(
asList( (SqmExpression<String>) x, (SqmExpression<Integer>) length ),
null,
getQueryEngine(),
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<String> right(Expression<String> x, int length) {
return right( x, value( length ) );
}
@Override
public SqmFunction<String> right(Expression<String> x, Expression<Integer> length) {
return getFunctionDescriptor( "right" ).generateSqmExpression(
asList( (SqmExpression<String>) x, (SqmExpression<Integer>) length ),
null,
getQueryEngine(),
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<String> replace(Expression<String> x, String pattern, String replacement) {
SqmExpression<String> sqmPattern = value( pattern );
return replace( x, sqmPattern, value( replacement, sqmPattern ) );
}
@Override
public SqmFunction<String> replace(Expression<String> x, String pattern, Expression<String> replacement) {
return replace( x, value( pattern ), replacement );
}
@Override
public SqmFunction<String> replace(Expression<String> x, Expression<String> pattern, String replacement) {
return replace( x, pattern, value( replacement ) );
}
@Override
public SqmFunction<String> replace(
Expression<String> x,
Expression<String> pattern,
Expression<String> replacement) {
return getFunctionDescriptor( "replace" ).generateSqmExpression(
asList(
(SqmExpression<String>) x,
(SqmExpression<String>) pattern,
(SqmExpression<String>) replacement
),
null,
getQueryEngine(),
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<String> collate(Expression<String> x, String collation) {
SqmCollation sqmCollation = new SqmCollation( collation, null, this );
return getFunctionDescriptor( "collate" ).generateSqmExpression(
asList( (SqmExpression<String>) x, sqmCollation ),
null,
getQueryEngine(),
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<Double> log10(Expression<? extends Number> x) {
return getFunctionDescriptor( "log10" ).generateSqmExpression(
(SqmTypedNode<?>) x,
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<Double> log(Number b, Expression<? extends Number> x) {
return log( value( b ), x );
}
@Override
public SqmFunction<Double> log(Expression<? extends Number> b, Expression<? extends Number> x) {
return getFunctionDescriptor( "log" ).generateSqmExpression(
asList( (SqmTypedNode<?>) b, (SqmTypedNode<?>) x ),
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<Double> pi() {
return getFunctionDescriptor( "pi" ).generateSqmExpression(
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<Double> sin(Expression<? extends Number> x) {
return getFunctionDescriptor( "sin" ).generateSqmExpression(
(SqmTypedNode<?>) x,
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<Double> cos(Expression<? extends Number> x) {
return getFunctionDescriptor( "cos" ).generateSqmExpression(
(SqmTypedNode<?>) x,
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<Double> tan(Expression<? extends Number> x) {
return getFunctionDescriptor( "tan" ).generateSqmExpression(
(SqmTypedNode<?>) x,
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<Double> asin(Expression<? extends Number> x) {
return getFunctionDescriptor( "asin" ).generateSqmExpression(
(SqmTypedNode<?>) x,
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<Double> acos(Expression<? extends Number> x) {
return getFunctionDescriptor( "acos" ).generateSqmExpression(
(SqmTypedNode<?>) x,
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<Double> atan(Expression<? extends Number> x) {
return getFunctionDescriptor( "atan" ).generateSqmExpression(
(SqmTypedNode<?>) x,
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<Double> atan2(Number y, Expression<? extends Number> x) {
return atan2( value( y ), x );
}
@Override
public SqmFunction<Double> atan2(Expression<? extends Number> y, Number x) {
return atan2( y, value( x ) );
}
@Override
public SqmFunction<Double> atan2(Expression<? extends Number> y, Expression<? extends Number> x) {
return getFunctionDescriptor( "atan2" ).generateSqmExpression(
asList( (SqmTypedNode<?>) y, (SqmTypedNode<?>) x ),
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<Double> sinh(Expression<? extends Number> x) {
return getFunctionDescriptor( "sinh" ).generateSqmExpression(
(SqmTypedNode<?>) x,
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<Double> cosh(Expression<? extends Number> x) {
return getFunctionDescriptor( "cosh" ).generateSqmExpression(
(SqmTypedNode<?>) x,
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<Double> tanh(Expression<? extends Number> x) {
return getFunctionDescriptor( "tanh" ).generateSqmExpression(
(SqmTypedNode<?>) x,
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<Double> degrees(Expression<? extends Number> x) {
return getFunctionDescriptor( "degrees" ).generateSqmExpression(
(SqmTypedNode<?>) x,
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
@Override
public SqmFunction<Double> radians(Expression<? extends Number> x) {
return getFunctionDescriptor( "radians" ).generateSqmExpression(
(SqmTypedNode<?>) x,
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Window functions

View File

@ -0,0 +1,413 @@
/*
* 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.orm.test.query.criteria;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
import org.hibernate.testing.orm.domain.StandardDomainModel;
import org.hibernate.testing.orm.domain.gambit.EntityOfBasics;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.RequiresDialect;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import jakarta.persistence.Tuple;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Root;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Tests for various non JPA standard {@link HibernateCriteriaBuilder} functions.
*
* @author Marco Belladelli
*/
@DomainModel(standardModels = StandardDomainModel.GAMBIT)
@SessionFactory
public class HibernateCriteriaBuilderFunctionsTest {
private final static String DATETIME_PATTERN = "yyyy-MM-dd";
@BeforeEach
public void prepareData(SessionFactoryScope scope) {
scope.inTransaction( em -> {
Date now = new Date();
EntityOfBasics entity1 = new EntityOfBasics();
entity1.setId( 1 );
entity1.setTheString( "5" );
entity1.setTheInt( 5 );
entity1.setTheInteger( -1 );
entity1.setTheDouble( 1.0 );
entity1.setTheDate( now );
entity1.setTheLocalDateTime( LocalDateTime.now() );
entity1.setTheBoolean( true );
em.persist( entity1 );
EntityOfBasics entity2 = new EntityOfBasics();
entity2.setId( 2 );
entity2.setTheString( "6" );
entity2.setTheInt( 6 );
entity2.setTheInteger( -2 );
entity2.setTheDouble( 6.0 );
entity2.setTheBoolean( true );
em.persist( entity2 );
EntityOfBasics entity3 = new EntityOfBasics();
entity3.setId( 3 );
entity3.setTheString( "7" );
entity3.setTheInt( 7 );
entity3.setTheInteger( 3 );
entity3.setTheDouble( 7.0 );
entity3.setTheBoolean( false );
entity3.setTheDate( new Date( now.getTime() + 200000L ) );
em.persist( entity3 );
EntityOfBasics entity4 = new EntityOfBasics();
entity4.setId( 4 );
entity4.setTheString( "thirteen" );
entity4.setTheInt( 13 );
entity4.setTheInteger( 4 );
entity4.setTheDouble( 13.0 );
entity4.setTheBoolean( false );
entity4.setTheDate( new Date( now.getTime() + 300000L ) );
em.persist( entity4 );
EntityOfBasics entity5 = new EntityOfBasics();
entity5.setId( 5 );
entity5.setTheString( "5" );
entity5.setTheInt( 5 );
entity5.setTheInteger( 5 );
entity5.setTheDouble( 9.0 );
entity5.setTheBoolean( false );
em.persist( entity5 );
} );
}
@AfterEach
public void tearDown(SessionFactoryScope scope) {
scope.inTransaction( session -> session.createMutationQuery( "delete from EntityOfBasics" ).executeUpdate() );
}
@Test
public void testSql(SessionFactoryScope scope) {
scope.inTransaction( session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<String> query = cb.createQuery( String.class );
Root<EntityOfBasics> from = query.from( EntityOfBasics.class );
query.select( cb.sql( "'test'", String.class ) );
List<String> resultList = session.createQuery( query ).getResultList();
assertEquals( 5, resultList.size() );
resultList.forEach( r -> assertEquals( "test", r ) );
} );
}
@Test
@RequiresDialect(PostgreSQLDialect.class)
public void testSqlCustomType(SessionFactoryScope scope) {
scope.inTransaction( session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Integer> query = cb.createQuery( Integer.class );
Root<EntityOfBasics> from = query.from( EntityOfBasics.class );
try {
query.select( from.get( "id" ) ).where( cb.equal(
cb.value( InetAddress.getByName( "127.0.0.1" ) ),
cb.sql( "?::inet", InetAddress.class, cb.literal( "127.0.0.1" ) )
) );
}
catch (UnknownHostException e) {
throw new RuntimeException( e );
}
List<Integer> resultList = session.createQuery( query ).getResultList();
assertEquals( 5, resultList.size() );
} );
}
@Test
public void testFormatWithJavaUtilDate(SessionFactoryScope scope) {
scope.inTransaction( session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createQuery( Tuple.class );
Root<EntityOfBasics> from = query.from( EntityOfBasics.class );
Expression<LocalDate> theDate = from.get( "theDate" ).as( LocalDate.class );
query.multiselect( from.get( "id" ), cb.format( theDate, DATETIME_PATTERN ) )
.where( cb.isNotNull( theDate ) )
.orderBy( cb.asc( theDate ) );
List<Tuple> resultList = session.createQuery( query ).getResultList();
assertEquals( 3, resultList.size() );
EntityOfBasics eob = session.find( EntityOfBasics.class, resultList.get( 0 ).get( 0 ) );
String formattedDate = new SimpleDateFormat( DATETIME_PATTERN ).format( eob.getTheDate() );
assertEquals( formattedDate, resultList.get( 0 ).get( 1 ) );
} );
}
@Test
public void testFormatWithJavaTimeLocalDateTime(SessionFactoryScope scope) {
scope.inTransaction( session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<EntityOfBasics> from = query.from( EntityOfBasics.class );
Path<LocalDateTime> theLocalDateTime = from.get( "theLocalDateTime" );
query.multiselect( from.get( "id" ), cb.format( theLocalDateTime, DATETIME_PATTERN ) )
.where( cb.isNotNull( theLocalDateTime ) );
List<Tuple> resultList = session.createQuery( query ).getResultList();
assertEquals( 1, resultList.size() );
EntityOfBasics eob = session.find( EntityOfBasics.class, resultList.get( 0 ).get( 0 ) );
String formattedDate = DateTimeFormatter.ofPattern( DATETIME_PATTERN ).format( eob.getTheLocalDateTime() );
assertEquals( formattedDate, resultList.get( 0 ).get( 1 ) );
} );
}
@Test
public void testExtractFunctions(SessionFactoryScope scope) {
scope.inTransaction( session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<EntityOfBasics> from = query.from( EntityOfBasics.class );
Expression<LocalDateTime> theLocalDateTime = from.get( "theLocalDateTime" );
query.multiselect(
from.get( "id" ),
cb.year( theLocalDateTime ),
cb.month( theLocalDateTime ),
cb.day( theLocalDateTime ),
cb.hour( theLocalDateTime ),
cb.minute( theLocalDateTime )
).where( cb.isNotNull( theLocalDateTime ) );
Tuple result = session.createQuery( query ).getSingleResult();
EntityOfBasics eob = session.find( EntityOfBasics.class, result.get( 0 ) );
assertEquals( eob.getTheLocalDateTime().getYear(), result.get( 1 ) );
assertEquals( eob.getTheLocalDateTime().getMonth().getValue(), result.get( 2 ) );
assertEquals( eob.getTheLocalDateTime().getDayOfMonth(), result.get( 3 ) );
assertEquals( eob.getTheLocalDateTime().getHour(), result.get( 4 ) );
assertEquals( eob.getTheLocalDateTime().getMinute(), result.get( 5 ) );
} );
}
@Test
public void testOverlay(SessionFactoryScope scope) {
scope.inTransaction( session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<EntityOfBasics> from = query.from( EntityOfBasics.class );
Expression<String> theString = from.get( "theString" );
query.multiselect(
cb.overlay( theString, "33", 6 ),
cb.overlay( theString, from.get( "theInt" ).as( String.class ), 6 ),
cb.overlay( theString, "1234", from.get( "theInteger" ), 2 )
).where( cb.equal( from.get( "id" ), 4 ) );
Tuple result = session.createQuery( query ).getSingleResult();
assertEquals( "thirt33n", result.get( 0 ) );
assertEquals( "thirt13n", result.get( 1 ) );
assertEquals( "thi1234een", result.get( 2 ) );
} );
}
@Test
public void testPad(SessionFactoryScope scope) {
scope.inTransaction( session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<EntityOfBasics> from = query.from( EntityOfBasics.class );
Expression<String> theString = from.get( "theString" );
query.multiselect(
cb.pad( theString, 5 ),
cb.pad( CriteriaBuilder.Trimspec.TRAILING, theString, from.get( "theInt" ) ),
cb.pad( CriteriaBuilder.Trimspec.LEADING, theString, 3, '#' )
).where( cb.equal( from.get( "id" ), 1 ) );
Tuple result = session.createQuery( query ).getSingleResult();
assertEquals( "5 ", result.get( 0 ) );
assertEquals( "5 ", result.get( 1 ) );
assertEquals( "##5", result.get( 2 ) );
} );
}
@Test
public void testLeftRight(SessionFactoryScope scope) {
scope.inTransaction( session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<EntityOfBasics> from = query.from( EntityOfBasics.class );
Expression<String> theString = from.get( "theString" );
query.multiselect(
cb.left( theString, 3 ),
cb.right( theString, from.get( "theInteger" ) )
).where( cb.equal( from.get( "id" ), 4 ) );
Tuple result = session.createQuery( query ).getSingleResult();
assertEquals( "thi", result.get( 0 ) );
assertEquals( "teen", result.get( 1 ) );
} );
}
@Test
public void testReplace(SessionFactoryScope scope) {
scope.inTransaction( session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<EntityOfBasics> from = query.from( EntityOfBasics.class );
Expression<String> theString = from.get( "theString" );
query.multiselect(
cb.replace( theString, "thi", "12345" ),
cb.replace( theString, "t", from.get( "theInteger" ).as( String.class ) )
).where( cb.equal( from.get( "id" ), 4 ) );
Tuple result = session.createQuery( query ).getSingleResult();
assertEquals( "12345rteen", result.get( 0 ) );
assertEquals( "4hir4een", result.get( 1 ) );
} );
}
@Test
@RequiresDialect(PostgreSQLDialect.class)
public void testCollatePostgreSQL(SessionFactoryScope scope) {
scope.inTransaction( session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<String> query = cb.createQuery( String.class );
Root<EntityOfBasics> from = query.from( EntityOfBasics.class );
Expression<String> theString = from.get( "theString" );
query.select( theString )
.where( cb.isNotNull( theString ) )
.orderBy( cb.asc( cb.collate( theString, "ucs_basic" ) ) );
assertNotNull( session.createQuery( query ).getResultList() );
CriteriaQuery<Boolean> query2 = cb.createQuery( Boolean.class );
query2.select( cb.lessThan( cb.collate(
cb.literal( "bar" ),
"ucs_basic"
), cb.literal( "foo" ) ) );
assertTrue( session.createQuery( query2 ).getSingleResult() );
} );
}
@Test
public void testLog(SessionFactoryScope scope) {
scope.inTransaction( session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<EntityOfBasics> from = query.from( EntityOfBasics.class );
query.multiselect(
cb.log10( from.get( "theInt" ) ),
cb.log( 10, from.get( "theInt" ) )
).where( cb.equal( from.get( "id" ), 1 ) );
Tuple result = session.createQuery( query ).getSingleResult();
assertEquals( 0.698970, result.get( 0, Double.class ), 1e-6 );
assertEquals( 0.698970, result.get( 1, Double.class ), 1e-6 );
} );
}
@Test
public void testPi(SessionFactoryScope scope) {
scope.inTransaction( session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Double> query = cb.createQuery( Double.class ).select( cb.pi() );
assertEquals( 3.141592, session.createQuery( query ).getSingleResult(), 1e-6 );
} );
}
@Test
public void testTrigonometricFunctions(SessionFactoryScope scope) {
scope.inTransaction( session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<EntityOfBasics> from = query.from( EntityOfBasics.class );
Path<Double> theDouble = from.get( "theDouble" );
query.multiselect(
cb.sin( theDouble ),
cb.cos( theDouble ),
cb.tan( theDouble ),
cb.asin( theDouble ),
cb.acos( theDouble ),
cb.atan( theDouble ),
cb.atan2( cb.sin( theDouble ), 0 ),
cb.atan2( cb.sin( theDouble ), cb.cos( theDouble ) )
).where( cb.equal( from.get( "id" ), 1 ) );
Tuple result = session.createQuery( query ).getSingleResult();
assertEquals( Math.sin( 1.0 ), result.get( 0, Double.class ), 1e-6 );
assertEquals( Math.cos( 1.0 ), result.get( 1, Double.class ), 1e-6 );
assertEquals( Math.tan( 1.0 ), result.get( 2, Double.class ), 1e-6 );
assertEquals( Math.asin( 1.0 ), result.get( 3, Double.class ), 1e-6 );
assertEquals( Math.acos( 1.0 ), result.get( 4, Double.class ), 1e-6 );
assertEquals( Math.atan( 1.0 ), result.get( 5, Double.class ), 1e-6 );
assertEquals( Math.atan2( Math.sin( 1.0 ), 0 ), result.get( 6, Double.class ), 1e-6 );
assertEquals( Math.atan2( Math.sin( 1.0 ), Math.cos( 1.0 ) ), result.get( 7, Double.class ), 1e-6 );
} );
}
@Test
public void testHyperbolic(SessionFactoryScope scope) {
scope.inTransaction( session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<EntityOfBasics> from = query.from( EntityOfBasics.class );
Path<Double> theDouble = from.get( "theDouble" );
query.multiselect(
cb.sinh( theDouble ),
cb.cosh( theDouble ),
cb.tanh( theDouble )
).where( cb.equal( from.get( "id" ), 1 ) );
Tuple result = session.createQuery( query ).getSingleResult();
assertEquals( Math.sinh( 1.0 ), result.get( 0, Double.class ), 1e-6 );
assertEquals( Math.cosh( 1.0 ), result.get( 1, Double.class ), 1e-6 );
assertEquals( Math.tanh( 1.0 ), result.get( 2, Double.class ), 1e-6 );
} );
}
@Test
public void testDegrees(SessionFactoryScope scope) {
scope.inTransaction( session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
query.multiselect( cb.degrees( cb.pi() ), cb.radians( cb.literal( 180.0 ) ) );
Tuple result = session.createQuery( query ).getSingleResult();
assertEquals( 180.0, result.get( 0, Double.class ), 1e-9 );
assertEquals( Math.PI, result.get( 1, Double.class ), 1e-9 );
} );
}
}