Reject Limit parameter using String-based queries.

Document limitations, add test cases for derived queries.

Closes #1654
This commit is contained in:
Mark Paluch
2023-11-02 09:26:43 +01:00
parent 4ceb982197
commit 5312731623
8 changed files with 124 additions and 24 deletions

View File

@@ -100,6 +100,21 @@ public class StringBasedR2dbcQuery extends AbstractR2dbcQuery {
this.expressionQuery = ExpressionQuery.create(query);
this.binder = new ExpressionEvaluatingParameterBinder(expressionQuery, dataAccessStrategy);
this.expressionDependencies = createExpressionDependencies();
if (method.isSliceQuery()) {
throw new UnsupportedOperationException(
"Slice queries are not supported using string-based queries; Offending method: " + method);
}
if (method.isPageQuery()) {
throw new UnsupportedOperationException(
"Page queries are not supported using string-based queries; Offending method: " + method);
}
if (method.getParameters().hasLimitParameter()) {
throw new UnsupportedOperationException(
"Queries with Limit are not supported using string-based queries; Offending method: " + method);
}
}
private ExpressionDependencies createExpressionDependencies() {

View File

@@ -15,7 +15,21 @@
*/
package org.springframework.data.r2dbc.repository;
import static org.assertj.core.api.Assertions.*;
import io.r2dbc.spi.ConnectionFactory;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Hooks;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.stream.IntStream;
import javax.sql.DataSource;
import org.assertj.core.api.Condition;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -23,6 +37,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceCreator;
import org.springframework.data.domain.Limit;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactory;
@@ -35,17 +50,6 @@ import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.r2dbc.connection.R2dbcTransactionManager;
import org.springframework.transaction.reactive.TransactionalOperator;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Hooks;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.IntStream;
import static org.assertj.core.api.Assertions.*;
/**
* Abstract base class for integration tests for {@link LegoSetRepository} using {@link R2dbcRepositoryFactory}.
@@ -143,6 +147,22 @@ public abstract class AbstractR2dbcRepositoryIntegrationTests extends R2dbcInteg
}).verifyComplete();
}
@Test // GH-1654
void shouldFindItemsByNameContainsWithLimit() {
shouldInsertNewItems();
repository.findByNameContains("F", Limit.of(1)) //
.as(StepVerifier::create) //
.expectNextCount(1) //
.verifyComplete();
repository.findByNameContains("F", Limit.unlimited()) //
.as(StepVerifier::create) //
.expectNextCount(2) //
.verifyComplete();
}
@Test // GH-475, GH-607
void shouldFindApplyingInterfaceProjection() {
@@ -423,6 +443,8 @@ public abstract class AbstractR2dbcRepositoryIntegrationTests extends R2dbcInteg
Flux<LegoSet> findByNameContains(String name);
Flux<LegoSet> findByNameContains(String name, Limit limit);
Flux<LegoSet> findFirst10By();
Flux<LegoSet> findAllByOrderByManual(Pageable pageable);
@@ -483,6 +505,7 @@ public abstract class AbstractR2dbcRepositoryIntegrationTests extends R2dbcInteg
public LegoSet() {
}
@Override
public String getName() {
return this.name;
}
@@ -547,15 +570,15 @@ public abstract class AbstractR2dbcRepositoryIntegrationTests extends R2dbcInteg
public boolean equals(final Object o) {
if (o == this) return true;
if (!(o instanceof LegoDto)) return false;
final LegoDto other = (LegoDto) o;
if (!(o instanceof final LegoDto other))
return false;
final Object this$name = this.getName();
final Object other$name = other.getName();
if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false;
if (!Objects.equals(this$name, other$name))
return false;
final Object this$unknown = this.getUnknown();
final Object other$unknown = other.getUnknown();
if (this$unknown == null ? other$unknown != null : !this$unknown.equals(other$unknown)) return false;
return true;
return Objects.equals(this$unknown, other$unknown);
}
public int hashCode() {

View File

@@ -18,11 +18,8 @@ package org.springframework.data.r2dbc.repository.query;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import io.r2dbc.spi.R2dbcType;
import io.r2dbc.spi.test.MockColumnMetadata;
import io.r2dbc.spi.test.MockResult;
import io.r2dbc.spi.test.MockRow;
import io.r2dbc.spi.test.MockRowMetadata;
import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;
@@ -36,7 +33,7 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.data.domain.Limit;
import org.springframework.data.domain.Sort;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
@@ -288,8 +285,6 @@ public class StringBasedR2dbcQueryUnitTests {
@Test // gh-612
void selectsSimpleType() {
MockRowMetadata metadata = MockRowMetadata.builder()
.columnMetadata(MockColumnMetadata.builder().name("date").type(R2dbcType.DATE).build()).build();
LocalDate value = LocalDate.now();
MockResult result = MockResult.builder()
.row(MockRow.builder().identified(0, LocalDate.class, value).build()).build();
@@ -309,6 +304,12 @@ public class StringBasedR2dbcQueryUnitTests {
flux.as(StepVerifier::create).expectNext(value).verifyComplete();
}
@Test // GH-1654
void rejectsStringBasedLimitQuery() {
assertThatExceptionOfType(UnsupportedOperationException.class)
.isThrownBy(() -> getQueryMethod("unsupportedLimitQuery", String.class, Limit.class));
}
private StringBasedR2dbcQuery getQueryMethod(String name, Class<?>... args) {
Method method = ReflectionUtils.findMethod(SampleRepository.class, name, args);
@@ -366,6 +367,9 @@ public class StringBasedR2dbcQueryUnitTests {
@Query("SELECT MAX(DATE)")
Flux<LocalDate> findAllLocalDates();
@Query("SELECT * FROM person WHERE lastname = $1")
Person unsupportedLimitQuery(@Param("lastname") String lastname, Limit limit);
}
static class PersonDto {
@@ -388,6 +392,6 @@ public class StringBasedR2dbcQueryUnitTests {
}
enum MyEnum {
INSTANCE;
INSTANCE
}
}