/* * Copyright 2015, The Querydsl Team (http://www.querydsl.com/team) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.querydsl.core.types.dsl; import java.util.ArrayList; import java.util.List; import javax.annotation.Nullable; import com.querydsl.core.types.*; import com.querydsl.core.types.Ops.MathOps; import com.querydsl.core.util.MathUtils; /** * {@code NumberExpression} represents a numeric expression * * @author tiwe * * @param <T> expression type * @see java.lang.Number */ public abstract class NumberExpression<T extends Number & Comparable<?>> extends ComparableExpressionBase<T> { private static final long serialVersionUID = -5485902768703364888L; private static class Constants { private static final NumberExpression<Double> RANDOM = Expressions.numberOperation(Double.class, MathOps.RANDOM); } /** * Create a {@code max(left, right)} expression * * <p>Return the greater of the given values</p> * * @return max(left, right) */ public static <A extends Number & Comparable<?>> NumberExpression<A> max(Expression<A> left, Expression<A> right) { return Expressions.numberOperation(left.getType(), MathOps.MAX, left, right); } /** * Create a {@code min(left, right)} expression * * <p>Returns the smaller of the given values</p> * * @return min(left, right) */ public static <A extends Number & Comparable<?>> NumberExpression<A> min(Expression<A> left, Expression<A> right) { return Expressions.numberOperation(left.getType(), MathOps.MIN, left, right); } /** * Create a {@code random()} expression * * <p>Returns the random number</p> * * @return random() */ public static NumberExpression<Double> random() { return Constants.RANDOM; } @Nullable private transient volatile NumberExpression<T> abs, sum, min, max, floor, ceil, round; @Nullable private transient volatile NumberExpression<Double> avg, sqrt; @Nullable private transient volatile NumberExpression<T> negation; @Nullable private transient volatile StringExpression stringCast; public NumberExpression(Expression<T> mixin) { super(mixin); } @Override public NumberExpression<T> as(Path<T> alias) { return Expressions.numberOperation(getType(), Ops.ALIAS, mixin, alias); } @Override public NumberExpression<T> as(String alias) { return Expressions.numberOperation(getType(), Ops.ALIAS, mixin, ExpressionUtils.path(getType(), alias)); } /** * Create a cast to String expression * * @see java.lang.Object#toString() * @return string representation */ public StringExpression stringValue() { if (stringCast == null) { stringCast = Expressions.stringOperation(Ops.STRING_CAST, mixin); } return stringCast; } /** * Create a {@code abs(this)} expression * * <p>Returns the absolute value of this expression</p> * * @return abs(this) */ public NumberExpression<T> abs() { if (abs == null) { abs = Expressions.numberOperation(getType(), MathOps.ABS, mixin); } return abs; } /** * Create a {@code this + right} expression * * <p>Returns the sum of this and right</p> * * @param right rhs of expression * @return this + right */ public <N extends Number & Comparable<?>> NumberExpression<T> add(Expression<N> right) { return Expressions.numberOperation(getType(), Ops.ADD, mixin, right); } /** * Create a {@code this + right} expression * * <p>Get the sum of this and right</p> * * @param right rhs of expression * @return this + right */ public <N extends Number & Comparable<N>> NumberExpression<T> add(N right) { return Expressions.numberOperation(getType(), Ops.ADD, mixin, ConstantImpl.create(right)); } /** * Create a {@code avg(this)} expression * * <p>Get the average value of this expression (aggregation)</p> * * @return avg(this) */ public NumberExpression<Double> avg() { if (avg == null) { avg = Expressions.numberOperation(Double.class, Ops.AggOps.AVG_AGG, mixin); } return avg; } /** * Create a {@code cast(this as byte)} expression * * <p>Get the byte expression of this numeric expression</p> * * @return this.byteValue() * @see java.lang.Number#byteValue() */ public NumberExpression<Byte> byteValue() { return castToNum(Byte.class); } private T cast(Number number) { return MathUtils.cast(number, getType()); } @SuppressWarnings("unchecked") public <A extends Number & Comparable<? super A>> NumberExpression<A> castToNum(Class<A> type) { if (type.equals(getType())) { return (NumberExpression<A>) this; } else { return Expressions.numberOperation(type, Ops.NUMCAST, mixin, ConstantImpl.create(type)); } } /** * Create a {@code ceil(this)} expression * * <p>Returns the smallest (closest to negative infinity) * {@code double} value that is greater than or equal to the * argument and is equal to a mathematical integer</p> * * @return ceil(this) * @see java.lang.Math#ceil(double) */ public NumberExpression<T> ceil() { if (ceil == null) { ceil = Expressions.numberOperation(getType(), MathOps.CEIL, mixin); } return ceil; } private Class<?> getDivisionType(Class<?> left, Class<?> right) { if (!left.equals(right)) { return Double.class; } else { return left; } } /** * Create a {@code this / right} expression * * <p>Get the result of the operation this / right</p> * * @param right * @return this / right */ public <N extends Number & Comparable<?>> NumberExpression<T> divide(Expression<N> right) { @SuppressWarnings("unchecked") Class<T> type = (Class<T>) getDivisionType(getType(), right.getType()); return Expressions.numberOperation(type, Ops.DIV, mixin, right); } /** * Create a {@code this / right} expression * * <p>Get the result of the operation this / right</p> * * @param right * @return this / right */ public <N extends Number & Comparable<?>> NumberExpression<T> divide(N right) { @SuppressWarnings("unchecked") Class<T> type = (Class< T>) getDivisionType(getType(), right.getClass()); return Expressions.numberOperation(type, Ops.DIV, mixin, ConstantImpl.create(right)); } /** * Create a {@code cast(this as double)} expression * * <p>Get the double expression of this numeric expression</p> * * @return this.doubleValue() * @see java.lang.Number#doubleValue() */ public NumberExpression<Double> doubleValue() { return castToNum(Double.class); } /** * Create a {@code cast(this as double)} expression * * <p>Get the float expression of this numeric expression</p> * * @return this.floatValue() * @see java.lang.Number#floatValue() */ public NumberExpression<Float> floatValue() { return castToNum(Float.class); } /** * Create a {@code floor(this)} expression * * <p>Returns the largest (closest to positive infinity) * {@code double} value that is less than or equal to the * argument and is equal to a mathematical integer.</p> * * @return floor(this) * @see java.lang.Math#floor(double) */ public NumberExpression<T> floor() { if (floor == null) { floor = Expressions.numberOperation(getType(), MathOps.FLOOR, mixin); } return floor; } /** * Create a {@code this >= right} expression * * @param <A> * @param right rhs of the comparison * @return {@code this >= right} * @see java.lang.Comparable#compareTo(Object) */ public final <A extends Number & Comparable<?>> BooleanExpression goe(A right) { return goe(ConstantImpl.create(cast(right))); } /** * Create a {@code this >= right} expression * * @param <A> * @param right rhs of the comparison * @return {@code this >= right} * @see java.lang.Comparable#compareTo(Object) */ public final <A extends Number & Comparable<?>> BooleanExpression goe(Expression<A> right) { return Expressions.booleanOperation(Ops.GOE, mixin, right); } /** * Create a {@code this >= all right} expression * * @param right * @return this >= all right */ public BooleanExpression goeAll(CollectionExpression<?, ? super T> right) { return goe(ExpressionUtils.all(right)); } /** * Create a {@code this >= any right} expression * * @param right * @return this >= any right */ public BooleanExpression goeAny(CollectionExpression<?, ? super T> right) { return goe(ExpressionUtils.any(right)); } /** * Create a {@code this > right} expression * * @param <A> * @param right rhs of the comparison * @return {@code this > right} * @see java.lang.Comparable#compareTo(Object) */ public final <A extends Number & Comparable<?>> BooleanExpression gt(A right) { return gt(ConstantImpl.create(cast(right))); } /** * Create a {@code this > right} expression * * @param <A> * @param right rhs of the comparison * @return {@code this > right} * @see java.lang.Comparable#compareTo(Object) */ public final <A extends Number & Comparable<?>> BooleanExpression gt(Expression<A> right) { return Expressions.booleanOperation(Ops.GT, mixin, right); } /** * Create a {@code this > all right} expression * * @param right * @return this > all right */ public BooleanExpression gtAll(CollectionExpression<?, ? super T> right) { return gt(ExpressionUtils.all(right)); } /** * Create a {@code this > any right} expression * * @param right * @return this > any right */ public BooleanExpression gtAny(CollectionExpression<?, ? super T> right) { return gt(ExpressionUtils.any(right)); } /** * Create a {@code this > all right} expression * * @param right * @return this > all right */ public BooleanExpression gtAll(SubQueryExpression<? extends T> right) { return gt(ExpressionUtils.all(right)); } /** * Create a {@code this > any right} expression * * @param right * @return this > any right */ public BooleanExpression gtAny(SubQueryExpression<? extends T> right) { return gt(ExpressionUtils.any(right)); } /** * Create a {@code this between from and to} expression * * <p>Is equivalent to {@code from <= this <= to}</p> * * @param <A> * @param from inclusive start of range * @param to inclusive end of range * @return this between from and to */ public final <A extends Number & Comparable<?>> BooleanExpression between(@Nullable A from, @Nullable A to) { if (from == null) { if (to != null) { return loe(to); } else { throw new IllegalArgumentException("Either from or to needs to be non-null"); } } else if (to == null) { return goe(from); } else { return between(ConstantImpl.create(cast(from)), ConstantImpl.create(cast(to))); } } /** * Create a {@code this between from and to} expression * * <p>Is equivalent to {@code from <= this <= to}</p> * * @param <A> * @param from inclusive start of range * @param to inclusive end of range * @return this between from and to */ public final <A extends Number & Comparable<?>> BooleanExpression between(@Nullable Expression<A> from, @Nullable Expression<A> to) { if (from == null) { if (to != null) { return Expressions.booleanOperation(Ops.LOE, mixin, to); } else { throw new IllegalArgumentException("Either from or to needs to be non-null"); } } else if (to == null) { return Expressions.booleanOperation(Ops.GOE, mixin, from); } else { return Expressions.booleanOperation(Ops.BETWEEN, mixin, from, to); } } /** * Create a {@code this not between from and to} expression * * <p>Is equivalent to {@code this < from || this > to}</p> * * @param from inclusive start of range * @param to inclusive end of range * @return this not between from and to */ public final <A extends Number & Comparable<?>> BooleanExpression notBetween(A from, A to) { return between(from, to).not(); } /** * Create a {@code this not between from and to} expression * * <p>Is equivalent to {@code this < from || this > to}</p> * * @param from inclusive start of range * @param to inclusive end of range * @return this not between from and to */ public final <A extends Number & Comparable<?>> BooleanExpression notBetween(Expression<A> from, Expression<A> to) { return between(from, to).not(); } /** * Create a {@code this.intValue()} expression * * <p>Get the int expression of this numeric expression</p> * * @return this.intValue() * @see java.lang.Number#intValue() */ public NumberExpression<Integer> intValue() { return castToNum(Integer.class); } /** * Create a {@code this like str} expression * * @param str rhs * @return this like str */ public BooleanExpression like(String str) { return Expressions.booleanOperation(Ops.LIKE, stringValue(), ConstantImpl.create(str)); } /** * Create a {@code this like str} expression * * @param str * @return this like str */ public BooleanExpression like(Expression<String> str) { return Expressions.booleanOperation(Ops.LIKE, stringValue(), str); } /** * Create a {@code this <= right} expression * * @param <A> * @param right rhs of the comparison * @return {@code this <= right} * @see java.lang.Comparable#compareTo(Object) */ public final <A extends Number & Comparable<?>> BooleanExpression loe(A right) { return loe(ConstantImpl.create(cast(right))); } /** * Create a {@code this <= right} expression * * @param <A> * @param right rhs of the comparison * @return {@code this <= right} * @see java.lang.Comparable#compareTo(Object) */ public final <A extends Number & Comparable<?>> BooleanExpression loe(Expression<A> right) { return Expressions.booleanOperation(Ops.LOE, mixin, right); } /** * Create a {@code this <= all right} expression * * @param right rhs * @return this <= all right */ public BooleanExpression loeAll(CollectionExpression<?, ? super T> right) { return loe(ExpressionUtils.all(right)); } /** * Create a {@code this <= any right} expression * * @param right rhs * @return this <= any right */ public BooleanExpression loeAny(CollectionExpression<?, ? super T> right) { return loe(ExpressionUtils.any(right)); } /** * Create a {@code this.longValue()} expression * * <p>Get the long expression of this numeric expression</p> * * @return this.longValue() * @see java.lang.Number#longValue() */ public NumberExpression<Long> longValue() { return castToNum(Long.class); } /** * Create a {@code this < right} expression * * @param <A> * @param right rhs of the comparison * @return {@code this < right} * @see java.lang.Comparable#compareTo(Object) */ public final <A extends Number & Comparable<?>> BooleanExpression lt(A right) { return lt(ConstantImpl.create(cast(right))); } /** * Create a {@code this < right} expression * * @param <A> * @param right rhs of the comparison * @return {@code this < right} * @see java.lang.Comparable#compareTo(Object) */ public final <A extends Number & Comparable<?>> BooleanExpression lt(Expression<A> right) { return Expressions.booleanOperation(Ops.LT, this, right); } /** * Create a {@code this < all right} expression * * @param right rhs * @return this < all right */ public BooleanExpression ltAll(CollectionExpression<?, ? super T> right) { return lt(ExpressionUtils.all(right)); } /** * Create a {@code this < any right} expression * * @param right rhs * @return this < any right */ public BooleanExpression ltAny(CollectionExpression<?, ? super T> right) { return lt(ExpressionUtils.any(right)); } /** * Create a {@code max(this)} expression * * <p>Get the maximum value of this expression (aggregation)</p> * * @return max(this) */ @SuppressWarnings("unchecked") public NumberExpression<T> max() { if (max == null) { max = Expressions.numberOperation(getType(), Ops.AggOps.MAX_AGG, mixin); } return max; } /** * Create a {@code min(this)} expression * * <p>Get the minimum value of this expression (aggregation)</p> * * @return min(this) */ @SuppressWarnings("unchecked") public NumberExpression<T> min() { if (min == null) { min = Expressions.numberOperation(getType(), Ops.AggOps.MIN_AGG, mixin); } return min; } /** * Create a {@code mod(this, num)} expression * * @param num * @return mod(this, num) */ public NumberExpression<T> mod(Expression<T> num) { return Expressions.numberOperation(getType(), Ops.MOD, mixin, num); } /** * Create a {@code mod(this, num)} expression * * @param num * @return mod(this, num) */ public NumberExpression<T> mod(T num) { return Expressions.numberOperation(getType(), Ops.MOD, mixin, ConstantImpl.create(num)); } /** * Create a {@code this * right} expression * * <p>Get the result of the operation this * right</p> * * @param right * @return this * right */ public <N extends Number & Comparable<?>> NumberExpression<T> multiply(Expression<N> right) { return Expressions.numberOperation(getType(), Ops.MULT, mixin, right); } /** * Create a {@code this * right} expression * * <p>Get the result of the operation this * right</p> * * @param right * @return this * right */ public <N extends Number & Comparable<N>> NumberExpression<T> multiply(N right) { return Expressions.numberOperation(getType(), Ops.MULT, mixin, ConstantImpl.create(right)); } /** * Create a {@code this * -1} expression * * <p>Get the negation of this expression</p> * * @return this * -1 */ public NumberExpression<T> negate() { if (negation == null) { negation = Expressions.numberOperation(getType(), Ops.NEGATE, mixin); } return negation; } /** * Create a {@code round(this)} expression * * <p>Returns the closest {@code int} to this.</p> * * @return round(this) * @see java.lang.Math#round(double) * @see java.lang.Math#round(float) */ public NumberExpression<T> round() { if (round == null) { round = Expressions.numberOperation(getType(), MathOps.ROUND, mixin); } return round; } /** * Create a {@code this.shortValue()} expression * * <p>Get the short expression of this numeric expression</p> * * @return this.shortValue() * @see java.lang.Number#shortValue() */ public NumberExpression<Short> shortValue() { return castToNum(Short.class); } /** * Create a {@code sqrt(this)} expression * * <p>Get the square root of this numeric expressions</p> * * @return sqrt(this) */ public NumberExpression<Double> sqrt() { if (sqrt == null) { sqrt = Expressions.numberOperation(Double.class, MathOps.SQRT, mixin); } return sqrt; } /** * Create a {@code this - right} expression * * <p>Get the difference of this and right</p> * * @param right * @return this - right */ public <N extends Number & Comparable<?>> NumberExpression<T> subtract(Expression<N> right) { return Expressions.numberOperation(getType(), Ops.SUB, mixin, right); } /** * Create a {@code this - right} expression * * <p>Get the difference of this and right</p> * * @param right * @return this - right */ public <N extends Number & Comparable<?>> NumberExpression<T> subtract(N right) { return Expressions.numberOperation(getType(), Ops.SUB, mixin, ConstantImpl.create(right)); } /** * Create a {@code sum(this)} expression * * <p>Get the sum of this expression (aggregation)</p> * * @return sum(this) */ public NumberExpression<T> sum() { if (sum == null) { sum = Expressions.numberOperation(getType(), Ops.AggOps.SUM_AGG, mixin); } return sum; } @Override public BooleanExpression in(Number... numbers) { return super.in(convert(numbers)); } @Override public BooleanExpression notIn(Number... numbers) { return super.notIn(convert(numbers)); } private List<T> convert(Number... numbers) { List<T> list = new ArrayList<T>(numbers.length); for (int i = 0; i < numbers.length; i++) { list.add(MathUtils.cast(numbers[i], getType())); } return list; } }