mirror of
https://github.com/querydsl/querydsl.git
synced 2026-06-19 21:00:53 +08:00
#192 improved sum() support
This commit is contained in:
parent
8b492e2a2c
commit
67c477bf15
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2012, Mysema Ltd
|
||||
*
|
||||
* 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.mysema.query.support;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.mysema.query.types.Expression;
|
||||
import com.mysema.query.types.ExpressionBase;
|
||||
import com.mysema.query.types.FactoryExpression;
|
||||
import com.mysema.query.types.Visitor;
|
||||
import com.mysema.util.MathUtils;
|
||||
|
||||
/**
|
||||
* @author tiwe
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class NumberConversion<T> extends ExpressionBase<T> implements FactoryExpression<T> {
|
||||
|
||||
private static final long serialVersionUID = 7840412008633901748L;
|
||||
|
||||
private final List<Expression<?>> exprs;
|
||||
|
||||
public NumberConversion(Expression<T> expr) {
|
||||
super(expr.getType());
|
||||
exprs = Collections.<Expression<?>>singletonList(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, C> R accept(Visitor<R, C> v, C context) {
|
||||
return v.visit(this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression<?>> getArgs() {
|
||||
return exprs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T newInstance(Object... args) {
|
||||
return (T)MathUtils.cast((Number)args[0], (Class)getType());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2012, Mysema Ltd
|
||||
*
|
||||
* 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.mysema.query.support;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.mysema.query.types.Expression;
|
||||
import com.mysema.query.types.ExpressionBase;
|
||||
import com.mysema.query.types.FactoryExpression;
|
||||
import com.mysema.query.types.Visitor;
|
||||
import com.mysema.util.MathUtils;
|
||||
|
||||
/**
|
||||
* @author tiwe
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class NumberConversions<T> extends ExpressionBase<T> implements FactoryExpression<T> {
|
||||
|
||||
private static final long serialVersionUID = -7834053123363933721L;
|
||||
|
||||
private final FactoryExpression<T> expr;
|
||||
|
||||
public NumberConversions(FactoryExpression<T> expr) {
|
||||
super(expr.getType());
|
||||
this.expr = expr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, C> R accept(Visitor<R, C> v, C context) {
|
||||
return v.visit(this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression<?>> getArgs() {
|
||||
return expr.getArgs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T newInstance(Object... args) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
Class<?> type = expr.getArgs().get(i).getType();
|
||||
if (args[i] instanceof Number && !args[i].getClass().equals(type)) {
|
||||
args[i] = MathUtils.cast((Number)args[i], (Class)type);
|
||||
}
|
||||
}
|
||||
return expr.newInstance(args);
|
||||
}
|
||||
|
||||
}
|
||||
@ -19,8 +19,6 @@ import com.mysema.query.types.Expression;
|
||||
import com.mysema.query.types.Ops;
|
||||
import com.mysema.query.types.expr.ComparableExpression;
|
||||
import com.mysema.query.types.expr.ComparableOperation;
|
||||
import com.mysema.query.types.expr.NumberExpression;
|
||||
import com.mysema.query.types.expr.NumberOperation;
|
||||
import com.mysema.query.types.expr.StringExpression;
|
||||
import com.mysema.query.types.expr.StringOperation;
|
||||
|
||||
@ -46,30 +44,6 @@ public final class JPQLGrammar {
|
||||
public static <A extends Comparable<? super A>> ComparableExpression<A> min(CollectionExpression<?,A> left) {
|
||||
return ComparableOperation.create((Class)left.getParameter(0), Ops.QuantOps.MIN_IN_COL, (Expression<?>)left);
|
||||
}
|
||||
|
||||
/**
|
||||
* SUM returns Long when applied to state-fields of integral types (other
|
||||
* than BigInteger); Double when applied to state-fields of floating point
|
||||
* types; BigInteger when applied to state-fields of type BigInteger; and
|
||||
* BigDecimal when applied to state-fields of type BigDecimal.
|
||||
*/
|
||||
public static <D extends Number & Comparable<? super D>> NumberExpression<?> sum(Expression<D> left) {
|
||||
Class<?> type = left.getType();
|
||||
if (type.equals(Byte.class) || type.equals(Integer.class) || type.equals(Short.class)) {
|
||||
type = Long.class;
|
||||
} else if (type.equals(Float.class)) {
|
||||
type = Double.class;
|
||||
}
|
||||
return NumberOperation.create((Class<D>) type, Ops.AggOps.SUM_AGG, left);
|
||||
}
|
||||
|
||||
public static <D extends Number & Comparable<? super D>> NumberExpression<Long> sumAsLong(Expression<D> left) {
|
||||
return sum(left).longValue();
|
||||
}
|
||||
|
||||
public static <D extends Number & Comparable<? super D>> NumberExpression<Double> sumAsDouble(Expression<D> left) {
|
||||
return sum(left).doubleValue();
|
||||
}
|
||||
|
||||
public static StringExpression type(EntityPath<?> path) {
|
||||
return StringOperation.create(JPQLTemplates.TYPE, path);
|
||||
|
||||
@ -23,10 +23,15 @@ import com.mysema.query.JoinFlag;
|
||||
import com.mysema.query.QueryMetadata;
|
||||
import com.mysema.query.support.Context;
|
||||
import com.mysema.query.support.ListAccessVisitor;
|
||||
import com.mysema.query.support.NumberConversion;
|
||||
import com.mysema.query.support.NumberConversions;
|
||||
import com.mysema.query.support.QueryMixin;
|
||||
import com.mysema.query.types.EntityPath;
|
||||
import com.mysema.query.types.Expression;
|
||||
import com.mysema.query.types.ExpressionUtils;
|
||||
import com.mysema.query.types.FactoryExpression;
|
||||
import com.mysema.query.types.Operation;
|
||||
import com.mysema.query.types.Ops;
|
||||
import com.mysema.query.types.Path;
|
||||
import com.mysema.query.types.Predicate;
|
||||
import com.mysema.query.types.TemplateExpressionImpl;
|
||||
@ -75,6 +80,32 @@ public class JPQLQueryMixin<T> extends QueryMixin<T> {
|
||||
}
|
||||
return getSelf();
|
||||
}
|
||||
|
||||
public <RT> Expression<RT> convert(Expression<RT> expr){
|
||||
if (isAggSumWithConversion(expr)) {
|
||||
expr = new NumberConversion(expr);
|
||||
} else if (expr instanceof FactoryExpression) {
|
||||
FactoryExpression<?> factorye = (FactoryExpression<?>)expr;
|
||||
for (Expression e : factorye.getArgs()) {
|
||||
if (isAggSumWithConversion(e)) {
|
||||
expr = new NumberConversions(factorye);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return super.convert(expr);
|
||||
}
|
||||
|
||||
private boolean isAggSumWithConversion(Expression<?> expr) {
|
||||
if (expr instanceof Operation && ((Operation)expr).getOperator() == Ops.AggOps.SUM_AGG) {
|
||||
Class type = ((Operation)expr).getType();
|
||||
if (type.equals(Float.class) || type.equals(Integer.class) || type.equals(Short.class) || type.equals(Byte.class)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Predicate normalize(Predicate predicate, boolean where) {
|
||||
|
||||
@ -37,6 +37,7 @@ import javax.persistence.metamodel.SingularAttribute;
|
||||
import com.mysema.query.JoinExpression;
|
||||
import com.mysema.query.JoinType;
|
||||
import com.mysema.query.QueryMetadata;
|
||||
import com.mysema.query.support.Expressions;
|
||||
import com.mysema.query.support.SerializerBase;
|
||||
import com.mysema.query.types.Constant;
|
||||
import com.mysema.query.types.ConstantImpl;
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
*/
|
||||
package com.mysema.query;
|
||||
|
||||
import static com.mysema.query.jpa.JPQLGrammar.sum;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
@ -55,6 +54,7 @@ import com.mysema.query.jpa.domain.Company.Rating;
|
||||
import com.mysema.query.jpa.domain.DomesticCat;
|
||||
import com.mysema.query.jpa.domain.DoubleProjection;
|
||||
import com.mysema.query.jpa.domain.Employee;
|
||||
import com.mysema.query.jpa.domain.FloatProjection;
|
||||
import com.mysema.query.jpa.domain.Foo;
|
||||
import com.mysema.query.jpa.domain.JobFunction;
|
||||
import com.mysema.query.jpa.domain.QAnimal;
|
||||
@ -64,6 +64,7 @@ import com.mysema.query.jpa.domain.QCat;
|
||||
import com.mysema.query.jpa.domain.QCompany;
|
||||
import com.mysema.query.jpa.domain.QDoubleProjection;
|
||||
import com.mysema.query.jpa.domain.QEmployee;
|
||||
import com.mysema.query.jpa.domain.QFloatProjection;
|
||||
import com.mysema.query.jpa.domain.QFoo;
|
||||
import com.mysema.query.jpa.domain.QShow;
|
||||
import com.mysema.query.jpa.domain.QUser;
|
||||
@ -709,14 +710,14 @@ public abstract class AbstractStandardTest {
|
||||
@Ignore
|
||||
public void Sum() throws RecognitionException, TokenStreamException {
|
||||
// NOT SUPPORTED
|
||||
query().from(cat).list(sum(cat.kittens.size()));
|
||||
query().from(cat).list(cat.kittens.size().sum());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void Sum_2() throws RecognitionException, TokenStreamException {
|
||||
// NOT SUPPORTED
|
||||
query().from(cat).where(sum(cat.kittens.size()).gt(0)).list(cat);
|
||||
query().from(cat).where(cat.kittens.size().sum().gt(0)).list(cat);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -731,6 +732,19 @@ public abstract class AbstractStandardTest {
|
||||
assertEquals(val, projection.val, 0.001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void Sum_as_Float() {
|
||||
float val = query().from(cat).uniqueResult(cat.floatProperty.sum());
|
||||
assertTrue(val > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void Sum_as_Float_Projected() {
|
||||
float val = query().from(cat).uniqueResult(cat.floatProperty.sum());
|
||||
FloatProjection projection = query().from(cat).uniqueResult(new QFloatProjection(cat.floatProperty.sum()));
|
||||
assertEquals(val, projection.val, 0.001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void Substring() {
|
||||
for (String str : query().from(cat).list(cat.name.substring(1,2))) {
|
||||
|
||||
@ -13,19 +13,14 @@
|
||||
*/
|
||||
package com.mysema.query.jpa;
|
||||
|
||||
import static com.mysema.query.jpa.JPQLGrammar.sum;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.mysema.query.jpa.domain.QAccount;
|
||||
import com.mysema.query.jpa.domain.QInheritedProperties;
|
||||
import com.mysema.query.types.expr.NumberExpression;
|
||||
import com.mysema.query.types.path.NumberPath;
|
||||
|
||||
public class FeaturesTest extends AbstractQueryTest {
|
||||
@ -139,35 +134,35 @@ public class FeaturesTest extends AbstractQueryTest {
|
||||
// toString("distinct cat.bodyWeight", distinct(cat.bodyWeight));
|
||||
}
|
||||
|
||||
/**
|
||||
* specs :
|
||||
* http://opensource.atlassian.com/projects/hibernate/browse/HHH-1538
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void Bug326650() {
|
||||
assertEquals(Long.class, sum(var(Byte.class)).getType());
|
||||
assertEquals(Long.class, sum(var(Short.class)).getType());
|
||||
assertEquals(Long.class, sum(var(Integer.class)).getType());
|
||||
assertEquals(Long.class, sum(var(Long.class)).getType());
|
||||
|
||||
assertEquals(Double.class, sum(var(Float.class)).getType());
|
||||
assertEquals(Double.class, sum(var(Double.class)).getType());
|
||||
|
||||
assertEquals(BigInteger.class, sum(var(BigInteger.class)).getType());
|
||||
assertEquals(BigDecimal.class, sum(var(BigDecimal.class)).getType());
|
||||
|
||||
// sum to var
|
||||
NumberExpression<Long> sum = (NumberExpression) sum(var(Integer.class)); // via Java level cast
|
||||
sum = sum(var(Integer.class)).longValue();
|
||||
assertNotNull(sum);
|
||||
|
||||
// sum comparison
|
||||
|
||||
sum(var(Integer.class)).gt(0);
|
||||
sum(var(Integer.class)).intValue().gt(0);
|
||||
|
||||
}
|
||||
// /**
|
||||
// * specs :
|
||||
// * http://opensource.atlassian.com/projects/hibernate/browse/HHH-1538
|
||||
// */
|
||||
// @SuppressWarnings("unchecked")
|
||||
// @Test
|
||||
// public void Bug326650() {
|
||||
// assertEquals(Long.class, sum(var(Byte.class)).getType());
|
||||
// assertEquals(Long.class, sum(var(Short.class)).getType());
|
||||
// assertEquals(Long.class, sum(var(Integer.class)).getType());
|
||||
// assertEquals(Long.class, sum(var(Long.class)).getType());
|
||||
//
|
||||
// assertEquals(Double.class, sum(var(Float.class)).getType());
|
||||
// assertEquals(Double.class, sum(var(Double.class)).getType());
|
||||
//
|
||||
// assertEquals(BigInteger.class, sum(var(BigInteger.class)).getType());
|
||||
// assertEquals(BigDecimal.class, sum(var(BigDecimal.class)).getType());
|
||||
//
|
||||
// // sum to var
|
||||
// NumberExpression<Long> sum = (NumberExpression) sum(var(Integer.class)); // via Java level cast
|
||||
// sum = sum(var(Integer.class)).longValue();
|
||||
// assertNotNull(sum);
|
||||
//
|
||||
// // sum comparison
|
||||
//
|
||||
// sum(var(Integer.class)).gt(0);
|
||||
// sum(var(Integer.class)).intValue().gt(0);
|
||||
//
|
||||
// }
|
||||
|
||||
private <D extends Number & Comparable<?>> NumberPath<D> var(Class<D> cl){
|
||||
return new NumberPath<D>(cl, "var");
|
||||
|
||||
@ -15,7 +15,6 @@ package com.mysema.query.jpa;
|
||||
|
||||
import static com.mysema.query.alias.Alias.$;
|
||||
import static com.mysema.query.alias.Alias.alias;
|
||||
import static com.mysema.query.jpa.JPQLGrammar.sum;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Ignore;
|
||||
@ -70,7 +69,7 @@ public class ParsingTest extends AbstractQueryTest{
|
||||
public void DocoExamples910() throws Exception {
|
||||
query().from(cat)
|
||||
.groupBy(cat.color)
|
||||
.select(cat.color, sum(cat.weight), cat.count()).parse();
|
||||
.select(cat.color, cat.weight.sum(), cat.count()).parse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -78,7 +77,7 @@ public class ParsingTest extends AbstractQueryTest{
|
||||
query().from(cat)
|
||||
.groupBy(cat.color)
|
||||
.having(cat.color.in(Color.TABBY, Color.BLACK))
|
||||
.select(cat.color, sum(cat.weight), cat.count()).parse();
|
||||
.select(cat.color, cat.weight.sum(), cat.count()).parse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -87,7 +86,7 @@ public class ParsingTest extends AbstractQueryTest{
|
||||
query().from(cat).join(cat.kittens, kitten)
|
||||
.groupBy(cat)
|
||||
.having(kitten.weight.avg().gt(100.0))
|
||||
.orderBy(kitten.count().asc(), sum(kitten.weight).desc())
|
||||
.orderBy(kitten.count().asc(), kitten.weight.sum().desc())
|
||||
.select(cat)
|
||||
.parse();
|
||||
}
|
||||
@ -139,9 +138,9 @@ public class ParsingTest extends AbstractQueryTest{
|
||||
sub().from(catalog).where(
|
||||
catalog.effectiveDate.lt(DateExpression.currentDate()))
|
||||
.list(catalog.effectiveDate))))
|
||||
.groupBy(ord).having(sum(price.amount).gt(0l))
|
||||
.orderBy(sum(price.amount).desc())
|
||||
.select(ord.id, sum(price.amount), item.count());
|
||||
.groupBy(ord).having(price.amount.sum().gt(0l))
|
||||
.orderBy(price.amount.sum().desc())
|
||||
.select(ord.id, price.amount.sum(), item.count());
|
||||
|
||||
Customer c1 = new Customer();
|
||||
Catalog c2 = new Catalog();
|
||||
@ -151,9 +150,9 @@ public class ParsingTest extends AbstractQueryTest{
|
||||
.from(catalog).join(catalog.prices, price).where(
|
||||
ord.paid.not().and(ord.customer.eq(c1)).and(
|
||||
price.product.eq(product)).and(catalog.eq(c2)))
|
||||
.groupBy(ord).having(sum(price.amount).gt(0l))
|
||||
.orderBy(sum(price.amount).desc())
|
||||
.select(ord.id, sum(price.amount), item.count());
|
||||
.groupBy(ord).having(price.amount.sum().gt(0l))
|
||||
.orderBy(price.amount.sum().desc())
|
||||
.select(ord.id, price.amount.sum(), item.count());
|
||||
|
||||
}
|
||||
|
||||
@ -550,14 +549,14 @@ public class ParsingTest extends AbstractQueryTest{
|
||||
@Ignore
|
||||
public void Sum() throws RecognitionException, TokenStreamException {
|
||||
// NOT SUPPORTED
|
||||
query().from(cat).select(sum(cat.kittens.size())).parse();
|
||||
query().from(cat).select(cat.kittens.size().sum()).parse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void Sum_2() throws RecognitionException, TokenStreamException {
|
||||
// NOT SUPPORTED
|
||||
query().from(cat).where(sum(cat.kittens.size()).gt(0)).select(cat).parse();
|
||||
query().from(cat).where(cat.kittens.size().sum().gt(0)).select(cat).parse();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -41,6 +41,8 @@ public class Animal {
|
||||
// needed for JPA tests
|
||||
@Type(type="com.mysema.query.ExtDoubleType")
|
||||
private double bodyWeight;
|
||||
|
||||
private float floatProperty;
|
||||
|
||||
private Color color;
|
||||
|
||||
@ -140,4 +142,12 @@ public class Animal {
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
public float getFloatProperty() {
|
||||
return floatProperty;
|
||||
}
|
||||
|
||||
public void setFloatProperty(float floatProperty) {
|
||||
this.floatProperty = floatProperty;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -67,6 +67,7 @@ public class Cat extends Animal {
|
||||
public Cat(String name, int id, double bodyWeight){
|
||||
this(name, id);
|
||||
setBodyWeight(bodyWeight);
|
||||
setFloatProperty((float)bodyWeight);
|
||||
}
|
||||
|
||||
public int getBreed() {
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
package com.mysema.query.jpa.domain;
|
||||
|
||||
import com.mysema.query.annotations.QueryProjection;
|
||||
|
||||
public class FloatProjection {
|
||||
|
||||
public float val;
|
||||
|
||||
@QueryProjection
|
||||
public FloatProjection(float val) {
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user