diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/TypedIdCassandraRepository.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/TypedIdCassandraRepository.java index a967c3b15..8627e23ff 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/TypedIdCassandraRepository.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/TypedIdCassandraRepository.java @@ -1,12 +1,12 @@ /* - * Copyright 2013-2014 the original author or authors - * + * Copyright 2013-2017 the original author or authors + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -48,8 +48,8 @@ import org.springframework.data.repository.NoRepositoryBean; *
  • Define your repository interface to be a subinterface of this interface, including your entity type and * your primary key class type.
  • * - *
  • - * Strategy: embed identity fields or properties directly in your entity and use {@link CassandraRepository}
  • + *
  • Strategy: embed identity fields or properties directly in your entity and use + * {@link CassandraRepository}
  • * * - * + * * @author Alex Shvid * @author Matthew T. Adams */ @NoRepositoryBean -public interface TypedIdCassandraRepository extends CrudRepository {} +public interface TypedIdCassandraRepository extends CrudRepository { + + /** + * Inserts the given entity. Assumes the instance to be new to be able to apply insertion optimizations. Use the + * returned instance for further operations as the save operation might have changed the entity instance completely. + * Prefer using {@link #save(Object)} instead to avoid the usage of store-specific API. + * + * @param entity must not be {@literal null}. + * @return the saved entity + * @since 1.5.2 + */ + S insert(S entity); +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepository.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepository.java index c039fa656..33bce52f0 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepository.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepository.java @@ -1,12 +1,12 @@ /* * Copyright 2013-2017 the original author or authors - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -29,7 +29,7 @@ import com.datastax.driver.core.querybuilder.Select; /** * Repository base implementation for Cassandra. - * + * * @author Alex Shvid * @author Matthew T. Adams * @author Mark Paluch @@ -42,7 +42,7 @@ public class SimpleCassandraRepository implements Ty /** * Creates a new {@link SimpleCassandraRepository} for the given {@link CassandraEntityInformation} and * {@link CassandraTemplate}. - * + * * @param metadata must not be {@literal null}. * @param operations must not be {@literal null}. */ @@ -57,7 +57,14 @@ public class SimpleCassandraRepository implements Ty @Override public S save(S entity) { - return operations.insert(entity); + + Assert.notNull(entity, "Entity must not be null"); + + if (entityInformation.isNew(entity)) { + return operations.insert(entity); + } + + return operations.update(entity); } @Override @@ -65,6 +72,17 @@ public class SimpleCassandraRepository implements Ty return operations.insert(CollectionUtils.toList(entities)); } + /* (non-Javadoc) + * @see org.springframework.data.cassandra.repository.TypedIdCassandraRepository#insert(java.lang.Object) + */ + @Override + public S insert(S entity) { + + Assert.notNull(entity, "Entity must not be null"); + + return operations.insert(entity); + } + @Override public T findOne(ID id) { return operations.selectOneById(entityInformation.getJavaType(), id); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepositoryUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepositoryUnitTests.java new file mode 100644 index 000000000..96f144f52 --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepositoryUnitTests.java @@ -0,0 +1,139 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.cassandra.repository.support; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import lombok.Data; + +import java.io.Serializable; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.data.annotation.Id; +import org.springframework.data.cassandra.convert.MappingCassandraConverter; +import org.springframework.data.cassandra.core.CassandraOperations; +import org.springframework.data.cassandra.mapping.BasicCassandraMappingContext; +import org.springframework.data.cassandra.mapping.CassandraPersistentEntity; +import org.springframework.data.cassandra.mapping.UserTypeResolver; +import org.springframework.data.cassandra.test.integration.repository.querymethods.declared.Person; + +/** + * Unit tests for {@link SimpleCassandraRepository}. + * + * @author Mark Paluch + */ +@RunWith(MockitoJUnitRunner.class) +@SuppressWarnings("unchecked") +public class SimpleCassandraRepositoryUnitTests { + + BasicCassandraMappingContext mappingContext = new BasicCassandraMappingContext(); + MappingCassandraConverter converter = new MappingCassandraConverter(mappingContext); + + SimpleCassandraRepository repository; + + @Mock CassandraOperations cassandraOperations; + @Mock UserTypeResolver userTypeResolver; + + @Before + public void before() { + mappingContext.setUserTypeResolver(userTypeResolver); + } + + @Test // DATACASS-428 + public void saveShouldInsertNewPrimaryKeyOnlyEntity() { + + CassandraPersistentEntity entity = converter.getMappingContext().getPersistentEntity(SimplePerson.class); + + repository = new SimpleCassandraRepository(new MappingCassandraEntityInformation(entity, converter), + cassandraOperations); + + SimplePerson person = new SimplePerson(); + + when(cassandraOperations.insert(person)).thenReturn(person); + + Object result = repository.save(person); + + assertThat(result).isEqualTo(person); + verify(cassandraOperations).insert(person); + } + + @Test // DATACASS-428 + public void saveShouldUpdateNewEntity() { + + CassandraPersistentEntity entity = converter.getMappingContext().getPersistentEntity(Person.class); + + repository = new SimpleCassandraRepository(new MappingCassandraEntityInformation(entity, converter), + cassandraOperations); + + Person person = new Person(); + + when(cassandraOperations.update(person)).thenReturn(person); + + Object result = repository.save(person); + + assertThat(result).isEqualTo(person); + verify(cassandraOperations).update(person); + } + + @Test // DATACASS-428 + public void saveShouldUpdateExistingEntity() { + + CassandraPersistentEntity entity = converter.getMappingContext().getPersistentEntity(Person.class); + + repository = new SimpleCassandraRepository(new MappingCassandraEntityInformation(entity, converter), + cassandraOperations); + + Person person = new Person(); + person.setFirstname("foo"); + person.setLastname("bar"); + + when(cassandraOperations.update(person)).thenReturn(person); + + Object result = repository.save(person); + + assertThat(result).isEqualTo(person); + verify(cassandraOperations).update(person); + } + + @Test // DATACASS-428 + public void insertShouldInsertEntity() { + + CassandraPersistentEntity entity = converter.getMappingContext().getPersistentEntity(Person.class); + + repository = new SimpleCassandraRepository(new MappingCassandraEntityInformation(entity, converter), + cassandraOperations); + + Person person = new Person(); + + when(cassandraOperations.insert(person)).thenReturn(person); + + Object result = repository.insert(person); + + assertThat(result).isEqualTo(person); + verify(cassandraOperations).insert(person); + } + + @Data + static class SimplePerson { + + @Id String id; + } +}