Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c33addd

Browse files
committed
Fix deleteAllById(...) using composite keys.
We now correctly delete all elements when using composite keys (MapId, Primary Key classes). Previously, we did not support that case or removed only the first element. Closes #1298
1 parent 7975e90 commit c33addd

File tree

6 files changed

+139
-19
lines changed

6 files changed

+139
-19
lines changed

‎spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/FindByIdQuery.java‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@
2020
import java.util.List;
2121

2222
import org.springframework.dao.InvalidDataAccessApiUsageException;
23+
import org.springframework.data.cassandra.core.mapping.BasicCassandraPersistentEntity;
24+
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
2325
import org.springframework.data.cassandra.core.mapping.MapId;
26+
import org.springframework.data.mapping.context.MappingContext;
2427
import org.springframework.lang.Nullable;
2528
import org.springframework.util.Assert;
2629

@@ -85,9 +88,11 @@ static FindByIdQuery forIds(Iterable<?> ids) {
8588
* Check if the {@link Iterable} of {@code ID}s contains composite keys.
8689
*
8790
* @param ids
91+
* @param mappingContext
8892
* @return
8993
*/
90-
static boolean hasCompositeKeys(Iterable<?> ids) {
94+
static boolean hasCompositeKeys(Iterable<?> ids,
95+
MappingContext<BasicCassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext) {
9196

9297
Assert.notNull(ids, "The given Iterable of ids must not be null");
9398

@@ -100,6 +105,13 @@ static boolean hasCompositeKeys(Iterable<?> ids) {
100105
if (mapId.size() > 1) {
101106
return true;
102107
}
108+
} else {
109+
110+
BasicCassandraPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(id.getClass());
111+
112+
if (persistentEntity != null && persistentEntity.isCompositePrimaryKey()) {
113+
return true;
114+
}
103115
}
104116
}
105117

‎spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepository.java‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,11 @@ public void deleteAllById(Iterable<? extends ID> ids) {
200200

201201
Assert.notNull(ids, "The given Iterable of ids must not be null");
202202

203-
if (!ids.iterator().hasNext()) {
203+
if (FindByIdQuery.hasCompositeKeys(ids, this.mappingContext)) {
204+
205+
for (ID id : ids) {
206+
deleteById(id);
207+
}
204208
return;
205209
}
206210

‎spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleReactiveCassandraRepository.java‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ public Flux<T> findAllById(Iterable<ID> ids) {
183183

184184
Assert.notNull(ids, "The given Iterable of ids must not be null");
185185

186-
if (FindByIdQuery.hasCompositeKeys(ids)) {
186+
if (FindByIdQuery.hasCompositeKeys(ids, this.mappingContext)) {
187187
return findAllById(Flux.fromIterable(ids));
188188
}
189189

@@ -257,8 +257,8 @@ public Mono<Void> deleteAllById(Iterable<? extends ID> ids) {
257257

258258
Assert.notNull(ids, "The given Iterable of ids must not be null");
259259

260-
if (FindByIdQuery.hasCompositeKeys(ids)) {
261-
return deleteById(Flux.fromIterable(ids));
260+
if (FindByIdQuery.hasCompositeKeys(ids, this.mappingContext)) {
261+
return Flux.fromIterable(ids).flatMap(this::deleteById).then();
262262
}
263263

264264
if (!ids.iterator().hasNext()) {

‎spring-data-cassandra/src/test/java/org/springframework/data/cassandra/domain/CompositeKey.java‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
*/
1616
package org.springframework.data.cassandra.domain;
1717

18+
import lombok.AllArgsConstructor;
1819
import lombok.Data;
20+
import lombok.NoArgsConstructor;
1921

2022
import java.io.Serializable;
2123

@@ -28,6 +30,8 @@
2830
*/
2931
@PrimaryKeyClass
3032
@Data
33+
@AllArgsConstructor
34+
@NoArgsConstructor
3135
public class CompositeKey implements Serializable {
3236

3337
@PrimaryKeyColumn(type = PrimaryKeyType.PARTITIONED, ordinal = 1, name = "first_name") private String firstname;
Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static org.assertj.core.api.Assertions.*;
1919

20+
import java.util.Arrays;
2021
import java.util.Collections;
2122

2223
import org.junit.jupiter.api.BeforeEach;
@@ -26,20 +27,24 @@
2627
import org.springframework.data.cassandra.core.CassandraTemplate;
2728
import org.springframework.data.cassandra.core.mapping.BasicMapId;
2829
import org.springframework.data.cassandra.core.mapping.MapId;
30+
import org.springframework.data.cassandra.domain.CompositeKey;
31+
import org.springframework.data.cassandra.domain.TypeWithKeyClass;
2932
import org.springframework.data.cassandra.domain.TypeWithMapId;
3033
import org.springframework.data.cassandra.domain.User;
3134
import org.springframework.data.cassandra.test.util.AbstractKeyspaceCreatingIntegrationTests;
3235

3336
/**
34-
* Integration tests for {@link SimpleCassandraRepository} using MapId.
37+
* Integration tests for {@link SimpleCassandraRepository} using MapId and primary key classes.
3538
*
3639
* @author Mark Paluch
3740
*/
38-
class SimpleCassandraRepositoryMapIdIntegrationTests extends AbstractKeyspaceCreatingIntegrationTests {
41+
class SimpleCassandraRepositoryCompositeIdIntegrationTests extends AbstractKeyspaceCreatingIntegrationTests {
3942

4043
private SimpleCassandraRepository<User, MapId> simple;
4144

42-
private SimpleCassandraRepository<TypeWithMapId, MapId> composite;
45+
private SimpleCassandraRepository<TypeWithMapId, MapId> mapId;
46+
47+
private SimpleCassandraRepository<TypeWithKeyClass, CompositeKey> primaryKeyClass;
4348

4449
@BeforeEach
4550
@SuppressWarnings("unchecked")
@@ -48,17 +53,22 @@ void setUp() {
4853
CassandraTemplate template = new CassandraTemplate(this.session);
4954
SchemaTestUtils.potentiallyCreateTableFor(User.class, template);
5055
SchemaTestUtils.potentiallyCreateTableFor(TypeWithMapId.class, template);
56+
SchemaTestUtils.potentiallyCreateTableFor(TypeWithKeyClass.class, template);
5157

5258
SchemaTestUtils.truncate(TypeWithMapId.class, template);
53-
SchemaTestUtils.truncate(TypeWithMapId.class, template);
59+
SchemaTestUtils.truncate(TypeWithKeyClass.class, template);
5460

5561
simple = new SimpleCassandraRepository<>(new MappingCassandraEntityInformation(
5662
template.getConverter().getMappingContext().getRequiredPersistentEntity(User.class), template.getConverter()),
5763
template);
5864

59-
composite = new SimpleCassandraRepository<>(new MappingCassandraEntityInformation(
65+
mapId = new SimpleCassandraRepository<>(new MappingCassandraEntityInformation(
6066
template.getConverter().getMappingContext().getRequiredPersistentEntity(TypeWithMapId.class),
6167
template.getConverter()), template);
68+
69+
primaryKeyClass = new SimpleCassandraRepository<>(new MappingCassandraEntityInformation(
70+
template.getConverter().getMappingContext().getRequiredPersistentEntity(TypeWithKeyClass.class),
71+
template.getConverter()), template);
6272
}
6373

6474
@Test // DATACASS-661
@@ -81,9 +91,43 @@ void shouldFindByIdWithCompositeKey() {
8191
withMapId.setFirstname("Walter");
8292
withMapId.setLastname("White");
8393

84-
composite.save(withMapId);
94+
mapId.save(withMapId);
8595

86-
assertThatThrownBy(() -> composite.findAllById(Collections.singletonList(withMapId.getMapId())))
96+
assertThatThrownBy(() -> mapId.findAllById(Collections.singletonList(withMapId.getMapId())))
8797
.isInstanceOf(InvalidDataAccessApiUsageException.class);
8898
}
99+
100+
@Test // GH-1298
101+
void shouldDeleteAllByMapId() {
102+
103+
TypeWithMapId withMapId1 = new TypeWithMapId();
104+
withMapId1.setFirstname("Walter");
105+
withMapId1.setLastname("White");
106+
107+
TypeWithMapId withMapId2 = new TypeWithMapId();
108+
withMapId2.setFirstname("Skyler");
109+
withMapId2.setLastname("White");
110+
111+
mapId.saveAll(Arrays.asList(withMapId1, withMapId2));
112+
113+
mapId.deleteAllById(Arrays.asList(withMapId1.getMapId(), withMapId2.getMapId()));
114+
115+
assertThat(mapId.findAll()).isEmpty();
116+
}
117+
118+
@Test // GH-1298
119+
void shouldDeleteAllByCompositeId() {
120+
121+
TypeWithKeyClass composite1 = new TypeWithKeyClass();
122+
composite1.setKey(new CompositeKey("Walter", "White"));
123+
124+
TypeWithKeyClass composite2 = new TypeWithKeyClass();
125+
composite2.setKey(new CompositeKey("Skyler", "White"));
126+
127+
primaryKeyClass.saveAll(Arrays.asList(composite1, composite2));
128+
129+
primaryKeyClass.deleteAllById(Arrays.asList(composite1.getKey(), composite2.getKey()));
130+
131+
assertThat(primaryKeyClass.findAll()).isEmpty();
132+
}
89133
}
Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import reactor.test.StepVerifier;
1919

20+
import java.util.Arrays;
2021
import java.util.Collections;
2122

2223
import org.junit.jupiter.api.BeforeEach;
@@ -27,20 +28,24 @@
2728
import org.springframework.data.cassandra.core.cql.session.DefaultBridgedReactiveSession;
2829
import org.springframework.data.cassandra.core.mapping.BasicMapId;
2930
import org.springframework.data.cassandra.core.mapping.MapId;
31+
import org.springframework.data.cassandra.domain.CompositeKey;
32+
import org.springframework.data.cassandra.domain.TypeWithKeyClass;
3033
import org.springframework.data.cassandra.domain.TypeWithMapId;
3134
import org.springframework.data.cassandra.domain.User;
3235
import org.springframework.data.cassandra.test.util.AbstractKeyspaceCreatingIntegrationTests;
3336

3437
/**
35-
* Integration tests for {@link SimpleReactiveCassandraRepository} using MapId.
38+
* Integration tests for {@link SimpleReactiveCassandraRepository} using MapId and primary key classes.
3639
*
3740
* @author Mark Paluch
3841
*/
39-
class SimpleReactiveCassandraRepositoryMapIdIntegrationTests extends AbstractKeyspaceCreatingIntegrationTests {
42+
class SimpleReactiveCassandraRepositoryCompositeIdIntegrationTests extends AbstractKeyspaceCreatingIntegrationTests {
4043

4144
private SimpleReactiveCassandraRepository<User, MapId> simple;
4245

43-
private SimpleReactiveCassandraRepository<TypeWithMapId, MapId> composite;
46+
private SimpleReactiveCassandraRepository<TypeWithMapId, MapId> mapId;
47+
48+
private SimpleReactiveCassandraRepository<TypeWithKeyClass, CompositeKey> primaryKeyClass;
4449

4550
@BeforeEach
4651
@SuppressWarnings("unchecked")
@@ -49,9 +54,10 @@ void setUp() {
4954
CassandraTemplate template = new CassandraTemplate(this.session);
5055
SchemaTestUtils.potentiallyCreateTableFor(User.class, template);
5156
SchemaTestUtils.potentiallyCreateTableFor(TypeWithMapId.class, template);
57+
SchemaTestUtils.potentiallyCreateTableFor(TypeWithKeyClass.class, template);
5258

5359
SchemaTestUtils.truncate(TypeWithMapId.class, template);
54-
SchemaTestUtils.truncate(TypeWithMapId.class, template);
60+
SchemaTestUtils.truncate(TypeWithKeyClass.class, template);
5561

5662
ReactiveCassandraTemplate reactiveTemplate = new ReactiveCassandraTemplate(
5763
new DefaultBridgedReactiveSession(this.session));
@@ -60,9 +66,13 @@ void setUp() {
6066
template.getConverter().getMappingContext().getRequiredPersistentEntity(User.class), template.getConverter()),
6167
reactiveTemplate);
6268

63-
composite = new SimpleReactiveCassandraRepository<>(new MappingCassandraEntityInformation(
69+
mapId = new SimpleReactiveCassandraRepository<>(new MappingCassandraEntityInformation(
6470
template.getConverter().getMappingContext().getRequiredPersistentEntity(TypeWithMapId.class),
6571
template.getConverter()), reactiveTemplate);
72+
73+
primaryKeyClass = new SimpleReactiveCassandraRepository<>(new MappingCassandraEntityInformation(
74+
template.getConverter().getMappingContext().getRequiredPersistentEntity(TypeWithKeyClass.class),
75+
template.getConverter()), reactiveTemplate);
6676
}
6777

6878
@Test // DATACASS-661
@@ -91,14 +101,60 @@ void shouldFindByIdWithCompositeKey() {
91101
withMapId.setFirstname("Walter");
92102
withMapId.setLastname("White");
93103

94-
composite.save(withMapId) //
104+
mapId.save(withMapId) //
95105
.as(StepVerifier::create) //
96106
.expectNextCount(1) //
97107
.verifyComplete();
98108

99-
composite.findAllById(Collections.singletonList(withMapId.getMapId())) //
109+
mapId.findAllById(Collections.singletonList(withMapId.getMapId())) //
100110
.as(StepVerifier::create) //
101111
.expectNextCount(1) //
102112
.verifyComplete();
103113
}
114+
115+
@Test // GH-1298
116+
void shouldDeleteAllByMapId() {
117+
118+
TypeWithMapId withMapId1 = new TypeWithMapId();
119+
withMapId1.setFirstname("Walter");
120+
withMapId1.setLastname("White");
121+
122+
TypeWithMapId withMapId2 = new TypeWithMapId();
123+
withMapId2.setFirstname("Skyler");
124+
withMapId2.setLastname("White");
125+
126+
mapId.saveAll(Arrays.asList(withMapId1, withMapId2)).then() //
127+
.as(StepVerifier::create) //
128+
.verifyComplete();
129+
130+
mapId.deleteAllById(Arrays.asList(withMapId1.getMapId(), withMapId2.getMapId())) //
131+
.as(StepVerifier::create) //
132+
.verifyComplete();
133+
134+
mapId.findAll() //
135+
.as(StepVerifier::create) //
136+
.verifyComplete();
137+
}
138+
139+
@Test // GH-1298
140+
void shouldDeleteAllByCompositeId() {
141+
142+
TypeWithKeyClass composite1 = new TypeWithKeyClass();
143+
composite1.setKey(new CompositeKey("Walter", "White"));
144+
145+
TypeWithKeyClass composite2 = new TypeWithKeyClass();
146+
composite2.setKey(new CompositeKey("Skyler", "White"));
147+
148+
primaryKeyClass.saveAll(Arrays.asList(composite1, composite2)).then() //
149+
.as(StepVerifier::create) //
150+
.verifyComplete();
151+
152+
primaryKeyClass.deleteAllById(Arrays.asList(composite1.getKey(), composite2.getKey())) //
153+
.as(StepVerifier::create) //
154+
.verifyComplete();
155+
156+
primaryKeyClass.findAll() //
157+
.as(StepVerifier::create) //
158+
.verifyComplete();
159+
}
104160
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /