From 42924c0739e63e1cc3775cf5dac9de29cac76a3b Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 28 Oct 2019 14:50:32 +0100 Subject: [PATCH] =?UTF-8?q?DATACASS-696=20-=20Fix=20return=20of=20null=20v?= =?UTF-8?q?alues=20through=20selectOne(=E2=80=A6).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Null values are now correctly handled when selecting a single element. --- .../core/AsyncCassandraTemplate.java | 3 +-- .../cassandra/core/CassandraTemplate.java | 4 +++- .../core/ReactiveCassandraTemplate.java | 4 +++- .../core/AsyncCassandraTemplateUnitTests.java | 15 +++++++++--- .../CassandraTemplateIntegrationTests.java | 9 ++++++++ .../core/CassandraTemplateUnitTests.java | 12 +++++++++- .../ReactiveCassandraTemplateUnitTests.java | 23 +++++++++++-------- 7 files changed, 53 insertions(+), 17 deletions(-) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java index db945deb5..db79ad9d0 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java @@ -294,9 +294,8 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations, Applica */ @Override public ListenableFuture selectOne(Statement statement, Class entityClass) { - return new MappingListenableFutureAdapter<>(select(statement, entityClass), - list -> list.stream().findFirst().orElse(null)); + list -> list.isEmpty() ? null : list.get(0)); } // ------------------------------------------------------------------------- diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java index daca636bd..173593c71 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java @@ -299,7 +299,9 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP */ @Override public T selectOne(Statement statement, Class entityClass) { - return select(statement, entityClass).stream().findFirst().orElse(null); + + List result = select(statement, entityClass); + return result.isEmpty() ? null : result.get(0); } // ------------------------------------------------------------------------- diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplate.java index 53b1bcd53..2f006d3d0 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplate.java @@ -696,7 +696,9 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations, A T result = (T) (targetType.isInterface() ? getProjectionFactory().createProjection(targetType, source) : source); - maybeEmitEvent(new AfterConvertEvent<>(row, result, tableName)); + if (result != null) { + maybeEmitEvent(new AfterConvertEvent<>(row, result, tableName)); + } return result; }; diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/AsyncCassandraTemplateUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/AsyncCassandraTemplateUnitTests.java index 7b826fd5a..f41c07e96 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/AsyncCassandraTemplateUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/AsyncCassandraTemplateUnitTests.java @@ -16,9 +16,7 @@ package org.springframework.data.cassandra.core; import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import java.util.ArrayList; @@ -36,6 +34,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; + import org.springframework.data.cassandra.CassandraConnectionFailureException; import org.springframework.data.cassandra.core.query.Query; import org.springframework.data.cassandra.domain.User; @@ -185,6 +184,16 @@ public class AsyncCassandraTemplateUnitTests { assertThat(statementCaptor.getValue().toString()).isEqualTo("SELECT * FROM users WHERE id='myid';"); } + @Test // DATACASS-696 + public void selectOneShouldNull() { + + when(resultSet.iterator()).thenReturn(Collections.singleton(row).iterator()); + + ListenableFuture future = template.selectOne("SELECT id FROM users WHERE id='myid';", String.class); + + assertThat(getUninterruptibly(future)).isNull(); + } + @Test // DATACASS-292 public void existsShouldReturnExistingElement() { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateIntegrationTests.java index 8da49108a..c8dc59b6c 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateIntegrationTests.java @@ -31,6 +31,7 @@ import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -146,6 +147,14 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI assertThat(loaded).isEqualTo(token1); } + @Test + public void shouldSelectNullByQuery() { + + UUID loaded = template.selectOne("SELECT MAX(user_id) FROM user_tokens", UUID.class); + + System.out.println(loaded); + } + @Test // DATACASS-292, DATACASS-573 public void insertShouldInsertEntity() { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateUnitTests.java index d844a149b..e9d9a372e 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateUnitTests.java @@ -95,7 +95,7 @@ public class CassandraTemplateUnitTests { } @Test // DATACASS-292 - public void selectShouldTranslateException() throws Exception { + public void selectShouldTranslateException() { when(resultSet.iterator()).thenThrow(new NoHostAvailableException(Collections.emptyMap())); @@ -130,6 +130,16 @@ public class CassandraTemplateUnitTests { assertThat(statementCaptor.getValue().toString()).isEqualTo("SELECT * FROM users WHERE id='myid';"); } + @Test // DATACASS-696 + public void selectOneShouldNull() { + + when(resultSet.iterator()).thenReturn(Collections.singleton(row).iterator()); + + String nullValue = template.selectOne("SELECT id FROM users WHERE id='myid';", String.class); + + assertThat(nullValue).isNull(); + } + @Test // DATACASS-292 public void selectOneByIdShouldReturnMappedResults() { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplateUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplateUnitTests.java index adee666bd..878d24a05 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplateUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplateUnitTests.java @@ -15,20 +15,16 @@ */ package org.springframework.data.cassandra.core; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Collections; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; +import java.util.Collections; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -131,6 +127,15 @@ public class ReactiveCassandraTemplateUnitTests { assertThat(statementCaptor.getValue().toString()).isEqualTo("SELECT * FROM users WHERE id='myid';"); } + @Test // DATACASS-696 + public void selectOneShouldNull() { + + when(reactiveResultSet.rows()).thenReturn(Flux.just(row)); + + template.selectOne("SELECT id FROM users WHERE id='myid';", String.class).as(StepVerifier::create) // + .verifyComplete(); + } + @Test // DATACASS-335 public void existsShouldReturnExistingElement() {