#282 - Polishing.

Move query derivation infrastructure to Spring Data Relational. Adapt to newly introduced ValueFunction for deferred value mapping. Use query derivation in integration tests.

Tweak javadoc, add since and author tags, reformat code.

Related ticket: https://jira.spring.io/browse/DATAJDBC-514
Original pull request: #295.
This commit is contained in:
Mark Paluch
2020-03-27 16:17:48 +01:00
parent a9a3919cf1
commit 4e5bf95504
20 changed files with 317 additions and 890 deletions

View File

@@ -43,6 +43,7 @@ import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscription;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.annotation.Id;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;

View File

@@ -22,7 +22,7 @@ import java.util.Arrays;
import org.assertj.core.api.SoftAssertions;
import org.junit.Test;
import org.springframework.data.r2dbc.query.Criteria.*;
import org.springframework.data.relational.core.sql.SqlIdentifier;
/**
@@ -72,7 +72,6 @@ public class CriteriaUnitTests {
assertThat(Criteria.from(empty, notEmpty).isEmpty()).isFalse();
assertThat(Criteria.from(notEmpty, empty).isEmpty()).isFalse();
});
}
@@ -272,16 +271,18 @@ public class CriteriaUnitTests {
assertThat(criteria.getComparator()).isEqualTo(Comparator.IS_NOT_NULL);
}
@Test
@Test // gh-282
public void shouldBuildIsTrueCriteria() {
Criteria criteria = where("foo").isTrue();
assertThat(criteria.getColumn()).isEqualTo(SqlIdentifier.unquoted("foo"));
assertThat(criteria.getComparator()).isEqualTo(Comparator.IS_TRUE);
}
@Test
@Test // gh-282
public void shouldBuildIsFalseCriteria() {
Criteria criteria = where("foo").isFalse();
assertThat(criteria.getColumn()).isEqualTo(SqlIdentifier.unquoted("foo"));

View File

@@ -130,7 +130,7 @@ public abstract class AbstractR2dbcRepositoryIntegrationTests extends R2dbcInteg
shouldInsertNewItems();
repository.findByNameContains("%F%") //
repository.findByNameContains("F") //
.map(LegoSet::getName) //
.collectList() //
.as(StepVerifier::create) //

View File

@@ -114,10 +114,6 @@ public class H2R2dbcRepositoryIntegrationTests extends AbstractR2dbcRepositoryIn
interface H2LegoSetRepository extends LegoSetRepository {
@Override
@Query("SELECT * FROM legoset WHERE name like $1")
Flux<LegoSet> findByNameContains(String name);
@Override
@Query("SELECT name FROM legoset")
Flux<Named> findAsProjection();

View File

@@ -82,10 +82,6 @@ public class JasyncMySqlR2dbcRepositoryIntegrationTests extends AbstractR2dbcRep
interface MySqlLegoSetRepository extends LegoSetRepository {
@Override
@Query("SELECT * FROM legoset WHERE name like ?")
Flux<LegoSet> findByNameContains(String name);
@Override
@Query("SELECT name FROM legoset")
Flux<Named> findAsProjection();

View File

@@ -81,10 +81,6 @@ public class MariaDbR2dbcRepositoryIntegrationTests extends AbstractR2dbcReposit
interface MySqlLegoSetRepository extends LegoSetRepository {
@Override
@Query("SELECT * FROM legoset WHERE name like ?")
Flux<LegoSet> findByNameContains(String name);
@Override
@Query("SELECT name FROM legoset")
Flux<Named> findAsProjection();

View File

@@ -81,10 +81,6 @@ public class MySqlR2dbcRepositoryIntegrationTests extends AbstractR2dbcRepositor
interface MySqlLegoSetRepository extends LegoSetRepository {
@Override
@Query("SELECT * FROM legoset WHERE name like ?")
Flux<LegoSet> findByNameContains(String name);
@Override
@Query("SELECT name FROM legoset")
Flux<Named> findAsProjection();

View File

@@ -81,10 +81,6 @@ public class PostgresR2dbcRepositoryIntegrationTests extends AbstractR2dbcReposi
interface PostgresLegoSetRepository extends LegoSetRepository {
@Override
@Query("SELECT * FROM legoset WHERE name like $1")
Flux<LegoSet> findByNameContains(String name);
@Override
@Query("SELECT name FROM legoset")
Flux<Named> findAsProjection();

View File

@@ -1,71 +0,0 @@
/*
* Copyright 2020 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
*
* https://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.r2dbc.repository.query;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.Test;
/**
* @author Roman Chigvintsev
*/
public class LikeEscaperUnitTests {
@Test
public void ignoresNulls() {
assertNull(LikeEscaper.DEFAULT.escape(null));
}
@Test
public void ignoresEmptyString() {
assertThat(LikeEscaper.DEFAULT.escape("")).isEqualTo("");
}
@Test
public void ignoresBlankString() {
assertThat(LikeEscaper.DEFAULT.escape(" ")).isEqualTo(" ");
}
@Test(expected = IllegalArgumentException.class)
public void throwsExceptionWhenEscapeCharacterIsUnderscore() {
LikeEscaper.of('_');
}
@Test(expected = IllegalArgumentException.class)
public void throwsExceptionWhenEscapeCharacterIsPercent() {
LikeEscaper.of('%');
}
@Test
public void escapesUnderscoresUsingDefaultEscapeCharacter() {
assertThat(LikeEscaper.DEFAULT.escape("_test_")).isEqualTo("\\_test\\_");
}
@Test
public void escapesPercentsUsingDefaultEscapeCharacter() {
assertThat(LikeEscaper.DEFAULT.escape("%test%")).isEqualTo("\\%test\\%");
}
@Test
public void escapesSpecialCharactersUsingCustomEscapeCharacter() {
assertThat(LikeEscaper.of('$').escape("_%")).isEqualTo("$_$%");
}
@Test
public void doublesEscapeCharacter() {
assertThat(LikeEscaper.DEFAULT.escape("\\")).isEqualTo("\\\\");
}
}

