Skip to content
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-relational-parent</artifactId>
<version>2.3.0-SNAPSHOT</version>
<version>2.3.0-908-boolean-for-derived-queries-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data Relational Parent</name>
Expand Down
2 changes: 1 addition & 1 deletion spring-data-jdbc-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-relational-parent</artifactId>
<version>2.3.0-SNAPSHOT</version>
<version>2.3.0-908-boolean-for-derived-queries-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
4 changes: 2 additions & 2 deletions spring-data-jdbc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<modelVersion>4.0.0</modelVersion>

<artifactId>spring-data-jdbc</artifactId>
<version>2.3.0-SNAPSHOT</version>
<version>2.3.0-908-boolean-for-derived-queries-SNAPSHOT</version>

<name>Spring Data JDBC</name>
<description>Spring Data module for JDBC repositories.</description>
Expand All @@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-relational-parent</artifactId>
<version>2.3.0-SNAPSHOT</version>
<version>2.3.0-908-boolean-for-derived-queries-SNAPSHOT</version>
</parent>

<properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public JdbcCustomConversions jdbcCustomConversions() {
}
}

private List<?> userConverters() {
protected List<?> userConverters() {
return Collections.emptyList();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,11 +402,15 @@ private Condition createCondition(Column column, @Nullable Object mappedValue, i
}

if (comparator == Comparator.IS_TRUE) {
return column.isEqualTo(SQL.literalOf(true));

Expression bind = bindBoolean(column, parameterSource, true);
return column.isEqualTo(bind);
}

if (comparator == Comparator.IS_FALSE) {
return column.isEqualTo(SQL.literalOf(false));

Expression bind = bindBoolean(column, parameterSource, false);
return column.isEqualTo(bind);
}

Expression columnExpression = column;
Expand Down Expand Up @@ -495,6 +499,12 @@ private Condition createCondition(Column column, @Nullable Object mappedValue, i
}
}

private Expression bindBoolean(Column column, MapSqlParameterSource parameterSource, boolean value) {

Object converted = converter.writeValue(value, ClassTypeInformation.OBJECT);
return bind(converted, Types.BIT, parameterSource, column.getName().getReference());
}

Field createPropertyField(@Nullable RelationalPersistentEntity<?> entity, SqlIdentifier key) {
return entity == null ? new Field(key) : new MetadataBackedField(key, entity, mappingContext, converter);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,19 @@ public void pageQueryProjectionShouldReturnProjectedEntities() {
assertThat(result.getContent().get(0).getName()).isEqualTo("Entity Name");
}

@Test // #908
void derivedQueryWithBooleanLiteralFindsCorrectValues() {

repository.save(createDummyEntity());
DummyEntity entity = createDummyEntity();
entity.flag = true;
entity = repository.save(entity);

List<DummyEntity> result = repository.findByFlagTrue();

assertThat(result).extracting(e -> e.idProp).containsExactly(entity.idProp);
}

private Instant createDummyBeforeAndAfterNow() {

Instant now = Instant.now();
Expand Down Expand Up @@ -557,6 +570,8 @@ interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> {

@Query("SELECT * FROM DUMMY_ENTITY WHERE OFFSET_DATE_TIME > :threshhold")
List<DummyEntity> findByOffsetDateTime(@Param("threshhold") OffsetDateTime threshhold);

List<DummyEntity> findByFlagTrue();
}

@Configuration
Expand Down Expand Up @@ -603,10 +618,12 @@ public void onApplicationEvent(AbstractRelationalEvent<?> event) {
@Data
@NoArgsConstructor
static class DummyEntity {

String name;
Instant pointInTime;
OffsetDateTime offsetDateTime;
@Id private Long idProp;
boolean flag;

public DummyEntity(String name) {
this.name = name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@
*/
package org.springframework.data.jdbc.repository.config;

import static java.util.Arrays.*;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;

import java.util.Arrays;
import java.util.Collections;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;

import org.junit.jupiter.api.Test;
Expand All @@ -29,14 +30,17 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.relational.core.dialect.Dialect;
import org.springframework.data.relational.core.dialect.HsqlDbDialect;
import org.springframework.data.relational.core.dialect.LimitClause;
import org.springframework.data.relational.core.dialect.LockClause;
import org.springframework.data.relational.core.sql.render.SelectRenderContext;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
Expand All @@ -53,7 +57,7 @@ void configuresInfrastructureComponents() {

assertApplicationContext(context -> {

List<Class<?>> expectedBeanTypes = Arrays.asList(DataAccessStrategy.class, //
List<Class<?>> expectedBeanTypes = asList(DataAccessStrategy.class, //
JdbcMappingContext.class, //
JdbcConverter.class, //
JdbcCustomConversions.class, //
Expand All @@ -70,11 +74,26 @@ void configuresInfrastructureComponents() {
void registersSimpleTypesFromCustomConversions() {

assertApplicationContext(context -> {

JdbcMappingContext mappingContext = context.getBean(JdbcMappingContext.class);
assertThat( //
mappingContext.getPersistentEntity(AbstractJdbcConfigurationUnderTest.Blah.class) //
).describedAs("Blah should not be an entity, since there is a WritingConversion configured for it") //
.isNull();

}, AbstractJdbcConfigurationUnderTest.class, Infrastructure.class);
}

@Test // #908
void userProvidedConversionsOverwriteDialectSpecificConversions() {

assertApplicationContext(applicationContext -> {

Optional<Class<?>> customWriteTarget = applicationContext.getBean(JdbcCustomConversions.class)
.getCustomWriteTarget(Boolean.class);

assertThat(customWriteTarget).contains(String.class);

}, AbstractJdbcConfigurationUnderTest.class, Infrastructure.class);
}

Expand Down Expand Up @@ -106,12 +125,12 @@ static class AbstractJdbcConfigurationUnderTest extends AbstractJdbcConfiguratio
@Override
@Bean
public Dialect jdbcDialect(NamedParameterJdbcOperations operations) {
return HsqlDbDialect.INSTANCE;
return new DummyDialect();
}

@Override
public JdbcCustomConversions jdbcCustomConversions() {
return new JdbcCustomConversions(Collections.singletonList(Blah2BlubbConverter.INSTANCE));
protected List<?> userConverters() {
return asList(Blah2BlubbConverter.INSTANCE, BooleanToYnConverter.INSTANCE);
}

@WritingConverter
Expand All @@ -127,6 +146,59 @@ public Blubb convert(Blah blah) {
private static class Blah {}

private static class Blubb {}

private static class DummyDialect implements Dialect {
@Override
public LimitClause limit() {
return null;
}

@Override
public LockClause lock() {
return null;
}

@Override
public SelectRenderContext getSelectContext() {
return null;
}

@Override
public Collection<Object> getConverters() {
return asList(BooleanToNumberConverter.INSTANCE, NumberToBooleanConverter.INSTANCE);
}
}

@WritingConverter
enum BooleanToNumberConverter implements Converter<Boolean, Number> {
INSTANCE;

@Override
public Number convert(Boolean source) {
return source ? 1 : 0;
}
}

@ReadingConverter
enum NumberToBooleanConverter implements Converter<Number, Boolean> {
INSTANCE;

@Override
public Boolean convert(Number source) {
return source.intValue() == 0;
}
}

@WritingConverter
enum BooleanToYnConverter implements Converter<Boolean, String> {
INSTANCE;

@Override
public String convert(Boolean source) {
return source ? "Y" : "N";
}
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.List;
import java.util.Properties;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
Expand Down Expand Up @@ -457,7 +458,7 @@ public void createsQueryToFindAllEntitiesByBooleanAttributeTrue() throws Excepti
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]);
ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);

assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"ACTIVE\" = TRUE");
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"ACTIVE\" = :active");
}

@Test // DATAJDBC-318
Expand All @@ -468,7 +469,7 @@ public void createsQueryToFindAllEntitiesByBooleanAttributeFalse() throws Except
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]);
ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);

assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"ACTIVE\" = FALSE");
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"ACTIVE\" = :active");
}

@Test // DATAJDBC-318
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ CREATE TABLE dummy_entity
id_Prop BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
NAME VARCHAR(100),
POINT_IN_TIME TIMESTAMP,
OFFSET_DATE_TIME TIMESTAMP -- with time zone is only supported with z/OS
OFFSET_DATE_TIME TIMESTAMP, -- with time zone is only supported with z/OS
FLAG BOOLEAN
);
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ CREATE TABLE dummy_entity
id_Prop BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
NAME VARCHAR(100),
POINT_IN_TIME TIMESTAMP,
OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE
OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE,
FLAG BOOLEAN
);
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ CREATE TABLE dummy_entity
id_Prop BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
NAME VARCHAR(100),
POINT_IN_TIME TIMESTAMP,
OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE
OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE,
FLAG BOOLEAN
);
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ CREATE TABLE dummy_entity
id_Prop BIGINT AUTO_INCREMENT PRIMARY KEY,
NAME VARCHAR(100),
POINT_IN_TIME TIMESTAMP(3),
OFFSET_DATE_TIME TIMESTAMP(3)
OFFSET_DATE_TIME TIMESTAMP(3),
FLAG BOOLEAN
);
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ CREATE TABLE dummy_entity
id_Prop BIGINT IDENTITY PRIMARY KEY,
NAME VARCHAR(100),
POINT_IN_TIME DATETIME,
OFFSET_DATE_TIME DATETIMEOFFSET
OFFSET_DATE_TIME DATETIMEOFFSET,
FLAG BIT
);
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
SET SQL_MODE='ALLOW_INVALID_DATES';

