Browse Source

#468 - Correctly map result of exists queries.

We now map results of exists queries to a boolean flag to ensure proper decoding. Previously, results were attempted to be mapped onto a primitive type which failed as there's no converter registered for Row to Boolean.
pull/1188/head
Mark Paluch 5 years ago
parent
commit
d3823947aa
No known key found for this signature in database
GPG Key ID: 51A00FA751B91849
  1. 36
      src/main/java/org/springframework/data/r2dbc/repository/query/AbstractR2dbcQuery.java
  2. 18
      src/main/java/org/springframework/data/r2dbc/repository/query/PartTreeR2dbcQuery.java
  3. 6
      src/main/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryExecution.java
  4. 19
      src/main/java/org/springframework/data/r2dbc/repository/query/StringBasedR2dbcQuery.java
  5. 29
      src/test/java/org/springframework/data/r2dbc/repository/AbstractR2dbcRepositoryIntegrationTests.java

36
src/main/java/org/springframework/data/r2dbc/repository/query/AbstractR2dbcQuery.java

@ -89,17 +89,21 @@ public abstract class AbstractR2dbcQuery implements RepositoryQuery {
return createQuery(parameterAccessor).flatMapMany(it -> executeQuery(parameterAccessor, it)); return createQuery(parameterAccessor).flatMapMany(it -> executeQuery(parameterAccessor, it));
} }
@SuppressWarnings({ "unchecked", "rawtypes" })
private Publisher<?> executeQuery(RelationalParameterAccessor parameterAccessor, BindableQuery it) { private Publisher<?> executeQuery(RelationalParameterAccessor parameterAccessor, BindableQuery it) {
ResultProcessor processor = method.getResultProcessor().withDynamicProjection(parameterAccessor); ResultProcessor processor = method.getResultProcessor().withDynamicProjection(parameterAccessor);
DatabaseClient.GenericExecuteSpec boundQuery = it.bind(databaseClient.sql(it)); DatabaseClient.GenericExecuteSpec boundQuery = it.bind(databaseClient.sql(it));
FetchSpec<?> fetchSpec; FetchSpec<Object> fetchSpec;
if (requiresMapping()) {
EntityRowMapper<?> rowMapper = new EntityRowMapper<>(resolveResultType(processor), converter); if (isExistsQuery()) {
fetchSpec = (FetchSpec) boundQuery.map(row -> true);
} else if (requiresMapping()) {
EntityRowMapper rowMapper = new EntityRowMapper<>(resolveResultType(processor), converter);
fetchSpec = new FetchSpecAdapter<>(boundQuery.map(rowMapper)); fetchSpec = new FetchSpecAdapter<>(boundQuery.map(rowMapper));
} else { } else {
fetchSpec = boundQuery.fetch(); fetchSpec = (FetchSpec) boundQuery.fetch();
} }
SqlIdentifier tableName = method.getEntityInformation().getTableName(); SqlIdentifier tableName = method.getEntityInformation().getTableName();
@ -143,6 +147,14 @@ public abstract class AbstractR2dbcQuery implements RepositoryQuery {
return (q, t, c) -> q.rowsUpdated(); return (q, t, c) -> q.rowsUpdated();
} }
if (isCountQuery()) {
return (q, t, c) -> q.first().defaultIfEmpty(0L);
}
if (isExistsQuery()) {
return (q, t, c) -> q.first().defaultIfEmpty(false);
}
if (method.isCollectionQuery()) { if (method.isCollectionQuery()) {
return (q, t, c) -> q.all(); return (q, t, c) -> q.all();
} }
@ -158,6 +170,22 @@ public abstract class AbstractR2dbcQuery implements RepositoryQuery {
*/ */
protected abstract boolean isModifyingQuery(); protected abstract boolean isModifyingQuery();
/**
* Returns whether the query should get a count projection applied.
*
* @return
* @since 1.2
*/
protected abstract boolean isCountQuery();
/**
* Returns whether the query should get an exists projection applied.
*
* @return
* @since 1.2
*/
protected abstract boolean isExistsQuery();
/** /**
* Creates a {@link BindableQuery} instance using the given {@link ParameterAccessor} * Creates a {@link BindableQuery} instance using the given {@link ParameterAccessor}
* *

18
src/main/java/org/springframework/data/r2dbc/repository/query/PartTreeR2dbcQuery.java

@ -82,6 +82,24 @@ public class PartTreeR2dbcQuery extends AbstractR2dbcQuery {
return this.tree.isDelete(); return this.tree.isDelete();
} }
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.repository.query.AbstractR2dbcQuery#isCountQuery()
*/
@Override
protected boolean isCountQuery() {
return this.tree.isCountProjection();
}
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.repository.query.AbstractR2dbcQuery#isExistsQuery()
*/
@Override
protected boolean isExistsQuery() {
return this.tree.isExistsProjection();
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* @see org.springframework.data.r2dbc.repository.query.AbstractR2dbcQuery#createQuery(org.springframework.data.relational.repository.query.RelationalParameterAccessor) * @see org.springframework.data.r2dbc.repository.query.AbstractR2dbcQuery#createQuery(org.springframework.data.relational.repository.query.RelationalParameterAccessor)

6
src/main/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryExecution.java

@ -41,7 +41,7 @@ import org.springframework.util.ClassUtils;
*/ */
interface R2dbcQueryExecution { interface R2dbcQueryExecution {
Publisher<?> execute(FetchSpec<?> query, Class<?> type, SqlIdentifier tableName); Publisher<?> execute(FetchSpec<Object> query, Class<?> type, SqlIdentifier tableName);
/** /**
* An {@link R2dbcQueryExecution} that wraps the results of the given delegate with the given result processing. * An {@link R2dbcQueryExecution} that wraps the results of the given delegate with the given result processing.
@ -60,8 +60,8 @@ interface R2dbcQueryExecution {
* @see org.springframework.data.r2dbc.repository.query.R2dbcQueryExecution#execute(org.springframework.data.r2dbc.function.FetchSpec, java.lang.Class, java.lang.String) * @see org.springframework.data.r2dbc.repository.query.R2dbcQueryExecution#execute(org.springframework.data.r2dbc.function.FetchSpec, java.lang.Class, java.lang.String)
*/ */
@Override @Override
public Publisher<?> execute(FetchSpec<?> query, Class<?> type, SqlIdentifier tableName) { public Publisher<Object> execute(FetchSpec<Object> query, Class<?> type, SqlIdentifier tableName) {
return (Publisher<?>) this.converter.convert(this.delegate.execute(query, type, tableName)); return (Publisher<Object>) this.converter.convert(this.delegate.execute(query, type, tableName));
} }
} }

19
src/main/java/org/springframework/data/r2dbc/repository/query/StringBasedR2dbcQuery.java

@ -112,6 +112,24 @@ public class StringBasedR2dbcQuery extends AbstractR2dbcQuery {
return getQueryMethod().isModifyingQuery(); return getQueryMethod().isModifyingQuery();
} }
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.repository.query.AbstractR2dbcQuery#isCountQuery()
*/
@Override
protected boolean isCountQuery() {
return false;
}
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.repository.query.AbstractR2dbcQuery#isExistsQuery()
*/
@Override
protected boolean isExistsQuery() {
return false;
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* @see org.springframework.data.r2dbc.repository.query.AbstractR2dbcQuery#createQuery(org.springframework.data.relational.repository.query.RelationalParameterAccessor) * @see org.springframework.data.r2dbc.repository.query.AbstractR2dbcQuery#createQuery(org.springframework.data.relational.repository.query.RelationalParameterAccessor)
@ -133,6 +151,7 @@ public class StringBasedR2dbcQuery extends AbstractR2dbcQuery {
}); });
} }
private Mono<R2dbcSpELExpressionEvaluator> getSpelEvaluator(RelationalParameterAccessor accessor) { private Mono<R2dbcSpELExpressionEvaluator> getSpelEvaluator(RelationalParameterAccessor accessor) {
return evaluationContextProvider return evaluationContextProvider

29
src/test/java/org/springframework/data/r2dbc/repository/AbstractR2dbcRepositoryIntegrationTests.java

@ -296,6 +296,33 @@ public abstract class AbstractR2dbcRepositoryIntegrationTests extends R2dbcInteg
.verifyComplete(); .verifyComplete();
} }
@Test // gh-363
void derivedQueryWithCount() {
shouldInsertNewItems();
repository.countByNameContains("SCH") //
.as(StepVerifier::create) //
.assertNext(i -> assertThat(i).isEqualTo(2)) //
.verifyComplete();
}
@Test // gh-468
void derivedQueryWithExists() {
shouldInsertNewItems();
repository.existsByName("ABS") //
.as(StepVerifier::create) //
.expectNext(Boolean.FALSE) //
.verifyComplete();
repository.existsByName("SCHAUFELRADBAGGER") //
.as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();
}
@Test // gh-421 @Test // gh-421
void shouldDeleteAllAndReturnCount() { void shouldDeleteAllAndReturnCount() {
@ -345,6 +372,8 @@ public abstract class AbstractR2dbcRepositoryIntegrationTests extends R2dbcInteg
Mono<Integer> deleteAllAndReturnCount(); Mono<Integer> deleteAllAndReturnCount();
Mono<Integer> countByNameContains(String namePart); Mono<Integer> countByNameContains(String namePart);
Mono<Boolean> existsByName(String name);
} }
@Getter @Getter

Loading…
Cancel
Save