DATACASS-288 - Polish.

Re-implemented CassandraBatchTemplate to take a vararg array of Object entities rather than a single entity and guarded against null.

Original pull request: #78.
This commit is contained in:
John Blum
2016-07-24 20:17:33 -07:00
parent e818d3bc29
commit d0610b2812
5 changed files with 109 additions and 105 deletions

View File

@@ -36,8 +36,8 @@ public interface CassandraBatchOperations {
/**
* Execute the batch. The batch can be executed only once.
*
* @throws IllegalStateException if the batch is executed after it was executed once
*
* @throws IllegalStateException if the batch is executed after it was executed already.
*/
void execute();
@@ -45,62 +45,63 @@ public interface CassandraBatchOperations {
* Apply a given {@code timestamp} to the whole batch.
*
* @param timestamp the timestamp to apply.
* @return {@code this} {@link CassandraBatchOperations}
* @throws IllegalStateException if the batch was already executed
* @return {@code this} {@link CassandraBatchOperations}.
* @throws IllegalStateException if the batch was already executed.
*/
CassandraBatchOperations withTimestamp(long timestamp);
/**
* Add a single insert to the batch.
* Add an array of inserts to the batch.
*
* @param entity the entity to insert, must not be {@literal null}.
* @return {@code this} {@link CassandraBatchOperations}
* @throws IllegalStateException if the batch was already executed
* @param entities the entities to insert; must not be {@literal null}.
* @return {@code this} {@link CassandraBatchOperations}.
* @throws IllegalStateException if the batch was already executed.
*/
CassandraBatchOperations insert(Object entity);
CassandraBatchOperations insert(Object... entities);
/**
* Add a collection of inserts to the batch.
*
* @param entities the entities to insert, must not be {@literal null}.
* @return {@code this} {@link CassandraBatchOperations}
* @throws IllegalStateException if the batch was already executed
*
* @param entities the entities to insert; must not be {@literal null}.
* @return {@code this} {@link CassandraBatchOperations}.
* @throws IllegalStateException if the batch was already executed.
*/
CassandraBatchOperations insert(Iterable<? extends Object> entities);
CassandraBatchOperations insert(Iterable<?> entities);
/**
* Add a single update to the batch.
*
* @param entity the entity to update, must not be {@literal null}.
* @return {@code this} {@link CassandraBatchOperations}
* @throws IllegalStateException if the batch was already executed
* Add an array of updates to the batch.
*
* @param entities the entities to update; must not be {@literal null}.
* @return {@code this} {@link CassandraBatchOperations}.
* @throws IllegalStateException if the batch was already executed.
*/
CassandraBatchOperations update(Object entity);
CassandraBatchOperations update(Object... entities);
/**
* Add a collection of updates to the batch.
*
* @param entities the entities to insert, must not be {@literal null}.
* @return {@code this} {@link CassandraBatchOperations}
* @throws IllegalStateException if the batch was already executed
*
* @param entities the entities to update; must not be {@literal null}.
* @return {@code this} {@link CassandraBatchOperations}.
* @throws IllegalStateException if the batch was already executed.
*/
CassandraBatchOperations update(Iterable<? extends Object> entities);
CassandraBatchOperations update(Iterable<?> entities);
/**
* Add a single delete to the batch.
*
* @param entity the entity to delete, must not be {@literal null}.
* @return {@code this} {@link CassandraBatchOperations}
* @throws IllegalStateException if the batch was already executed
* Add an array of deletes to the batch.
*
* @param entities the entities to delete; must not be {@literal null}.
* @return {@code this} {@link CassandraBatchOperations}.
* @throws IllegalStateException if the batch was already executed.
*/
CassandraBatchOperations delete(Object entity);
CassandraBatchOperations delete(Object... entities);
/**
* Add a collection of deletes to the batch.
*
* @param entities the entities to delete, must not be {@literal null}.
* @return {@code this} {@link CassandraBatchOperations}
* @throws IllegalStateException if the batch was already executed
*
* @param entities the entities to delete; must not be {@literal null}.
* @return {@code this} {@link CassandraBatchOperations}.
* @throws IllegalStateException if the batch was already executed.
*/
CassandraBatchOperations delete(Iterable<? extends Object> entities);
CassandraBatchOperations delete(Iterable<?> entities);
}

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.cassandra.core;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.atomic.AtomicBoolean;
import org.springframework.util.Assert;
@@ -26,14 +28,19 @@ import com.datastax.driver.core.querybuilder.QueryBuilder;
* Default implementation for {@link CassandraBatchOperations}.
*
* @author Mark Paluch
* @author John Blum
* @since 1.5
*/
class CassandraBatchTemplate implements CassandraBatchOperations {
private final CassandraTemplate cassandraTemplate;
private final Batch batch;
static final Object[] EMPTY_ARRAY = new Object[0];
private AtomicBoolean executed = new AtomicBoolean();
private final Batch batch;
private final CassandraTemplate cassandraTemplate;
public CassandraBatchTemplate(CassandraTemplate cassandraTemplate) {
Assert.notNull(cassandraTemplate, "CassandraTemplate must not be null");
@@ -42,7 +49,7 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
this.batch = QueryBuilder.batch();
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraBatchOperations#execute()
*/
@@ -54,48 +61,42 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
return;
}
ensureNotExecuted();
assertNotExecuted();
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraBatchOperations#withTimestamp(long)
*/
@Override
public CassandraBatchOperations withTimestamp(long timestamp) {
ensureNotExecuted();
assertNotExecuted();
batch.using(QueryBuilder.timestamp(timestamp));
return this;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraBatchOperations#insert(java.lang.Object)
* @see org.springframework.data.cassandra.core.CassandraBatchOperations#insert(Object...)
*/
@Override
public CassandraBatchOperations insert(Object entity) {
ensureNotExecuted();
Assert.notNull(entity, "Entity must not be null");
batch.add(cassandraTemplate.createInsertQuery(entity, null));
return this;
public CassandraBatchOperations insert(Object... entities) {
return insert(nullSafeIterable(entities));
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraBatchOperations#insert(java.lang.Iterable)
*/
@Override
public CassandraBatchOperations insert(Iterable<? extends Object> entities) {
public CassandraBatchOperations insert(Iterable<?> entities) {
ensureNotExecuted();
Assert.notNull(entities, "Entities must not be null");
for (Object entity : entities) {
assertNotExecuted();
for (Object entity : nullSafeIterable(entities)) {
Assert.notNull(entity, "Entity must not be null");
batch.add(cassandraTemplate.createInsertQuery(entity, null));
}
@@ -103,33 +104,25 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
return this;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraBatchOperations#update(java.lang.Object)
* @see org.springframework.data.cassandra.core.CassandraBatchOperations#update(Object...)
*/
@Override
public CassandraBatchOperations update(Object entity) {
ensureNotExecuted();
Assert.notNull(entity, "Entity must not be null");
batch.add(cassandraTemplate.createUpdateQuery(entity, null));
return this;
public CassandraBatchOperations update(Object... entities) {
return update(nullSafeIterable(entities));
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraBatchOperations#update(java.lang.Iterable)
*/
@Override
public CassandraBatchOperations update(Iterable<? extends Object> entities) {
public CassandraBatchOperations update(Iterable<?> entities) {
ensureNotExecuted();
Assert.notNull(entities, "Entities must not be null");
for (Object entity : entities) {
assertNotExecuted();
for (Object entity : nullSafeIterable(entities)) {
Assert.notNull(entity, "Entity must not be null");
batch.add(cassandraTemplate.createUpdateQuery(entity, null));
}
@@ -137,19 +130,13 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
return this;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraBatchOperations#delete(java.lang.Object)
* @see org.springframework.data.cassandra.core.CassandraBatchOperations#delete(Object...)
*/
@Override
public CassandraBatchOperations delete(Object entity) {
ensureNotExecuted();
Assert.notNull(entity, "Entity must not be null");
batch.add(cassandraTemplate.createDeleteQuery(entity, null));
return this;
public CassandraBatchOperations delete(Object... entities) {
return delete(nullSafeIterable(entities));
}
/*
@@ -157,13 +144,11 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
* @see org.springframework.data.cassandra.core.CassandraBatchOperations#delete(java.lang.Iterable)
*/
@Override
public CassandraBatchOperations delete(Iterable<? extends Object> entities) {
public CassandraBatchOperations delete(Iterable<?> entities) {
ensureNotExecuted();
Assert.notNull(entities, "Entities must not be null");
for (Object entity : entities) {
assertNotExecuted();
for (Object entity : nullSafeIterable(entities)) {
Assert.notNull(entity, "Entity must not be null");
batch.add(cassandraTemplate.createDeleteQuery(entity, null));
}
@@ -171,7 +156,15 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
return this;
}
private void ensureNotExecuted() {
private void assertNotExecuted() {
Assert.state(!executed.get(), "This Cassandra Batch was already executed");
}
private <T> Iterable<T> nullSafeIterable(T... array) {
return (array == null ? Collections.<T>emptyList() : Arrays.asList(array));
}
private <T> Iterable<T> nullSafeIterable(Iterable<T> iterable) {
return (iterable != null ? iterable : Collections.<T>emptyList());
}
}

View File

@@ -704,8 +704,9 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
protected <T> T doInsert(T entity, WriteOptions options) {
Assert.notNull(entity, "Entity must not be null");
Insert insert = createInsertQuery(entity, options);
execute(insert);
execute(createInsertQuery(entity, options));
return entity;
}
@@ -917,7 +918,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
return executeAsynchronously(createUpdateQuery(entity, options), queryListener);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#batchOps(java.lang.Class)
*/

View File

@@ -39,7 +39,7 @@ import com.datastax.driver.core.Row;
/**
* Integration tests for {@link CassandraBatchTemplate}.
*
*
* @author Mark Paluch
*/
@RunWith(SpringJUnit4ClassRunner.class)
@@ -63,7 +63,7 @@ public class CassandraBatchTemplateIntegrationTests extends AbstractSpringDataEm
}
/**
* @see DATACASS-288
* @see <a href="https://jira.spring.io/browse/DATACASS-288">DATACASS-288</a>
*/
@Test
public void shouldInsertEntities() {
@@ -75,11 +75,12 @@ public class CassandraBatchTemplateIntegrationTests extends AbstractSpringDataEm
batchOperations.insert(walter).insert(mike).execute();
Group loaded = cassandraTemplate.selectOneById(Group.class, walter.getId());
assertThat(loaded.getId().getUsername(), is(equalTo(walter.getId().getUsername())));
}
/**
* @see DATACASS-288
* @see <a href="https://jira.spring.io/browse/DATACASS-288">DATACASS-288</a>
*/
@Test
public void shouldInsertCollectionOfEntities() {
@@ -91,11 +92,12 @@ public class CassandraBatchTemplateIntegrationTests extends AbstractSpringDataEm
batchOperations.insert(Arrays.asList(walter, mike)).execute();
Group loaded = cassandraTemplate.selectOneById(Group.class, walter.getId());
assertThat(loaded.getId().getUsername(), is(equalTo(walter.getId().getUsername())));
}
/**
* @see DATACASS-288
* @see <a href="https://jira.spring.io/browse/DATACASS-288">DATACASS-288</a>
*/
@Test
public void shouldUpdateEntities() {
@@ -110,11 +112,12 @@ public class CassandraBatchTemplateIntegrationTests extends AbstractSpringDataEm
batchOperations.update(walter).update(mike).execute();
Group loaded = cassandraTemplate.selectOneById(Group.class, walter.getId());
assertThat(loaded.getEmail(), is(equalTo(walter.getEmail())));
}
/**
* @see DATACASS-288
* @see <a href="https://jira.spring.io/browse/DATACASS-288">DATACASS-288</a>
*/
@Test
public void shouldUpdateCollectionOfEntities() {
@@ -129,11 +132,12 @@ public class CassandraBatchTemplateIntegrationTests extends AbstractSpringDataEm
batchOperations.update(Arrays.asList(walter, mike)).execute();
Group loaded = cassandraTemplate.selectOneById(Group.class, walter.getId());
assertThat(loaded.getEmail(), is(equalTo(walter.getEmail())));
}
/**
* @see DATACASS-288
* @see <a href="https://jira.spring.io/browse/DATACASS-288">DATACASS-288</a>
*/
@Test
public void shouldUpdatesCollectionOfEntities() {
@@ -148,11 +152,12 @@ public class CassandraBatchTemplateIntegrationTests extends AbstractSpringDataEm
batchOperations.update(Arrays.asList(walter, mike)).execute();
FlatGroup loaded = cassandraTemplate.selectOneById(FlatGroup.class, walter);
assertThat(loaded.getEmail(), is(equalTo(walter.getEmail())));
}
/**
* @see DATACASS-288
* @see <a href="https://jira.spring.io/browse/DATACASS-288">DATACASS-288</a>
*/
@Test
public void shouldDeleteEntities() {
@@ -165,11 +170,12 @@ public class CassandraBatchTemplateIntegrationTests extends AbstractSpringDataEm
batchOperations.delete(walter).delete(mike).execute();
Group loaded = cassandraTemplate.selectOneById(Group.class, walter.getId());
assertThat(loaded, is(nullValue()));
}
/**
* @see DATACASS-288
* @see <a href="https://jira.spring.io/browse/DATACASS-288">DATACASS-288</a>
*/
@Test
public void shouldDeleteCollectionOfEntities() {
@@ -182,11 +188,12 @@ public class CassandraBatchTemplateIntegrationTests extends AbstractSpringDataEm
batchOperations.delete(Arrays.asList(walter, mike)).execute();
Group loaded = cassandraTemplate.selectOneById(Group.class, walter.getId());
assertThat(loaded, is(nullValue()));
}
/**
* @see DATACASS-288
* @see <a href="https://jira.spring.io/browse/DATACASS-288">DATACASS-288</a>
*/
@Test
public void shouldApplyTimestampToAllEntities() {
@@ -205,13 +212,14 @@ public class CassandraBatchTemplateIntegrationTests extends AbstractSpringDataEm
ResultSet resultSet = cassandraTemplate.query("SELECT writetime(email) FROM group;");
assertThat(resultSet.getAvailableWithoutFetching(), is(2));
for (Row row : resultSet) {
assertThat(row.getLong(0), is(timestamp));
}
}
/**
* @see DATACASS-288
* @see <a href="https://jira.spring.io/browse/DATACASS-288">DATACASS-288</a>
*/
@Test(expected = IllegalStateException.class)
public void shouldNotExecuteTwice() {
@@ -220,11 +228,12 @@ public class CassandraBatchTemplateIntegrationTests extends AbstractSpringDataEm
batchOperations.insert(new Group(new GroupKey("users", "0x1", "walter"))).execute();
batchOperations.execute();
fail("Missing IllegalStateException");
}
/**
* @see DATACASS-288
* @see <a href="https://jira.spring.io/browse/DATACASS-288">DATACASS-288</a>
*/
@Test(expected = IllegalStateException.class)
public void shouldNotAllowModificationAfterExecution() {
@@ -233,6 +242,7 @@ public class CassandraBatchTemplateIntegrationTests extends AbstractSpringDataEm
batchOperations.insert(new Group(new GroupKey("users", "0x1", "walter"))).execute();
batchOperations.update(new Group());
fail("Missing IllegalStateException");
}
}

View File

@@ -172,11 +172,10 @@ public class CassandraTemplateUnitTests {
}
/**
* @see DATACASS-288
* @see <a href="https://jira.spring.io/browse/DATACASS-288">DATACASS-288</a>
*/
@Test
public void batchOperationsShouldCallSession() {
template.batchOps().insert(new Book()).execute();
verify(mockSession).execute(Mockito.any(Batch.class));