#30 - Address review feedback.
Introduce ArrayColumns type to encapsulate Dialect-specific array support. Apply array conversion for properties that do not match the native array type. Add integration tests for Postgres array columns. Original pull request: #31.
This commit is contained in:
committed by
Jens Schauder
parent
be5383abed
commit
9f68352ac7
@@ -1,8 +1,8 @@
|
||||
package org.springframework.data.r2dbc.dialect;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.api.SoftAssertions.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -28,35 +28,50 @@ public class PostgresDialectUnitTests {
|
||||
}
|
||||
|
||||
@Test // gh-30
|
||||
public void shouldConsiderCollectionTypesAsSimple() {
|
||||
public void shouldConsiderSimpleTypes() {
|
||||
|
||||
SimpleTypeHolder holder = PostgresDialect.INSTANCE.getSimpleTypeHolder();
|
||||
|
||||
assertThat(holder.isSimpleType(List.class)).isTrue();
|
||||
assertThat(holder.isSimpleType(Collection.class)).isTrue();
|
||||
assertSoftly(it -> {
|
||||
it.assertThat(holder.isSimpleType(String.class)).isTrue();
|
||||
it.assertThat(holder.isSimpleType(int.class)).isTrue();
|
||||
it.assertThat(holder.isSimpleType(Integer.class)).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test // gh-30
|
||||
public void shouldConsiderStringArrayTypeAsSimple() {
|
||||
public void shouldSupportArrays() {
|
||||
|
||||
SimpleTypeHolder holder = PostgresDialect.INSTANCE.getSimpleTypeHolder();
|
||||
ArrayColumns arrayColumns = PostgresDialect.INSTANCE.getArraySupport();
|
||||
|
||||
assertThat(holder.isSimpleType(String[].class)).isTrue();
|
||||
assertThat(arrayColumns.isSupported()).isTrue();
|
||||
}
|
||||
|
||||
@Test // gh-30
|
||||
public void shouldConsiderIntArrayTypeAsSimple() {
|
||||
@Test // gh-30
|
||||
public void shouldUseBoxedArrayTypesForPrimitiveTypes() {
|
||||
|
||||
SimpleTypeHolder holder = PostgresDialect.INSTANCE.getSimpleTypeHolder();
|
||||
ArrayColumns arrayColumns = PostgresDialect.INSTANCE.getArraySupport();
|
||||
|
||||
assertThat(holder.isSimpleType(int[].class)).isTrue();
|
||||
}
|
||||
assertSoftly(it -> {
|
||||
it.assertThat(arrayColumns.getArrayType(int.class)).isEqualTo(Integer.class);
|
||||
it.assertThat(arrayColumns.getArrayType(double.class)).isEqualTo(Double.class);
|
||||
it.assertThat(arrayColumns.getArrayType(String.class)).isEqualTo(String.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // gh-30
|
||||
public void shouldConsiderIntegerArrayTypeAsSimple() {
|
||||
@Test // gh-30
|
||||
public void shouldRejectNonSimpleArrayTypes() {
|
||||
|
||||
SimpleTypeHolder holder = PostgresDialect.INSTANCE.getSimpleTypeHolder();
|
||||
ArrayColumns arrayColumns = PostgresDialect.INSTANCE.getArraySupport();
|
||||
|
||||
assertThat(holder.isSimpleType(Integer[].class)).isTrue();
|
||||
}
|
||||
assertThatThrownBy(() -> arrayColumns.getArrayType(getClass())).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test // gh-30
|
||||
public void shouldRejectNestedCollections() {
|
||||
|
||||
ArrayColumns arrayColumns = PostgresDialect.INSTANCE.getArraySupport();
|
||||
|
||||
assertThatThrownBy(() -> arrayColumns.getArrayType(List.class)).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,4 +33,13 @@ public class SqlServerDialectUnitTests {
|
||||
|
||||
assertThat(holder.isSimpleType(UUID.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test // gh-30
|
||||
public void shouldNotSupportArrays() {
|
||||
|
||||
ArrayColumns arrayColumns = SqlServerDialect.INSTANCE.getArraySupport();
|
||||
|
||||
assertThat(arrayColumns.isSupported()).isFalse();
|
||||
assertThatThrownBy(() -> arrayColumns.getArrayType(String.class)).isInstanceOf(UnsupportedOperationException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2018 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;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import lombok.AllArgsConstructor;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.r2dbc.testing.ExternalDatabase;
|
||||
import org.springframework.data.r2dbc.testing.PostgresTestSupport;
|
||||
import org.springframework.data.r2dbc.testing.R2dbcIntegrationTestSupport;
|
||||
import org.springframework.data.relational.core.mapping.Table;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/**
|
||||
* Integration tests for PostgreSQL-specific features such as array support.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class PostgresIntegrationTests extends R2dbcIntegrationTestSupport {
|
||||
|
||||
@ClassRule public static final ExternalDatabase database = PostgresTestSupport.database();
|
||||
|
||||
DataSource dataSource = PostgresTestSupport.createDataSource(database);
|
||||
ConnectionFactory connectionFactory = PostgresTestSupport.createConnectionFactory(database);
|
||||
JdbcTemplate template = createJdbcTemplate(dataSource);
|
||||
DatabaseClient client = DatabaseClient.create(connectionFactory);
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
|
||||
template.execute("DROP TABLE IF EXISTS with_arrays");
|
||||
template.execute("CREATE TABLE with_arrays (" //
|
||||
+ "boxed_array INT[]," //
|
||||
+ "primitive_array INT[]," //
|
||||
+ "multidimensional_array INT[]," //
|
||||
+ "collection_array INT[][])");
|
||||
}
|
||||
|
||||
@Test // gh-30
|
||||
@Ignore("https://github.com/r2dbc/r2dbc-postgresql/issues/40, r2dbc-postgresql returns Object[] instead of Integer[]")
|
||||
public void shouldReadAndWritePrimitiveSingleDimensionArrays() {
|
||||
|
||||
EntityWithArrays withArrays = new EntityWithArrays(null, new int[] { 1, 2, 3 }, null, null);
|
||||
|
||||
insert(withArrays);
|
||||
selectAndAssert(actual -> {
|
||||
assertThat(actual.primitiveArray).containsExactly(1, 2, 3);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // gh-30
|
||||
public void shouldReadAndWriteBoxedSingleDimensionArrays() {
|
||||
|
||||
EntityWithArrays withArrays = new EntityWithArrays(new Integer[] { 1, 2, 3 }, null, null, null);
|
||||
|
||||
insert(withArrays);
|
||||
|
||||
selectAndAssert(actual -> {
|
||||
|
||||
assertThat(actual.boxedArray).containsExactly(1, 2, 3);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Test // gh-30
|
||||
public void shouldReadAndWriteConvertedDimensionArrays() {
|
||||
|
||||
EntityWithArrays withArrays = new EntityWithArrays(null, null, null, Arrays.asList(5, 6, 7));
|
||||
|
||||
insert(withArrays);
|
||||
|
||||
selectAndAssert(actual -> {
|
||||
assertThat(actual.collectionArray).containsExactly(5, 6, 7);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // gh-30
|
||||
@Ignore("https://github.com/r2dbc/r2dbc-postgresql/issues/42, Multi-dimensional arrays not supported yet")
|
||||
public void shouldReadAndWriteMultiDimensionArrays() {
|
||||
|
||||
EntityWithArrays withArrays = new EntityWithArrays(null, null, new int[][] { { 1, 2, 3 }, { 4, 5 } }, null);
|
||||
|
||||
insert(withArrays);
|
||||
|
||||
selectAndAssert(actual -> {
|
||||
|
||||
assertThat(actual.multidimensionalArray).hasSize(2);
|
||||
assertThat(actual.multidimensionalArray[0]).containsExactly(1, 2, 3);
|
||||
assertThat(actual.multidimensionalArray[1]).containsExactly(4, 5, 6);
|
||||
});
|
||||
}
|
||||
|
||||
private void insert(EntityWithArrays object) {
|
||||
|
||||
client.insert() //
|
||||
.into(EntityWithArrays.class) //
|
||||
.using(object) //
|
||||
.then() //
|
||||
.as(StepVerifier::create) //
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
private void selectAndAssert(Consumer<? super EntityWithArrays> assertion) {
|
||||
|
||||
client.select() //
|
||||
.from(EntityWithArrays.class).fetch() //
|
||||
.first() //
|
||||
.as(StepVerifier::create) //
|
||||
.consumeNextWith(assertion).verifyComplete();
|
||||
}
|
||||
|
||||
@Table("with_arrays")
|
||||
@AllArgsConstructor
|
||||
static class EntityWithArrays {
|
||||
|
||||
Integer[] boxedArray;
|
||||
int[] primitiveArray;
|
||||
int[][] multidimensionalArray;
|
||||
List<Integer> collectionArray;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import io.r2dbc.spi.RowMetadata;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -20,6 +21,7 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentEnti
|
||||
* Unit tests for {@link EntityRowMapper}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class EntityRowMapperUnitTests {
|
||||
@@ -73,7 +75,7 @@ public class EntityRowMapperUnitTests {
|
||||
public void shouldConvertArrayToSet() {
|
||||
|
||||
EntityRowMapper<EntityWithCollection> mapper = getRowMapper(EntityWithCollection.class);
|
||||
when(rowMock.get("integerSet")).thenReturn((new int[] { 3, 14 }));
|
||||
when(rowMock.get("integer_set")).thenReturn((new int[] { 3, 14 }));
|
||||
|
||||
EntityWithCollection result = mapper.apply(rowMock, metadata);
|
||||
assertThat(result.integerSet).contains(3, 14);
|
||||
@@ -83,7 +85,7 @@ public class EntityRowMapperUnitTests {
|
||||
public void shouldConvertArrayMembers() {
|
||||
|
||||
EntityRowMapper<EntityWithCollection> mapper = getRowMapper(EntityWithCollection.class);
|
||||
when(rowMock.get("primitiveIntegers")).thenReturn((new long[] { 3L, 14L }));
|
||||
when(rowMock.get("primitive_integers")).thenReturn((new Long[] { 3L, 14L }));
|
||||
|
||||
EntityWithCollection result = mapper.apply(rowMock, metadata);
|
||||
assertThat(result.primitiveIntegers).contains(3, 14);
|
||||
@@ -93,11 +95,12 @@ public class EntityRowMapperUnitTests {
|
||||
public void shouldConvertArrayToBoxedArray() {
|
||||
|
||||
EntityRowMapper<EntityWithCollection> mapper = getRowMapper(EntityWithCollection.class);
|
||||
when(rowMock.get("boxedIntegers")).thenReturn((new int[] { 3, 11 }));
|
||||
when(rowMock.get("boxed_integers")).thenReturn((new int[] { 3, 11 }));
|
||||
|
||||
EntityWithCollection result = mapper.apply(rowMock, metadata);
|
||||
assertThat(result.boxedIntegers).contains(3, 11);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> EntityRowMapper<T> getRowMapper(Class<T> type) {
|
||||
RelationalPersistentEntity<T> entity = (RelationalPersistentEntity<T>) strategy.getMappingContext()
|
||||
|
||||
Reference in New Issue
Block a user