diff --git a/src/main/java/org/springframework/data/r2dbc/config/AbstractR2dbcConfiguration.java b/src/main/java/org/springframework/data/r2dbc/config/AbstractR2dbcConfiguration.java index d32a74d..8d7f8fa 100644 --- a/src/main/java/org/springframework/data/r2dbc/config/AbstractR2dbcConfiguration.java +++ b/src/main/java/org/springframework/data/r2dbc/config/AbstractR2dbcConfiguration.java @@ -17,7 +17,6 @@ package org.springframework.data.r2dbc.config; import io.r2dbc.spi.ConnectionFactory; -import java.util.Collections; import java.util.Optional; import org.springframework.context.annotation.Bean; @@ -153,7 +152,7 @@ public abstract class AbstractR2dbcConfiguration { Dialect dialect = getDialect(connectionFactory()); StoreConversions storeConversions = StoreConversions.of(dialect.getSimpleTypeHolder()); - return new R2dbcCustomConversions(storeConversions, Collections.emptyList()); + return new R2dbcCustomConversions(storeConversions, R2dbcCustomConversions.STORE_CONVERTERS); } /** diff --git a/src/main/java/org/springframework/data/r2dbc/dialect/Dialect.java b/src/main/java/org/springframework/data/r2dbc/dialect/Dialect.java index be1d493..9314527 100644 --- a/src/main/java/org/springframework/data/r2dbc/dialect/Dialect.java +++ b/src/main/java/org/springframework/data/r2dbc/dialect/Dialect.java @@ -3,6 +3,7 @@ package org.springframework.data.r2dbc.dialect; import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.Set; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.r2dbc.dialect.ArrayColumns.Unsupported; @@ -40,7 +41,11 @@ public interface Dialect { * @see #getSimpleTypes() */ default SimpleTypeHolder getSimpleTypeHolder() { - return new SimpleTypeHolder(new HashSet<>(getSimpleTypes()), true); + + Set> simpleTypes = new HashSet<>(getSimpleTypes()); + simpleTypes.addAll(R2dbcSimpleTypeHolder.R2DBC_SIMPLE_TYPES); + + return new SimpleTypeHolder(simpleTypes, true); } /** diff --git a/src/main/java/org/springframework/data/r2dbc/dialect/R2dbcSimpleTypeHolder.java b/src/main/java/org/springframework/data/r2dbc/dialect/R2dbcSimpleTypeHolder.java new file mode 100644 index 0000000..d32d815 --- /dev/null +++ b/src/main/java/org/springframework/data/r2dbc/dialect/R2dbcSimpleTypeHolder.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019 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 + * + * http://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.dialect; + +import io.r2dbc.spi.Row; + +import java.util.Collections; +import java.util.Set; + +import org.springframework.data.mapping.model.SimpleTypeHolder; + +/** + * Simple constant holder for a {@link SimpleTypeHolder} enriched with R2DBC specific simple types. + * + * @author Mark Paluch + */ +public class R2dbcSimpleTypeHolder extends SimpleTypeHolder { + + /** + * Set of R2DBC simple types. + */ + public static final Set> R2DBC_SIMPLE_TYPES = Collections.singleton(Row.class); + + public static final SimpleTypeHolder HOLDER = new R2dbcSimpleTypeHolder(); + + /** + * Create a new {@link R2dbcSimpleTypeHolder} instance. + */ + private R2dbcSimpleTypeHolder() { + super(R2DBC_SIMPLE_TYPES, true); + } + +} diff --git a/src/main/java/org/springframework/data/r2dbc/function/convert/MappingR2dbcConverter.java b/src/main/java/org/springframework/data/r2dbc/function/convert/MappingR2dbcConverter.java index e24c2db..f851534 100644 --- a/src/main/java/org/springframework/data/r2dbc/function/convert/MappingR2dbcConverter.java +++ b/src/main/java/org/springframework/data/r2dbc/function/convert/MappingR2dbcConverter.java @@ -42,6 +42,7 @@ import org.springframework.data.relational.core.conversion.BasicRelationalConver import org.springframework.data.relational.core.conversion.RelationalConverter; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; +import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -61,7 +62,7 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R */ public MappingR2dbcConverter( MappingContext, ? extends RelationalPersistentProperty> context) { - super(context, new R2dbcCustomConversions(CustomConversions.StoreConversions.NONE, Collections.emptyList())); + super(context, new R2dbcCustomConversions(Collections.emptyList())); } /** @@ -81,6 +82,19 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R @Override public R read(Class type, Row row) { + + TypeInformation typeInfo = ClassTypeInformation.from(type); + Class rawType = typeInfo.getType(); + + if (Row.class.isAssignableFrom(rawType)) { + return type.cast(row); + } + + if (getConversions().hasCustomReadTarget(Row.class, rawType) + || getConversionService().canConvert(Row.class, rawType)) { + return getConversionService().convert(row, rawType); + } + return read(getRequiredPersistentEntity(type), row); } diff --git a/src/main/java/org/springframework/data/r2dbc/function/convert/R2dbcConverters.java b/src/main/java/org/springframework/data/r2dbc/function/convert/R2dbcConverters.java new file mode 100644 index 0000000..62b3d41 --- /dev/null +++ b/src/main/java/org/springframework/data/r2dbc/function/convert/R2dbcConverters.java @@ -0,0 +1,233 @@ +/* + * Copyright 2019 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 + * + * http://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.function.convert; + +import io.r2dbc.spi.Row; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.converter.ConverterFactory; +import org.springframework.data.r2dbc.function.convert.R2dbcConverters.RowToNumberConverterFactory.RowToOffsetDateTimeConverter; +import org.springframework.data.r2dbc.function.convert.R2dbcConverters.RowToNumberConverterFactory.RowToStringConverter; +import org.springframework.data.r2dbc.function.convert.R2dbcConverters.RowToNumberConverterFactory.RowToUuidConverter; +import org.springframework.data.r2dbc.function.convert.R2dbcConverters.RowToNumberConverterFactory.RowToZonedDateTimeConverter; +import org.springframework.util.Assert; +import org.springframework.util.NumberUtils; + +/** + * Wrapper class to contain useful converters for the usage with R2DBC. + * + * @author Hebert Coelho + * @author Mark Paluch + */ +abstract class R2dbcConverters { + + private R2dbcConverters() {} + + /** + * @return A list of the registered converters + */ + public static Collection getConvertersToRegister() { + + List converters = new ArrayList<>(); + + converters.add(RowToBooleanConverter.INSTANCE); + converters.add(RowToNumberConverterFactory.INSTANCE); + converters.add(RowToLocalDateConverter.INSTANCE); + converters.add(RowToLocalDateTimeConverter.INSTANCE); + converters.add(RowToLocalTimeConverter.INSTANCE); + converters.add(RowToOffsetDateTimeConverter.INSTANCE); + converters.add(RowToStringConverter.INSTANCE); + converters.add(RowToUuidConverter.INSTANCE); + converters.add(RowToZonedDateTimeConverter.INSTANCE); + + return converters; + } + + /** + * Simple singleton to convert {@link Row}s to their {@link Boolean} representation. + * + * @author Hebert Coelho + */ + public enum RowToBooleanConverter implements Converter { + + INSTANCE; + + @Override + public Boolean convert(Row row) { + return row.get(0, Boolean.class); + } + } + + /** + * Simple singleton to convert {@link Row}s to their {@link LocalDate} representation. + * + * @author Hebert Coelho + */ + public enum RowToLocalDateConverter implements Converter { + + INSTANCE; + + @Override + public LocalDate convert(Row row) { + return row.get(0, LocalDate.class); + } + } + + /** + * Simple singleton to convert {@link Row}s to their {@link LocalDateTime} representation. + * + * @author Hebert Coelho + */ + public enum RowToLocalDateTimeConverter implements Converter { + + INSTANCE; + + @Override + public LocalDateTime convert(Row row) { + return row.get(0, LocalDateTime.class); + } + } + + /** + * Simple singleton to convert {@link Row}s to their {@link LocalTime} representation. + * + * @author Hebert Coelho + */ + public enum RowToLocalTimeConverter implements Converter { + + INSTANCE; + + @Override + public LocalTime convert(Row row) { + return row.get(0, LocalTime.class); + } + } + + /** + * Singleton converter factory to convert the first column of a {@link Row} to a {@link Number}. + *

+ * Support Number classes including Byte, Short, Integer, Float, Double, Long, BigInteger, BigDecimal. This class + * delegates to {@link NumberUtils#convertNumberToTargetClass(Number, Class)} to perform the conversion. + * + * @see Byte + * @see Short + * @see Integer + * @see Long + * @see java.math.BigInteger + * @see Float + * @see Double + * @see java.math.BigDecimal + * @author Hebert Coelho + */ + public enum RowToNumberConverterFactory implements ConverterFactory { + + INSTANCE; + + @Override + public Converter getConverter(Class targetType) { + Assert.notNull(targetType, "Target type must not be null"); + return new RowToNumber<>(targetType); + } + + static class RowToNumber implements Converter { + + private final Class targetType; + + RowToNumber(Class targetType) { + this.targetType = targetType; + } + + @Override + public T convert(Row source) { + + Object object = source.get(0, targetType); + + return (object != null ? NumberUtils.convertNumberToTargetClass((Number) object, this.targetType) : null); + } + } + + /** + * Simple singleton to convert {@link Row}s to their {@link OffsetDateTime} representation. + * + * @author Hebert Coelho + */ + public enum RowToOffsetDateTimeConverter implements Converter { + + INSTANCE; + + @Override + public OffsetDateTime convert(Row row) { + return row.get(0, OffsetDateTime.class); + } + } + + /** + * Simple singleton to convert {@link Row}s to their {@link String} representation. + * + * @author Hebert Coelho + */ + public enum RowToStringConverter implements Converter { + + INSTANCE; + + @Override + public String convert(Row row) { + return row.get(0, String.class); + } + } + + /** + * Simple singleton to convert {@link Row}s to their {@link UUID} representation. + * + * @author Hebert Coelho + */ + public enum RowToUuidConverter implements Converter { + + INSTANCE; + + @Override + public UUID convert(Row row) { + return row.get(0, UUID.class); + } + } + + /** + * Simple singleton to convert {@link Row}s to their {@link ZonedDateTime} representation. + * + * @author Hebert Coelho + */ + public enum RowToZonedDateTimeConverter implements Converter { + + INSTANCE; + + @Override + public ZonedDateTime convert(Row row) { + return row.get(0, ZonedDateTime.class); + } + } + } +} diff --git a/src/main/java/org/springframework/data/r2dbc/function/convert/R2dbcCustomConversions.java b/src/main/java/org/springframework/data/r2dbc/function/convert/R2dbcCustomConversions.java index 8c3a692..da6be5f 100644 --- a/src/main/java/org/springframework/data/r2dbc/function/convert/R2dbcCustomConversions.java +++ b/src/main/java/org/springframework/data/r2dbc/function/convert/R2dbcCustomConversions.java @@ -1,8 +1,13 @@ package org.springframework.data.r2dbc.function.convert; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.List; import org.springframework.data.convert.CustomConversions; +import org.springframework.data.convert.JodaTimeConverters; +import org.springframework.data.r2dbc.dialect.R2dbcSimpleTypeHolder; /** * Value object to capture custom conversion. {@link R2dbcCustomConversions} also act as factory for @@ -14,8 +19,32 @@ import org.springframework.data.convert.CustomConversions; */ public class R2dbcCustomConversions extends CustomConversions { + public static final List STORE_CONVERTERS; + + private static final StoreConversions STORE_CONVERSIONS; + + static { + + List converters = new ArrayList<>(); + + converters.addAll(R2dbcConverters.getConvertersToRegister()); + converters.addAll(JodaTimeConverters.getConvertersToRegister()); + + STORE_CONVERTERS = Collections.unmodifiableList(converters); + STORE_CONVERSIONS = StoreConversions.of(R2dbcSimpleTypeHolder.HOLDER, STORE_CONVERTERS); + } + /** - * Creates a new {@link CustomConversions} instance registering the given converters. + * Creates a new {@link R2dbcCustomConversions} instance registering the given converters. + * + * @param converters must not be {@literal null}. + */ + public R2dbcCustomConversions(Collection converters) { + super(STORE_CONVERSIONS, converters); + } + + /** + * Creates a new {@link R2dbcCustomConversions} instance registering the given converters. * * @param storeConversions must not be {@literal null}. * @param converters must not be {@literal null}. diff --git a/src/main/java/org/springframework/data/r2dbc/repository/query/RowDataConverter.java b/src/main/java/org/springframework/data/r2dbc/repository/query/RowDataConverter.java deleted file mode 100644 index 2b3c8aa..0000000 --- a/src/main/java/org/springframework/data/r2dbc/repository/query/RowDataConverter.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright 2019 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 - * - * http://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 io.r2dbc.spi.Row; -import org.springframework.core.convert.converter.Converter; -import org.springframework.core.convert.converter.ConverterFactory; -import org.springframework.data.r2dbc.repository.query.RowDataConverter.RowToNumberConverterFactory.RowToOffsetDateTimeConverter; -import org.springframework.data.r2dbc.repository.query.RowDataConverter.RowToNumberConverterFactory.RowToStringConverter; -import org.springframework.data.r2dbc.repository.query.RowDataConverter.RowToNumberConverterFactory.RowToUuidConverter; -import org.springframework.data.r2dbc.repository.query.RowDataConverter.RowToNumberConverterFactory.RowToZonedDateTimeConverter; -import org.springframework.util.Assert; -import org.springframework.util.NumberUtils; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.UUID; - -/** - * Base class for row data converter. - * - * @author Hebert Coelho - */ -abstract class RowDataConverter { - private RowDataConverter() { - } - - /** - * @return A list of the registered converters - */ - static Collection getConvertersToRegister() { - List converters = new ArrayList<>(); - - converters.add(RowToBooleanConverter.INSTANCE); - converters.add(RowToLocalDateConverter.INSTANCE); - converters.add(RowToLocalDateTimeConverter.INSTANCE); - converters.add(RowToLocalTimeConverter.INSTANCE); - converters.add(RowToOffsetDateTimeConverter.INSTANCE); - converters.add(RowToStringConverter.INSTANCE); - converters.add(RowToUuidConverter.INSTANCE); - converters.add(RowToZonedDateTimeConverter.INSTANCE); - - return converters; - } - - /** - * Simple singleton to convert {@link Row}s to their {@link Boolean} representation. - * - * @author Hebert Coelho - */ - public enum RowToBooleanConverter implements Converter { - INSTANCE; - - @Override - public Boolean convert(Row row) { - return row.get(0, Boolean.class); - } - } - - /** - * Simple singleton to convert {@link Row}s to their {@link LocalDate} representation. - * - * @author Hebert Coelho - */ - public enum RowToLocalDateConverter implements Converter { - INSTANCE; - - @Override - public LocalDate convert(Row row) { - return row.get(0, LocalDate.class); - } - } - - /** - * Simple singleton to convert {@link Row}s to their {@link LocalDateTime} representation. - * - * @author Hebert Coelho - */ - public enum RowToLocalDateTimeConverter implements Converter { - INSTANCE; - - @Override - public LocalDateTime convert(Row row) { - return row.get(0, LocalDateTime.class); - } - } - - /** - * Simple singleton to convert {@link Row}s to their {@link LocalTime} representation. - * - * @author Hebert Coelho - */ - public enum RowToLocalTimeConverter implements Converter { - INSTANCE; - - @Override - public LocalTime convert(Row row) { - return row.get(0, LocalTime.class); - } - } - - /** - * Singleton converter factory to convert the first column of a {@link Row} to a {@link Number}. - *

- * Support Number classes including Byte, Short, Integer, Float, Double, Long, BigInteger, BigDecimal. This class - * delegates to {@link NumberUtils#convertNumberToTargetClass(Number, Class)} to perform the conversion. - * - * @see Byte - * @see Short - * @see Integer - * @see Long - * @see java.math.BigInteger - * @see Float - * @see Double - * @see java.math.BigDecimal - * - * @author Hebert Coelho - */ - public enum RowToNumberConverterFactory implements ConverterFactory { - INSTANCE; - - @Override - public Converter getConverter(Class targetType) { - Assert.notNull(targetType, "Target type must not be null"); - return new RowToNumber<>(targetType); - } - - private static final class RowToNumber implements Converter { - private final Class targetType; - - RowToNumber(Class targetType) { - this.targetType = targetType; - } - - @Override - public T convert(Row source) { - - Object object = source.get(0, targetType); - - return (object != null ? NumberUtils.convertNumberToTargetClass((Number) object, this.targetType) : null); - } - } - - /** - * Simple singleton to convert {@link Row}s to their {@link OffsetDateTime} representation. - * - * @author Hebert Coelho - */ - public enum RowToOffsetDateTimeConverter implements Converter { - INSTANCE; - - @Override - public OffsetDateTime convert(Row row) { - return row.get(0, OffsetDateTime.class); - } - } - - /** - * Simple singleton to convert {@link Row}s to their {@link String} representation. - * - * @author Hebert Coelho - */ - public enum RowToStringConverter implements Converter { - INSTANCE; - - @Override - public String convert(Row row) { - return row.get(0, String.class); - } - } - - /** - * Simple singleton to convert {@link Row}s to their {@link UUID} representation. - * - * @author Hebert Coelho - */ - public enum RowToUuidConverter implements Converter { - INSTANCE; - - @Override - public UUID convert(Row row) { - return row.get(0, UUID.class); - } - } - - /** - * Simple singleton to convert {@link Row}s to their {@link ZonedDateTime} representation. - * - * @author Hebert Coelho - */ - public enum RowToZonedDateTimeConverter implements Converter { - INSTANCE; - - @Override - public ZonedDateTime convert(Row row) { - return row.get(0, ZonedDateTime.class); - } - } - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/function/convert/MappingR2dbcConverterUnitTests.java b/src/test/java/org/springframework/data/r2dbc/function/convert/MappingR2dbcConverterUnitTests.java index dbc9e4e..9fcbe4c 100644 --- a/src/test/java/org/springframework/data/r2dbc/function/convert/MappingR2dbcConverterUnitTests.java +++ b/src/test/java/org/springframework/data/r2dbc/function/convert/MappingR2dbcConverterUnitTests.java @@ -16,7 +16,9 @@ package org.springframework.data.r2dbc.function.convert; import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; +import io.r2dbc.spi.Row; import lombok.AllArgsConstructor; import org.junit.Test; @@ -45,6 +47,27 @@ public class MappingR2dbcConverterUnitTests { assertThat(row).containsEntry("lastname", new SettableValue("White", String.class)); } + @Test // gh-41 + public void shouldPassThroughRow() { + + Row rowMock = mock(Row.class); + + Row result = converter.read(Row.class, rowMock); + + assertThat(result).isSameAs(rowMock); + } + + @Test // gh-41 + public void shouldConvertRowToNumber() { + + Row rowMock = mock(Row.class); + when(rowMock.get(0, Integer.class)).thenReturn(42); + + Integer result = converter.read(Integer.class, rowMock); + + assertThat(result).isEqualTo(42); + } + @AllArgsConstructor static class Person { @Id String id; diff --git a/src/test/java/org/springframework/data/r2dbc/function/convert/R2dbcConvertersUnitTests.java b/src/test/java/org/springframework/data/r2dbc/function/convert/R2dbcConvertersUnitTests.java new file mode 100644 index 0000000..bbbf931 --- /dev/null +++ b/src/test/java/org/springframework/data/r2dbc/function/convert/R2dbcConvertersUnitTests.java @@ -0,0 +1,150 @@ +/* + * Copyright 2019 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 + * + * http://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.function.convert; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import io.r2dbc.spi.Row; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; +import java.util.UUID; + +import org.junit.Test; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.r2dbc.function.convert.R2dbcConverters.RowToBooleanConverter; +import org.springframework.data.r2dbc.function.convert.R2dbcConverters.RowToLocalDateConverter; +import org.springframework.data.r2dbc.function.convert.R2dbcConverters.RowToLocalDateTimeConverter; +import org.springframework.data.r2dbc.function.convert.R2dbcConverters.RowToLocalTimeConverter; +import org.springframework.data.r2dbc.function.convert.R2dbcConverters.RowToNumberConverterFactory; +import org.springframework.data.r2dbc.function.convert.R2dbcConverters.RowToNumberConverterFactory.RowToOffsetDateTimeConverter; +import org.springframework.data.r2dbc.function.convert.R2dbcConverters.RowToNumberConverterFactory.RowToStringConverter; +import org.springframework.data.r2dbc.function.convert.R2dbcConverters.RowToNumberConverterFactory.RowToUuidConverter; +import org.springframework.data.r2dbc.function.convert.R2dbcConverters.RowToNumberConverterFactory.RowToZonedDateTimeConverter; + +/** + * Unit tests for {@link R2dbcConverters}. + * + * @author Hebert Coelho + * @author Mark Paluch + */ +public class R2dbcConvertersUnitTests { + + @Test // gh-41 + public void isReturningAllCreatedConverts() { + assertThat(R2dbcConverters.getConvertersToRegister()).hasSize(9); + } + + @Test // gh-41 + public void isConvertingBoolean() { + + Row row = mock(Row.class); + when(row.get(0, Boolean.class)).thenReturn(true); + + assertThat(RowToBooleanConverter.INSTANCE.convert(row)).isTrue(); + } + + @Test // gh-41 + public void isConvertingLocalDate() { + + LocalDate now = LocalDate.now(); + Row row = mock(Row.class); + when(row.get(0, LocalDate.class)).thenReturn(now); + + assertThat(RowToLocalDateConverter.INSTANCE.convert(row)).isEqualTo(now); + } + + @Test // gh-41 + public void isConvertingLocalDateTime() { + + LocalDateTime now = LocalDateTime.now(); + Row row = mock(Row.class); + when(row.get(0, LocalDateTime.class)).thenReturn(now); + + assertThat(RowToLocalDateTimeConverter.INSTANCE.convert(row)).isEqualTo(now); + } + + @Test // gh-41 + public void isConvertingLocalTime() { + + LocalTime now = LocalTime.now(); + Row row = mock(Row.class); + when(row.get(0, LocalTime.class)).thenReturn(now); + + assertThat(RowToLocalTimeConverter.INSTANCE.convert(row)).isEqualTo(now); + } + + @Test // gh-41 + public void isConvertingOffsetDateTime() { + + OffsetDateTime now = OffsetDateTime.now(); + Row row = mock(Row.class); + when(row.get(0, OffsetDateTime.class)).thenReturn(now); + + assertThat(RowToOffsetDateTimeConverter.INSTANCE.convert(row)).isEqualTo(now); + } + + @Test // gh-41 + public void isConvertingString() { + + String value = "aValue"; + Row row = mock(Row.class); + when(row.get(0, String.class)).thenReturn(value); + + assertThat(RowToStringConverter.INSTANCE.convert(row)).isEqualTo(value); + } + + @Test // gh-41 + public void isConvertingUUID() { + + UUID value = UUID.randomUUID(); + Row row = mock(Row.class); + when(row.get(0, UUID.class)).thenReturn(value); + + assertThat(RowToUuidConverter.INSTANCE.convert(row)).isEqualTo(value); + } + + @Test // gh-41 + public void isConvertingZonedDateTime() { + + ZonedDateTime now = ZonedDateTime.now(); + Row row = mock(Row.class); + when(row.get(0, ZonedDateTime.class)).thenReturn(now); + + assertThat(RowToZonedDateTimeConverter.INSTANCE.convert(row)).isEqualTo(now); + } + + @Test // gh-41 + public void isConvertingNumber() { + + Row row = mock(Row.class); + when(row.get(0, Integer.class)).thenReturn(33); + + final Converter converter = RowToNumberConverterFactory.INSTANCE.getConverter(Integer.class); + + assertThat(converter.convert(row)).isEqualTo(33); + } + + @Test // gh-41 + public void isRaisingExceptionForInvalidNumber() { + assertThatIllegalArgumentException().isThrownBy(() -> RowToNumberConverterFactory.INSTANCE.getConverter(null)); + } +} diff --git a/src/test/java/org/springframework/data/r2dbc/repository/AbstractR2dbcRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/repository/AbstractR2dbcRepositoryIntegrationTests.java index 7f92d93..6e88035 100644 --- a/src/test/java/org/springframework/data/r2dbc/repository/AbstractR2dbcRepositoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/r2dbc/repository/AbstractR2dbcRepositoryIntegrationTests.java @@ -157,6 +157,19 @@ public abstract class AbstractR2dbcRepositoryIntegrationTests extends R2dbcInteg }).verifyComplete(); } + @Test // gh-41 + public void shouldFindApplyingSimpleTypeProjection() { + + shouldInsertNewItems(); + + repository.findAllIds() // + .collectList() // + .as(StepVerifier::create) // + .consumeNextWith(actual -> { + assertThat(actual).hasSize(2).allMatch(Integer.class::isInstance); + }).verifyComplete(); + } + @Test public void shouldInsertItemsTransactional() { @@ -196,6 +209,8 @@ public abstract class AbstractR2dbcRepositoryIntegrationTests extends R2dbcInteg Flux findAsProjection(); Mono findByManual(int manual); + + Flux findAllIds(); } @Data diff --git a/src/test/java/org/springframework/data/r2dbc/repository/PostgresR2dbcRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/repository/PostgresR2dbcRepositoryIntegrationTests.java index 37ec7fc..626cb40 100644 --- a/src/test/java/org/springframework/data/r2dbc/repository/PostgresR2dbcRepositoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/r2dbc/repository/PostgresR2dbcRepositoryIntegrationTests.java @@ -23,6 +23,7 @@ import javax.sql.DataSource; import org.junit.ClassRule; import org.junit.runner.RunWith; + import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; @@ -90,5 +91,9 @@ public class PostgresR2dbcRepositoryIntegrationTests extends AbstractR2dbcReposi @Override @Query("SELECT * FROM legoset WHERE manual = :manual") Mono findByManual(int manual); + + @Override + @Query("SELECT id FROM legoset") + Flux findAllIds(); } } diff --git a/src/test/java/org/springframework/data/r2dbc/repository/SqlServerR2dbcRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/repository/SqlServerR2dbcRepositoryIntegrationTests.java index 7a53754..8661d9f 100644 --- a/src/test/java/org/springframework/data/r2dbc/repository/SqlServerR2dbcRepositoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/r2dbc/repository/SqlServerR2dbcRepositoryIntegrationTests.java @@ -24,6 +24,7 @@ import javax.sql.DataSource; import org.junit.ClassRule; import org.junit.Ignore; import org.junit.runner.RunWith; + import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; @@ -95,5 +96,9 @@ public class SqlServerR2dbcRepositoryIntegrationTests extends AbstractR2dbcRepos @Override @Query("SELECT * FROM legoset WHERE manual = :manual") Mono findByManual(int manual); + + @Override + @Query("SELECT id FROM legoset") + Flux findAllIds(); } } diff --git a/src/test/java/org/springframework/data/r2dbc/repository/query/RowDataConverterTests.java b/src/test/java/org/springframework/data/r2dbc/repository/query/RowDataConverterTests.java deleted file mode 100644 index 413553c..0000000 --- a/src/test/java/org/springframework/data/r2dbc/repository/query/RowDataConverterTests.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.springframework.data.r2dbc.repository.query; - -import io.r2dbc.spi.Row; -import org.junit.Test; -import org.springframework.core.convert.converter.Converter; -import org.springframework.data.r2dbc.repository.query.RowDataConverter.RowToBooleanConverter; -import org.springframework.data.r2dbc.repository.query.RowDataConverter.RowToLocalDateConverter; -import org.springframework.data.r2dbc.repository.query.RowDataConverter.RowToLocalDateTimeConverter; -import org.springframework.data.r2dbc.repository.query.RowDataConverter.RowToLocalTimeConverter; -import org.springframework.data.r2dbc.repository.query.RowDataConverter.RowToNumberConverterFactory; -import org.springframework.data.r2dbc.repository.query.RowDataConverter.RowToNumberConverterFactory.RowToOffsetDateTimeConverter; -import org.springframework.data.r2dbc.repository.query.RowDataConverter.RowToNumberConverterFactory.RowToStringConverter; -import org.springframework.data.r2dbc.repository.query.RowDataConverter.RowToNumberConverterFactory.RowToUuidConverter; -import org.springframework.data.r2dbc.repository.query.RowDataConverter.RowToNumberConverterFactory.RowToZonedDateTimeConverter; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.ZonedDateTime; -import java.util.UUID; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class RowDataConverterTests { - private static final int TOTAL_REGISTERED_CONVERTERS = 8; - - @Test - public void isReturningAllCreatedConverts() { - assertThat(RowDataConverter.getConvertersToRegister().size()) - .isEqualTo(TOTAL_REGISTERED_CONVERTERS); - } - - @Test - public void isConvertingBoolean() { - Row row = mock(Row.class); - when(row.get(0, Boolean.class)).thenReturn(true); - - assertTrue(RowToBooleanConverter.INSTANCE.convert(row)); - } - - @Test - public void isConvertingLocalDate() { - LocalDate now = LocalDate.now(); - Row row = mock(Row.class); - when(row.get(0, LocalDate.class)).thenReturn(now); - - assertThat(RowToLocalDateConverter.INSTANCE.convert(row)).isEqualTo(now); - } - - @Test - public void isConvertingLocalDateTime() { - LocalDateTime now = LocalDateTime.now(); - Row row = mock(Row.class); - when(row.get(0, LocalDateTime.class)).thenReturn(now); - - assertThat(RowToLocalDateTimeConverter.INSTANCE.convert(row)).isEqualTo(now); - } - - @Test - public void isConvertingLocalTime() { - LocalTime now = LocalTime.now(); - Row row = mock(Row.class); - when(row.get(0, LocalTime.class)).thenReturn(now); - - assertThat(RowToLocalTimeConverter.INSTANCE.convert(row)).isEqualTo(now); - } - - @Test - public void isConvertingOffsetDateTime() { - OffsetDateTime now = OffsetDateTime.now(); - Row row = mock(Row.class); - when(row.get(0, OffsetDateTime.class)).thenReturn(now); - - assertThat(RowToOffsetDateTimeConverter.INSTANCE.convert(row)).isEqualTo(now); - } - - @Test - public void isConvertingString() { - String value = "aValue"; - Row row = mock(Row.class); - when(row.get(0, String.class)).thenReturn(value); - - assertThat(RowToStringConverter.INSTANCE.convert(row)).isEqualTo(value); - } - - @Test - public void isConvertingUUID() { - UUID value = UUID.randomUUID(); - Row row = mock(Row.class); - when(row.get(0, UUID.class)).thenReturn(value); - - assertThat(RowToUuidConverter.INSTANCE.convert(row)).isEqualTo(value); - } - - @Test - public void isConvertingZonedDateTime() { - ZonedDateTime now = ZonedDateTime.now(); - Row row = mock(Row.class); - when(row.get(0, ZonedDateTime.class)).thenReturn(now); - - assertThat(RowToZonedDateTimeConverter.INSTANCE.convert(row)).isEqualTo(now); - } - - @Test - public void isConvertingNumber() { - Row row = mock(Row.class); - when(row.get(0, Integer.class)).thenReturn(33); - - final Converter converter = RowToNumberConverterFactory.INSTANCE.getConverter(Integer.class); - - assertThat(converter.convert(row)).isEqualTo(33); - } - - @Test - public void isRaisingExceptionForInvalidNumber() { - assertThatIllegalArgumentException().isThrownBy( - () -> RowToNumberConverterFactory.INSTANCE.getConverter(null) - ); - } -}