HHH-17109 date/time arithmetic in criteria queries
This commit is contained in:
parent
bdd78fe39c
commit
2e5c6fe3a1
|
@ -11,7 +11,9 @@ import java.math.BigInteger;
|
||||||
import java.sql.Date;
|
import java.sql.Date;
|
||||||
import java.sql.Time;
|
import java.sql.Time;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.Temporal;
|
||||||
import java.time.temporal.TemporalAccessor;
|
import java.time.temporal.TemporalAccessor;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -386,7 +388,6 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
|
||||||
@Override
|
@Override
|
||||||
<N extends Number> JpaExpression<N> abs(Expression<N> x);
|
<N extends Number> JpaExpression<N> abs(Expression<N> x);
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
<N extends Number> JpaExpression<N> sum(Expression<? extends N> x, Expression<? extends N> y);
|
<N extends Number> JpaExpression<N> sum(Expression<? extends N> x, Expression<? extends N> y);
|
||||||
|
|
||||||
|
@ -435,6 +436,127 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
|
||||||
@Override
|
@Override
|
||||||
JpaExpression<Double> sqrt(Expression<? extends Number> x);
|
JpaExpression<Double> sqrt(Expression<? extends Number> x);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add two {@linkplain Duration durations}.
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
JpaExpression<Duration> durationSum(Expression<Duration> x, Expression<Duration> y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add two {@linkplain Duration durations}.
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
JpaExpression<Duration> durationSum(Expression<Duration> x, Duration y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtract one {@linkplain Duration duration} from another.
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
JpaExpression<Duration> durationDiff(Expression<Duration> x, Expression<Duration> y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtract one {@linkplain Duration duration} from another.
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
JpaExpression<Duration> durationDiff(Expression<Duration> x, Duration y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scale a {@linkplain Duration duration} by a number.
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
JpaExpression<Duration> durationScaled(Expression<? extends Number> number, Expression<Duration> duration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scale a {@linkplain Duration duration} by a number.
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
JpaExpression<Duration> durationScaled(Number number, Expression<Duration> duration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scale a {@linkplain Duration duration} by a number.
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
JpaExpression<Duration> durationScaled(Expression<? extends Number> number, Duration duration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A literal {@link Duration}, for example, "five days" or "30 minutes".
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
@Incubating // layer breaker (leaks SQM type)
|
||||||
|
JpaExpression<Duration> duration(long magnitude, TemporalUnit unit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a {@link Duration} to a numeric magnitude in the given units.
|
||||||
|
* @param unit a choice of temporal granularity
|
||||||
|
* @param duration the duration in a "unit-free" form
|
||||||
|
* @return the magnitude of the duration measured in the given units
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
@Incubating // layer breaker (leaks SQM type)
|
||||||
|
JpaExpression<Long> durationByUnit(TemporalUnit unit, Expression<Duration> duration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtract two dates or two datetimes, returning the duration between the
|
||||||
|
* two dates or between two datetimes.
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
<T extends Temporal> JpaExpression<Duration> durationBetween(Expression<T> x, Expression<T> y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtract two dates or two datetimes, returning the duration between the
|
||||||
|
* two dates or between two datetimes.
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
<T extends Temporal> JpaExpression<Duration> durationBetween(Expression<T> x, T y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a duration to a date or datetime, that is, return a later date or
|
||||||
|
* datetime which is separated from the given date or datetime by the given
|
||||||
|
* duration.
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
<T extends Temporal> JpaExpression<T> addDuration(Expression<T> datetime, Expression<Duration> duration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a duration to a date or datetime, that is, return a later date or
|
||||||
|
* datetime which is separated from the given date or datetime by the given
|
||||||
|
* duration.
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
<T extends Temporal> JpaExpression<T> addDuration(Expression<T> datetime, Duration duration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a duration to a date or datetime, that is, return a later date or
|
||||||
|
* datetime which is separated from the given date or datetime by the given
|
||||||
|
* duration.
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
<T extends Temporal> JpaExpression<T> addDuration(T datetime, Expression<Duration> duration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtract a duration to a date or datetime, that is, return an earlier date
|
||||||
|
* or datetime which is separated from the given date or datetime by the given
|
||||||
|
* duration.
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
<T extends Temporal> JpaExpression<T> subtractDuration(Expression<T> datetime, Expression<Duration> duration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtract a duration to a date or datetime, that is, return an earlier date
|
||||||
|
* or datetime which is separated from the given date or datetime by the given
|
||||||
|
* duration.
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
<T extends Temporal> JpaExpression<T> subtractDuration(Expression<T> datetime, Duration duration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtract a duration to a date or datetime, that is, return an earlier date
|
||||||
|
* or datetime which is separated from the given date or datetime by the given
|
||||||
|
* duration.
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
<T extends Temporal> JpaExpression<T> subtractDuration(T datetime, Expression<Duration> duration);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
JpaExpression<Long> toLong(Expression<? extends Number> number);
|
JpaExpression<Long> toLong(Expression<? extends Number> number);
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,12 @@ import java.math.BigInteger;
|
||||||
import java.sql.Date;
|
import java.sql.Date;
|
||||||
import java.sql.Time;
|
import java.sql.Time;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
|
import java.time.temporal.Temporal;
|
||||||
import java.time.temporal.TemporalAccessor;
|
import java.time.temporal.TemporalAccessor;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -2039,4 +2041,89 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
|
||||||
Expression<?>... arguments) {
|
Expression<?>... arguments) {
|
||||||
return criteriaBuilder.percentRank( order, filter, window, arguments );
|
return criteriaBuilder.percentRank( order, filter, window, arguments );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JpaExpression<Duration> durationSum(Expression<Duration> x, Expression<Duration> y) {
|
||||||
|
return criteriaBuilder.durationSum( x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JpaExpression<Duration> durationSum(Expression<Duration> x, Duration y) {
|
||||||
|
return criteriaBuilder.durationSum( x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JpaExpression<Duration> durationDiff(Expression<Duration> x, Expression<Duration> y) {
|
||||||
|
return criteriaBuilder.durationDiff( x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JpaExpression<Duration> durationDiff(Expression<Duration> x, Duration y) {
|
||||||
|
return criteriaBuilder.durationDiff( x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JpaExpression<Duration> durationScaled(Expression<? extends Number> number, Expression<Duration> duration) {
|
||||||
|
return criteriaBuilder.durationScaled( number, duration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JpaExpression<Duration> durationScaled(Number number, Expression<Duration> duration) {
|
||||||
|
return criteriaBuilder.durationScaled( number, duration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JpaExpression<Duration> durationScaled(Expression<? extends Number> number, Duration duration) {
|
||||||
|
return criteriaBuilder.durationScaled( number, duration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Temporal> JpaExpression<Duration> durationBetween(Expression<T> x, Expression<T> y) {
|
||||||
|
return criteriaBuilder.durationBetween( x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Temporal> JpaExpression<Duration> durationBetween(Expression<T> x, T y) {
|
||||||
|
return criteriaBuilder.durationBetween( x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Temporal> JpaExpression<T> addDuration(Expression<T> datetime, Expression<Duration> duration) {
|
||||||
|
return criteriaBuilder.addDuration( datetime, duration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Temporal> JpaExpression<T> addDuration(Expression<T> datetime, Duration duration) {
|
||||||
|
return criteriaBuilder.addDuration( datetime, duration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Temporal> JpaExpression<T> addDuration(T datetime, Expression<Duration> duration) {
|
||||||
|
return criteriaBuilder.addDuration(datetime, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Temporal> JpaExpression<T> subtractDuration(Expression<T> datetime, Expression<Duration> duration) {
|
||||||
|
return criteriaBuilder.subtractDuration( datetime, duration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Temporal> JpaExpression<T> subtractDuration(Expression<T> datetime, Duration duration) {
|
||||||
|
return criteriaBuilder.subtractDuration( datetime, duration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Temporal> JpaExpression<T> subtractDuration(T datetime, Expression<Duration> duration) {
|
||||||
|
return criteriaBuilder.subtractDuration(datetime, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JpaExpression<Long> durationByUnit(TemporalUnit unit, Expression<Duration> duration) {
|
||||||
|
return criteriaBuilder.durationByUnit(unit, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JpaExpression<Duration> duration(long magnitude, TemporalUnit unit) {
|
||||||
|
return criteriaBuilder.duration( magnitude, unit );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -649,6 +649,8 @@ public interface NodeBuilder extends HibernateCriteriaBuilder {
|
||||||
|
|
||||||
BasicType<Integer> getIntegerType();
|
BasicType<Integer> getIntegerType();
|
||||||
|
|
||||||
|
BasicType<Long> getLongType();
|
||||||
|
|
||||||
BasicType<Character> getCharacterType();
|
BasicType<Character> getCharacterType();
|
||||||
|
|
||||||
SessionFactoryImplementor getSessionFactory();
|
SessionFactoryImplementor getSessionFactory();
|
||||||
|
|
|
@ -13,10 +13,12 @@ import java.math.BigInteger;
|
||||||
import java.sql.Date;
|
import java.sql.Date;
|
||||||
import java.sql.Time;
|
import java.sql.Time;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
|
import java.time.temporal.Temporal;
|
||||||
import java.time.temporal.TemporalAccessor;
|
import java.time.temporal.TemporalAccessor;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -97,6 +99,7 @@ import org.hibernate.query.sqm.tree.domain.SqmSetJoin;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmSingularJoin;
|
import org.hibernate.query.sqm.tree.domain.SqmSingularJoin;
|
||||||
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
|
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
|
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
|
||||||
|
import org.hibernate.query.sqm.tree.expression.SqmByUnit;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
|
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
|
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
|
import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
|
||||||
|
@ -104,6 +107,7 @@ import org.hibernate.query.sqm.tree.expression.SqmCoalesce;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmCollation;
|
import org.hibernate.query.sqm.tree.expression.SqmCollation;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
|
import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
|
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
|
||||||
|
import org.hibernate.query.sqm.tree.expression.SqmDurationUnit;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
|
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmFormat;
|
import org.hibernate.query.sqm.tree.expression.SqmFormat;
|
||||||
|
@ -112,6 +116,7 @@ import org.hibernate.query.sqm.tree.expression.SqmLiteral;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmLiteralNull;
|
import org.hibernate.query.sqm.tree.expression.SqmLiteralNull;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression;
|
import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmOver;
|
import org.hibernate.query.sqm.tree.expression.SqmOver;
|
||||||
|
import org.hibernate.query.sqm.tree.expression.SqmToDuration;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification;
|
import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmTuple;
|
import org.hibernate.query.sqm.tree.expression.SqmTuple;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation;
|
import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation;
|
||||||
|
@ -191,6 +196,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
private final transient ValueHandlingMode criteriaValueHandlingMode;
|
private final transient ValueHandlingMode criteriaValueHandlingMode;
|
||||||
private transient BasicType<Boolean> booleanType;
|
private transient BasicType<Boolean> booleanType;
|
||||||
private transient BasicType<Integer> integerType;
|
private transient BasicType<Integer> integerType;
|
||||||
|
private transient BasicType<Long> longType;
|
||||||
private transient BasicType<Character> characterType;
|
private transient BasicType<Character> characterType;
|
||||||
private final transient Map<Class<? extends HibernateCriteriaBuilder>, HibernateCriteriaBuilder> extensions;
|
private final transient Map<Class<? extends HibernateCriteriaBuilder>, HibernateCriteriaBuilder> extensions;
|
||||||
|
|
||||||
|
@ -258,6 +264,17 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
return integerType;
|
return integerType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BasicType<Long> getLongType() {
|
||||||
|
final BasicType<Long> longType = this.longType;
|
||||||
|
if ( longType == null ) {
|
||||||
|
return this.longType =
|
||||||
|
getTypeConfiguration().getBasicTypeRegistry()
|
||||||
|
.resolve( StandardBasicTypes.LONG );
|
||||||
|
}
|
||||||
|
return longType;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BasicType<Character> getCharacterType() {
|
public BasicType<Character> getCharacterType() {
|
||||||
final BasicType<Character> characterType = this.characterType;
|
final BasicType<Character> characterType = this.characterType;
|
||||||
|
@ -921,11 +938,122 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <N extends Number> SqmExpression<N> sum(Expression<? extends N> x, Expression<? extends N> y) {
|
public JpaExpression<Duration> duration(long magnitude, TemporalUnit unit) {
|
||||||
return createSqmArithmeticNode( BinaryArithmeticOperator.ADD, (SqmExpression<?>) x, (SqmExpression<?>) y );
|
return new SqmToDuration<>(
|
||||||
|
literal( magnitude ),
|
||||||
|
new SqmDurationUnit<>( unit, getLongType(), this ),
|
||||||
|
getTypeConfiguration().standardBasicTypeForJavaType( Duration.class ),
|
||||||
|
this
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <N extends Number> SqmExpression<N> createSqmArithmeticNode(
|
@Override
|
||||||
|
public JpaExpression<Long> durationByUnit(TemporalUnit unit, Expression<Duration> duration) {
|
||||||
|
return new SqmByUnit(
|
||||||
|
new SqmDurationUnit<>( unit, getLongType(), this ),
|
||||||
|
(SqmExpression<Duration>) duration,
|
||||||
|
getLongType(),
|
||||||
|
this
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JpaExpression<Duration> durationSum(Expression<Duration> x, Expression<Duration> y) {
|
||||||
|
return createSqmArithmeticNode( BinaryArithmeticOperator.ADD,
|
||||||
|
(SqmExpression<Duration>) x, (SqmExpression<Duration>) y );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JpaExpression<Duration> durationSum(Expression<Duration> x, Duration y) {
|
||||||
|
return createSqmArithmeticNode( BinaryArithmeticOperator.ADD,
|
||||||
|
(SqmExpression<Duration>) x, value( y ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JpaExpression<Duration> durationDiff(Expression<Duration> x, Expression<Duration> y) {
|
||||||
|
return createSqmArithmeticNode( BinaryArithmeticOperator.SUBTRACT,
|
||||||
|
(SqmExpression<Duration>) x, (SqmExpression<Duration>) y );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JpaExpression<Duration> durationDiff(Expression<Duration> x, Duration y) {
|
||||||
|
return createSqmArithmeticNode( BinaryArithmeticOperator.SUBTRACT,
|
||||||
|
(SqmExpression<Duration>) x, value( y ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JpaExpression<Duration> durationScaled(Expression<? extends Number> number, Expression<Duration> duration) {
|
||||||
|
return createSqmArithmeticNode( BinaryArithmeticOperator.MULTIPLY,
|
||||||
|
(SqmExpression<? extends Number>) number, (SqmExpression<Duration>) duration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JpaExpression<Duration> durationScaled(Number number, Expression<Duration> duration) {
|
||||||
|
return createSqmArithmeticNode( BinaryArithmeticOperator.MULTIPLY,
|
||||||
|
value( number ), (SqmExpression<Duration>) duration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JpaExpression<Duration> durationScaled(Expression<? extends Number> number, Duration duration) {
|
||||||
|
return createSqmArithmeticNode( BinaryArithmeticOperator.MULTIPLY,
|
||||||
|
(SqmExpression<? extends Number>) number, value( duration ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Temporal> JpaExpression<Duration> durationBetween(Expression<T> x, Expression<T> y) {
|
||||||
|
return createSqmArithmeticNode( BinaryArithmeticOperator.SUBTRACT,
|
||||||
|
(SqmExpression<T>) x, (SqmExpression<T>) y );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Temporal> JpaExpression<Duration> durationBetween(Expression<T> x, T y) {
|
||||||
|
return createSqmArithmeticNode( BinaryArithmeticOperator.SUBTRACT,
|
||||||
|
(SqmExpression<T>) x, value( y ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Temporal> JpaExpression<T> addDuration(Expression<T> datetime, Expression<Duration> duration) {
|
||||||
|
return createSqmArithmeticNode( BinaryArithmeticOperator.ADD,
|
||||||
|
(SqmExpression<T>) datetime, (SqmExpression<Duration>) duration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Temporal> JpaExpression<T> addDuration(Expression<T> datetime, Duration duration) {
|
||||||
|
return createSqmArithmeticNode( BinaryArithmeticOperator.ADD,
|
||||||
|
(SqmExpression<T>) datetime, value( duration ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Temporal> JpaExpression<T> addDuration(T datetime, Expression<Duration> duration) {
|
||||||
|
return createSqmArithmeticNode( BinaryArithmeticOperator.ADD,
|
||||||
|
value( datetime ), (SqmExpression<Duration>) duration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Temporal> JpaExpression<T> subtractDuration(Expression<T> datetime, Expression<Duration> duration) {
|
||||||
|
return createSqmArithmeticNode( BinaryArithmeticOperator.SUBTRACT,
|
||||||
|
(SqmExpression<T>) datetime, (SqmExpression<Duration>) duration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Temporal> JpaExpression<T> subtractDuration(Expression<T> datetime, Duration duration) {
|
||||||
|
return createSqmArithmeticNode( BinaryArithmeticOperator.SUBTRACT,
|
||||||
|
(SqmExpression<T>) datetime, value( duration ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Temporal> JpaExpression<T> subtractDuration(T datetime, Expression<Duration> duration) {
|
||||||
|
return createSqmArithmeticNode( BinaryArithmeticOperator.SUBTRACT,
|
||||||
|
value( datetime ), (SqmExpression<Duration>) duration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <N extends Number> SqmExpression<N> sum(Expression<? extends N> x, Expression<? extends N> y) {
|
||||||
|
return createSqmArithmeticNode( BinaryArithmeticOperator.ADD,
|
||||||
|
(SqmExpression<? extends N>) x, (SqmExpression<? extends N>) y );
|
||||||
|
}
|
||||||
|
|
||||||
|
private <N> SqmExpression<N> createSqmArithmeticNode(
|
||||||
BinaryArithmeticOperator operator,
|
BinaryArithmeticOperator operator,
|
||||||
SqmExpression<?> leftHandExpression,
|
SqmExpression<?> leftHandExpression,
|
||||||
SqmExpression<?> rightHandExpression) {
|
SqmExpression<?> rightHandExpression) {
|
||||||
|
@ -947,7 +1075,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
public <N extends Number> SqmExpression<N> sum(Expression<? extends N> x, N y) {
|
public <N extends Number> SqmExpression<N> sum(Expression<? extends N> x, N y) {
|
||||||
return createSqmArithmeticNode(
|
return createSqmArithmeticNode(
|
||||||
BinaryArithmeticOperator.ADD,
|
BinaryArithmeticOperator.ADD,
|
||||||
(SqmExpression<?>) x,
|
(SqmExpression<? extends N>) x,
|
||||||
value( y )
|
value( y )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -957,7 +1085,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
return createSqmArithmeticNode(
|
return createSqmArithmeticNode(
|
||||||
BinaryArithmeticOperator.ADD,
|
BinaryArithmeticOperator.ADD,
|
||||||
value( x ),
|
value( x ),
|
||||||
(SqmExpression<?>) y
|
(SqmExpression<? extends N>) y
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -965,8 +1093,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
public <N extends Number> SqmExpression<N> prod(Expression<? extends N> x, Expression<? extends N> y) {
|
public <N extends Number> SqmExpression<N> prod(Expression<? extends N> x, Expression<? extends N> y) {
|
||||||
return createSqmArithmeticNode(
|
return createSqmArithmeticNode(
|
||||||
BinaryArithmeticOperator.MULTIPLY,
|
BinaryArithmeticOperator.MULTIPLY,
|
||||||
(SqmExpression<?>) x,
|
(SqmExpression<? extends N>) x,
|
||||||
(SqmExpression<?>) y
|
(SqmExpression<? extends N>) y
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -974,7 +1102,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
public <N extends Number> SqmExpression<N> prod(Expression<? extends N> x, N y) {
|
public <N extends Number> SqmExpression<N> prod(Expression<? extends N> x, N y) {
|
||||||
return createSqmArithmeticNode(
|
return createSqmArithmeticNode(
|
||||||
BinaryArithmeticOperator.MULTIPLY,
|
BinaryArithmeticOperator.MULTIPLY,
|
||||||
(SqmExpression<?>) x,
|
(SqmExpression<? extends N>) x,
|
||||||
value( y )
|
value( y )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -984,7 +1112,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
return createSqmArithmeticNode(
|
return createSqmArithmeticNode(
|
||||||
BinaryArithmeticOperator.MULTIPLY,
|
BinaryArithmeticOperator.MULTIPLY,
|
||||||
value( x ),
|
value( x ),
|
||||||
(SqmExpression<?>) y
|
(SqmExpression<? extends N>) y
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -992,8 +1120,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
public <N extends Number> SqmExpression<N> diff(Expression<? extends N> x, Expression<? extends N> y) {
|
public <N extends Number> SqmExpression<N> diff(Expression<? extends N> x, Expression<? extends N> y) {
|
||||||
return createSqmArithmeticNode(
|
return createSqmArithmeticNode(
|
||||||
BinaryArithmeticOperator.SUBTRACT,
|
BinaryArithmeticOperator.SUBTRACT,
|
||||||
(SqmExpression<?>) x,
|
(SqmExpression<? extends N>) x,
|
||||||
(SqmExpression<?>) y
|
(SqmExpression<? extends N>) y
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1001,7 +1129,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
public <N extends Number> SqmExpression<N> diff(Expression<? extends N> x, N y) {
|
public <N extends Number> SqmExpression<N> diff(Expression<? extends N> x, N y) {
|
||||||
return createSqmArithmeticNode(
|
return createSqmArithmeticNode(
|
||||||
BinaryArithmeticOperator.SUBTRACT,
|
BinaryArithmeticOperator.SUBTRACT,
|
||||||
(SqmExpression<?>) x,
|
(SqmExpression<? extends N>) x,
|
||||||
value( y )
|
value( y )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1011,7 +1139,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
return createSqmArithmeticNode(
|
return createSqmArithmeticNode(
|
||||||
BinaryArithmeticOperator.SUBTRACT,
|
BinaryArithmeticOperator.SUBTRACT,
|
||||||
value( x ),
|
value( x ),
|
||||||
(SqmExpression<?>) y
|
(SqmExpression<? extends N>) y
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1019,8 +1147,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
public SqmExpression<Number> quot(Expression<? extends Number> x, Expression<? extends Number> y) {
|
public SqmExpression<Number> quot(Expression<? extends Number> x, Expression<? extends Number> y) {
|
||||||
return createSqmArithmeticNode(
|
return createSqmArithmeticNode(
|
||||||
BinaryArithmeticOperator.QUOT,
|
BinaryArithmeticOperator.QUOT,
|
||||||
(SqmExpression<?>) x,
|
(SqmExpression<? extends Number>) x,
|
||||||
(SqmExpression<?>) y
|
(SqmExpression<? extends Number>) y
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1028,7 +1156,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
public SqmExpression<Number> quot(Expression<? extends Number> x, Number y) {
|
public SqmExpression<Number> quot(Expression<? extends Number> x, Number y) {
|
||||||
return createSqmArithmeticNode(
|
return createSqmArithmeticNode(
|
||||||
BinaryArithmeticOperator.QUOT,
|
BinaryArithmeticOperator.QUOT,
|
||||||
(SqmExpression<?>) x,
|
(SqmExpression<? extends Number>) x,
|
||||||
value( y )
|
value( y )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1650,7 +1778,17 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> SqmExpression<T> value(T value) {
|
public <T> SqmExpression<T> value(T value) {
|
||||||
return inlineValue( value ) ? literal( value ) : valueParameter( value );
|
if ( value instanceof Duration ) {
|
||||||
|
final Duration duration = (Duration) value;
|
||||||
|
final JpaExpression<Duration> expression = duration.getNano() == 0
|
||||||
|
? duration( duration.getSeconds(), TemporalUnit.SECOND )
|
||||||
|
: duration( duration.getNano() + duration.getSeconds() * 1_000_000_000, TemporalUnit.NANOSECOND );
|
||||||
|
//noinspection unchecked
|
||||||
|
return (SqmExpression<T>) expression;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return inlineValue( value ) ? literal( value ) : valueParameter( value );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> boolean isInstance(BindableType<T> bindableType, T value) {
|
private <T> boolean isInstance(BindableType<T> bindableType, T value) {
|
||||||
|
|
|
@ -8,17 +8,24 @@ package org.hibernate.orm.test.jpa.criteria.basic;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.dialect.DB2Dialect;
|
import org.hibernate.dialect.DB2Dialect;
|
||||||
import org.hibernate.dialect.DerbyDialect;
|
import org.hibernate.dialect.DerbyDialect;
|
||||||
|
import org.hibernate.dialect.PostgresPlusDialect;
|
||||||
|
import org.hibernate.dialect.SybaseDialect;
|
||||||
import org.hibernate.orm.test.jpa.metamodel.AbstractMetamodelSpecificTest;
|
import org.hibernate.orm.test.jpa.metamodel.AbstractMetamodelSpecificTest;
|
||||||
import org.hibernate.orm.test.jpa.metamodel.Phone;
|
import org.hibernate.orm.test.jpa.metamodel.Phone;
|
||||||
import org.hibernate.orm.test.jpa.metamodel.Product;
|
import org.hibernate.orm.test.jpa.metamodel.Product;
|
||||||
import org.hibernate.orm.test.jpa.metamodel.Product_;
|
import org.hibernate.orm.test.jpa.metamodel.Product_;
|
||||||
import org.hibernate.query.Query;
|
import org.hibernate.query.Query;
|
||||||
|
|
||||||
|
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
|
||||||
|
import org.hibernate.query.sqm.TemporalUnit;
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
@ -252,6 +259,107 @@ public class ExpressionsTest extends AbstractMetamodelSpecificTest {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test @SkipForDialect(dialectClass = SybaseDialect.class, matchSubTypes = true, reason = "numeric overflows")
|
||||||
|
@SkipForDialect(dialectClass = PostgresPlusDialect.class, reason = "does not support extract(epoch)")
|
||||||
|
public void testDateTimeOperations() {
|
||||||
|
HibernateCriteriaBuilder builder = (HibernateCriteriaBuilder) this.builder;
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory,
|
||||||
|
entityManager -> {
|
||||||
|
CriteriaQuery<LocalDate> criteria = builder.createQuery(LocalDate.class);
|
||||||
|
criteria.select( builder.addDuration( builder.localDate(),
|
||||||
|
builder.duration(2, TemporalUnit.YEAR) ) );
|
||||||
|
entityManager.createQuery(criteria).getSingleResult();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory,
|
||||||
|
entityManager -> {
|
||||||
|
CriteriaQuery<LocalDate> criteria = builder.createQuery(LocalDate.class);
|
||||||
|
criteria.select( builder.addDuration(
|
||||||
|
// had to call literal() here because parameter-based binding caused error from
|
||||||
|
// database since it couldn't tell what sort of dateadd() function was being called
|
||||||
|
builder.literal( LocalDate.of(2000,1, 1) ),
|
||||||
|
builder.duration(2, TemporalUnit.YEAR) ) );
|
||||||
|
assertEquals( LocalDate.of(2002,1, 1),
|
||||||
|
entityManager.createQuery(criteria).getSingleResult() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
//SQL Server and others don't like this
|
||||||
|
// doInJPA(
|
||||||
|
// this::entityManagerFactory,
|
||||||
|
// entityManager -> {
|
||||||
|
// CriteriaQuery<LocalDate> criteria = builder.createQuery(LocalDate.class);
|
||||||
|
// criteria.select( builder.after( builder.localDate(), Duration.ofDays(2*365) ) );
|
||||||
|
// entityManager.createQuery(criteria).getSingleResult();
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory,
|
||||||
|
entityManager -> {
|
||||||
|
CriteriaQuery<LocalDateTime> criteria = builder.createQuery(LocalDateTime.class);
|
||||||
|
criteria.select( builder.subtractDuration( builder.localDateTime(), Duration.ofMinutes(30) ) );
|
||||||
|
entityManager.createQuery(criteria).getSingleResult();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory,
|
||||||
|
entityManager -> {
|
||||||
|
CriteriaQuery<Duration> criteria = builder.createQuery(Duration.class);
|
||||||
|
criteria.select( builder.durationScaled( 5, builder.duration(2, TemporalUnit.HOUR ) ) );
|
||||||
|
assertEquals( Duration.ofHours(10), entityManager.createQuery(criteria).getSingleResult() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory,
|
||||||
|
entityManager -> {
|
||||||
|
CriteriaQuery<Duration> criteria = builder.createQuery(Duration.class);
|
||||||
|
criteria.select( builder.durationSum( builder.duration(30, TemporalUnit.MINUTE ),
|
||||||
|
builder.duration(2, TemporalUnit.HOUR) ) );
|
||||||
|
assertEquals( Duration.ofMinutes(150), entityManager.createQuery(criteria).getSingleResult() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory,
|
||||||
|
entityManager -> {
|
||||||
|
CriteriaQuery<Long> criteria = builder.createQuery(Long.class);
|
||||||
|
criteria.select( builder.durationByUnit( TemporalUnit.SECOND,
|
||||||
|
builder.durationSum( builder.duration(30, TemporalUnit.MINUTE),
|
||||||
|
builder.duration(2, TemporalUnit.HOUR) ) ) );
|
||||||
|
assertEquals( 150*60L, entityManager.createQuery(criteria).getSingleResult() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory,
|
||||||
|
entityManager -> {
|
||||||
|
CriteriaQuery<Duration> criteria = builder.createQuery(Duration.class);
|
||||||
|
criteria.select( builder.durationBetween( builder.localDate(),
|
||||||
|
LocalDate.of(2000,1, 1) ) );
|
||||||
|
entityManager.createQuery(criteria).getSingleResult();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory,
|
||||||
|
entityManager -> {
|
||||||
|
CriteriaQuery<Duration> criteria = builder.createQuery(Duration.class);
|
||||||
|
criteria.select( builder.durationBetween( builder.localDate(),
|
||||||
|
builder.subtractDuration( builder.localDate(),
|
||||||
|
builder.duration(2, TemporalUnit.DAY) ) ) );
|
||||||
|
assertEquals( Duration.ofDays(2), entityManager.createQuery(criteria).getSingleResult() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory,
|
||||||
|
entityManager -> {
|
||||||
|
CriteriaQuery<Duration> criteria = builder.createQuery(Duration.class);
|
||||||
|
criteria.select( builder.durationBetween( builder.localDateTime(),
|
||||||
|
builder.subtractDuration( builder.localDateTime(),
|
||||||
|
builder.duration(20, TemporalUnit.HOUR) ) ) );
|
||||||
|
assertEquals( Duration.ofHours(20), entityManager.createQuery(criteria).getSingleResult() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "By default, unless some kind of context enables inference," +
|
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "By default, unless some kind of context enables inference," +
|
||||||
"a numeric/decimal parameter has the type DECIMAL(31,31) which might cause an overflow on certain arithmetics." +
|
"a numeric/decimal parameter has the type DECIMAL(31,31) which might cause an overflow on certain arithmetics." +
|
||||||
|
|
Loading…
Reference in New Issue