Return null from a load() with no matches, rather than throwing a NoSuchElement
exception. I'm tempted to reinstate the NoSuchElement exception for a load() that attempts to project fields from the selected rows, but I think it makes more sense for a load() which aggregates over zero rows to return null than to throw a NoSuchElement exception.
This commit is contained in:
@@ -364,48 +364,53 @@ public class QueryBuilder<T extends PersistentRecord>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value from the first row that matches the configured query clauses.
|
||||
* Returns the value from the first row that matches the configured query clauses. This value
|
||||
* may be null if the query clauses match no rows.
|
||||
*/
|
||||
public <V> V load (SQLExpression<V> selexp)
|
||||
{
|
||||
return select(selexp).get(0); // TODO: revamp FindOneQuery and use that
|
||||
return getLoaded(select(selexp)); // TODO: revamp FindOneQuery and use that
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value from the first row that matches the configured query clauses.
|
||||
* Returns the value from the first row that matches the configured query clauses. This value
|
||||
* may be null if the query clauses match no rows.
|
||||
*/
|
||||
public <V1, V2> Tuple2<V1, V2> load (SQLExpression<V1> exp1, SQLExpression<V2> exp2)
|
||||
{
|
||||
return select(exp1, exp2).get(0); // TODO: revamp FindOneQuery and use that
|
||||
return getLoaded(select(exp1, exp2)); // TODO: revamp FindOneQuery and use that
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value from the first row that matches the configured query clauses.
|
||||
* Returns the value from the first row that matches the configured query clauses. This value
|
||||
* may be null if the query clauses match no rows.
|
||||
*/
|
||||
public <V1, V2, V3> Tuple3<V1, V2, V3> load (
|
||||
SQLExpression<V1> exp1, SQLExpression<V2> exp2, SQLExpression<V3> exp3)
|
||||
{
|
||||
return select(exp1, exp2, exp3).get(0); // TODO: revamp FindOneQuery and use that
|
||||
return getLoaded(select(exp1, exp2, exp3)); // TODO: revamp FindOneQuery and use that
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value from the first row that matches the configured query clauses.
|
||||
* Returns the value from the first row that matches the configured query clauses. This value
|
||||
* may be null if the query clauses match no rows.
|
||||
*/
|
||||
public <V1, V2, V3, V4> Tuple4<V1, V2, V3, V4> load (
|
||||
SQLExpression<V1> exp1, SQLExpression<V2> exp2,
|
||||
SQLExpression<V3> exp3, SQLExpression<V4> exp4)
|
||||
{
|
||||
return select(exp1, exp2, exp3, exp4).get(0); // TODO: revamp FindOneQuery and use that
|
||||
return getLoaded(select(exp1, exp2, exp3, exp4)); // TODO: revamp FindOneQuery and use that
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value from the first row that matches the configured query clauses.
|
||||
* Returns the value from the first row that matches the configured query clauses. This value
|
||||
* may be null if the query clauses match no rows.
|
||||
*/
|
||||
public <V1, V2, V3, V4, V5> Tuple5<V1, V2, V3, V4, V5> load (
|
||||
SQLExpression<V1> exp1, SQLExpression<V2> exp2, SQLExpression<V3> exp3,
|
||||
SQLExpression<V4> exp4, SQLExpression<V5> exp5)
|
||||
{
|
||||
return select(exp1, exp2, exp3, exp4, exp5).get(0); // TODO: use revamped FindOneQuery
|
||||
return getLoaded(select(exp1, exp2, exp3, exp4, exp5)); // TODO: use revamped FindOneQuery
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -553,6 +558,11 @@ public class QueryBuilder<T extends PersistentRecord>
|
||||
checkState(_forUpdate == null, "ForUpdate clause not supported by delete.");
|
||||
}
|
||||
|
||||
protected static <T> T getLoaded (List<T> selections)
|
||||
{
|
||||
return selections.isEmpty() ? null : selections.get(0);
|
||||
}
|
||||
|
||||
protected final PersistenceContext _ctx;
|
||||
protected final DepotRepository _repo;
|
||||
protected final Class<T> _pclass;
|
||||
|
||||
@@ -96,6 +96,19 @@ public class ProjectionTest extends TestBase
|
||||
assertEquals(20, jdata.size());
|
||||
}
|
||||
|
||||
@Test public void testNoMatches ()
|
||||
{
|
||||
QueryBuilder<TestRecord> empty =
|
||||
_repo.from(TestRecord.class).where(TestRecord.AGE.greaterThan(100));
|
||||
|
||||
// test a projection from a query that returns no matches
|
||||
assertNull(empty.load(TestRecord.RECORD_ID));
|
||||
assertEquals(0, empty.select().size());
|
||||
|
||||
// test an aggregate on a query that matches no rows
|
||||
assertNull(empty.load(Funcs.max(TestRecord.RECORD_ID)));
|
||||
}
|
||||
|
||||
@Test public void testAggregates ()
|
||||
{
|
||||
// test computed expressions on the RHS (the casts are just to cope with JUnit's overloads)
|
||||
|
||||
Reference in New Issue
Block a user