View File

@@ -20,6 +20,7 @@ import static org.mockito.Mockito.*;
import io.r2dbc.spi.ConnectionFactory;
import io.r2dbc.spi.ConnectionFactoryMetadata;
import lombok.Data;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -29,12 +30,11 @@ import java.util.Collections;
import java.util.Date;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.annotation.Id;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.r2dbc.convert.R2dbcConverter;
@@ -51,29 +51,28 @@ import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
/**
* Unit tests for {@link PartTreeR2dbcQuery}.
*
* @author Roman Chigvintsev
* @author Mark Paluch
*/
@RunWith(MockitoJUnitRunner.class)
public class PartTreeR2dbcQueryIntegrationTests {
public class PartTreeR2dbcQueryUnitTests {
private static final String TABLE = "users";
private static final String ALL_FIELDS = TABLE + ".id, "
+ TABLE + ".first_name, "
+ TABLE + ".last_name, "
+ TABLE + ".date_of_birth, "
+ TABLE + ".age, "
+ TABLE + ".active";
private static final String ALL_FIELDS = TABLE + ".id, " + TABLE + ".first_name, " + TABLE + ".last_name, " + TABLE
+ ".date_of_birth, " + TABLE + ".age, " + TABLE + ".active";
@Mock private ConnectionFactory connectionFactory;
@Mock private R2dbcConverter r2dbcConverter;
@Mock ConnectionFactory connectionFactory;
@Mock R2dbcConverter r2dbcConverter;
@Rule public ExpectedException thrown = ExpectedException.none();
private RelationalMappingContext mappingContext;
private ReactiveDataAccessStrategy dataAccessStrategy;
private DatabaseClient databaseClient;
RelationalMappingContext mappingContext;
ReactiveDataAccessStrategy dataAccessStrategy;
DatabaseClient databaseClient;
@Before
public void setUp() {
ConnectionFactoryMetadata metadataMock = mock(ConnectionFactoryMetadata.class);
when(metadataMock.getName()).thenReturn("PostgreSQL");
when(connectionFactory.getMetadata()).thenReturn(metadataMock);
@@ -90,195 +89,225 @@ public class PartTreeR2dbcQueryIntegrationTests {
.dataAccessStrategy(dataAccessStrategy).build();
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByStringAttribute() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByFirstName", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
BindableQuery bindableQuery = r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[] { "John" }));
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name = $1";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name = $1");
}
@Test
@Test // gh-282
public void createsQueryWithIsNullCondition() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByFirstName", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
BindableQuery bindableQuery = r2dbcQuery.createQuery((getAccessor(queryMethod, new Object[] { null })));
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name IS NULL";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name IS NULL");
}
@Test
@Test // gh-282
public void createsQueryWithLimitForExistsProjection() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("existsByFirstName", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
BindableQuery query = r2dbcQuery.createQuery((getAccessor(queryMethod, new Object[] { "John" })));
String expectedSql = "SELECT " + TABLE + ".id FROM " + TABLE + " WHERE " + TABLE + ".first_name = $1 LIMIT 1";
assertThat(query.get()).isEqualTo(expectedSql);
assertThat(query.get())
.isEqualTo("SELECT " + TABLE + ".id FROM " + TABLE + " WHERE " + TABLE + ".first_name = $1 LIMIT 1");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByTwoStringAttributes() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByLastNameAndFirstName", String.class, String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
BindableQuery bindableQuery = r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[] { "Doe", "John" }));
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE
+ " WHERE " + TABLE + ".last_name = $1 AND (" + TABLE + ".first_name = $2)";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get()).isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE
+ ".last_name = $1 AND (" + TABLE + ".first_name = $2)");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByOneOfTwoStringAttributes() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByLastNameOrFirstName", String.class, String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
BindableQuery bindableQuery = r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[] { "Doe", "John" }));
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE
+ " WHERE " + TABLE + ".last_name = $1 OR (" + TABLE + ".first_name = $2)";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get()).isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE
+ ".last_name = $1 OR (" + TABLE + ".first_name = $2)");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByDateAttributeBetween() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByDateOfBirthBetween", Date.class, Date.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod,
new Object[] { new Date(), new Date() });
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { new Date(), new Date() });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE
+ " WHERE " + TABLE + ".date_of_birth >= $1 AND " + TABLE + ".date_of_birth <= $2";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".date_of_birth BETWEEN $1 AND $2");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByIntegerAttributeLessThan() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByAgeLessThan", Integer.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 30 });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age < $1";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age < $1");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByIntegerAttributeLessThanEqual() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByAgeLessThanEqual", Integer.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 30 });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age <= $1";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age <= $1");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByIntegerAttributeGreaterThan() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByAgeGreaterThan", Integer.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 30 });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age > $1";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age > $1");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByIntegerAttributeGreaterThanEqual() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByAgeGreaterThanEqual", Integer.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 30 });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age >= $1";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age >= $1");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByDateAttributeAfter() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByDateOfBirthAfter", Date.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { new Date() });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".date_of_birth > $1";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".date_of_birth > $1");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByDateAttributeBefore() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByDateOfBirthBefore", Date.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { new Date() });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".date_of_birth < $1";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".date_of_birth < $1");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByIntegerAttributeIsNull() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByAgeIsNull");
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]);
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age IS NULL";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age IS NULL");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByIntegerAttributeIsNotNull() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByAgeIsNotNull");
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]);
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age IS NOT NULL";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age IS NOT NULL");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByStringAttributeLike() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameLike", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "%John%" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name LIKE $1";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name LIKE $1");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByStringAttributeNotLike() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameNotLike", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "%John%" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name NOT LIKE $1";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name NOT LIKE $1");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByStringAttributeStartingWith() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameStartingWith", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "Jo" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name LIKE $1";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name LIKE $1");
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
@Test // gh-282
public void appendsLikeOperatorParameterWithPercentSymbolForStartingWithQuery() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameStartingWith", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
@@ -286,23 +315,27 @@ public class PartTreeR2dbcQueryIntegrationTests {
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
DatabaseClient.BindSpec bindSpecMock = mock(DatabaseClient.BindSpec.class);
bindableQuery.bind(bindSpecMock);
verify(bindSpecMock, times(1)).bind(0, "Jo%");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByStringAttributeEndingWith() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameEndingWith", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "hn" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name LIKE $1";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name LIKE $1");
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
@Test // gh-282
public void prependsLikeOperatorParameterWithPercentSymbolForEndingWithQuery() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameEndingWith", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
@@ -310,23 +343,27 @@ public class PartTreeR2dbcQueryIntegrationTests {
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
DatabaseClient.BindSpec bindSpecMock = mock(DatabaseClient.BindSpec.class);
bindableQuery.bind(bindSpecMock);
verify(bindSpecMock, times(1)).bind(0, "%hn");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByStringAttributeContaining() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameContaining", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name LIKE $1";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name LIKE $1");
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
@Test // gh-282
public void wrapsLikeOperatorParameterWithPercentSymbolsForContainingQuery() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameContaining", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
@@ -334,24 +371,27 @@ public class PartTreeR2dbcQueryIntegrationTests {
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
DatabaseClient.BindSpec bindSpecMock = mock(DatabaseClient.BindSpec.class);
bindableQuery.bind(bindSpecMock);
verify(bindSpecMock, times(1)).bind(0, "%oh%");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByStringAttributeNotContaining() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameNotContaining", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE
+ " WHERE " + TABLE + ".first_name NOT LIKE $1";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name NOT LIKE $1");
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
@Test // gh-282
public void wrapsLikeOperatorParameterWithPercentSymbolsForNotContainingQuery() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameNotContaining", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
@@ -359,10 +399,11 @@ public class PartTreeR2dbcQueryIntegrationTests {
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
DatabaseClient.BindSpec bindSpecMock = mock(DatabaseClient.BindSpec.class);
bindableQuery.bind(bindSpecMock);
verify(bindSpecMock, times(1)).bind(0, "%oh%");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByIntegerAttributeWithDescendingOrderingByStringAttribute()
throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByAgeOrderByLastNameDesc", Integer.class);
@@ -370,48 +411,50 @@ public class PartTreeR2dbcQueryIntegrationTests {
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE
+ " WHERE " + TABLE + ".age = $1 ORDER BY users.last_name DESC";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age = $1 ORDER BY last_name DESC");
}
@Test
public void createsQueryToFindAllEntitiesByIntegerAttributeWithAscendingOrderingByStringAttribute()
throws Exception {
@Test // gh-282
public void createsQueryToFindAllEntitiesByIntegerAttributeWithAscendingOrderingByStringAttribute() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByAgeOrderByLastNameAsc", Integer.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE
+ " WHERE " + TABLE + ".age = $1 ORDER BY users.last_name ASC";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age = $1 ORDER BY last_name ASC");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByStringAttributeNot() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByLastNameNot", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "Doe" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".last_name != $1";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".last_name != $1");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByIntegerAttributeIn() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByAgeIn", Collection.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod,
new Object[] { Collections.singleton(25) });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age IN ($1)";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age IN ($1)");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByIntegerAttributeNotIn() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByAgeNotIn", Collection.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
@@ -419,118 +462,120 @@ public class PartTreeR2dbcQueryIntegrationTests {
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod,
new Object[] { Collections.singleton(25) });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age NOT IN ($1)";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age NOT IN ($1)");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByBooleanAttributeTrue() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByActiveTrue");
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]);
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".active = TRUE";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".active = TRUE");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByBooleanAttributeFalse() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByActiveFalse");
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]);
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".active = FALSE";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".active = FALSE");
}
@Test
@Test // gh-282
public void createsQueryToFindAllEntitiesByStringAttributeIgnoringCase() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameIgnoreCase", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "John" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE
+ " WHERE UPPER(" + TABLE + ".first_name) = UPPER($1)";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE UPPER(" + TABLE + ".first_name) = UPPER($1)");
}
@Test
@Test // gh-282
public void throwsExceptionWhenIgnoringCaseIsImpossible() throws Exception {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Unable to ignore case of java.lang.Long type, "
+ "the property 'id' must reference a string");
R2dbcQueryMethod queryMethod = getQueryMethod("findByIdIgnoringCase", Long.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[] { 1L }));
assertThatIllegalStateException()
.isThrownBy(() -> r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[] { 1L })));
}
@Test
@Test // gh-282
public void throwsExceptionWhenInPredicateHasNonIterableParameter() throws Exception {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Operator IN on id requires a Collection argument, "
+ "found class java.lang.Long in method findAllByIdIn.");
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByIdIn", Long.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[] { 1L }));
assertThatIllegalArgumentException()
.isThrownBy(() -> new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter, dataAccessStrategy));
}
@Test
@Test // gh-282
public void throwsExceptionWhenSimplePropertyPredicateHasIterableParameter() throws Exception {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Operator SIMPLE_PROPERTY on id requires a scalar argument, "
+ "found interface java.util.Collection in method findAllById.");
R2dbcQueryMethod queryMethod = getQueryMethod("findAllById", Collection.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[] { Collections.singleton(1L) }));
assertThatIllegalArgumentException()
.isThrownBy(() -> new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter, dataAccessStrategy));
}
@Test
@Test // gh-282
public void throwsExceptionWhenConditionKeywordIsUnsupported() throws Exception {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Unsupported keyword IS_EMPTY");
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByIdIsEmpty");
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[0]));
assertThatIllegalArgumentException()
.isThrownBy(() -> r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[0])));
}
@Test
@Test // gh-282
public void throwsExceptionWhenInvalidNumberOfParameterIsGiven() throws Exception {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Invalid number of parameters given!");
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByFirstName", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[0]));
assertThatIllegalArgumentException()
.isThrownBy(() -> r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[0])));
}
@Test
@Test // gh-282
public void createsQueryWithLimitToFindEntitiesByStringAttribute() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findTop3ByFirstName", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "John" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE
+ " WHERE " + TABLE + ".first_name = $1 LIMIT 3";
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name = $1 LIMIT 3";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
}
@Test
@Test // gh-282
public void createsQueryToFindFirstEntityByStringAttribute() throws Exception {
R2dbcQueryMethod queryMethod = getQueryMethod("findFirstByFirstName", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "John" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE
+ " WHERE " + TABLE + ".first_name = $1 LIMIT 1";
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name = $1 LIMIT 1";
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
}
@@ -544,7 +589,8 @@ public class PartTreeR2dbcQueryIntegrationTests {
return new RelationalParametersParameterAccessor(queryMethod, values);
}
private interface UserRepository extends Repository<User, Long> {
interface UserRepository extends Repository<User, Long> {
Flux<User> findAllByFirstName(String firstName);
Flux<User> findAllByLastNameAndFirstName(String lastName, String firstName);
@@ -613,60 +659,14 @@ public class PartTreeR2dbcQueryIntegrationTests {
}
@Table("users")
@Data
private static class User {
@Id private Long id;
private @Id Long id;
private String firstName;
private String lastName;
private Date dateOfBirth;
private Integer age;
private Boolean active;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Date getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Boolean getActive() {
return active;
}
public void setActive(Boolean active) {
this.active = active;
}
}
}

View File

@@ -32,16 +32,13 @@ import org.springframework.data.r2dbc.core.PreparedOperation;
@RunWith(MockitoJUnitRunner.class)
@Ignore
public class PreparedOperationBindableQueryUnitTests {
@Mock private PreparedOperation<?> preparedOperation;
@Test(expected = IllegalArgumentException.class)
public void throwsExceptionWhenPreparedOperationIsNull() {
new PreparedOperationBindableQuery(null);
}
@Mock PreparedOperation<?> preparedOperation;
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
@Test // gh-282
public void bindsQueryParameterValues() {
DatabaseClient.BindSpec bindSpecMock = mock(DatabaseClient.BindSpec.class);
PreparedOperationBindableQuery query = new PreparedOperationBindableQuery(preparedOperation);
@@ -49,12 +46,12 @@ public class PreparedOperationBindableQueryUnitTests {
verify(preparedOperation, times(1)).bindTo(any());
}
@Test
@Test // gh-282
public void returnsSqlQuery() {
String sql = "SELECT * FROM test";
when(preparedOperation.get()).thenReturn(sql);
when(preparedOperation.get()).thenReturn("SELECT * FROM test");
PreparedOperationBindableQuery query = new PreparedOperationBindableQuery(preparedOperation);
assertThat(query.get()).isEqualTo(sql);
assertThat(query.get()).isEqualTo("SELECT * FROM test");
}
}