Added support for limit to deleteAll.

I would have prefered to only add this support to the Query interface, and not
clutter up DepotRepository with two additional overloaded methods. However,
that would not have been possible without duplicating a bunch of logic from
DepotRepository. Yet another reason why the Query builder approach is awesome
and the fuckloads of overloaded methods approach isn't.
This commit is contained in:
Michael Bayne
2011-06-23 22:12:47 +00:00
parent ee93f91e61
commit e3ff96745d
6 changed files with 81 additions and 14 deletions
@@ -24,6 +24,7 @@ import com.samskivert.util.ArrayUtil;
import com.samskivert.depot.clause.FieldOverride;
import com.samskivert.depot.clause.InsertClause;
import com.samskivert.depot.clause.Limit;
import com.samskivert.depot.clause.QueryClause;
import com.samskivert.depot.clause.WhereClause;
import com.samskivert.depot.expression.ColumnExp;
@@ -673,20 +674,34 @@ public abstract class DepotRepository
*
* @throws DatabaseException if any problem is encountered communicating with the database.
*/
public <T extends PersistentRecord> int deleteAll (Class<T> type, final WhereClause where)
public <T extends PersistentRecord> int deleteAll (Class<T> type, WhereClause where)
throws DatabaseException
{
return deleteAll(type, where, null, null);
}
/**
* Deletes all persistent objects from the database that match the supplied where clause, up to
* the specified limit.
*
* @return the number of rows deleted by this action.
*
* @throws DatabaseException if any problem is encountered communicating with the database.
*/
public <T extends PersistentRecord> int deleteAll (Class<T> type, WhereClause where, Limit lim)
throws DatabaseException
{
if (where instanceof CacheInvalidator) {
// our where clause knows how to do its own deletion, yay!
return deleteAll(type, where, (CacheInvalidator)where);
return deleteAll(type, where, lim, (CacheInvalidator)where);
} else if (_ctx.getMarshaller(type).hasPrimaryKey()) {
// look up the primary keys for all matching rows matching and delete using those
KeySet<T> pwhere = KeySet.newKeySet(type, findAllKeys(type, true, where));
KeySet<T> pwhere = KeySet.newKeySet(type, findAllKeys(type, true, where, lim));
return deleteAll(type, pwhere, pwhere);
} else {
// otherwise just do the delete directly as we can't have cached a record that has no
// primary key in the first place
return deleteAll(type, where, null);
return deleteAll(type, where, lim, null);
}
}
@@ -698,7 +713,22 @@ public abstract class DepotRepository
* @throws DatabaseException if any problem is encountered communicating with the database.
*/
public <T extends PersistentRecord> int deleteAll (
final Class<T> type, final WhereClause where, CacheInvalidator invalidator)
Class<T> type, WhereClause where, CacheInvalidator invalidator)
throws DatabaseException
{
return deleteAll(type, where, null, invalidator);
}
/**
* Deletes all persistent objects from the database that match the supplied key, up to the
* supplied limit.
*
* @return the number of rows deleted by this action.
*
* @throws DatabaseException if any problem is encountered communicating with the database.
*/
public <T extends PersistentRecord> int deleteAll (
final Class<T> type, WhereClause where, Limit limit, CacheInvalidator invalidator)
throws DatabaseException
{
if (invalidator instanceof ValidatingCacheInvalidator) {
@@ -706,7 +736,7 @@ public abstract class DepotRepository
}
where.validateQueryType(type); // and another
DeleteClause delete = new DeleteClause(type, where);
DeleteClause delete = new DeleteClause(type, where, limit);
final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, delete));
builder.newQuery(delete);
+10 -7
View File
@@ -523,8 +523,8 @@ public class Query<T extends PersistentRecord>
}
/**
* Deletes the records that match the configured query clauses. Note that only the where
* clauses are used to evaluate a deletion. Attempts to use other clauses will result in
* Deletes the records that match the configured query clauses. Note that only the where and
* limit clauses are used to evaluate a deletion. Attempts to use other clauses will result in
* failure.
*
* @return the number of rows deleted by this action.
@@ -534,12 +534,16 @@ public class Query<T extends PersistentRecord>
public int delete ()
{
assertValidDelete();
return _repo.deleteAll(_pclass, _where);
return _repo.deleteAll(_pclass, _where, _limit);
}
/**
* Deletes the records that match the configured query clauses. The supplied cache invalidator
* is used to remove deleted records from the cache.
* Deletes the records that match the configured query clauses. Note that only the where and
* limit clauses are used to evaluate a deletion. Attempts to use other clauses will result in
* failure.
*
* @param invalidator if non-null, used to remove deleted records from the cache; if null, no
* cache deletion will be performed.
*
* @return the number of rows deleted by this action.
*
@@ -548,7 +552,7 @@ public class Query<T extends PersistentRecord>
public int delete (CacheInvalidator invalidator)
{
assertValidDelete();
return _repo.deleteAll(_pclass, _where, invalidator);
return _repo.deleteAll(_pclass, _where, _limit, invalidator);
}
protected Query (PersistenceContext ctx, DepotRepository repo, Class<T> pclass)
@@ -602,7 +606,6 @@ public class Query<T extends PersistentRecord>
checkState(_joins == null, "Join clauses not supported by delete.");
checkState(_orderBy == null, "OrderBy clause not applicable for delete.");
checkState(_groupBy == null, "GroupBy clause not applicable for delete.");
checkState(_limit == null, "Limit clause not supported by delete.");
checkState(_fromOverride == null, "FromOverride clause not applicable for delete.");
checkState(_fieldDefs == null, "FieldDefinition clauses not applicable for delete.");
checkState(_forUpdate == null, "ForUpdate clause not supported by delete.");
@@ -469,6 +469,9 @@ public abstract class BuildVisitor implements FragmentVisitor<Void>
appendTableAbbreviation(deleteClause.getPersistentClass());
_builder.append(" ");
deleteClause.getWhereClause().accept(this);
if (deleteClause.getLimit() != null) {
deleteClause.getLimit().accept(this);
}
return null;
}
@@ -52,6 +52,9 @@ public class MySQLBuilder
_types.setUseTableAbbreviations(false);
try {
deleteClause.getWhereClause().accept(this);
if (deleteClause.getLimit() != null) {
deleteClause.getLimit().accept(this);
}
} finally {
_types.setUseTableAbbreviations(savedFlag);
}
@@ -7,6 +7,7 @@ package com.samskivert.depot.impl.clause;
import java.util.Collection;
import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.clause.Limit;
import com.samskivert.depot.clause.QueryClause;
import com.samskivert.depot.clause.WhereClause;
@@ -18,10 +19,11 @@ import com.samskivert.depot.impl.FragmentVisitor;
public class DeleteClause
implements QueryClause
{
public DeleteClause (Class<? extends PersistentRecord> pClass, WhereClause where)
public DeleteClause (Class<? extends PersistentRecord> pClass, WhereClause where, Limit limit)
{
_pClass = pClass;
_where = where;
_limit = limit;
}
public Class<? extends PersistentRecord> getPersistentClass ()
@@ -34,6 +36,11 @@ public class DeleteClause
return _where;
}
public Limit getLimit ()
{
return _limit;
}
// from SQLFragment
public void addClasses (Collection<Class<? extends PersistentRecord>> classSet)
{
@@ -51,4 +58,7 @@ public class DeleteClause
/** The where clause. */
protected WhereClause _where;
/** An optional limit clause. */
protected Limit _limit;
}
@@ -94,6 +94,24 @@ public class QueryTest extends TestBase
// _repo.deleteAll(TestRecord.class, KeySet.newSimpleKeySet(TestRecord.class, ids));
}
@Test public void testLimitedDelete ()
{
for (int ii = 1; ii <= CREATE_RECORDS; ii++) {
TestRecord record = createTestRecord(ii);
record.name = "Spam! " + ii;
record.age = RandomUtil.getInt(100);
record.awesomeness = RandomUtil.getFloat(1.0F);
record.homeTown = "Over there";
_repo.insert(record);
}
_repo.from(TestRecord.class).whereTrue().limit(50).delete();
assertEquals(CREATE_RECORDS-50, _repo.findAll(TestRecord.class).size());
_repo.from(TestRecord.class).whereTrue().delete();
assertEquals(0, _repo.findAll(TestRecord.class).size());
}
// the HSQL in-memory database persists for the lifetime of the VM, which means we have to
// clean up after ourselves in every test; thus we go ahead and share a repository
protected TestRepository _repo = createTestRepository();