Author: max.ross
Date: 2007-07-27 23:10:55 -0400 (Fri, 27 Jul 2007)
New Revision: 12836
Added:
shards/trunk/src/java/org/hibernate/shards/strategy/exit/AvgResultsExitOperation.java
shards/trunk/src/test/org/hibernate/shards/strategy/exit/AvgResultsExitOperationTest.java
Modified:
shards/trunk/src/java/org/hibernate/shards/criteria/ExitOperationsCriteriaCollector.java
shards/trunk/src/java/org/hibernate/shards/criteria/ShardedCriteriaImpl.java
shards/trunk/src/test/org/hibernate/shards/NonPermutedTests.java
shards/trunk/src/test/org/hibernate/shards/integration/model/ModelCriteriaPermutedIntegrationTest.java
shards/trunk/src/test/org/hibernate/shards/integration/model/ModelDataFactory.java
shards/trunk/src/test/org/hibernate/shards/integration/platform/hsql/HSQLDatabasePlatform.java
shards/trunk/src/test/org/hibernate/shards/integration/platform/hsql/config/mappings-shardedTableHiLo.hbm.xml
shards/trunk/src/test/org/hibernate/shards/integration/platform/hsql/config/mappings-shardedUUID.hbm.xml
shards/trunk/src/test/org/hibernate/shards/integration/platform/hsql/config/mappings.hbm.xml
shards/trunk/src/test/org/hibernate/shards/integration/platform/mysql/config/mappings-shardedTableHiLo.hbm.xml
shards/trunk/src/test/org/hibernate/shards/integration/platform/mysql/config/mappings-shardedUUID.hbm.xml
shards/trunk/src/test/org/hibernate/shards/integration/platform/mysql/config/mappings.hbm.xml
shards/trunk/src/test/org/hibernate/shards/model/Floor.java
Log:
HSHARDS-39
Implement avg projection
Modified:
shards/trunk/src/java/org/hibernate/shards/criteria/ExitOperationsCriteriaCollector.java
===================================================================
---
shards/trunk/src/java/org/hibernate/shards/criteria/ExitOperationsCriteriaCollector.java 2007-07-27
12:06:55 UTC (rev 12835)
+++
shards/trunk/src/java/org/hibernate/shards/criteria/ExitOperationsCriteriaCollector.java 2007-07-28
03:10:55 UTC (rev 12836)
@@ -26,6 +26,7 @@
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.RowCountProjection;
import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.shards.strategy.exit.AvgResultsExitOperation;
import org.hibernate.shards.strategy.exit.DistinctExitOperation;
import org.hibernate.shards.strategy.exit.ExitOperationsCollector;
import org.hibernate.shards.strategy.exit.FirstResultExitOperation;
@@ -162,14 +163,16 @@
result = new MaxResultsExitOperation(maxResults).apply(result);
}
- ProjectionExitOperationFactory factory = ProjectionExitOperationFactory
- .getFactory();
+ ProjectionExitOperationFactory factory =
+ ProjectionExitOperationFactory.getFactory();
if (rowCountProjection != null) {
result = factory.getProjectionExitOperation(rowCountProjection,
sessionFactoryImplementor).apply(result);
}
- // TODO(maulik) average should go here
+ if (avgProjection != null) {
+ result = new AvgResultsExitOperation().apply(result);
+ }
// min, max, sum
if (aggregateProjection != null) {
Modified: shards/trunk/src/java/org/hibernate/shards/criteria/ShardedCriteriaImpl.java
===================================================================
---
shards/trunk/src/java/org/hibernate/shards/criteria/ShardedCriteriaImpl.java 2007-07-27
12:06:55 UTC (rev 12835)
+++
shards/trunk/src/java/org/hibernate/shards/criteria/ShardedCriteriaImpl.java 2007-07-28
03:10:55 UTC (rev 12836)
@@ -26,9 +26,12 @@
import org.hibernate.LockMode;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
+import org.hibernate.criterion.AvgProjection;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
+import org.hibernate.criterion.ProjectionList;
+import org.hibernate.criterion.Projections;
import org.hibernate.shards.Shard;
import org.hibernate.shards.ShardOperation;
import org.hibernate.shards.strategy.access.ShardAccessStrategy;
@@ -126,9 +129,30 @@
public Criteria setProjection(Projection projection) {
criteriaCollector.addProjection(projection);
+ if(projection instanceof AvgProjection) {
+ setAvgProjection(projection);
+ }
+ // TODO - handle ProjectionList
return this;
}
+ private void setAvgProjection(Projection projection) {
+ // We need to modify the query to pull back not just the average but also
+ // the count. We'll do this by creating a ProjectionList with both the
+ // average and the row count.
+ ProjectionList projectionList = Projections.projectionList();
+ projectionList.add(projection);
+ projectionList.add(Projections.rowCount());
+ CriteriaEvent event = new SetProjectionEvent(projectionList);
+ for (Shard shard : shards) {
+ if (shard.getCriteriaById(criteriaId) != null) {
+ shard.getCriteriaById(criteriaId).setProjection(projectionList);
+ } else {
+ shard.addCriteriaEvent(criteriaId, event);
+ }
+ }
+ }
+
public Criteria add(Criterion criterion) {
CriteriaEvent event = new AddCriterionEvent(criterion);
for (Shard shard : shards) {
Added:
shards/trunk/src/java/org/hibernate/shards/strategy/exit/AvgResultsExitOperation.java
===================================================================
--- shards/trunk/src/java/org/hibernate/shards/strategy/exit/AvgResultsExitOperation.java
(rev 0)
+++
shards/trunk/src/java/org/hibernate/shards/strategy/exit/AvgResultsExitOperation.java 2007-07-28
03:10:55 UTC (rev 12836)
@@ -0,0 +1,97 @@
+/**
+ * Copyright (C) 2007 Google Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+package org.hibernate.shards.strategy.exit;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.shards.util.Pair;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Performs post-processing on a result set that has had an average projection
+ * applied.
+ *
+ * This may not yield the exact same result as you'd get if you ran the query
+ * on a single shard because there seems to be some platform-specific wiggle.
+ * Here's a specific example:
+ * On hsqldb, if you have a column of type DECIMAL(10, 4) and you ask for the
+ * average of the values in that column, you get the floor of the result.
+ * On MySQL, if you have a column of the same type, you get a result back with
+ * the expected precision. So, um, just be careful.
+ *
+ * @author maxr(a)google.com (Max Ross)
+ */
+public class AvgResultsExitOperation implements ExitOperation {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ public List<Object> apply(List<Object> results) {
+ List<Object> nonNullResults = ExitOperationUtils.getNonNullList(results);
+ Double total = null;
+ int numResults = 0;
+ for(Object result : nonNullResults) {
+ /**
+ * We expect all entries to be Object arrays.
+ * the first entry in the array is the average (a double)
+ * the second entry in the array is the number of rows that were examined
+ * to arrive at the average.
+ */
+ Pair<Double, Integer> pair = getResultPair(result);
+ Double shardAvg = pair.first;
+ if(shardAvg == null) {
+ // if there's no result from this shard it doesn't go into the
+ // calculation. This is consistent with how avg is implemented
+ // in the database
+ continue;
+ }
+ int shardResults = pair.second;
+ Double shardTotal = shardAvg * shardResults;
+ if(total == null) {
+ total = shardTotal;
+ } else {
+ total += shardTotal;
+ }
+ numResults += shardResults;
+ }
+ if(numResults == 0 || total == null) {
+ return Collections.singletonList(null);
+ }
+ return Collections.<Object>singletonList(total / numResults);
+ }
+
+ private Pair<Double, Integer> getResultPair(Object result) {
+ if(!(result instanceof Object[])) {
+ final String msg =
+ "Wrong type in result list. Expected " + Object[].class +
+ " but found " + result.getClass();
+ log.error(msg);
+ throw new IllegalStateException(msg);
+ }
+ Object[] resultArr = (Object[]) result;
+ if(resultArr.length != 2) {
+ final String msg =
+ "Result array is wrong size. Expected 2 " +
+ " but found " + resultArr.length;
+ log.error(msg);
+ throw new IllegalStateException(msg);
+ }
+ return Pair.of((Double) resultArr[0], (Integer) resultArr[1]);
+ }
+}
Modified: shards/trunk/src/test/org/hibernate/shards/NonPermutedTests.java
===================================================================
--- shards/trunk/src/test/org/hibernate/shards/NonPermutedTests.java 2007-07-27 12:06:55
UTC (rev 12835)
+++ shards/trunk/src/test/org/hibernate/shards/NonPermutedTests.java 2007-07-28 03:10:55
UTC (rev 12836)
@@ -18,6 +18,7 @@
package org.hibernate.shards;
import junit.framework.TestCase;
+
import org.hibernate.shards.util.Lists;
import java.util.Collections;
@@ -117,6 +118,7 @@
classes.add(org.hibernate.shards.strategy.access.ParallelShardOperationCallableTest.class);
classes.add(org.hibernate.shards.strategy.access.StartAwareFutureTaskTest.class);
classes.add(org.hibernate.shards.strategy.exit.AggregateExitOperationTest.class);
+ classes.add(org.hibernate.shards.strategy.exit.AvgResultsExitOperationTest.class);
classes.add(org.hibernate.shards.strategy.exit.ExitOperationUtilsTest.class);
classes.add(org.hibernate.shards.strategy.exit.FirstNonNullResultExitStrategyTest.class);
classes.add(org.hibernate.shards.strategy.exit.FirstResultExitOperationTest.class);
Modified:
shards/trunk/src/test/org/hibernate/shards/integration/model/ModelCriteriaPermutedIntegrationTest.java
===================================================================
---
shards/trunk/src/test/org/hibernate/shards/integration/model/ModelCriteriaPermutedIntegrationTest.java 2007-07-27
12:06:55 UTC (rev 12835)
+++
shards/trunk/src/test/org/hibernate/shards/integration/model/ModelCriteriaPermutedIntegrationTest.java 2007-07-28
03:10:55 UTC (rev 12836)
@@ -53,9 +53,12 @@
super.setUp();
session.beginTransaction();
b1 = ModelDataFactory.building("b1");
- b1f1 = ModelDataFactory.floor(b1, 1);
- b1f2 = ModelDataFactory.floor(b1, 2);
- b1f3 = ModelDataFactory.floor(b1, 3);
+ // because of the fuzziness in how avg gets computed on hsqldb
+ // we need to make sure the per-shard avg is a round number, otherwise
+ // our test will fail
+ b1f1 = ModelDataFactory.floor(b1, 1, new BigDecimal(10.00));
+ b1f2 = ModelDataFactory.floor(b1, 2, new BigDecimal(20.00));
+ b1f3 = ModelDataFactory.floor(b1, 3, new BigDecimal(30.00));
b1f3o1 = ModelDataFactory.office("NOT LAHGE", b1f3);
b1f3o2 = ModelDataFactory.office("LAHGE", b1f3);
session.save(b1);
@@ -63,7 +66,7 @@
session.beginTransaction();
b2 = ModelDataFactory.building("b2");
- b2f1 = ModelDataFactory.floor(b2, 1);
+ b2f1 = ModelDataFactory.floor(b2, 1, new BigDecimal(20.00));
b2f1o1 = ModelDataFactory.office("LAHGE", b2f1);
session.save(b2);
session.getTransaction().commit();
@@ -220,7 +223,7 @@
assertEquals(2, l.size());
}
- public void testProjection() {
+ public void testRowCountProjection() {
Criteria crit =
session.createCriteria(Building.class).setProjection(Projections.rowCount());
Criteria floorCrit = crit.createCriteria("floors");
Criteria officeCrit = floorCrit.createCriteria("offices");
@@ -235,6 +238,14 @@
assertEquals(2, total);
}
+ public void testAvgProjection() {
+ Criteria crit =
session.createCriteria(Floor.class).setProjection(Projections.avg("squareFeet"));
+ List<Double> l = list(crit);
+ assertEquals(1, l.size());
+ assertEquals(20.0, l.get(0));
+ }
+
+
public void testMaxResults() throws Exception {
Criteria crit = session.createCriteria(Building.class).setMaxResults(1);
assertEquals(1, list(crit).size());
Modified:
shards/trunk/src/test/org/hibernate/shards/integration/model/ModelDataFactory.java
===================================================================
---
shards/trunk/src/test/org/hibernate/shards/integration/model/ModelDataFactory.java 2007-07-27
12:06:55 UTC (rev 12835)
+++
shards/trunk/src/test/org/hibernate/shards/integration/model/ModelDataFactory.java 2007-07-28
03:10:55 UTC (rev 12836)
@@ -27,6 +27,7 @@
import org.hibernate.shards.model.Tenant;
import org.hibernate.shards.model.Window;
+import java.math.BigDecimal;
import java.util.List;
/**
@@ -53,14 +54,19 @@
}
public static Floor floor(Building b, int number) {
- return floor(b, number, null, null);
+ return floor(b, number, null, null, null);
}
- public static Floor floor(Building b, int number, Escalator up, Escalator down) {
+ public static Floor floor(Building b, int number, BigDecimal squareFeet) {
+ return floor(b, number, squareFeet, null, null);
+ }
+
+ public static Floor floor(Building b, int number, BigDecimal squareFeet, Escalator up,
Escalator down) {
Floor f = new Floor();
f.setBuilding(b);
b.getFloors().add(f);
f.setNumber(number);
+ f.setSquareFeet(squareFeet);
f.setGoingDown(down);
f.setGoingUp(up);
return f;
Modified:
shards/trunk/src/test/org/hibernate/shards/integration/platform/hsql/HSQLDatabasePlatform.java
===================================================================
---
shards/trunk/src/test/org/hibernate/shards/integration/platform/hsql/HSQLDatabasePlatform.java 2007-07-27
12:06:55 UTC (rev 12835)
+++
shards/trunk/src/test/org/hibernate/shards/integration/platform/hsql/HSQLDatabasePlatform.java 2007-07-28
03:10:55 UTC (rev 12836)
@@ -46,7 +46,7 @@
,"INSERT INTO hibernate_unique_key(next_hi) VALUES(1)"
,"CREATE TABLE Elevator (elevatorId DECIMAL(40,0) PRIMARY KEY, buildingId
DECIMAL(40,0))"
,"CREATE TABLE Building (buildingId DECIMAL(40,0) PRIMARY KEY, name
VARCHAR(50))"
- ,"CREATE TABLE Floor (floorId DECIMAL(40,0) PRIMARY KEY, buildingId
DECIMAL(40,0), upEscalatorId DECIMAL(40,0), downEscalatorId DECIMAL(40,0), number
DECIMAL(40,0))"
+ ,"CREATE TABLE Floor (floorId DECIMAL(40,0) PRIMARY KEY, buildingId
DECIMAL(40,0), upEscalatorId DECIMAL(40,0), downEscalatorId DECIMAL(40,0), number
DECIMAL(40,0), squareFeet DECIMAL(40, 4))"
,"CREATE TABLE Tenant (tenantId DECIMAL(40,0) PRIMARY KEY, name
VARCHAR(50))"
,"CREATE TABLE BuildingTenant (buildingId DECIMAL(40,0), tenantId DECIMAL(40,0),
PRIMARY KEY(buildingId, tenantId))"
,"CREATE TABLE Office (officeId DECIMAL(40,0) PRIMARY KEY, floorId
DECIMAL(40,0), label VARCHAR(50), windowId DECIMAL(40,0))"
Modified:
shards/trunk/src/test/org/hibernate/shards/integration/platform/hsql/config/mappings-shardedTableHiLo.hbm.xml
===================================================================
---
shards/trunk/src/test/org/hibernate/shards/integration/platform/hsql/config/mappings-shardedTableHiLo.hbm.xml 2007-07-27
12:06:55 UTC (rev 12835)
+++
shards/trunk/src/test/org/hibernate/shards/integration/platform/hsql/config/mappings-shardedTableHiLo.hbm.xml 2007-07-28
03:10:55 UTC (rev 12836)
@@ -109,6 +109,7 @@
<generator
class="org.hibernate.shards.id.ShardedTableHiLoGenerator"/>
</id>
<property name="number" not-null="true"/>
+ <property name="squareFeet" not-null="false"/>
<many-to-one name="goingUp" column="upEscalatorId"
unique="true" not-null="false" class="Escalator"
cascade="all"/>
<many-to-one name="goingDown" column="downEscalatorId"
unique="true" not-null="false" class="Escalator"
cascade="all"/>
<many-to-one name="building" column="buildingId"
not-null="true" class="Building"/>
Modified:
shards/trunk/src/test/org/hibernate/shards/integration/platform/hsql/config/mappings-shardedUUID.hbm.xml
===================================================================
---
shards/trunk/src/test/org/hibernate/shards/integration/platform/hsql/config/mappings-shardedUUID.hbm.xml 2007-07-27
12:06:55 UTC (rev 12835)
+++
shards/trunk/src/test/org/hibernate/shards/integration/platform/hsql/config/mappings-shardedUUID.hbm.xml 2007-07-28
03:10:55 UTC (rev 12836)
@@ -108,6 +108,7 @@
<generator class="org.hibernate.shards.id.ShardedUUIDGenerator"/>
</id>
<property name="number" not-null="true"/>
+ <property name="squareFeet" not-null="false"/>
<many-to-one name="goingUp" column="upEscalatorId"
unique="true" not-null="false" class="Escalator"
cascade="all"/>
<many-to-one name="goingDown" column="downEscalatorId"
unique="true" not-null="false" class="Escalator"
cascade="all"/>
<many-to-one name="building" column="buildingId"
not-null="true" class="Building"/>
Modified:
shards/trunk/src/test/org/hibernate/shards/integration/platform/hsql/config/mappings.hbm.xml
===================================================================
---
shards/trunk/src/test/org/hibernate/shards/integration/platform/hsql/config/mappings.hbm.xml 2007-07-27
12:06:55 UTC (rev 12835)
+++
shards/trunk/src/test/org/hibernate/shards/integration/platform/hsql/config/mappings.hbm.xml 2007-07-28
03:10:55 UTC (rev 12836)
@@ -108,6 +108,7 @@
<generator class="org.hibernate.shards.id.UUIDBigIntGenerator"/>
</id>
<property name="number" not-null="true"/>
+ <property name="squareFeet" not-null="false"/>
<many-to-one name="goingUp" column="upEscalatorId"
unique="true" not-null="false" class="Escalator"
cascade="all"/>
<many-to-one name="goingDown" column="downEscalatorId"
unique="true" not-null="false" class="Escalator"
cascade="all"/>
<many-to-one name="building" column="buildingId"
not-null="true" class="Building"/>
Modified:
shards/trunk/src/test/org/hibernate/shards/integration/platform/mysql/config/mappings-shardedTableHiLo.hbm.xml
===================================================================
---
shards/trunk/src/test/org/hibernate/shards/integration/platform/mysql/config/mappings-shardedTableHiLo.hbm.xml 2007-07-27
12:06:55 UTC (rev 12835)
+++
shards/trunk/src/test/org/hibernate/shards/integration/platform/mysql/config/mappings-shardedTableHiLo.hbm.xml 2007-07-28
03:10:55 UTC (rev 12836)
@@ -108,6 +108,7 @@
<generator
class="org.hibernate.shards.id.ShardedTableHiLoGenerator"/>
</id>
<property name="number" not-null="true"/>
+ <property name="squareFeet" not-null="false"/>
<many-to-one name="goingUp" column="upEscalatorId"
unique="true" not-null="false" class="Escalator"
cascade="all"/>
<many-to-one name="goingDown" column="downEscalatorId"
unique="true" not-null="false" class="Escalator"
cascade="all"/>
<many-to-one name="building" column="buildingId"
not-null="true" class="Building"/>
Modified:
shards/trunk/src/test/org/hibernate/shards/integration/platform/mysql/config/mappings-shardedUUID.hbm.xml
===================================================================
---
shards/trunk/src/test/org/hibernate/shards/integration/platform/mysql/config/mappings-shardedUUID.hbm.xml 2007-07-27
12:06:55 UTC (rev 12835)
+++
shards/trunk/src/test/org/hibernate/shards/integration/platform/mysql/config/mappings-shardedUUID.hbm.xml 2007-07-28
03:10:55 UTC (rev 12836)
@@ -108,6 +108,7 @@
<generator class="org.hibernate.shards.id.ShardedUUIDGenerator"/>
</id>
<property name="number" not-null="true"/>
+ <property name="squareFeet" not-null="false"/>
<many-to-one name="goingUp" column="upEscalatorId"
unique="true" not-null="false" class="Escalator"
cascade="all"/>
<many-to-one name="goingDown" column="downEscalatorId"
unique="true" not-null="false" class="Escalator"
cascade="all"/>
<many-to-one name="building" column="buildingId"
not-null="true" class="Building"/>
Modified:
shards/trunk/src/test/org/hibernate/shards/integration/platform/mysql/config/mappings.hbm.xml
===================================================================
---
shards/trunk/src/test/org/hibernate/shards/integration/platform/mysql/config/mappings.hbm.xml 2007-07-27
12:06:55 UTC (rev 12835)
+++
shards/trunk/src/test/org/hibernate/shards/integration/platform/mysql/config/mappings.hbm.xml 2007-07-28
03:10:55 UTC (rev 12836)
@@ -108,6 +108,7 @@
<generator class="org.hibernate.shards.id.UUIDBigIntGenerator"/>
</id>
<property name="number" not-null="true"/>
+ <property name="squareFeet" not-null="false"/>
<many-to-one name="goingUp" column="upEscalatorId"
unique="true" not-null="false" class="Escalator"
cascade="all"/>
<many-to-one name="goingDown" column="downEscalatorId"
unique="true" not-null="false" class="Escalator"
cascade="all"/>
<many-to-one name="building" column="buildingId"
not-null="true" class="Building"/>
Modified: shards/trunk/src/test/org/hibernate/shards/model/Floor.java
===================================================================
--- shards/trunk/src/test/org/hibernate/shards/model/Floor.java 2007-07-27 12:06:55 UTC
(rev 12835)
+++ shards/trunk/src/test/org/hibernate/shards/model/Floor.java 2007-07-28 03:10:55 UTC
(rev 12836)
@@ -21,6 +21,7 @@
import org.hibernate.shards.util.Lists;
import java.io.Serializable;
+import java.math.BigDecimal;
import java.util.List;
/**
@@ -30,6 +31,7 @@
private Serializable floorId;
private int number;
+ private BigDecimal squareFeet;
private List<Tenant> tenants;
private List<Office> offices = Lists.newArrayList();
private List<Elevator> elevators = Lists.newArrayList();
@@ -53,6 +55,14 @@
this.number = number;
}
+ public BigDecimal getSquareFeet() {
+ return squareFeet;
+ }
+
+ public void setSquareFeet(BigDecimal squareFeet) {
+ this.squareFeet = squareFeet;
+ }
+
public List<Tenant> getTenants() {
return tenants;
}
Added:
shards/trunk/src/test/org/hibernate/shards/strategy/exit/AvgResultsExitOperationTest.java
===================================================================
---
shards/trunk/src/test/org/hibernate/shards/strategy/exit/AvgResultsExitOperationTest.java
(rev 0)
+++
shards/trunk/src/test/org/hibernate/shards/strategy/exit/AvgResultsExitOperationTest.java 2007-07-28
03:10:55 UTC (rev 12836)
@@ -0,0 +1,101 @@
+/**
+ * Copyright (C) 2007 Google Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+package org.hibernate.shards.strategy.exit;
+
+import junit.framework.TestCase;
+
+import org.hibernate.Hibernate;
+import org.hibernate.criterion.AvgProjection;
+import org.hibernate.shards.util.Lists;
+import org.hibernate.type.Type;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author maxr(a)google.com (Max Ross)
+ */
+public class AvgResultsExitOperationTest extends TestCase {
+
+ public void testAvgProjectionComesBackAsDouble() {
+ // sharded avg calculation assumes that the avg projection implementation
+ // returns a Double, so let's make sure that assumption is valid
+ AvgProjection ap = new AvgProjection("yam");
+ Type[] types = ap.getTypes(null, null);
+ assertNotNull(types);
+ assertEquals(1, types.length);
+ assertEquals(Hibernate.DOUBLE, types[0]);
+ }
+
+ public void testEmptyList() {
+ AvgResultsExitOperation op = new AvgResultsExitOperation();
+
+ List<Object> result = op.apply(Collections.emptyList());
+ assertEquals(1, result.size());
+ assertNull(result.get(0));
+ }
+
+ public void testSingleResult() {
+ AvgResultsExitOperation op = new AvgResultsExitOperation();
+
+ Object[] objArr = {null, 3};
+ List<Object> result = op.apply(Collections.singletonList((Object) objArr));
+ assertEquals(1, result.size());
+ assertNull(result.get(0));
+
+ objArr[0] = 9.0;
+ result = op.apply(Collections.singletonList((Object) objArr));
+ assertEquals(1, result.size());
+ assertEquals(9.0, result.get(0));
+ }
+
+ public void testMultipleResults() {
+ AvgResultsExitOperation op = new AvgResultsExitOperation();
+
+ Object[] objArr1 = {null, 3};
+ Object[] objArr2 = {2.5, 2};
+ List<Object> result = op.apply(Lists.<Object>newArrayList(objArr1,
objArr2));
+ assertEquals(1, result.size());
+ assertEquals(2.5, result.get(0));
+
+ objArr1[0] = 2.0;
+ result = op.apply(Lists.<Object>newArrayList(objArr1, objArr2));
+ assertEquals(1, result.size());
+ assertEquals(2.2, result.get(0));
+ }
+
+ public void testBadInput() {
+ AvgResultsExitOperation op = new AvgResultsExitOperation();
+
+ Object[] objArr = {null};
+ try {
+ op.apply(Collections.singletonList((Object) objArr));
+ fail("expected rte");
+ } catch (IllegalStateException rte) {
+ // good
+ }
+
+ Object obj = new Object();
+ try {
+ op.apply(Collections.singletonList(obj));
+ fail("expected rte");
+ } catch (IllegalStateException rte) {
+ // good
+ }
+ }
+}