Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-r2dbc</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<version>1.0.0.gh-30-SNAPSHOT</version>

<name>Spring Data R2DBC</name>
<description>Spring Data module for R2DBC.</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,20 @@

import io.r2dbc.spi.ConnectionFactory;

import java.util.Collections;
import java.util.Optional;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.convert.CustomConversions.StoreConversions;
import org.springframework.data.r2dbc.dialect.Database;
import org.springframework.data.r2dbc.dialect.Dialect;
import org.springframework.data.r2dbc.function.DatabaseClient;
import org.springframework.data.r2dbc.function.DefaultReactiveDataAccessStrategy;
import org.springframework.data.r2dbc.function.ReactiveDataAccessStrategy;
import org.springframework.data.r2dbc.function.convert.R2dbcCustomConversions;
import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator;
import org.springframework.data.r2dbc.support.SqlErrorCodeR2dbcExceptionTranslator;
import org.springframework.data.relational.core.conversion.BasicRelationalConverter;
Expand Down Expand Up @@ -95,33 +100,59 @@ public DatabaseClient databaseClient(ReactiveDataAccessStrategy dataAccessStrate
* Register a {@link RelationalMappingContext} and apply an optional {@link NamingStrategy}.
*
* @param namingStrategy optional {@link NamingStrategy}. Use {@link NamingStrategy#INSTANCE} as fallback.
* @param r2dbcCustomConversions customized R2DBC conversions.
* @return must not be {@literal null}.
* @throws IllegalArgumentException if any of the required args is {@literal null}.
*/
@Bean
public RelationalMappingContext r2dbcMappingContext(Optional<NamingStrategy> namingStrategy) {
public RelationalMappingContext r2dbcMappingContext(Optional<NamingStrategy> namingStrategy,
R2dbcCustomConversions r2dbcCustomConversions) {

Assert.notNull(namingStrategy, "NamingStrategy must not be null!");

return new RelationalMappingContext(namingStrategy.orElse(NamingStrategy.INSTANCE));
RelationalMappingContext relationalMappingContext = new RelationalMappingContext(
namingStrategy.orElse(NamingStrategy.INSTANCE));
relationalMappingContext.setSimpleTypeHolder(r2dbcCustomConversions.getSimpleTypeHolder());

return relationalMappingContext;
}

/**
* Creates a {@link ReactiveDataAccessStrategy} using the configured {@link #r2dbcMappingContext(Optional)
* Creates a {@link ReactiveDataAccessStrategy} using the configured {@link #r2dbcMappingContext(Optional, R2dbcCustomConversions)}
* RelationalMappingContext}.
*
* @param mappingContext the configured {@link RelationalMappingContext}.
* @param r2dbcCustomConversions customized R2DBC conversions.
* @return must not be {@literal null}.
* @see #r2dbcMappingContext(Optional)
* @see #r2dbcMappingContext(Optional, R2dbcCustomConversions)
* @see #getDialect(ConnectionFactory)
* @throws IllegalArgumentException if any of the {@literal mappingContext} is {@literal null}.
*/
@Bean
public ReactiveDataAccessStrategy reactiveDataAccessStrategy(RelationalMappingContext mappingContext) {
public ReactiveDataAccessStrategy reactiveDataAccessStrategy(RelationalMappingContext mappingContext,
R2dbcCustomConversions r2dbcCustomConversions) {

Assert.notNull(mappingContext, "MappingContext must not be null!");
return new DefaultReactiveDataAccessStrategy(getDialect(connectionFactory()),
new BasicRelationalConverter(mappingContext));

BasicRelationalConverter converter = new BasicRelationalConverter(mappingContext, r2dbcCustomConversions);

return new DefaultReactiveDataAccessStrategy(getDialect(connectionFactory()), converter);
}

/**
* Register custom {@link Converter}s in a {@link CustomConversions} object if required. These
* {@link CustomConversions} will be registered with the {@link BasicRelationalConverter} and
* {@link #r2dbcMappingContext(Optional, R2dbcCustomConversions)}. Returns an empty {@link R2dbcCustomConversions}
* instance by default.
*
* @return must not be {@literal null}.
*/
@Bean
public R2dbcCustomConversions r2dbcCustomConversions() {

Dialect dialect = getDialect(connectionFactory());
StoreConversions storeConversions = StoreConversions.of(dialect.getSimpleTypeHolder());
return new R2dbcCustomConversions(storeConversions, Collections.emptyList());
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.springframework.data.r2dbc.dialect;

/**
* Interface declaring methods that express how a dialect supports array-typed columns.
*
* @author Mark Paluch
*/
public interface ArrayColumns {

/**
* Returns {@literal true} if the dialect supports array-typed columns.
*
* @return {@literal true} if the dialect supports array-typed columns.
*/
boolean isSupported();

/**
* Translate the {@link Class user type} of an array into the dialect-specific type. This method considers only the
* component type.
*
* @param userType component type of the array.
* @return the dialect-supported array type.
* @throws UnsupportedOperationException if array typed columns are not supported.
* @throws IllegalArgumentException if the {@code userType} is not a supported array type.
*/
Class<?> getArrayType(Class<?> userType);

/**
* Default {@link ArrayColumns} implementation for dialects that do not support array-typed columns.
*/
enum Unsupported implements ArrayColumns {

INSTANCE;

/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.ArrayColumns#isSupported()
*/
@Override
public boolean isSupported() {
return false;
}

/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.ArrayColumns#getArrayType(java.lang.Class)
*/
@Override
public Class<?> getArrayType(Class<?> userType) {
throw new UnsupportedOperationException("Array types not supported");
}
}
}
37 changes: 37 additions & 0 deletions src/main/java/org/springframework/data/r2dbc/dialect/Dialect.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
package org.springframework.data.r2dbc.dialect;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;

import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.r2dbc.dialect.ArrayColumns.Unsupported;

/**
* Represents a dialect that is implemented by a particular database.
*
Expand All @@ -26,10 +33,40 @@ public interface Dialect {
@Deprecated
String generatedKeysClause();

/**
* Return a collection of types that are natively supported by this database/driver. Defaults to
* {@link Collections#emptySet()}.
*
* @return a collection of types that are natively supported by this database/driver. Defaults to
* {@link Collections#emptySet()}.
*/
default Collection<? extends Class<?>> getSimpleTypes() {
return Collections.emptySet();
}

/**
* Return the {@link SimpleTypeHolder} for this dialect.
*
* @return the {@link SimpleTypeHolder} for this dialect.
* @see #getSimpleTypes()
*/
default SimpleTypeHolder getSimpleTypeHolder() {
return new SimpleTypeHolder(new HashSet<>(getSimpleTypes()), true);
}

/**
* Return the {@link LimitClause} used by this dialect.
*
* @return the {@link LimitClause} used by this dialect.
*/
LimitClause limit();

/**
* Returns the array support object that describes how array-typed columns are supported by this dialect.
*
* @return the array support object that describes how array-typed columns are supported by this dialect.
*/
default ArrayColumns getArraySupport() {
return Unsupported.INSTANCE;
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
package org.springframework.data.r2dbc.dialect;

import lombok.RequiredArgsConstructor;

import java.net.InetAddress;
import java.net.URI;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

/**
* An SQL dialect for Postgres.
*
* @author Mark Paluch
*/
public class PostgresDialect implements Dialect {

private static final Set<Class<?>> SIMPLE_TYPES = new HashSet<>(
Arrays.asList(UUID.class, URL.class, URI.class, InetAddress.class));

/**
* Singleton instance.
*/
Expand Down Expand Up @@ -44,6 +62,8 @@ public Position getClausePosition() {
}
};

private final PostgresArrayColumns ARRAY_COLUMNS = new PostgresArrayColumns(getSimpleTypeHolder());

/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.Dialect#getBindMarkersFactory()
Expand All @@ -62,6 +82,15 @@ public String generatedKeysClause() {
return "RETURNING *";
}

/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.Dialect#getSimpleTypesKeys()
*/
@Override
public Collection<? extends Class<?>> getSimpleTypes() {
return SIMPLE_TYPES;
}

/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.Dialect#limit()
Expand All @@ -70,4 +99,44 @@ public String generatedKeysClause() {
public LimitClause limit() {
return LIMIT_CLAUSE;
}

/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.Dialect#getArraySupport()
*/
@Override
public ArrayColumns getArraySupport() {
return ARRAY_COLUMNS;
}

@RequiredArgsConstructor
static class PostgresArrayColumns implements ArrayColumns {

private final SimpleTypeHolder simpleTypes;

/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.ArrayColumns#isSupported()
*/
@Override
public boolean isSupported() {
return true;
}

/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.ArrayColumns#getArrayType(java.lang.Class)
*/
@Override
public Class<?> getArrayType(Class<?> userType) {

Assert.notNull(userType, "Array component type must not be null");

if (!simpleTypes.isSimpleType(userType)) {
throw new IllegalArgumentException("Unsupported array type: " + ClassUtils.getQualifiedName(userType));
}

return ClassUtils.resolvePrimitiveIfNecessary(userType);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
package org.springframework.data.r2dbc.dialect;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

/**
* An SQL dialect for Microsoft SQL Server.
*
* @author Mark Paluch
*/
public class SqlServerDialect implements Dialect {

private static final Set<Class<?>> SIMPLE_TYPES = new HashSet<>(Collections.singletonList(UUID.class));

/**
* Singleton instance.
*/
Expand Down Expand Up @@ -63,6 +71,15 @@ public String generatedKeysClause() {
return "select SCOPE_IDENTITY() AS GENERATED_KEYS";
}

/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.Dialect#getSimpleTypesKeys()
*/
@Override
public Collection<? extends Class<?>> getSimpleTypes() {
return SIMPLE_TYPES;
}

/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.Dialect#limit()
Expand Down
Loading