CREATE TABLE dummy_entity
CREATE TABLE DUMMY_ENTITY
(
id_Prop BIGINT AUTO_INCREMENT PRIMARY KEY,
ID_PROP BIGINT AUTO_INCREMENT PRIMARY KEY,
NAME VARCHAR(100),
POINT_IN_TIME TIMESTAMP(3) default null,
OFFSET_DATE_TIME TIMESTAMP(3) default null
POINT_IN_TIME TIMESTAMP(3) DEFAULT NULL,
OFFSET_DATE_TIME TIMESTAMP(3) DEFAULT NULL,
FLAG BIT(1)
);
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ CREATE TABLE DUMMY_ENTITY
ID_PROP NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,
NAME VARCHAR2(100),
POINT_IN_TIME TIMESTAMP,
OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE
OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE,
FLAG NUMBER(1,0)
);
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ CREATE TABLE dummy_entity
id_Prop SERIAL PRIMARY KEY,
NAME VARCHAR(100),
POINT_IN_TIME TIMESTAMP,
OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE
OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE,
FLAG BOOLEAN
);
4 changes: 2 additions & 2 deletions spring-data-relational/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
<modelVersion>4.0.0</modelVersion>

<artifactId>spring-data-relational</artifactId>
<version>2.3.0-SNAPSHOT</version>
<version>2.3.0-908-boolean-for-derived-queries-SNAPSHOT</version>

<name>Spring Data Relational</name>
<description>Spring Data Relational support</description>

<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-relational-parent</artifactId>
<version>2.3.0-SNAPSHOT</version>
<version>2.3.0-908-boolean-for-derived-queries-SNAPSHOT</version>
</parent>

<properties>
Expand Down
Loading