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)
|
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)
|
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 (
|
public <V1, V2, V3> Tuple3<V1, V2, V3> load (
|
||||||
SQLExpression<V1> exp1, SQLExpression<V2> exp2, SQLExpression<V3> exp3)
|
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 (
|
public <V1, V2, V3, V4> Tuple4<V1, V2, V3, V4> load (
|
||||||
SQLExpression<V1> exp1, SQLExpression<V2> exp2,
|
SQLExpression<V1> exp1, SQLExpression<V2> exp2,
|
||||||
SQLExpression<V3> exp3, SQLExpression<V4> exp4)
|
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 (
|
public <V1, V2, V3, V4, V5> Tuple5<V1, V2, V3, V4, V5> load (
|
||||||
SQLExpression<V1> exp1, SQLExpression<V2> exp2, SQLExpression<V3> exp3,
|
SQLExpression<V1> exp1, SQLExpression<V2> exp2, SQLExpression<V3> exp3,
|
||||||
SQLExpression<V4> exp4, SQLExpression<V5> exp5)
|
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.");
|
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 PersistenceContext _ctx;
|
||||||
protected final DepotRepository _repo;
|
protected final DepotRepository _repo;
|
||||||
protected final Class<T> _pclass;
|
protected final Class<T> _pclass;
|
||||||
|
|||||||
@@ -96,6 +96,19 @@ public class ProjectionTest extends TestBase
|
|||||||
assertEquals(20, jdata.size());
|
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 public void testAggregates ()
|
||||||
{
|
{
|
||||||
// test computed expressions on the RHS (the casts are just to cope with JUnit's overloads)
|
// test computed expressions on the RHS (the casts are just to cope with JUnit's overloads)
|
||||||
|
|||||||
Reference in New Issue
Block a user