From d34fa9e3e931a5bf2a30d2be9fb278756aa0419a Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Wed, 11 Nov 2020 13:30:23 +0100 Subject: [PATCH 1/3] DATACASS-825 - Prepare branch --- pom.xml | 4 ++-- spring-data-cassandra-distribution/pom.xml | 2 +- spring-data-cassandra/pom.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 0eec33a1a..577b6c38b 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.springframework.data spring-data-cassandra-parent - 3.2.0-SNAPSHOT + 3.2.0-DATACASS-825-SNAPSHOT pom Spring Data for Apache Cassandra @@ -98,7 +98,7 @@ 0.5.4 1.01 multi - 2.5.0-SNAPSHOT + 2.4.0-DATACMNS-800-SNAPSHOT diff --git a/spring-data-cassandra-distribution/pom.xml b/spring-data-cassandra-distribution/pom.xml index b814eecbf..a1a92c62a 100644 --- a/spring-data-cassandra-distribution/pom.xml +++ b/spring-data-cassandra-distribution/pom.xml @@ -8,7 +8,7 @@ org.springframework.data spring-data-cassandra-parent - 3.2.0-SNAPSHOT + 3.2.0-DATACASS-825-SNAPSHOT ../pom.xml diff --git a/spring-data-cassandra/pom.xml b/spring-data-cassandra/pom.xml index c8229277b..b2503e082 100644 --- a/spring-data-cassandra/pom.xml +++ b/spring-data-cassandra/pom.xml @@ -8,7 +8,7 @@ org.springframework.data spring-data-cassandra-parent - 3.2.0-SNAPSHOT + 3.2.0-DATACASS-825-SNAPSHOT ../pom.xml From 9144a27894931f1fa4f8b93c935c39a207d0ba4c Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Wed, 11 Nov 2020 14:04:32 +0100 Subject: [PATCH 2/3] DATACASS-825 - Implements deleteAllById(Iterable ids). --- .../support/SimpleCassandraRepository.java | 9 +++++++ .../SimpleReactiveCassandraRepository.java | 9 +++++++ ...leCassandraRepositoryIntegrationTests.java | 24 ++++++++++++++----- ...veCassandraRepositoryIntegrationTests.java | 13 ++++++++++ 4 files changed, 49 insertions(+), 6 deletions(-) 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 b81a3bcb6..534f21152 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 @@ -44,6 +44,7 @@ * @author Matthew T. Adams * @author Mark Paluch * @author John Blum + * @author Jens Schauder * @see org.springframework.data.cassandra.repository.CassandraRepository */ public class SimpleCassandraRepository implements CassandraRepository { @@ -247,6 +248,14 @@ public void deleteAll(Iterable entities) { entities.forEach(this.operations::delete); } + @Override + public void deleteAllById(Iterable ids) { + + Assert.notNull(ids, "The given Iterable of ids must not be null"); + + ids.forEach(id -> operations.deleteById(id, entityInformation.getJavaType())); + } + /* (non-Javadoc) * @see org.springframework.data.repository.CrudRepository#deleteAll() */ diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleReactiveCassandraRepository.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleReactiveCassandraRepository.java index 70ae3d66e..b47e42323 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleReactiveCassandraRepository.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleReactiveCassandraRepository.java @@ -40,6 +40,7 @@ * * @author Mark Paluch * @author Christoph Strobl + * @author Jens Schauder * @since 2.0 */ public class SimpleReactiveCassandraRepository implements ReactiveCassandraRepository { @@ -304,6 +305,14 @@ public Mono deleteAll(Iterable entities) { return Flux.fromIterable(entities).flatMap(this.operations::delete).then(); } + @Override + public Mono deleteAllById(Iterable ids) { + + Assert.notNull(ids, "The given Iterable of entities must not be null"); + + return Flux.fromIterable(ids).flatMap(this::deleteById).then(); + } + /* (non-Javadoc) * @see org.springframework.data.repository.reactive.ReactiveCrudRepository#deleteAll(org.reactivestreams.Publisher) */ diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepositoryIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepositoryIntegrationTests.java index 59afe765f..0e30dc58a 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepositoryIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepositoryIntegrationTests.java @@ -15,6 +15,7 @@ */ package org.springframework.data.cassandra.repository.support; +import static java.util.Arrays.*; import static org.assertj.core.api.Assertions.*; import static org.junit.Assume.*; @@ -62,6 +63,7 @@ * Integration tests for {@link SimpleCassandraRepository}. * * @author Mark Paluch + * @author Jens Schauder */ @SpringJUnitConfig public class SimpleCassandraRepositoryIntegrationTests extends IntegrationTestsSupport @@ -125,7 +127,7 @@ void setUp() { carter = new User("49", "Carter", "Beauford"); boyd = new User("45", "Boyd", "Tinsley"); - repository.saveAll(Arrays.asList(oliver, dave, carter, boyd)); + repository.saveAll(asList(oliver, dave, carter, boyd)); eventListener.clear(); } @@ -181,7 +183,7 @@ void findAllShouldReturnAllResults() { @Test // DATACASS-396, DATACASS-416 void findAllByIterableOfIdShouldReturnResults() { - List Users = repository.findAllById(Arrays.asList(dave.getId(), boyd.getId())); + List Users = repository.findAllById(asList(dave.getId(), boyd.getId())); assertThat(Users).hasSize(2); } @@ -253,7 +255,7 @@ void insertIterableOfEntitiesShouldInsertEntity() { repository.deleteAll(); - repository.insert(Arrays.asList(dave, oliver, boyd)); + repository.insert(asList(dave, oliver, boyd)); assertThat(repository.count()).isEqualTo(3); } @@ -309,7 +311,7 @@ void saveIterableOfNewEntitiesShouldInsertEntity() { repository.deleteAll(); - List saved = repository.saveAll(Arrays.asList(dave, oliver, boyd)); + List saved = repository.saveAll(asList(dave, oliver, boyd)); assertThat(saved).hasSize(3).contains(dave, oliver, boyd); @@ -324,7 +326,7 @@ void saveIterableOfMixedEntitiesShouldInsertEntity() { dave.setFirstname("Hello, Dave"); dave.setLastname("Bowman"); - List saved = repository.saveAll(Arrays.asList(User, dave)); + List saved = repository.saveAll(asList(User, dave)); assertThat(saved).hasSize(2); @@ -355,6 +357,16 @@ void deleteByIdShouldRemoveEntity() { assertThat(loaded).isEmpty(); } + @Test // DATACASS-825 + void deleteAllByIdShouldRemoveEntity() { + + repository.deleteAllById(asList(dave.getId())); + + Optional loaded = repository.findById(dave.getId()); + + assertThat(loaded).isEmpty(); + } + @Test // DATACASS-396 void deleteShouldRemoveEntity() { @@ -368,7 +380,7 @@ void deleteShouldRemoveEntity() { @Test // DATACASS-396 void deleteIterableOfEntitiesShouldRemoveEntities() { - repository.deleteAll(Arrays.asList(dave, boyd)); + repository.deleteAll(asList(dave, boyd)); Optional loaded = repository.findById(boyd.getId()); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleReactiveCassandraRepositoryIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleReactiveCassandraRepositoryIntegrationTests.java index d3337fc32..74f808cd3 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleReactiveCassandraRepositoryIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleReactiveCassandraRepositoryIntegrationTests.java @@ -15,6 +15,7 @@ */ package org.springframework.data.cassandra.repository.support; +import static org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils.*; import static org.assertj.core.api.Assertions.*; import static org.junit.Assume.*; @@ -59,6 +60,7 @@ * * @author Mark Paluch * @author Christoph Strobl + * @author Jens Schauder */ @SpringJUnitConfig public class SimpleReactiveCassandraRepositoryIntegrationTests extends IntegrationTestsSupport @@ -391,6 +393,17 @@ void deleteByIdUsingMonoShouldRemoveEntity() { repository.existsById(dave.getId()).as(StepVerifier::create).expectNext(false).verifyComplete(); } + @Test // DATACASS-825 + void deleteAllByIdRemovesEntities() { + + insertTestData(); + + repository.deleteAllById(Arrays.asList(dave.getId(), carter.getId())).as(StepVerifier::create).verifyComplete(); + + repository.existsById(dave.getId()).as(StepVerifier::create).expectNext(false).verifyComplete(); + repository.existsById(carter.getId()).as(StepVerifier::create).expectNext(false).verifyComplete(); + } + @Test // DATACASS-462 void deleteByIdUsingFluxShouldRemoveFirstEntity() { From 62d34d9d31ae7042dd5f6b6a9f686609510a75cc Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Tue, 24 Nov 2020 17:17:41 +0100 Subject: [PATCH 3/3] DATACASS-825 - Improving the implementations to use a single query. --- .../support/SimpleCassandraRepository.java | 32 +++++++++++------ .../SimpleReactiveCassandraRepository.java | 36 +++++++++++++------ ...leCassandraRepositoryIntegrationTests.java | 15 ++++---- 3 files changed, 53 insertions(+), 30 deletions(-) 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 534f21152..13a59ce2c 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 @@ -22,6 +22,7 @@ import java.util.List; import java.util.Optional; +import org.jetbrains.annotations.NotNull; import org.springframework.data.cassandra.core.CassandraOperations; import org.springframework.data.cassandra.core.CassandraTemplate; import org.springframework.data.cassandra.core.InsertOptions; @@ -189,19 +190,11 @@ public List findAllById(Iterable ids) { Assert.notNull(ids, "The given Iterable of id's must not be null"); - FindByIdQuery mapIdQuery = FindByIdQuery.forIds(ids); - List idCollection = mapIdQuery.getIdCollection(); - String idField = mapIdQuery.getIdProperty(); - - if (idCollection.isEmpty()) { + if (!ids.iterator().hasNext()) { return Collections.emptyList(); } - if (idField == null) { - idField = this.entityInformation.getIdAttribute(); - } - - return this.operations.select(Query.query(where(idField).in(idCollection)), this.entityInformation.getJavaType()); + return this.operations.select(createIdsInQuery(ids), this.entityInformation.getJavaType()); } /* (non-Javadoc) @@ -253,7 +246,11 @@ public void deleteAllById(Iterable ids) { Assert.notNull(ids, "The given Iterable of ids must not be null"); - ids.forEach(id -> operations.deleteById(id, entityInformation.getJavaType())); + if (!ids.iterator().hasNext()) { + return; + } + + this.operations.delete(createIdsInQuery(ids), this.entityInformation.getJavaType()); } /* (non-Javadoc) @@ -263,4 +260,17 @@ public void deleteAllById(Iterable ids) { public void deleteAll() { this.operations.truncate(this.entityInformation.getJavaType()); } + + private Query createIdsInQuery(Iterable ids) { + FindByIdQuery mapIdQuery = FindByIdQuery.forIds(ids); + List idCollection = mapIdQuery.getIdCollection(); + String idField = mapIdQuery.getIdProperty(); + + if (idField == null) { + idField = this.entityInformation.getIdAttribute(); + } + + return Query.query(where(idField).in(idCollection)); + } + } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleReactiveCassandraRepository.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleReactiveCassandraRepository.java index b47e42323..b1067c537 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleReactiveCassandraRepository.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleReactiveCassandraRepository.java @@ -17,6 +17,7 @@ import static org.springframework.data.cassandra.core.query.Criteria.*; +import org.jetbrains.annotations.NotNull; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -225,19 +226,11 @@ public Flux findAllById(Iterable ids) { return findAllById(Flux.fromIterable(ids)); } - FindByIdQuery query = FindByIdQuery.forIds(ids); - List idCollection = query.getIdCollection(); - String idField = query.getIdProperty(); - - if (idCollection.isEmpty()) { + if (!ids.iterator().hasNext()) { return Flux.empty(); } - if (idField == null) { - idField = this.entityInformation.getIdAttribute(); - } - - return this.operations.select(Query.query(where(idField).in(idCollection)), this.entityInformation.getJavaType()); + return this.operations.select(createIdsInCollectionQuery(ids), this.entityInformation.getJavaType()); } /* @@ -310,7 +303,15 @@ public Mono deleteAllById(Iterable ids) { Assert.notNull(ids, "The given Iterable of entities must not be null"); - return Flux.fromIterable(ids).flatMap(this::deleteById).then(); + if (FindByIdQuery.hasCompositeKeys(ids)) { + return deleteById(Flux.fromIterable(ids)); + } + + if (!ids.iterator().hasNext()) { + return Mono.empty(); + } + + return this.operations.delete(createIdsInCollectionQuery(ids), this.entityInformation.getJavaType()).then(); } /* (non-Javadoc) @@ -323,4 +324,17 @@ public Mono deleteAll(Publisher entityStream) { return Flux.from(entityStream).flatMap(this.operations::delete).then(); } + + private Query createIdsInCollectionQuery(Iterable ids) { + + FindByIdQuery query = FindByIdQuery.forIds(ids); + List idCollection = query.getIdCollection(); + String idField = query.getIdProperty(); + + if (idField == null) { + idField = this.entityInformation.getIdAttribute(); + } + + return Query.query(where(idField).in(idCollection)); + } } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepositoryIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepositoryIntegrationTests.java index 0e30dc58a..4adac539a 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepositoryIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepositoryIntegrationTests.java @@ -15,7 +15,6 @@ */ package org.springframework.data.cassandra.repository.support; -import static java.util.Arrays.*; import static org.assertj.core.api.Assertions.*; import static org.junit.Assume.*; @@ -127,7 +126,7 @@ void setUp() { carter = new User("49", "Carter", "Beauford"); boyd = new User("45", "Boyd", "Tinsley"); - repository.saveAll(asList(oliver, dave, carter, boyd)); + repository.saveAll(Arrays.asList(oliver, dave, carter, boyd)); eventListener.clear(); } @@ -183,7 +182,7 @@ void findAllShouldReturnAllResults() { @Test // DATACASS-396, DATACASS-416 void findAllByIterableOfIdShouldReturnResults() { - List Users = repository.findAllById(asList(dave.getId(), boyd.getId())); + List Users = repository.findAllById(Arrays.asList(dave.getId(), boyd.getId())); assertThat(Users).hasSize(2); } @@ -255,7 +254,7 @@ void insertIterableOfEntitiesShouldInsertEntity() { repository.deleteAll(); - repository.insert(asList(dave, oliver, boyd)); + repository.insert(Arrays.asList(dave, oliver, boyd)); assertThat(repository.count()).isEqualTo(3); } @@ -311,7 +310,7 @@ void saveIterableOfNewEntitiesShouldInsertEntity() { repository.deleteAll(); - List saved = repository.saveAll(asList(dave, oliver, boyd)); + List saved = repository.saveAll(Arrays.asList(dave, oliver, boyd)); assertThat(saved).hasSize(3).contains(dave, oliver, boyd); @@ -326,7 +325,7 @@ void saveIterableOfMixedEntitiesShouldInsertEntity() { dave.setFirstname("Hello, Dave"); dave.setLastname("Bowman"); - List saved = repository.saveAll(asList(User, dave)); + List saved = repository.saveAll(Arrays.asList(User, dave)); assertThat(saved).hasSize(2); @@ -360,7 +359,7 @@ void deleteByIdShouldRemoveEntity() { @Test // DATACASS-825 void deleteAllByIdShouldRemoveEntity() { - repository.deleteAllById(asList(dave.getId())); + repository.deleteAllById(Arrays.asList(dave.getId())); Optional loaded = repository.findById(dave.getId()); @@ -380,7 +379,7 @@ void deleteShouldRemoveEntity() { @Test // DATACASS-396 void deleteIterableOfEntitiesShouldRemoveEntities() { - repository.deleteAll(asList(dave, boyd)); + repository.deleteAll(Arrays.asList(dave, boyd)); Optional loaded = repository.findById(boyd.getId());