improvements to aggregate method usage

This commit is contained in:
Timo Westkämper 2009-11-24 13:05:00 +00:00
parent 19c240e8d3
commit 75416a1e2a
29 changed files with 188 additions and 49 deletions

View File

@ -13,7 +13,6 @@ import com.mysema.query.types.operation.ONumber;
import com.mysema.query.types.operation.Ops;
import com.mysema.query.types.operation.Ops.MathOps;
/**
* ENumber represents a numeric expression
*
@ -104,7 +103,7 @@ public abstract class ENumber<D extends Number & Comparable<?>> extends ECompara
*/
public ENumber<Double> avg(){
if (avg == null){
avg = ONumber.create(Double.class, Ops.AggOps.AVG_AGG, this);
avg = ONumber.create(Double.class, Ops.AggOps.AVG_AGG, this);
}
return avg;
}

View File

@ -6,6 +6,7 @@
package com.mysema.util;
import java.math.BigDecimal;
import java.math.BigInteger;
public class MathUtils {
@ -30,6 +31,8 @@ public class MathUtils {
else if (type.equals(Integer.class)) rv = num.intValue();
else if (type.equals(Long.class)) rv = num.longValue();
else if (type.equals(Short.class)) rv = num.shortValue();
else if (type.equals(BigDecimal.class)) rv = num;
else if (type.equals(BigInteger.class)) rv = num.toBigInteger();
else throw new IllegalArgumentException(String.format("Illegal type : %s", type.getSimpleName()));
return (D) rv;
}

View File

@ -41,7 +41,7 @@ public class CoverageTest {
Set<Operator<?>> usedOperators = new HashSet<Operator<?>>();
List<Expr<?>> exprs = new ArrayList<Expr<?>>();
// numeric
exprs.addAll(projections.numeric($(0), $(1), 1));
exprs.addAll(projections.numeric($(0), $(1), 1, false));
exprs.addAll(matchers.numeric($(0), $(1), 1));
exprs.addAll(filters.numeric($(0), $(1), 1));
exprs.addAll(projections.numericCasts($(0), $(1), 1));

View File

@ -145,7 +145,7 @@ public class Filters {
@SuppressWarnings("unchecked")
<A extends Number & Comparable<A>> Collection<EBoolean> numeric(ENumber<A> expr, ENumber<A> other, A knownValue){
List<EBoolean> rv = new ArrayList<EBoolean>();
for (ENumber<?> num : projections.numeric(expr, other, knownValue)){
for (ENumber<?> num : projections.numeric(expr, other, knownValue, true)){
rv.add(num.lt(expr));
}
rv.add(expr.ne(other));

View File

@ -82,15 +82,15 @@ public class Projections {
return rv;
}
<A extends Number & Comparable<A>> Collection<ENumber<?>> numeric(ENumber<A> expr, ENumber<A> other, A knownValue){
<A extends Number & Comparable<A>> Collection<ENumber<?>> numeric(ENumber<A> expr, ENumber<A> other, A knownValue, boolean forFilter){
HashSet<ENumber<?>> rv = new HashSet<ENumber<?>>();
rv.addAll(numeric(expr, other));
rv.addAll(numeric(expr, ENumberConst.create(knownValue)));
rv.addAll(numeric(expr, other, forFilter));
rv.addAll(numeric(expr, ENumberConst.create(knownValue), forFilter));
return rv;
}
@SuppressWarnings("unchecked")
private <A extends Number & Comparable<A>> Collection<ENumber<?>> numeric(ENumber<A> expr, ENumber<?> other){
private <A extends Number & Comparable<A>> Collection<ENumber<?>> numeric(ENumber<A> expr, ENumber<?> other, boolean forFilter){
HashSet<ENumber<?>> rv = new HashSet<ENumber<?>>();
rv.add(expr.abs());
rv.add(expr.add(other));
@ -99,6 +99,13 @@ public class Projections {
rv.add(expr.sqrt());
rv.add(expr.subtract(other));
if (!forFilter && module != Module.COLLECTIONS){
rv.add(expr.min());
rv.add(expr.max());
rv.add(expr.avg());
rv.add(expr.count());
}
if (!(other instanceof Constant || module == Module.JDOQL || module == Module.RDFBEAN)){
CaseBuilder cases = new CaseBuilder();
rv.add(ENumberConst.create(1).add(cases

View File

@ -182,7 +182,7 @@ public abstract class StandardTest {
public <A extends Number & Comparable<A>> void numericTests(ENumber<A> expr, ENumber<A> other, A knownValue){
execute(matchers.numeric(expr, other, knownValue), true);
execute(filters.numeric(expr, other, knownValue), false);
execute(projections.numeric(expr, other, knownValue));
execute(projections.numeric(expr, other, knownValue, false));
}
public void stringTests(EString expr, EString other, String knownValue){

View File

@ -21,7 +21,6 @@ import com.mysema.query.types.expr.Expr;
import com.mysema.query.types.operation.OSimple;
import com.mysema.query.types.operation.Ops;
import com.mysema.query.types.path.PEntity;
import com.mysema.query.types.path.PCollection;
import com.mysema.query.types.path.PMap;
import com.mysema.query.types.path.PSimple;
import com.mysema.query.types.path.Path;
@ -76,8 +75,7 @@ public abstract class HQLQueryBase<SubType extends HQLQueryBase<SubType>> extend
Map<String, Object> map) {
BooleanBuilder expr = new BooleanBuilder();
for (Map.Entry<String, Object> entry : map.entrySet()) {
PathMetadata<String> md = PathMetadata.forProperty(entity, entry
.getKey());
PathMetadata<String> md = PathMetadata.forProperty(entity, entry.getKey());
PSimple<Object> path = new PSimple<Object>(Object.class, md);
if (entry.getValue() != null) {
expr.and(path.eq(entry.getValue()));

View File

@ -1,9 +1,21 @@
package com.mysema.query.hql.hibernate;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.Query;
import org.hibernate.type.BigDecimalType;
import org.hibernate.type.BigIntegerType;
import org.hibernate.type.ByteType;
import org.hibernate.type.DoubleType;
import org.hibernate.type.FloatType;
import org.hibernate.type.IntegerType;
import org.hibernate.type.LongType;
import org.hibernate.type.ShortType;
import org.hibernate.type.Type;
/**
* Utility methods for Hibernate
@ -13,6 +25,19 @@ import org.hibernate.Query;
*/
public final class HibernateUtil {
private static final Map<Class<?>,Type> types = new HashMap<Class<?>,Type>();
static{
types.put(Byte.class, new ByteType());
types.put(Short.class, new ShortType());
types.put(Integer.class, new IntegerType());
types.put(Long.class, new LongType());
types.put(BigInteger.class, new BigIntegerType());
types.put(Double.class, new DoubleType());
types.put(Float.class, new FloatType());
types.put(BigDecimal.class, new BigDecimalType());
}
private HibernateUtil(){}
public static void setConstants(Query query, Map<Object,String> constants) {
@ -23,9 +48,14 @@ public final class HibernateUtil {
if (val instanceof Collection<?>) {
// NOTE : parameter types should be given explicitly
query.setParameterList(key, (Collection<?>) val);
} else if (val.getClass().isArray()) {
// NOTE : parameter types should be given explicitly
query.setParameterList(key, (Object[]) val);
}else if (types.containsKey(val.getClass())){
query.setParameter(key, val, types.get(val.getClass()));
} else {
// NOTE : parameter types should be given explicitly
query.setParameter(key, val);

View File

@ -4,6 +4,7 @@ import java.util.Map;
import javax.persistence.Query;
/**
* Utility methods for JPA
*
@ -11,7 +12,7 @@ import javax.persistence.Query;
*
*/
public final class JPAUtil {
private JPAUtil(){}
public static void setConstants(Query query, Map<Object,String> constants) {

View File

@ -86,11 +86,11 @@ public abstract class AbstractStandardTest {
public void setUp(){
Cat prev = null;
for (Cat cat : Arrays.asList(
new Cat("Bob123", 1),
new Cat("Ruth123", 2),
new Cat("Felix123", 3),
new Cat("Allen123", 4),
new Cat("Mary123", 5))){
new Cat("Bob123", 1, 1.0),
new Cat("Ruth123", 2, 2.0),
new Cat("Felix123", 3, 3.0),
new Cat("Allen123", 4, 4.0),
new Cat("Mary123", 5, 5.0))){
if (prev != null){
cat.getKittens().add(prev);
}
@ -102,7 +102,7 @@ public abstract class AbstractStandardTest {
prev = cat;
}
Cat cat = new Cat("Some",6);
Cat cat = new Cat("Some",6, 6.0);
save(cat);
savedCats.add(cat);
}
@ -118,8 +118,15 @@ public abstract class AbstractStandardTest {
standardTest.dateTimeTests(cat.birthdate, otherCat.birthdate, birthDate);
standardTest.listTests(cat.kittens, otherCat.kittens, kitten, noKitten);
// standardTest.mapTests(cat.kittensByName, otherCat.kittensByName, "Kitty", kitten);
// int
standardTest.numericCasts(cat.id, otherCat.id, 1);
standardTest.numericTests(cat.id, otherCat.id, 1);
// double
standardTest.numericCasts(cat.bodyWeight, otherCat.bodyWeight, 1.0);
standardTest.numericTests(cat.bodyWeight, otherCat.bodyWeight, 1.0);
standardTest.stringTests(cat.name, otherCat.name, kitten.getName());
standardTest.timeTests(cat.timeField, otherCat.timeField, time);

View File

@ -0,0 +1,16 @@
package com.mysema.query;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.hibernate.type.DoubleType;
@SuppressWarnings("serial")
public class ExtDoubleType extends DoubleType{
@Override
public void set(PreparedStatement st, Object value, int index) throws SQLException {
st.setDouble( index, ( (Number) value ).doubleValue() );
}
}

View File

@ -5,6 +5,7 @@
*/
package com.mysema.query;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;

View File

@ -14,21 +14,21 @@ public class MathTest extends AbstractQueryTest{
@Test
public void test(){
PNumber<Integer> path = QCat.cat.bodyWeight;
PNumber<Double> path = QCat.cat.bodyWeight;
toString("(cat.bodyWeight - sum(cat.bodyWeight)) * cat.bodyWeight", path.subtract(path.sum()).multiply(path));
}
@Test
public void testArithmeticOperationsInFunctionalWay() {
public void testArithmeticOperationsInFunctionalWay() {
toString("cat.bodyWeight + :a1", cat.bodyWeight.add(10));
toString("cat.bodyWeight - :a1", cat.bodyWeight.subtract(10));
toString("cat.bodyWeight * :a1", cat.bodyWeight.multiply(10));
toString("cat.bodyWeight / :a1", cat.bodyWeight.divide(10));
toString("cat.bodyWeight + :a1 < :a1", cat.bodyWeight.add(10).lt(10));
toString("cat.bodyWeight - :a1 < :a1", cat.bodyWeight.subtract(10).lt(10));
toString("cat.bodyWeight * :a1 < :a1", cat.bodyWeight.multiply(10).lt(10));
toString("cat.bodyWeight / :a1 < :a2", cat.bodyWeight.divide(10).lt(10d));
toString("cat.bodyWeight + :a1 < :a1", cat.bodyWeight.add(10.0).lt(10.0));
toString("cat.bodyWeight - :a1 < :a1", cat.bodyWeight.subtract(10.0).lt(10.0));
toString("cat.bodyWeight * :a1 < :a1", cat.bodyWeight.multiply(10.0).lt(10.0));
toString("cat.bodyWeight / :a1 < :a2", cat.bodyWeight.divide(10.0).lt(20.0));
toString("(cat.bodyWeight + :a1) * :a2", cat.bodyWeight.add(10).multiply(20));
toString("(cat.bodyWeight - :a1) * :a2", cat.bodyWeight.subtract(10).multiply(20));

View File

@ -927,7 +927,7 @@ public class ParserTest implements Constants {
@Test
public void testCasts() throws Exception {
ENumber<Integer> bw = cat.bodyWeight;
ENumber<Double> bw = cat.bodyWeight;
query().from(cat).select(bw.byteValue(), bw.doubleValue(), bw.floatValue(),
bw.intValue(), bw.longValue(), bw.shortValue(),
bw.stringValue()).parse();

View File

@ -8,6 +8,10 @@ package com.mysema.query.hql.domain;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.annotations.Type;
import com.mysema.query.ExtDoubleType;
/**
* The Class Animal.
*/
@ -17,7 +21,11 @@ public class Animal {
private java.util.Date birthdate;
private int bodyWeight, weight, toes;
private int weight, toes;
// needed for JPA tests
@Type(type="com.mysema.query.ExtDoubleType")
private double bodyWeight;
private Color color;
@ -34,7 +42,7 @@ public class Animal {
return birthdate;
}
public int getBodyWeight() {
public double getBodyWeight() {
return bodyWeight;
}
@ -78,7 +86,7 @@ public class Animal {
this.birthdate = birthdate;
}
public void setBodyWeight(int bodyWeight) {
public void setBodyWeight(double bodyWeight) {
this.bodyWeight = bodyWeight;
}

View File

@ -19,6 +19,7 @@ import org.hibernate.annotations.IndexColumn;
*/
@Entity
public class Cat extends Animal {
private int breed;
private Color eyecolor;
@ -37,6 +38,11 @@ public class Cat extends Animal {
this.setName( name);
}
public Cat(String name, int id, double bodyWeight){
this(name, id);
this.setBodyWeight(bodyWeight);
}
public int getBreed() {
return breed;
}

View File

@ -6,8 +6,8 @@
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="derby">
<!--
<provider>org.hibernate.ejb.HibernatePersistence</provider>
-->

View File

@ -13,6 +13,8 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -216,7 +218,7 @@ public abstract class AbstractSQLQuery<SubType extends AbstractSQLQuery<SubType>
}
@SuppressWarnings("unchecked")
private <RT> List<RT> listSingle(Expr<RT> expr) throws SQLException {
private <RT> List<RT> listSingle(@Nullable Expr<RT> expr) throws SQLException {
String queryString = buildQueryString(false);
logger.debug("query : {}", queryString);
PreparedStatement stmt = conn.prepareStatement(queryString);
@ -224,26 +226,33 @@ public abstract class AbstractSQLQuery<SubType extends AbstractSQLQuery<SubType>
ResultSet rs = stmt.executeQuery();
try {
List<RT> rv = new ArrayList<RT>();
if (expr instanceof EConstructor) {
EConstructor<RT> c = (EConstructor<RT>) expr;
java.lang.reflect.Constructor<RT> cc = c.getJavaConstructor();
while (rs.next()) {
try {
try {
if (expr instanceof EConstructor) {
EConstructor<RT> c = (EConstructor<RT>) expr;
java.lang.reflect.Constructor<RT> cc = c.getJavaConstructor();
while (rs.next()) {
List<Object> args = new ArrayList<Object>();
for (int i = 0; i < c.getArgs().size(); i++) {
args.add(get(rs, i + 1, c.getArg(i).getType()));
}
rv.add(cc.newInstance(args.toArray()));
} catch (Exception e) {
String error = "Caught " + e.getClass().getName();
logger.error(error, e);
throw new RuntimeException(e.getMessage(), e);
}
} else if (expr != null){
while (rs.next()) {
rv.add(get(rs, 1, expr.getType()));
}
}else{
while (rs.next()) {
rv.add((RT) rs.getObject(1));
}
}
} else {
while (rs.next()) {
rv.add((RT) rs.getObject(1));
}
} catch (Exception e) {
String error = "Caught " + e.getClass().getName();
logger.error(error, e);
throw new RuntimeException(e.getMessage(), e);
}
return rv;
} finally {

View File

@ -1,4 +1,6 @@
/**
/*
* Copyright (c) 2009 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.sql;

View File

@ -1,4 +1,6 @@
/**
/*
* Copyright (c) 2009 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.sql;

View File

@ -1,3 +1,8 @@
/*
* Copyright (c) 2009 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.sql;
import java.sql.PreparedStatement;

View File

@ -1,4 +1,6 @@
/**
/*
* Copyright (c) 2009 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.sql;

View File

@ -1,3 +1,8 @@
/*
* Copyright (c) 2009 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.sql;
import com.mysema.query.Projectable;

View File

@ -1,3 +1,8 @@
/*
* Copyright (c) 2009 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.sql;
import com.mysema.query.DefaultQueryMetadata;

View File

@ -1,3 +1,8 @@
/*
* Copyright (c) 2009 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.sql;
import java.sql.SQLException;
@ -5,6 +10,11 @@ import java.util.List;
import com.mysema.query.types.OrderSpecifier;
/**
* @author tiwe
*
* @param <RT>
*/
public interface Union<RT> {
Union<RT> orderBy(OrderSpecifier<?>... o);

View File

@ -1,3 +1,8 @@
/*
* Copyright (c) 2009 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.sql.dml;
import java.sql.PreparedStatement;

View File

@ -1,3 +1,8 @@
/*
* Copyright (c) 2009 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.sql.dml;
import java.sql.Connection;

View File

@ -1,3 +1,8 @@
/*
* Copyright (c) 2009 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.sql.dml;
import java.sql.Connection;

View File

@ -12,6 +12,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
@ -134,8 +135,15 @@ public abstract class AbstractSQLTest {
public void standardTest(){
standardTest.booleanTests(employee.firstname.isNull(), employee2.lastname.isNotNull());
standardTest.dateTests(employee.datefield, employee2.datefield, date);
// int
standardTest.numericCasts(employee.id, employee2.id, 1);
standardTest.numericTests(employee.id, employee2.id, 1);
// BigDecimal
// standardTest.numericCasts(employee.salary, employee2.salary, new BigDecimal("30000.00"));
standardTest.numericTests(employee.salary, employee2.salary, new BigDecimal("30000.00"));
standardTest.stringTests(employee.firstname, employee2.firstname, "Jennifer");
standardTest.timeTests(employee.timefield, employee2.timefield, time);
@ -362,12 +370,12 @@ public abstract class AbstractSQLTest {
// uniqueResult
assertEquals(min, query().from(employee).uniqueResult(employee.salary.min()).intValue());
// assertEquals(avg, query().from(employee).uniqueResult(employee.salary.avg()).intValue());
assertEquals(avg, query().from(employee).uniqueResult(employee.salary.avg()).intValue());
assertEquals(max, query().from(employee).uniqueResult(employee.salary.max()).intValue());
// list
assertEquals(min, query().from(employee).list(employee.salary.min()).get(0).intValue());
// assertEquals(avg, query().from(employee).list(employee.salary.avg()).get(0).intValue());
assertEquals(avg, query().from(employee).list(employee.salary.avg()).get(0).intValue());
assertEquals(max, query().from(employee).list(employee.salary.max()).get(0).intValue());
}