diff --git a/pom.xml b/pom.xml index eaee823fa0..83e9e0993e 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ org.springframework.data spring-data-relational-parent - 4.0.0-SNAPSHOT + 4.0.0-1993-force-quoting-SNAPSHOT pom Spring Data Relational Parent diff --git a/spring-data-jdbc-distribution/pom.xml b/spring-data-jdbc-distribution/pom.xml index b3c39e64c3..c0cf7c24a7 100644 --- a/spring-data-jdbc-distribution/pom.xml +++ b/spring-data-jdbc-distribution/pom.xml @@ -14,7 +14,7 @@ org.springframework.data spring-data-relational-parent - 4.0.0-SNAPSHOT + 4.0.0-1993-force-quoting-SNAPSHOT ../pom.xml diff --git a/spring-data-jdbc/pom.xml b/spring-data-jdbc/pom.xml index e61fd64020..753b0846d2 100644 --- a/spring-data-jdbc/pom.xml +++ b/spring-data-jdbc/pom.xml @@ -6,7 +6,7 @@ 4.0.0 spring-data-jdbc - 4.0.0-SNAPSHOT + 4.0.0-1993-force-quoting-SNAPSHOT Spring Data JDBC Spring Data module for JDBC repositories. @@ -15,7 +15,7 @@ org.springframework.data spring-data-relational-parent - 4.0.0-SNAPSHOT + 4.0.0-1993-force-quoting-SNAPSHOT diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/mapping/JdbcMappingContext.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/mapping/JdbcMappingContext.java index deff95518c..a2af75cb5e 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/mapping/JdbcMappingContext.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/mapping/JdbcMappingContext.java @@ -54,6 +54,61 @@ public JdbcMappingContext(NamingStrategy namingStrategy) { setSimpleTypeHolder(JdbcSimpleTypes.HOLDER); } + /** + * Create a new {@code JdbcMappingContext} using {@link #setForceQuote(boolean) plain identifiers}. Plain + * {@link org.springframework.data.relational.core.sql.SqlIdentifier identifiers} (i.e. table and column names) are + * typically not case-sensitive (case-sensitivity can be still enforced by specific database configurations). + * + * @return a new {@code JdbcMappingContext} using plain identifiers. + * @since 4.0 + */ + public static JdbcMappingContext forPlainIdentifiers() { + JdbcMappingContext context = forQuotedIdentifiers(); + context.setForceQuote(false); + return context; + } + + /** + * Create a new {@code JdbcMappingContext} using {@link #setForceQuote(boolean) plain identifiers} and the given + * {@link NamingStrategy}. Plain {@link org.springframework.data.relational.core.sql.SqlIdentifier identifiers} (i.e. + * table and column names) are typically not case-sensitive (case-sensitivity can be still enforced by specific + * database configurations). + * + * @param namingStrategy must not be {@literal null}. + * @return a new {@code JdbcMappingContext} using plain identifiers. + * @since 4.0 + */ + public static JdbcMappingContext forPlainIdentifiers(NamingStrategy namingStrategy) { + JdbcMappingContext context = forQuotedIdentifiers(namingStrategy); + context.setForceQuote(false); + return context; + } + + /** + * Create a new {@code JdbcMappingContext} using {@link #setForceQuote(boolean) quoted identifiers} (default + * behavior). Quoted {@link org.springframework.data.relational.core.sql.SqlIdentifier identifiers} (i.e. table and + * column names) are typically case-sensitive. + * + * @return a new {@code JdbcMappingContext} using quoted identifiers. + * @since 4.0 + */ + public static JdbcMappingContext forQuotedIdentifiers() { + return new JdbcMappingContext(); + } + + /** + * Create a new {@code JdbcMappingContext} using {@link #setForceQuote(boolean) quoted identifiers} (default behavior) + * and the given {@link NamingStrategy}. Quoted {@link org.springframework.data.relational.core.sql.SqlIdentifier + * identifiers} (i.e. table and column names) are typically case-sensitive. + * + * @param namingStrategy must not be {@literal null}. + * @return a new {@code JdbcMappingContext} using quoted identifiers. + * @since 4.0 + */ + public static JdbcMappingContext forQuotedIdentifiers(NamingStrategy namingStrategy) { + return new JdbcMappingContext(namingStrategy); + } + @Override protected RelationalPersistentProperty createPersistentProperty(Property property, RelationalPersistentEntity owner, SimpleTypeHolder simpleTypeHolder) { diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java index 8b5f305149..e482daf737 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java @@ -116,7 +116,8 @@ public RelationalManagedTypes jdbcManagedTypes() throws ClassNotFoundException { public JdbcMappingContext jdbcMappingContext(Optional namingStrategy, JdbcCustomConversions customConversions, RelationalManagedTypes jdbcManagedTypes) { - JdbcMappingContext mappingContext = new JdbcMappingContext(namingStrategy.orElse(DefaultNamingStrategy.INSTANCE)); + JdbcMappingContext mappingContext = JdbcMappingContext + .forQuotedIdentifiers(namingStrategy.orElse(DefaultNamingStrategy.INSTANCE)); mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder()); mappingContext.setManagedTypes(jdbcManagedTypes); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/EntityRowMapperUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/EntityRowMapperUnitTests.java index 507fcd3dc0..08fb721301 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/EntityRowMapperUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/EntityRowMapperUnitTests.java @@ -1032,7 +1032,7 @@ private EntityRowMapper createRowMapper(Class type) { @SuppressWarnings("unchecked") private EntityRowMapper createRowMapper(Class type, NamingStrategy namingStrategy) { - RelationalMappingContext context = new JdbcMappingContext(namingStrategy); + RelationalMappingContext context = JdbcMappingContext.forQuotedIdentifiers(namingStrategy); DataAccessStrategy accessStrategy = mock(DataAccessStrategy.class); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/JdbcIdentifierBuilderUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/JdbcIdentifierBuilderUnitTests.java index 5c0daa2e0b..9451bdd89e 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/JdbcIdentifierBuilderUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/JdbcIdentifierBuilderUnitTests.java @@ -40,7 +40,7 @@ */ class JdbcIdentifierBuilderUnitTests { - JdbcMappingContext context = new JdbcMappingContext(); + JdbcMappingContext context = JdbcMappingContext.forQuotedIdentifiers(); JdbcConverter converter = new MappingJdbcConverter(context, (identifier, path) -> { throw new UnsupportedOperationException(); }); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/MappingJdbcConverterUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/MappingJdbcConverterUnitTests.java index b623b6ef94..9859151633 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/MappingJdbcConverterUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/MappingJdbcConverterUnitTests.java @@ -165,7 +165,7 @@ void accessesCorrectValuesForOneToOneRelationshipWithIdenticallyNamedIdPropertie @Test // GH-1750 void readByteArrayToNestedUuidWithCustomConverter() { - JdbcMappingContext context = new JdbcMappingContext(); + JdbcMappingContext context = JdbcMappingContext.forQuotedIdentifiers(); StubbedJdbcTypeFactory typeFactory = new StubbedJdbcTypeFactory(); Converter customConverter = new ByteArrayToUuid(); MappingJdbcConverter converter = new MappingJdbcConverter( // diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/RowDocumentResultSetExtractorUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/RowDocumentResultSetExtractorUnitTests.java index 8616882934..fd1958e426 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/RowDocumentResultSetExtractorUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/RowDocumentResultSetExtractorUnitTests.java @@ -48,7 +48,7 @@ */ public class RowDocumentResultSetExtractorUnitTests { - RelationalMappingContext context = new JdbcMappingContext(new DefaultNamingStrategy()); + RelationalMappingContext context = JdbcMappingContext.forQuotedIdentifiers(new DefaultNamingStrategy()); private final PathToColumnMapping column = new PathToColumnMapping() { @Override diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorContextBasedNamingStrategyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorContextBasedNamingStrategyUnitTests.java index f25f421c30..fc45db1c6a 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorContextBasedNamingStrategyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorContextBasedNamingStrategyUnitTests.java @@ -212,7 +212,7 @@ private void threadedTest(String user, CountDownLatch latch, Consumer te */ private SqlGenerator configureSqlGenerator(NamingStrategy namingStrategy) { - RelationalMappingContext context = new JdbcMappingContext(namingStrategy); + RelationalMappingContext context = JdbcMappingContext.forQuotedIdentifiers(namingStrategy); JdbcConverter converter = new MappingJdbcConverter(context, (identifier, path) -> { throw new UnsupportedOperationException(); }); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorEmbeddedUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorEmbeddedUnitTests.java index 9a011a8802..80283e4caa 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorEmbeddedUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorEmbeddedUnitTests.java @@ -46,7 +46,7 @@ */ class SqlGeneratorEmbeddedUnitTests { - private RelationalMappingContext context = new JdbcMappingContext(); + private RelationalMappingContext context = JdbcMappingContext.forPlainIdentifiers(); private JdbcConverter converter = new MappingJdbcConverter(context, (identifier, path) -> { throw new UnsupportedOperationException(); }); @@ -54,7 +54,6 @@ class SqlGeneratorEmbeddedUnitTests { @BeforeEach void setUp() { - this.context.setForceQuote(false); this.sqlGenerator = createSqlGenerator(DummyEntity.class); } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorFixedNamingStrategyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorFixedNamingStrategyUnitTests.java index 5ecbdd9cc8..570cf2c7de 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorFixedNamingStrategyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorFixedNamingStrategyUnitTests.java @@ -196,7 +196,7 @@ private PersistentPropertyPath getPath(String path */ private SqlGenerator configureSqlGenerator(NamingStrategy namingStrategy) { - context = new JdbcMappingContext(namingStrategy); + context = JdbcMappingContext.forQuotedIdentifiers(namingStrategy); JdbcConverter converter = new MappingJdbcConverter(context, (identifier, path) -> { throw new UnsupportedOperationException(); }); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorUnitTests.java index 7e7989ef48..08831d801a 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorUnitTests.java @@ -15,17 +15,11 @@ */ package org.springframework.data.jdbc.core.convert; -import static java.util.Collections.emptySet; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.Assertions.entry; -import static org.assertj.core.api.SoftAssertions.assertSoftly; -import static org.springframework.data.relational.core.mapping.ForeignKeyNaming.APPLY_RENAMING; -import static org.springframework.data.relational.core.mapping.ForeignKeyNaming.IGNORE_RENAMING; -import static org.springframework.data.relational.core.sql.SqlIdentifier.EMPTY; -import static org.springframework.data.relational.core.sql.SqlIdentifier.quoted; -import static org.springframework.data.relational.core.sql.SqlIdentifier.unquoted; +import static java.util.Collections.*; +import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.SoftAssertions.*; +import static org.springframework.data.relational.core.mapping.ForeignKeyNaming.*; +import static org.springframework.data.relational.core.sql.SqlIdentifier.*; import java.util.Map; import java.util.Set; @@ -87,7 +81,7 @@ class SqlGeneratorUnitTests { private static final Identifier BACKREF = Identifier.of(unquoted("backref"), "some-value", String.class); private final PrefixingNamingStrategy namingStrategy = new PrefixingNamingStrategy(); - private RelationalMappingContext context = new JdbcMappingContext(namingStrategy); + private RelationalMappingContext context = JdbcMappingContext.forQuotedIdentifiers(namingStrategy); private final JdbcConverter converter = new MappingJdbcConverter(context, (identifier, path) -> { throw new UnsupportedOperationException(); }); @@ -977,7 +971,7 @@ void selectByQueryPaginationValidTest() { void backReferenceShouldConsiderRenamedParent() { namingStrategy.setForeignKeyNaming(APPLY_RENAMING); - context = new JdbcMappingContext(namingStrategy); + context = JdbcMappingContext.forQuotedIdentifiers(namingStrategy); String sql = sqlGenerator.createDeleteInByPath(getPath("ref", RenamedDummy.class)); @@ -988,7 +982,7 @@ void backReferenceShouldConsiderRenamedParent() { void backReferenceShouldIgnoreRenamedParent() { namingStrategy.setForeignKeyNaming(IGNORE_RENAMING); - context = new JdbcMappingContext(namingStrategy); + context = JdbcMappingContext.forQuotedIdentifiers(namingStrategy); String sql = sqlGenerator.createDeleteInByPath(getPath("ref", RenamedDummy.class)); @@ -999,7 +993,7 @@ void backReferenceShouldIgnoreRenamedParent() { void keyColumnShouldConsiderRenamedParent() { namingStrategy.setForeignKeyNaming(APPLY_RENAMING); - context = new JdbcMappingContext(namingStrategy); + context = JdbcMappingContext.forQuotedIdentifiers(namingStrategy); SqlGenerator sqlGenerator = createSqlGenerator(ReferencedEntity.class); String sql = sqlGenerator.getFindAllByProperty(Identifier.of(unquoted("parentId"), 23, RenamedDummy.class), @@ -1012,7 +1006,7 @@ void keyColumnShouldConsiderRenamedParent() { void keyColumnShouldIgnoreRenamedParent() { namingStrategy.setForeignKeyNaming(IGNORE_RENAMING); - context = new JdbcMappingContext(namingStrategy); + context = JdbcMappingContext.forQuotedIdentifiers(namingStrategy); SqlGenerator sqlGenerator = createSqlGenerator(ReferencedEntity.class); String sql = sqlGenerator.getFindAllByProperty(Identifier.of(unquoted("parentId"), 23, RenamedDummy.class), diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mapping/model/DefaultNamingStrategyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mapping/model/DefaultNamingStrategyUnitTests.java index 69f0f5bf50..2f0f521a1c 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mapping/model/DefaultNamingStrategyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mapping/model/DefaultNamingStrategyUnitTests.java @@ -15,18 +15,19 @@ */ package org.springframework.data.jdbc.mapping.model; +import static org.assertj.core.api.Assertions.*; + +import java.time.LocalDateTime; +import java.util.List; + import org.junit.jupiter.api.Test; + import org.springframework.data.annotation.Id; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.relational.core.mapping.DefaultNamingStrategy; import org.springframework.data.relational.core.mapping.NamingStrategy; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; -import java.time.LocalDateTime; -import java.util.List; - -import static org.assertj.core.api.Assertions.*; - /** * Unit tests for the default {@link NamingStrategy}. * @@ -39,7 +40,7 @@ public class DefaultNamingStrategyUnitTests { private final NamingStrategy target = DefaultNamingStrategy.INSTANCE; private final RelationalPersistentEntity persistentEntity = // - new JdbcMappingContext(target).getRequiredPersistentEntity(DummyEntity.class); + JdbcMappingContext.forQuotedIdentifiers(target).getRequiredPersistentEntity(DummyEntity.class); @Test // DATAJDBC-184 public void getTableName() { diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/DeclaredQueryRepositoryUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/DeclaredQueryRepositoryUnitTests.java index 2670ed88be..0abd9c745d 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/DeclaredQueryRepositoryUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/DeclaredQueryRepositoryUnitTests.java @@ -16,15 +16,13 @@ package org.springframework.data.jdbc.repository; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.RETURNS_DEEP_STUBS; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; + import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.annotation.Id; import org.springframework.data.jdbc.core.convert.DataAccessStrategy; @@ -98,7 +96,7 @@ private String query() { Dialect dialect = JdbcHsqlDbDialect.INSTANCE; - RelationalMappingContext context = new JdbcMappingContext(); + RelationalMappingContext context = JdbcMappingContext.forQuotedIdentifiers(); DelegatingDataAccessStrategy delegatingDataAccessStrategy = new DelegatingDataAccessStrategy(); JdbcConverter converter = new MappingJdbcConverter(context, delegatingDataAccessStrategy, diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java index 4ea56b1ee7..ebc73a2058 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java @@ -125,7 +125,8 @@ DataAccessStrategy defaultDataAccessStrategy( JdbcMappingContext jdbcMappingContextWithOutSingleQueryLoading(Optional namingStrategy, CustomConversions conversions) { - JdbcMappingContext mappingContext = new JdbcMappingContext(namingStrategy.orElse(DefaultNamingStrategy.INSTANCE)); + JdbcMappingContext mappingContext = JdbcMappingContext + .forQuotedIdentifiers(namingStrategy.orElse(DefaultNamingStrategy.INSTANCE)); mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder()); return mappingContext; } @@ -135,7 +136,8 @@ JdbcMappingContext jdbcMappingContextWithOutSingleQueryLoading(Optional namingStrategy, CustomConversions conversions) { - JdbcMappingContext mappingContext = new JdbcMappingContext(namingStrategy.orElse(DefaultNamingStrategy.INSTANCE)); + JdbcMappingContext mappingContext = JdbcMappingContext + .forQuotedIdentifiers(namingStrategy.orElse(DefaultNamingStrategy.INSTANCE)); mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder()); mappingContext.setSingleQueryLoadingEnabled(true); return mappingContext; diff --git a/spring-data-r2dbc/pom.xml b/spring-data-r2dbc/pom.xml index 3ee76fd3c1..f228bc9bcb 100644 --- a/spring-data-r2dbc/pom.xml +++ b/spring-data-r2dbc/pom.xml @@ -6,7 +6,7 @@ 4.0.0 spring-data-r2dbc - 4.0.0-SNAPSHOT + 4.0.0-1993-force-quoting-SNAPSHOT Spring Data R2DBC Spring Data module for R2DBC @@ -15,7 +15,7 @@ org.springframework.data spring-data-relational-parent - 4.0.0-SNAPSHOT + 4.0.0-1993-force-quoting-SNAPSHOT diff --git a/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/config/AbstractR2dbcConfiguration.java b/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/config/AbstractR2dbcConfiguration.java index 2b86b2821f..1ca3a89227 100644 --- a/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/config/AbstractR2dbcConfiguration.java +++ b/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/config/AbstractR2dbcConfiguration.java @@ -177,7 +177,8 @@ public R2dbcMappingContext r2dbcMappingContext(Optional namingSt Assert.notNull(namingStrategy, "NamingStrategy must not be null"); - R2dbcMappingContext context = new R2dbcMappingContext(namingStrategy.orElse(DefaultNamingStrategy.INSTANCE)); + R2dbcMappingContext context = R2dbcMappingContext + .forQuotedIdentifiers(namingStrategy.orElse(DefaultNamingStrategy.INSTANCE)); context.setSimpleTypeHolder(r2dbcCustomConversions.getSimpleTypeHolder()); context.setManagedTypes(r2dbcManagedTypes); diff --git a/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/mapping/R2dbcMappingContext.java b/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/mapping/R2dbcMappingContext.java index 5053291be6..e7494e0fa5 100644 --- a/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/mapping/R2dbcMappingContext.java +++ b/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/mapping/R2dbcMappingContext.java @@ -25,15 +25,14 @@ * R2DBC-specific extension to {@link RelationalMappingContext}. * * @author Mark Paluch + * @author Jens Schauder */ public class R2dbcMappingContext extends RelationalMappingContext { /** * Create a new {@link R2dbcMappingContext}. */ - public R2dbcMappingContext() { - setForceQuote(false); - } + public R2dbcMappingContext() {} /** * Create a new {@link R2dbcMappingContext} using the given {@link NamingStrategy}. @@ -42,7 +41,62 @@ public R2dbcMappingContext() { */ public R2dbcMappingContext(NamingStrategy namingStrategy) { super(namingStrategy); - setForceQuote(false); + } + + /** + * Create a new {@code R2dbcMappingContext} using {@link #setForceQuote(boolean) plain identifiers}. Plain + * {@link org.springframework.data.relational.core.sql.SqlIdentifier identifiers} (i.e. table and column names) are + * typically not case-sensitive (case-sensitivity can be still enforced by specific database configurations). + * + * @return a new {@code R2dbcMappingContext} using plain identifiers. + * @since 4.0 + */ + public static R2dbcMappingContext forPlainIdentifiers() { + R2dbcMappingContext context = forQuotedIdentifiers(); + context.setForceQuote(false); + return context; + } + + /** + * Create a new {@code R2dbcMappingContext} using {@link #setForceQuote(boolean) plain identifiers} and the given + * {@link NamingStrategy}. Plain {@link org.springframework.data.relational.core.sql.SqlIdentifier identifiers} (i.e. + * table and column names) are typically not case-sensitive (case-sensitivity can be still enforced by specific + * database configurations). + * + * @param namingStrategy must not be {@literal null}. + * @return a new {@code R2dbcMappingContext} using plain identifiers. + * @since 4.0 + */ + public static R2dbcMappingContext forPlainIdentifiers(NamingStrategy namingStrategy) { + R2dbcMappingContext context = forQuotedIdentifiers(namingStrategy); + context.setForceQuote(false); + return context; + } + + /** + * Create a new {@code R2dbcMappingContext} using {@link #setForceQuote(boolean) quoted identifiers} (default + * behavior). Quoted {@link org.springframework.data.relational.core.sql.SqlIdentifier identifiers} (i.e. table and + * column names) are typically case-sensitive. + * + * @return a new {@code R2dbcMappingContext} using quoted identifiers. + * @since 4.0 + */ + public static R2dbcMappingContext forQuotedIdentifiers() { + return new R2dbcMappingContext(); + } + + /** + * Create a new {@code R2dbcMappingContext} using {@link #setForceQuote(boolean) quoted identifiers} (default + * behavior) and the given {@link NamingStrategy}. Quoted + * {@link org.springframework.data.relational.core.sql.SqlIdentifier identifiers} (i.e. table and column names) are + * typically case-sensitive. + * + * @param namingStrategy must not be {@literal null}. + * @return a new {@code R2dbcMappingContext} using quoted identifiers. + * @since 4.0 + */ + public static R2dbcMappingContext forQuotedIdentifiers(NamingStrategy namingStrategy) { + return new R2dbcMappingContext(namingStrategy); } @Override diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/convert/MappingR2dbcConverterUnitTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/convert/MappingR2dbcConverterUnitTests.java index 1dc70a1f48..2bed00a42a 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/convert/MappingR2dbcConverterUnitTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/convert/MappingR2dbcConverterUnitTests.java @@ -15,11 +15,21 @@ */ package org.springframework.data.r2dbc.convert; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + import io.r2dbc.spi.R2dbcType; import io.r2dbc.spi.Row; import io.r2dbc.spi.test.MockColumnMetadata; import io.r2dbc.spi.test.MockRow; import io.r2dbc.spi.test.MockRowMetadata; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Value; @@ -37,23 +47,15 @@ import org.springframework.data.relational.core.sql.SqlIdentifier; import org.springframework.r2dbc.core.Parameter; -import java.time.Instant; -import java.time.LocalDateTime; -import java.util.Arrays; -import java.util.Collections; -import java.util.Map; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - /** * Unit tests for {@link MappingR2dbcConverter}. * * @author Mark Paluch + * @author Jens Schauder */ public class MappingR2dbcConverterUnitTests { - private RelationalMappingContext mappingContext = new R2dbcMappingContext(); + private RelationalMappingContext mappingContext = R2dbcMappingContext.forPlainIdentifiers(); private MappingR2dbcConverter converter = new MappingR2dbcConverter(mappingContext); @BeforeEach @@ -65,7 +67,6 @@ void before() { StringToSimplePersonConverter.INSTANCE)); mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder()); - converter = new MappingR2dbcConverter(mappingContext, conversions); } @@ -261,8 +262,7 @@ void writeShouldObtainIdFromIdentifierAccessor() { } static class Person { - @Id - String id; + @Id String id; String firstname, lastname; Instant instant; LocalDateTime localDateTime; @@ -298,8 +298,7 @@ public void setLastname(String lastname) { } static class WithEnum { - @Id - String id; + @Id String id; Condition condition; public WithEnum(String id, Condition condition) { @@ -313,8 +312,7 @@ enum Condition { } static class PersonWithConversions { - @Id - String id; + @Id String id; Map nested; NonMappableEntity unsupported; @@ -325,8 +323,7 @@ public PersonWithConversions(String id, Map nested, NonMappableE } } - record WithPrimitiveId ( - @Id long id){ + record WithPrimitiveId(@Id long id) { } static class CustomConversionPerson { diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/convert/MySqlMappingR2dbcConverterUnitTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/convert/MySqlMappingR2dbcConverterUnitTests.java index 19f8ca46a2..cdb2a6e27a 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/convert/MySqlMappingR2dbcConverterUnitTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/convert/MySqlMappingR2dbcConverterUnitTests.java @@ -34,11 +34,13 @@ import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; import org.springframework.data.r2dbc.testing.OutboundRowAssert; import org.springframework.data.relational.core.mapping.RelationalMappingContext; +import org.springframework.data.relational.core.sql.SqlIdentifier; /** * MySQL-specific unit tests for {@link MappingR2dbcConverter}. * * @author Mark Paluch + * @author Jens Schauder */ class MySqlMappingR2dbcConverterUnitTests { @@ -68,8 +70,9 @@ void shouldWriteBooleanToByte() { converter.write(object, row); - OutboundRowAssert.assertThat(row).containsColumnWithValue("flag1", (byte) 1).containsColumnWithValue("flag2", - (byte) 0); + OutboundRowAssert.assertThat(row) // + .containsColumnWithValue(SqlIdentifier.quoted("FLAG1"), (byte) 1) // + .containsColumnWithValue(SqlIdentifier.quoted("FLAG2"), (byte) 0); } @Test // gh-589 @@ -96,7 +99,7 @@ void shouldPreserveByteValue() { converter.write(object, row); - OutboundRowAssert.assertThat(row).containsColumnWithValue("state", (byte) 3); + OutboundRowAssert.assertThat(row).containsColumnWithValue(SqlIdentifier.quoted("STATE"), (byte) 3); } record BooleanMapping( @@ -104,10 +107,7 @@ record BooleanMapping( Integer id, boolean flag1, boolean flag2) { } - record WithByte ( - - Integer id, - byte state){ + record WithByte(Integer id, byte state) { } } diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/convert/PostgresMappingR2dbcConverterUnitTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/convert/PostgresMappingR2dbcConverterUnitTests.java index d29d618933..82888b43a6 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/convert/PostgresMappingR2dbcConverterUnitTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/convert/PostgresMappingR2dbcConverterUnitTests.java @@ -49,6 +49,7 @@ * Postgres-specific unit tests for {@link MappingR2dbcConverter}. * * @author Mark Paluch + * @author Jens Schauder */ class PostgresMappingR2dbcConverterUnitTests { @@ -79,7 +80,7 @@ void shouldPassThruJson() { OutboundRow row = new OutboundRow(); converter.write(person, row); - assertThat(row).containsEntry(SqlIdentifier.unquoted("json_value"), Parameter.from(person.jsonValue)); + assertThat(row).containsEntry(SqlIdentifier.quoted("JSON_VALUE"), Parameter.from(person.jsonValue)); } @Test // gh-453 @@ -127,24 +128,18 @@ void shouldApplyCustomWritingConverter() { OutboundRow row = new OutboundRow(); converter.write(object, row); - Parameter parameter = row.get(SqlIdentifier.unquoted("holder")); + Parameter parameter = row.get(SqlIdentifier.quoted("HOLDER")); assertThat(parameter).isNotNull(); assertThat(parameter.getValue()).isInstanceOf(Json.class); } - record JsonPerson( - @Id Long id, - Json jsonValue) { + record JsonPerson(@Id Long id, Json jsonValue) { } - record ConvertedJson( - @Id Long id, - String jsonString, - byte[] jsonBytes) { + record ConvertedJson(@Id Long id, String jsonString, byte[] jsonBytes) { } - record WithJsonHolder( - JsonHolder holder) { + record WithJsonHolder(JsonHolder holder) { } @ReadingConverter diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/PostgresReactiveDataAccessStrategyTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/PostgresReactiveDataAccessStrategyTests.java index add4f1a970..a2ace3fe52 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/PostgresReactiveDataAccessStrategyTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/PostgresReactiveDataAccessStrategyTests.java @@ -33,9 +33,12 @@ import org.springframework.data.convert.ReadingConverter; import org.springframework.data.convert.WritingConverter; import org.springframework.data.r2dbc.convert.EnumWriteSupport; +import org.springframework.data.r2dbc.convert.MappingR2dbcConverter; +import org.springframework.data.r2dbc.convert.R2dbcCustomConversions; import org.springframework.data.r2dbc.core.StatementMapper.InsertSpec; import org.springframework.data.r2dbc.dialect.PostgresDialect; import org.springframework.data.r2dbc.mapping.OutboundRow; +import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; import org.springframework.data.relational.core.sql.SqlIdentifier; import org.springframework.r2dbc.core.Parameter; import org.springframework.r2dbc.core.PreparedOperation; @@ -45,11 +48,28 @@ * {@link PostgresDialect} specific tests for {@link ReactiveDataAccessStrategy}. * * @author Mark Paluch + * @author Jens Schauder */ public class PostgresReactiveDataAccessStrategyTests extends ReactiveDataAccessStrategyTestSupport { - private final ReactiveDataAccessStrategy strategy = new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE, - Arrays.asList(DurationToIntervalConverter.INSTANCE, IntervalToDurationConverter.INSTANCE)); + private R2dbcMappingContext context; + private final ReactiveDataAccessStrategy strategy; + + PostgresReactiveDataAccessStrategyTests() { + + context = R2dbcMappingContext.forPlainIdentifiers(); + strategy = createReactiveDataAccessStrategy(DurationToIntervalConverter.INSTANCE, + IntervalToDurationConverter.INSTANCE); + } + + private DefaultReactiveDataAccessStrategy createReactiveDataAccessStrategy(Object... converters) { + + R2dbcCustomConversions customConversions = R2dbcCustomConversions.of(PostgresDialect.INSTANCE, converters); + + MappingR2dbcConverter converter = new MappingR2dbcConverter(context, customConversions); + return new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE, + converter); + } @Override protected ReactiveDataAccessStrategy getStrategy() { @@ -98,8 +118,6 @@ void shouldConvertCollectionToArray() { @Test // gh-139 void shouldConvertToArray() { - DefaultReactiveDataAccessStrategy strategy = new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE); - WithArray withArray = new WithArray(); withArray.stringArray = new String[] { "hello", "world" }; withArray.stringList = Arrays.asList("hello", "world"); @@ -113,8 +131,7 @@ void shouldConvertToArray() { @Test // gh-139 void shouldApplyCustomConversion() { - DefaultReactiveDataAccessStrategy strategy = new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE, - Collections.singletonList(MyObjectsToStringConverter.INSTANCE)); + DefaultReactiveDataAccessStrategy strategy = createReactiveDataAccessStrategy(MyObjectsToStringConverter.INSTANCE); WithConversion withConversion = new WithConversion(); withConversion.myObjects = Arrays.asList(new MyObject("one"), new MyObject("two")); @@ -127,8 +144,7 @@ void shouldApplyCustomConversion() { @Test // gh-139 void shouldApplyCustomConversionForNull() { - DefaultReactiveDataAccessStrategy strategy = new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE, - Collections.singletonList(MyObjectsToStringConverter.INSTANCE)); + DefaultReactiveDataAccessStrategy strategy = createReactiveDataAccessStrategy(MyObjectsToStringConverter.INSTANCE); WithConversion withConversion = new WithConversion(); withConversion.myObjects = null; @@ -152,8 +168,6 @@ void shouldApplyCustomConversionForEmptyList() { @Test // gh-252, gh-593 void shouldConvertCollectionOfEnumToString() { - DefaultReactiveDataAccessStrategy strategy = new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE); - WithEnumCollections withEnums = new WithEnumCollections(); withEnums.enumSet = EnumSet.of(MyEnum.ONE, MyEnum.TWO); withEnums.enumList = Arrays.asList(MyEnum.ONE, MyEnum.TWO); @@ -170,8 +184,6 @@ void shouldConvertCollectionOfEnumToString() { @Test // gh-593 void shouldCorrectlyWriteConvertedEnumNullValues() { - DefaultReactiveDataAccessStrategy strategy = new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE); - WithEnumCollections withEnums = new WithEnumCollections(); OutboundRow outboundRow = strategy.getOutboundRow(withEnums); @@ -185,8 +197,6 @@ void shouldCorrectlyWriteConvertedEnumNullValues() { @Test // gh-1544 void shouldCorrectlyWriteConvertedEmptyEnumCollections() { - DefaultReactiveDataAccessStrategy strategy = new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE); - WithEnumCollections withEnums = new WithEnumCollections(); withEnums.enumArray = new MyEnum[0]; withEnums.enumList = Collections.emptyList(); @@ -203,8 +213,7 @@ void shouldCorrectlyWriteConvertedEmptyEnumCollections() { @Test // gh-593 void shouldConvertCollectionOfEnumNatively() { - DefaultReactiveDataAccessStrategy strategy = new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE, - Collections.singletonList(new MyEnumSupport())); + DefaultReactiveDataAccessStrategy strategy = createReactiveDataAccessStrategy(new MyEnumSupport()); WithEnumCollections withEnums = new WithEnumCollections(); withEnums.enumSet = EnumSet.of(MyEnum.ONE, MyEnum.TWO); @@ -222,8 +231,7 @@ void shouldConvertCollectionOfEnumNatively() { @Test // gh-593 void shouldCorrectlyWriteNativeEnumNullValues() { - DefaultReactiveDataAccessStrategy strategy = new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE, - Collections.singletonList(new MyEnumSupport())); + DefaultReactiveDataAccessStrategy strategy = createReactiveDataAccessStrategy(new MyEnumSupport()); WithEnumCollections withEnums = new WithEnumCollections(); diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/R2dbcEntityTemplateUnitTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/R2dbcEntityTemplateUnitTests.java index 8c11f18781..a596fd0384 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/R2dbcEntityTemplateUnitTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/R2dbcEntityTemplateUnitTests.java @@ -113,7 +113,7 @@ void shouldCountBy() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("SELECT")); - assertThat(statement.getSql()).isEqualTo("SELECT COUNT(*) FROM person WHERE person.THE_NAME = $1"); + assertThat(statement.getSql()).isEqualTo("SELECT COUNT(*) FROM \"person\" WHERE \"person\".\"THE_NAME\" = $1"); assertThat(statement.getBindings()).hasSize(1).containsEntry(0, Parameter.from("Walter")); } @@ -136,7 +136,7 @@ void shouldApplyInterfaceProjection() { .assertNext(actual -> assertThat(actual.getName()).isEqualTo("Walter")).verifyComplete(); StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("SELECT")); - assertThat(statement.getSql()).isEqualTo("SELECT foo.THE_NAME FROM foo WHERE foo.THE_NAME = $1"); + assertThat(statement.getSql()).isEqualTo("SELECT foo.\"THE_NAME\" FROM foo WHERE foo.\"THE_NAME\" = $1"); } @Test // GH-1690 @@ -161,7 +161,7 @@ void shouldProjectEntityUsingInheritedInterface() { }).verifyComplete(); StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("SELECT")); - assertThat(statement.getSql()).isEqualTo("SELECT foo.* FROM foo WHERE foo.THE_NAME = $1"); + assertThat(statement.getSql()).isEqualTo("SELECT foo.* FROM foo WHERE foo.\"THE_NAME\" = $1"); } @Test // GH-469 @@ -217,7 +217,7 @@ void shouldExistsByCriteria() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("SELECT")); - assertThat(statement.getSql()).isEqualTo("SELECT 1 FROM person WHERE person.THE_NAME = $1 LIMIT 1"); + assertThat(statement.getSql()).isEqualTo("SELECT 1 FROM \"person\" WHERE \"person\".\"THE_NAME\" = $1 LIMIT 1"); assertThat(statement.getBindings()).hasSize(1).containsEntry(0, Parameter.from("Walter")); } @@ -232,8 +232,8 @@ void shouldSelectByCriteria() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("SELECT")); - assertThat(statement.getSql()) - .isEqualTo("SELECT person.* FROM person WHERE person.THE_NAME = $1 ORDER BY person.THE_NAME ASC"); + assertThat(statement.getSql()).isEqualTo( + "SELECT \"person\".* FROM \"person\" WHERE \"person\".\"THE_NAME\" = $1 ORDER BY \"person\".\"THE_NAME\" ASC"); assertThat(statement.getBindings()).hasSize(1).containsEntry(0, Parameter.from("Walter")); } @@ -274,8 +274,8 @@ void shouldSelectOne() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("SELECT")); - assertThat(statement.getSql()) - .isEqualTo("SELECT person.* FROM person WHERE person.THE_NAME = $1 ORDER BY person.THE_NAME ASC LIMIT 2"); + assertThat(statement.getSql()).isEqualTo( + "SELECT \"person\".* FROM \"person\" WHERE \"person\".\"THE_NAME\" = $1 ORDER BY \"person\".\"THE_NAME\" ASC LIMIT 2"); assertThat(statement.getBindings()).hasSize(1).containsEntry(0, Parameter.from("Walter")); } @@ -291,8 +291,8 @@ void shouldSelectOneDoNotOverrideExistingLimit() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("SELECT")); - assertThat(statement.getSql()) - .isEqualTo("SELECT person.* FROM person WHERE person.THE_NAME = $1 ORDER BY person.THE_NAME ASC LIMIT 1"); + assertThat(statement.getSql()).isEqualTo( + "SELECT \"person\".* FROM \"person\" WHERE \"person\".\"THE_NAME\" = $1 ORDER BY \"person\".\"THE_NAME\" ASC LIMIT 1"); assertThat(statement.getBindings()).hasSize(1).containsEntry(0, Parameter.from("Walter")); } @@ -311,7 +311,8 @@ void shouldUpdateByQuery() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("UPDATE")); - assertThat(statement.getSql()).isEqualTo("UPDATE person SET THE_NAME = $1 WHERE person.THE_NAME = $2"); + assertThat(statement.getSql()) + .isEqualTo("UPDATE \"person\" SET \"THE_NAME\" = $1 WHERE \"person\".\"THE_NAME\" = $2"); assertThat(statement.getBindings()).hasSize(2).containsEntry(0, Parameter.from("Heisenberg")).containsEntry(1, Parameter.from("Walter")); } @@ -330,7 +331,7 @@ void shouldDeleteByQuery() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("DELETE")); - assertThat(statement.getSql()).isEqualTo("DELETE FROM person WHERE person.THE_NAME = $1"); + assertThat(statement.getSql()).isEqualTo("DELETE FROM \"person\" WHERE \"person\".\"THE_NAME\" = $1"); assertThat(statement.getBindings()).hasSize(1).containsEntry(0, Parameter.from("Walter")); } @@ -347,7 +348,7 @@ void shouldDeleteEntity() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("DELETE")); - assertThat(statement.getSql()).isEqualTo("DELETE FROM person WHERE person.id = $1"); + assertThat(statement.getSql()).isEqualTo("DELETE FROM \"person\" WHERE \"person\".\"id\" = $1"); assertThat(statement.getBindings()).hasSize(1).containsEntry(0, Parameter.from("Walter")); } @@ -367,7 +368,8 @@ void shouldInsertVersioned() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("INSERT")); - assertThat(statement.getSql()).isEqualTo("INSERT INTO versioned_person (id, version, name) VALUES ($1, $2, $3)"); + assertThat(statement.getSql()) + .isEqualTo("INSERT INTO \"versioned_person\" (\"id\", \"version\", \"name\") VALUES ($1, $2, $3)"); assertThat(statement.getBindings()).hasSize(3).containsEntry(0, Parameter.from("id")).containsEntry(1, Parameter.from(1L)); } @@ -386,7 +388,7 @@ void shouldSkipDefaultIdValueOnInsert() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("INSERT")); - assertThat(statement.getSql()).isEqualTo("INSERT INTO person_with_primitive_id (name) VALUES ($1)"); + assertThat(statement.getSql()).isEqualTo("INSERT INTO \"person_with_primitive_id\" (\"name\") VALUES ($1)"); assertThat(statement.getBindings()).hasSize(1).containsEntry(0, Parameter.from("bar")); } @@ -407,7 +409,7 @@ void shouldSkipDefaultIdValueOnVersionedInsert() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("INSERT")); assertThat(statement.getSql()) - .isEqualTo("INSERT INTO versioned_person_with_primitive_id (version, name) VALUES ($1, $2)"); + .isEqualTo("INSERT INTO \"versioned_person_with_primitive_id\" (\"version\", \"name\") VALUES ($1, $2)"); assertThat(statement.getBindings()).hasSize(2).containsEntry(0, Parameter.from(1L)).containsEntry(1, Parameter.from("bar")); } @@ -437,7 +439,7 @@ void shouldInsertCorrectlyVersionedAndAudited() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("INSERT")); assertThat(statement.getSql()).isEqualTo( - "INSERT INTO with_auditing_and_optimistic_locking (version, name, created_date, last_modified_date) VALUES ($1, $2, $3, $4)"); + "INSERT INTO \"with_auditing_and_optimistic_locking\" (\"version\", \"name\", \"created_date\", \"last_modified_date\") VALUES ($1, $2, $3, $4)"); } @Test // GH-451 @@ -466,7 +468,7 @@ void shouldUpdateCorrectlyVersionedAndAudited() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("UPDATE")); assertThat(statement.getSql()).startsWith( - "UPDATE with_auditing_and_optimistic_locking SET version = $1, name = $2, created_date = $3, last_modified_date = $4"); + "UPDATE \"with_auditing_and_optimistic_locking\" SET \"version\" = $1, \"name\" = $2, \"created_date\" = $3, \"last_modified_date\" = $4"); } @Test // GH-215 @@ -492,7 +494,7 @@ void insertShouldInvokeCallback() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("INSERT")); - assertThat(statement.getSql()).isEqualTo("INSERT INTO person (THE_NAME, description) VALUES ($1, $2)"); + assertThat(statement.getSql()).isEqualTo("INSERT INTO \"person\" (\"THE_NAME\", \"description\") VALUES ($1, $2)"); assertThat(statement.getBindings()).hasSize(2).containsEntry(0, Parameter.from("before-convert")).containsEntry(1, Parameter.from("before-save")); } @@ -514,7 +516,7 @@ void shouldUpdateVersioned() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("UPDATE")); assertThat(statement.getSql()).isEqualTo( - "UPDATE versioned_person SET version = $1, name = $2 WHERE versioned_person.id = $3 AND (versioned_person.version = $4)"); + "UPDATE \"versioned_person\" SET \"version\" = $1, \"name\" = $2 WHERE \"versioned_person\".\"id\" = $3 AND (\"versioned_person\".\"version\" = $4)"); assertThat(statement.getBindings()).hasSize(4).containsEntry(0, Parameter.from(2L)).containsEntry(3, Parameter.from(1L)); } @@ -547,7 +549,8 @@ void updateShouldInvokeCallback() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("UPDATE")); - assertThat(statement.getSql()).isEqualTo("UPDATE person SET THE_NAME = $1, description = $2 WHERE person.id = $3"); + assertThat(statement.getSql()) + .isEqualTo("UPDATE \"person\" SET \"THE_NAME\" = $1, \"description\" = $2 WHERE \"person\".\"id\" = $3"); assertThat(statement.getBindings()).hasSize(3).containsEntry(0, Parameter.from("before-convert")).containsEntry(1, Parameter.from("before-save")); } @@ -566,7 +569,8 @@ void insertIncludesInsertOnlyColumns() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("INSERT")); - assertThat(statement.getSql()).isEqualTo("INSERT INTO with_insert_only (name, insert_only) VALUES ($1, $2)"); + assertThat(statement.getSql()) + .isEqualTo("INSERT INTO \"with_insert_only\" (\"name\", \"insert_only\") VALUES ($1, $2)"); assertThat(statement.getBindings()).hasSize(2).containsEntry(0, Parameter.from("Alfred")).containsEntry(1, Parameter.from("insert this")); } @@ -585,7 +589,8 @@ void updateExcludesInsertOnlyColumns() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("UPDATE")); - assertThat(statement.getSql()).isEqualTo("UPDATE with_insert_only SET name = $1 WHERE with_insert_only.id = $2"); + assertThat(statement.getSql()) + .isEqualTo("UPDATE \"with_insert_only\" SET \"name\" = $1 WHERE \"with_insert_only\".\"id\" = $2"); assertThat(statement.getBindings()).hasSize(2).containsEntry(0, Parameter.from("Alfred")).containsEntry(1, Parameter.from(23L)); } @@ -604,7 +609,7 @@ void shouldConsiderParameterConverter() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("INSERT")); - assertThat(statement.getSql()).isEqualTo("INSERT INTO with_money (money) VALUES ($1)"); + assertThat(statement.getSql()).isEqualTo("INSERT INTO \"with_money\" (\"money\") VALUES ($1)"); assertThat(statement.getBindings()).hasSize(1).containsEntry(0, Parameter.from(Parameters.in(R2dbcType.VARCHAR, "$$$"))); } @@ -875,7 +880,7 @@ static class ValueCapturingBeforeSaveCallback extends ValueCapturingEntityCallba public Mono onBeforeSave(Person entity, OutboundRow outboundRow, SqlIdentifier table) { capture(entity); - outboundRow.put(SqlIdentifier.unquoted("description"), Parameter.from("before-save")); + outboundRow.put(SqlIdentifier.quoted("DESCRIPTION"), Parameter.from("before-save")); return Mono.just(entity); } } diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveDeleteOperationUnitTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveDeleteOperationUnitTests.java index 5462eeb600..a1e29f91c5 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveDeleteOperationUnitTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveDeleteOperationUnitTests.java @@ -24,9 +24,9 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; - import org.springframework.data.annotation.Id; import org.springframework.data.r2dbc.dialect.PostgresDialect; +import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; import org.springframework.data.r2dbc.testing.StatementRecorder; import org.springframework.data.relational.core.mapping.Column; import org.springframework.r2dbc.core.DatabaseClient; @@ -50,6 +50,8 @@ void before() { client = DatabaseClient.builder().connectionFactory(recorder) .bindMarkers(PostgresDialect.INSTANCE.getBindMarkersFactory()).build(); entityTemplate = new R2dbcEntityTemplate(client, new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)); + ((R2dbcMappingContext) entityTemplate.getDataAccessStrategy().getConverter().getMappingContext()) + .setForceQuote(false); } @Test // gh-410 diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveInsertOperationUnitTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveInsertOperationUnitTests.java index 1b2afe6b4f..e605eeea86 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveInsertOperationUnitTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveInsertOperationUnitTests.java @@ -26,9 +26,9 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; - import org.springframework.data.annotation.Id; import org.springframework.data.r2dbc.dialect.PostgresDialect; +import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; import org.springframework.data.r2dbc.testing.StatementRecorder; import org.springframework.data.relational.core.mapping.Column; import org.springframework.r2dbc.core.DatabaseClient; @@ -52,14 +52,15 @@ void before() { client = DatabaseClient.builder().connectionFactory(recorder) .bindMarkers(PostgresDialect.INSTANCE.getBindMarkersFactory()).build(); entityTemplate = new R2dbcEntityTemplate(client, new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)); + ((R2dbcMappingContext) entityTemplate.getDataAccessStrategy().getConverter().getMappingContext()) + .setForceQuote(false); } @Test // gh-220 void shouldInsert() { MockRowMetadata metadata = MockRowMetadata.builder() - .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()) - .build(); + .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()).build(); MockResult result = MockResult.builder() .row(MockRow.builder().identified("id", Object.class, 42).metadata(metadata).build()).build(); @@ -87,8 +88,7 @@ void shouldInsert() { void shouldUpdateInTable() { MockRowMetadata metadata = MockRowMetadata.builder() - .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()) - .build(); + .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()).build(); MockResult result = MockResult.builder() .row(MockRow.builder().identified("id", Object.class, 42).metadata(metadata).build()).build(); diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveSelectOperationUnitTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveSelectOperationUnitTests.java index e0ec5d4d0a..bd2538be4a 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveSelectOperationUnitTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveSelectOperationUnitTests.java @@ -28,9 +28,9 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; - import org.springframework.data.annotation.Id; import org.springframework.data.r2dbc.dialect.PostgresDialect; +import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; import org.springframework.data.r2dbc.testing.StatementRecorder; import org.springframework.data.relational.core.mapping.Column; import org.springframework.r2dbc.core.DatabaseClient; @@ -54,14 +54,15 @@ void before() { client = DatabaseClient.builder().connectionFactory(recorder) .bindMarkers(PostgresDialect.INSTANCE.getBindMarkersFactory()).build(); entityTemplate = new R2dbcEntityTemplate(client, new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)); + ((R2dbcMappingContext) entityTemplate.getDataAccessStrategy().getConverter().getMappingContext()) + .setForceQuote(false); } @Test // GH-220 void shouldSelectAll() { MockRowMetadata metadata = MockRowMetadata.builder() - .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()) - .build(); + .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()).build(); MockResult result = MockResult.builder() .row(MockRow.builder().identified("id", Object.class, "Walter").metadata(metadata).build()).build(); @@ -84,8 +85,7 @@ void shouldSelectAll() { void shouldSelectAs() { MockRowMetadata metadata = MockRowMetadata.builder() - .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()) - .build(); + .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()).build(); MockResult result = MockResult.builder() .row(MockRow.builder().identified("id", Object.class, "Walter").metadata(metadata).build()).build(); @@ -125,15 +125,15 @@ void shouldSelectAsWithColumnName() { StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("SELECT")); - assertThat(statement.getSql()).isEqualTo("SELECT person.id, person.a_different_name FROM person WHERE person.THE_NAME = $1"); + assertThat(statement.getSql()) + .isEqualTo("SELECT person.id, person.a_different_name FROM person WHERE person.THE_NAME = $1"); } @Test // GH-220 void shouldSelectFromTable() { MockRowMetadata metadata = MockRowMetadata.builder() - .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()) - .build(); + .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()).build(); MockResult result = MockResult.builder().rowMetadata(metadata) .row(MockRow.builder().identified("id", Object.class, "Walter").metadata(metadata).build()).build(); @@ -156,8 +156,7 @@ void shouldSelectFromTable() { void shouldSelectFirst() { MockRowMetadata metadata = MockRowMetadata.builder() - .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()) - .build(); + .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()).build(); MockResult result = MockResult.builder().rowMetadata(metadata) .row(MockRow.builder().identified("id", Object.class, "Walter").metadata(metadata).build()).build(); @@ -179,8 +178,7 @@ void shouldSelectFirst() { void shouldSelectOne() { MockRowMetadata metadata = MockRowMetadata.builder() - .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()) - .build(); + .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()).build(); MockResult result = MockResult.builder() .row(MockRow.builder().identified("id", Object.class, "Walter").metadata(metadata).build()).build(); @@ -202,8 +200,7 @@ void shouldSelectOne() { void shouldSelectExists() { MockRowMetadata metadata = MockRowMetadata.builder() - .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()) - .build(); + .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()).build(); MockResult result = MockResult.builder() .row(MockRow.builder().identified("id", Object.class, "Walter").metadata(metadata).build()).build(); @@ -225,8 +222,7 @@ void shouldSelectExists() { void shouldSelectCount() { MockRowMetadata metadata = MockRowMetadata.builder() - .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()) - .build(); + .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()).build(); MockResult result = MockResult.builder() .row(MockRow.builder().identified(0, Long.class, 1L).metadata(metadata).build()).build(); @@ -248,11 +244,9 @@ void shouldSelectCount() { void shouldConsiderFetchSize() { MockRowMetadata metadata = MockRowMetadata.builder() - .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()) - .build(); + .columnMetadata(MockColumnMetadata.builder().name("id").type(R2dbcType.INTEGER).build()).build(); MockResult result = MockResult.builder() - .row(MockRow.builder().identified("id", Object.class, "Walter").metadata(metadata).build()) - .build(); + .row(MockRow.builder().identified("id", Object.class, "Walter").metadata(metadata).build()).build(); recorder.addStubbing(s -> s.startsWith("SELECT"), result); diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveUpdateOperationUnitTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveUpdateOperationUnitTests.java index 91106b342c..28f96c7be0 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveUpdateOperationUnitTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveUpdateOperationUnitTests.java @@ -24,9 +24,9 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; - import org.springframework.data.annotation.Id; import org.springframework.data.r2dbc.dialect.PostgresDialect; +import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; import org.springframework.data.r2dbc.testing.StatementRecorder; import org.springframework.data.relational.core.mapping.Column; import org.springframework.data.relational.core.query.Update; @@ -37,6 +37,7 @@ * Unit test for {@link ReactiveUpdateOperation}. * * @author Mark Paluch + * @author Jens Schauder */ public class ReactiveUpdateOperationUnitTests { @@ -51,6 +52,8 @@ void before() { client = DatabaseClient.builder().connectionFactory(recorder) .bindMarkers(PostgresDialect.INSTANCE.getBindMarkersFactory()).build(); entityTemplate = new R2dbcEntityTemplate(client, new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)); + ((R2dbcMappingContext) entityTemplate.getDataAccessStrategy().getConverter().getMappingContext()) + .setForceQuote(false); } @Test // gh-410 diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/SqlServerReactiveDataAccessStrategyTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/SqlServerReactiveDataAccessStrategyTests.java index f911873866..a721f809dc 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/SqlServerReactiveDataAccessStrategyTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/SqlServerReactiveDataAccessStrategyTests.java @@ -16,16 +16,22 @@ package org.springframework.data.r2dbc.core; import org.springframework.data.r2dbc.dialect.SqlServerDialect; +import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; /** * {@link SqlServerDialect} specific tests for {@link ReactiveDataAccessStrategy}. * * @author Mark Paluch + * @author Jens Schauder */ public class SqlServerReactiveDataAccessStrategyTests extends ReactiveDataAccessStrategyTestSupport { private final ReactiveDataAccessStrategy strategy = new DefaultReactiveDataAccessStrategy(SqlServerDialect.INSTANCE); + SqlServerReactiveDataAccessStrategyTests() { + ((R2dbcMappingContext) strategy.getConverter().getMappingContext()).setForceQuote(false); + } + @Override protected ReactiveDataAccessStrategy getStrategy() { return strategy; diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/query/QueryMapperUnitTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/query/QueryMapperUnitTests.java index 76ceb3b2e5..cb7ef38a1f 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/query/QueryMapperUnitTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/query/QueryMapperUnitTests.java @@ -69,7 +69,7 @@ QueryMapper createMapper(R2dbcDialect dialect, Converter... converters) { R2dbcCustomConversions conversions = R2dbcCustomConversions.of(dialect, Arrays.asList(converters)); - R2dbcMappingContext context = new R2dbcMappingContext(); + R2dbcMappingContext context = R2dbcMappingContext.forPlainIdentifiers(); context.setSimpleTypeHolder(conversions.getSimpleTypeHolder()); context.afterPropertiesSet(); diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/query/UpdateMapperUnitTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/query/UpdateMapperUnitTests.java index 6bb448d4b3..60100dd713 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/query/UpdateMapperUnitTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/query/UpdateMapperUnitTests.java @@ -22,7 +22,6 @@ import java.util.stream.Collectors; import org.junit.jupiter.api.Test; - import org.springframework.data.r2dbc.convert.MappingR2dbcConverter; import org.springframework.data.r2dbc.convert.R2dbcConverter; import org.springframework.data.r2dbc.dialect.PostgresDialect; @@ -43,10 +42,11 @@ * * @author Mark Paluch * @author Mingyuan Wu + * @author Jens Schauder */ public class UpdateMapperUnitTests { - private final R2dbcConverter converter = new MappingR2dbcConverter(new R2dbcMappingContext()); + private final R2dbcConverter converter = new MappingR2dbcConverter(R2dbcMappingContext.forPlainIdentifiers()); private final UpdateMapper mapper = new UpdateMapper(PostgresDialect.INSTANCE, converter); private final BindTarget bindTarget = mock(BindTarget.class); diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/CompositeIdRepositoryIntegrationTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/CompositeIdRepositoryIntegrationTests.java index 9e868577fb..1193773fdc 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/CompositeIdRepositoryIntegrationTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/CompositeIdRepositoryIntegrationTests.java @@ -20,6 +20,8 @@ import io.r2dbc.spi.ConnectionFactory; import reactor.test.StepVerifier; +import java.util.Optional; + import javax.sql.DataSource; import org.junit.jupiter.api.BeforeEach; @@ -32,9 +34,13 @@ import org.springframework.dao.DataAccessException; import org.springframework.data.annotation.Id; import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration; +import org.springframework.data.r2dbc.convert.R2dbcCustomConversions; +import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories; import org.springframework.data.r2dbc.testing.H2TestSupport; +import org.springframework.data.relational.RelationalManagedTypes; import org.springframework.data.relational.core.mapping.Embedded; +import org.springframework.data.relational.core.mapping.NamingStrategy; import org.springframework.data.relational.core.mapping.Table; import org.springframework.data.repository.reactive.ReactiveCrudRepository; import org.springframework.jdbc.core.JdbcTemplate; @@ -60,6 +66,16 @@ public ConnectionFactory connectionFactory() { return H2TestSupport.createConnectionFactory(); } + @Override + public R2dbcMappingContext r2dbcMappingContext(Optional namingStrategy, + R2dbcCustomConversions r2dbcCustomConversions, RelationalManagedTypes r2dbcManagedTypes) { + + R2dbcMappingContext context = super.r2dbcMappingContext(namingStrategy, r2dbcCustomConversions, + r2dbcManagedTypes); + context.setForceQuote(false); + + return context; + } } @BeforeEach diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/H2R2dbcRepositoryIntegrationTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/H2R2dbcRepositoryIntegrationTests.java index 5ac98729b0..3dc2cc827c 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/H2R2dbcRepositoryIntegrationTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/H2R2dbcRepositoryIntegrationTests.java @@ -15,7 +15,20 @@ */ package org.springframework.data.r2dbc.repository; +import static org.assertj.core.api.Assertions.*; + import io.r2dbc.spi.ConnectionFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import javax.sql.DataSource; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -27,31 +40,26 @@ import org.springframework.context.annotation.FilterType; import org.springframework.data.annotation.Id; import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration; +import org.springframework.data.r2dbc.convert.R2dbcCustomConversions; +import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; import org.springframework.data.r2dbc.mapping.event.AfterConvertCallback; import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories; import org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactory; import org.springframework.data.r2dbc.testing.H2TestSupport; +import org.springframework.data.relational.RelationalManagedTypes; +import org.springframework.data.relational.core.mapping.NamingStrategy; import org.springframework.data.relational.core.mapping.Table; import org.springframework.data.relational.core.sql.SqlIdentifier; import org.springframework.data.repository.reactive.ReactiveCrudRepository; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; - -import javax.sql.DataSource; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import static org.assertj.core.api.Assertions.*; /** * Integration tests for {@link LegoSetRepository} using {@link R2dbcRepositoryFactory} against H2. * * @author Mark Paluch * @author Zsombor Gegesy + * @author Jens Schauder */ @ExtendWith(SpringExtension.class) @ContextConfiguration @@ -63,7 +71,8 @@ public class H2R2dbcRepositoryIntegrationTests extends AbstractR2dbcRepositoryIn @Configuration @EnableR2dbcRepositories(considerNestedRepositories = true, - includeFilters = @Filter(classes = {H2LegoSetRepository.class, IdOnlyEntityRepository.class}, type = FilterType.ASSIGNABLE_TYPE)) + includeFilters = @Filter(classes = { H2LegoSetRepository.class, IdOnlyEntityRepository.class }, + type = FilterType.ASSIGNABLE_TYPE)) static class IntegrationTestConfiguration extends AbstractR2dbcConfiguration { @Bean @@ -72,6 +81,17 @@ public ConnectionFactory connectionFactory() { return H2TestSupport.createConnectionFactory(); } + @Override + public R2dbcMappingContext r2dbcMappingContext(Optional namingStrategy, + R2dbcCustomConversions r2dbcCustomConversions, RelationalManagedTypes r2dbcManagedTypes) { + + R2dbcMappingContext context = super.r2dbcMappingContext(namingStrategy, r2dbcCustomConversions, + r2dbcManagedTypes); + context.setForceQuote(false); + + return context; + } + @Bean public AfterConvertCallbackRecorder afterConvertCallbackRecorder() { return new AfterConvertCallbackRecorder(); @@ -158,11 +178,10 @@ void shouldInsertIdOnlyEntity() { this.jdbc.execute("CREATE TABLE ID_ONLY(id serial CONSTRAINT id_only_pk PRIMARY KEY)"); IdOnlyEntity entity1 = new IdOnlyEntity(); - idOnlyEntityRepository.saveAll(Collections.singletonList(entity1)) - .as(StepVerifier::create) // - .consumeNextWith( actual -> { - assertThat(actual.getId()).isNotNull(); - }).verifyComplete(); + idOnlyEntityRepository.saveAll(Collections.singletonList(entity1)).as(StepVerifier::create) // + .consumeNextWith(actual -> { + assertThat(actual.getId()).isNotNull(); + }).verifyComplete(); } @Test // gh-519 @@ -214,11 +233,9 @@ interface IdOnlyEntityRepository extends ReactiveCrudRepository namingStrategy, + R2dbcCustomConversions r2dbcCustomConversions, RelationalManagedTypes r2dbcManagedTypes) { + R2dbcMappingContext mappingContext = super.r2dbcMappingContext(namingStrategy, r2dbcCustomConversions, + r2dbcManagedTypes); + mappingContext.setForceQuote(false); + return mappingContext; + } } @Override diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/ProjectingRepositoryIntegrationTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/ProjectingRepositoryIntegrationTests.java index 4c1a8fc7bd..4f75bad392 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/ProjectingRepositoryIntegrationTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/ProjectingRepositoryIntegrationTests.java @@ -22,12 +22,13 @@ import reactor.core.publisher.Flux; import reactor.test.StepVerifier; +import java.util.Optional; + import javax.sql.DataSource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -35,8 +36,12 @@ import org.springframework.dao.DataAccessException; import org.springframework.data.annotation.Id; import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration; +import org.springframework.data.r2dbc.convert.R2dbcCustomConversions; +import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories; import org.springframework.data.r2dbc.testing.H2TestSupport; +import org.springframework.data.relational.RelationalManagedTypes; +import org.springframework.data.relational.core.mapping.NamingStrategy; import org.springframework.data.relational.core.mapping.Table; import org.springframework.data.repository.reactive.ReactiveCrudRepository; import org.springframework.jdbc.core.JdbcTemplate; @@ -47,24 +52,33 @@ * Integration tests projections. * * @author Mark Paluch + * @author Jens Schauder */ @ExtendWith(SpringExtension.class) public class ProjectingRepositoryIntegrationTests { - @Autowired - private ImmutableObjectRepository repository; + @Autowired private ImmutableObjectRepository repository; private JdbcTemplate jdbc; @Configuration - @EnableR2dbcRepositories( - includeFilters = @ComponentScan.Filter(value = ImmutableObjectRepository.class, type = FilterType.ASSIGNABLE_TYPE), - considerNestedRepositories = true) + @EnableR2dbcRepositories(includeFilters = @ComponentScan.Filter(value = ImmutableObjectRepository.class, + type = FilterType.ASSIGNABLE_TYPE), considerNestedRepositories = true) static class TestConfiguration extends AbstractR2dbcConfiguration { @Override public ConnectionFactory connectionFactory() { return H2TestSupport.createConnectionFactory(); } + @Override + public R2dbcMappingContext r2dbcMappingContext(Optional namingStrategy, + R2dbcCustomConversions r2dbcCustomConversions, RelationalManagedTypes r2dbcManagedTypes) { + + R2dbcMappingContext context = super.r2dbcMappingContext(namingStrategy, r2dbcCustomConversions, + r2dbcManagedTypes); + context.setForceQuote(false); + + return context; + } } @BeforeEach @@ -74,9 +88,7 @@ void before() { try { this.jdbc.execute("DROP TABLE immutable_non_null"); - } - catch (DataAccessException e) { - } + } catch (DataAccessException e) {} this.jdbc.execute("CREATE TABLE immutable_non_null (id serial PRIMARY KEY, name varchar(255), email varchar(255))"); this.jdbc.execute("INSERT INTO immutable_non_null VALUES (42, 'Walter', 'heisenberg@the-white-family.com')"); @@ -100,8 +112,7 @@ protected ConnectionFactory createConnectionFactory() { return H2TestSupport.createConnectionFactory(); } - @Test - // GH-1687 + @Test // GH-1687 void shouldApplyProjectionDirectly() { repository.findProjectionByEmail("heisenberg@the-white-family.com") // @@ -111,8 +122,7 @@ void shouldApplyProjectionDirectly() { }).verifyComplete(); } - @Test - // GH-1687 + @Test // GH-1687 void shouldApplyEntityQueryProjectionDirectly() { repository.findAllByEmail("heisenberg@the-white-family.com") // @@ -134,8 +144,7 @@ interface ImmutableObjectRepository extends ReactiveCrudRepository TABLE + f) .toArray(String[]::new); - private static final String ALL_FIELDS = String.join(", ", ALL_FIELDS_ARRAY_PREFIXED); - private static final String DISTINCT = "DISTINCT"; @Mock ConnectionFactory connectionFactory; @Mock R2dbcConverter r2dbcConverter; @@ -101,7 +99,7 @@ void setUp() { when(r2dbcConverter.writeValue(any(), any())).thenAnswer(invocation -> invocation.getArgument(0)); - mappingContext = new R2dbcMappingContext(); + mappingContext = R2dbcMappingContext.forPlainIdentifiers(); doReturn(mappingContext).when(r2dbcConverter).getMappingContext(); R2dbcDialect dialect = DialectResolver.getDialect(connectionFactory); @@ -692,8 +690,7 @@ void createsQueryToFindByOpenProjection() throws Exception { .from(TABLE); } - @Test - // GH-475, GH-1687 + @Test // GH-475, GH-1687 void createsDtoProjectionQuery() throws Exception { R2dbcQueryMethod queryMethod = getQueryMethod("findAsDtoProjectionByAge", Integer.TYPE); diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryMethodUnitTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryMethodUnitTests.java index b15c9b8d36..e71bf361bb 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryMethodUnitTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryMethodUnitTests.java @@ -18,8 +18,6 @@ import static org.assertj.core.api.Assertions.*; import kotlin.Unit; -import org.springframework.data.relational.repository.Lock; -import org.springframework.data.relational.core.sql.LockMode; import reactor.core.publisher.Mono; import java.lang.annotation.Retention; @@ -29,7 +27,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; - import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -39,7 +36,9 @@ import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; import org.springframework.data.r2dbc.repository.Modifying; import org.springframework.data.relational.core.mapping.RelationalMappingContext; +import org.springframework.data.relational.core.sql.LockMode; import org.springframework.data.relational.core.sql.SqlIdentifier; +import org.springframework.data.relational.repository.Lock; import org.springframework.data.relational.repository.query.RelationalEntityMetadata; import org.springframework.data.repository.Repository; import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; @@ -50,6 +49,7 @@ * @author Mark Paluch * @author Stephen Cohen * @author Diego Krupitza + * @author Jens Schauder */ class R2dbcQueryMethodUnitTests { @@ -57,7 +57,8 @@ class R2dbcQueryMethodUnitTests { @BeforeEach void setUp() { - this.context = new R2dbcMappingContext(); + + this.context = R2dbcMappingContext.forPlainIdentifiers(); } @Test diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/support/H2SimpleR2dbcRepositoryIntegrationTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/support/H2SimpleR2dbcRepositoryIntegrationTests.java index 40fe8cfc40..bafb3ddf1f 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/support/H2SimpleR2dbcRepositoryIntegrationTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/support/H2SimpleR2dbcRepositoryIntegrationTests.java @@ -15,7 +15,16 @@ */ package org.springframework.data.r2dbc.repository.support; +import static org.assertj.core.api.Assertions.*; + import io.r2dbc.spi.ConnectionFactory; +import reactor.test.StepVerifier; + +import java.util.Map; +import java.util.Optional; + +import javax.sql.DataSource; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -25,26 +34,25 @@ import org.springframework.data.annotation.Id; import org.springframework.data.domain.Persistable; import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration; +import org.springframework.data.r2dbc.convert.R2dbcCustomConversions; import org.springframework.data.r2dbc.core.R2dbcEntityTemplate; +import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; import org.springframework.data.r2dbc.testing.H2TestSupport; +import org.springframework.data.relational.RelationalManagedTypes; +import org.springframework.data.relational.core.mapping.NamingStrategy; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.repository.query.RelationalEntityInformation; import org.springframework.data.relational.repository.support.MappingRelationalEntityInformation; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; -import reactor.test.StepVerifier; - -import javax.sql.DataSource; -import java.util.Map; - -import static org.assertj.core.api.Assertions.*; /** * Integration tests for {@link SimpleR2dbcRepository} against H2. * * @author Mark Paluch * @author Greg Turnquist + * @author Jens Schauder */ @ExtendWith(SpringExtension.class) @ContextConfiguration @@ -61,6 +69,17 @@ static class IntegrationTestConfiguration extends AbstractR2dbcConfiguration { public ConnectionFactory connectionFactory() { return H2TestSupport.createConnectionFactory(); } + + @Override + public R2dbcMappingContext r2dbcMappingContext(Optional namingStrategy, + R2dbcCustomConversions r2dbcCustomConversions, RelationalManagedTypes r2dbcManagedTypes) { + + R2dbcMappingContext context = super.r2dbcMappingContext(namingStrategy, r2dbcCustomConversions, + r2dbcManagedTypes); + context.setForceQuote(false); + + return context; + } } @Override @@ -119,8 +138,7 @@ void updateShouldFailIfRowDoesNotExist() { static class AlwaysNew implements Persistable { - @Id - Long id; + @Id Long id; String name; public AlwaysNew(Long id, String name) { diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/support/SqlInspectingR2dbcRepositoryUnitTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/support/SqlInspectingR2dbcRepositoryUnitTests.java index 4e2a430e9f..a34325cc45 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/support/SqlInspectingR2dbcRepositoryUnitTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/support/SqlInspectingR2dbcRepositoryUnitTests.java @@ -32,7 +32,6 @@ import org.springframework.data.r2dbc.core.DefaultReactiveDataAccessStrategy; import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy; import org.springframework.data.r2dbc.dialect.H2Dialect; -import org.springframework.data.r2dbc.dialect.PostgresDialect; import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; import org.springframework.data.r2dbc.repository.Query; import org.springframework.data.r2dbc.testing.StatementRecorder; @@ -47,17 +46,21 @@ @ExtendWith(MockitoExtension.class) public class SqlInspectingR2dbcRepositoryUnitTests { - R2dbcConverter r2dbcConverter = new MappingR2dbcConverter(new R2dbcMappingContext()); + R2dbcMappingContext context; + R2dbcConverter r2dbcConverter; DatabaseClient databaseClient; StatementRecorder recorder = StatementRecorder.newInstance(); - ReactiveDataAccessStrategy dataAccessStrategy = new DefaultReactiveDataAccessStrategy(H2Dialect.INSTANCE); - + ReactiveDataAccessStrategy dataAccessStrategy; @BeforeEach @SuppressWarnings("unchecked") public void before() { + context = R2dbcMappingContext.forPlainIdentifiers(); + r2dbcConverter = new MappingR2dbcConverter(context); + dataAccessStrategy = new DefaultReactiveDataAccessStrategy(H2Dialect.INSTANCE, r2dbcConverter); + databaseClient = DatabaseClient.builder().connectionFactory(recorder) .bindMarkers(H2Dialect.INSTANCE.getBindMarkersFactory()).build(); @@ -75,7 +78,8 @@ public void replacesSpelExpressionInQuery() { repository.findBySpel().block(Duration.ofMillis(100)); - StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(SqlInspectingR2dbcRepositoryUnitTests::isSelect); + StatementRecorder.RecordedStatement statement = recorder + .getCreatedStatement(SqlInspectingR2dbcRepositoryUnitTests::isSelect); assertThat(statement.getSql()).isEqualTo("select * from PERSONx"); } diff --git a/spring-data-relational/pom.xml b/spring-data-relational/pom.xml index 8fd6d7a6f0..59e576e23d 100644 --- a/spring-data-relational/pom.xml +++ b/spring-data-relational/pom.xml @@ -6,7 +6,7 @@ 4.0.0 spring-data-relational - 4.0.0-SNAPSHOT + 4.0.0-1993-force-quoting-SNAPSHOT Spring Data Relational Spring Data Relational support @@ -14,7 +14,7 @@ org.springframework.data spring-data-relational-parent - 4.0.0-SNAPSHOT + 4.0.0-1993-force-quoting-SNAPSHOT diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/PostgresDialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/PostgresDialect.java index a06b4e3b25..4a787f9e19 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/PostgresDialect.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/PostgresDialect.java @@ -51,10 +51,9 @@ public class PostgresDialect extends AbstractDialect { * Singleton instance. * * @deprecated use either the {@code org.springframework.data.r2dbc.dialect.PostgresDialect} or - * {@code org.springframework.data.jdbc.core.dialect.JdbcPostgresDialect}. + * {@code org.springframework.data.jdbc.core.dialect.JdbcPostgresDialect}. */ - @Deprecated(forRemoval = true) - public static final PostgresDialect INSTANCE = new PostgresDialect(); + @Deprecated(forRemoval = true) public static final PostgresDialect INSTANCE = new PostgresDialect(); private static final Set> POSTGRES_SIMPLE_TYPES = Set.of(UUID.class, URL.class, URI.class, InetAddress.class, Map.class); @@ -102,7 +101,7 @@ public LimitClause limit() { return LIMIT_CLAUSE; } - private final PostgresLockClause LOCK_CLAUSE = new PostgresLockClause(this.getIdentifierProcessing()); + private final PostgresLockClause LOCK_CLAUSE = new PostgresLockClause(); @Override public LockClause lock() { @@ -121,12 +120,6 @@ public Collection getConverters() { static class PostgresLockClause implements LockClause { - private final IdentifierProcessing identifierProcessing; - - PostgresLockClause(IdentifierProcessing identifierProcessing) { - this.identifierProcessing = identifierProcessing; - } - @Override public String getLock(LockOptions lockOptions) { @@ -144,7 +137,7 @@ public String getLock(LockOptions lockOptions) { } // without schema - String tableName = last.toSql(this.identifierProcessing); + String tableName = last.toSql(PostgresDialect.identifierProcessing); return switch (lockOptions.getLockMode()) { case PESSIMISTIC_WRITE -> "FOR UPDATE OF " + tableName; diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/DerivedSqlIdentifier.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/DerivedSqlIdentifier.java index 945793f8fa..c3bd07e1dd 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/DerivedSqlIdentifier.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/DerivedSqlIdentifier.java @@ -42,6 +42,7 @@ class DerivedSqlIdentifier implements SqlIdentifier { DerivedSqlIdentifier(String name, boolean quoted) { Assert.hasText(name, "A database object must have at least on name part."); + this.name = name; this.quoted = quoted; this.toString = quoted ? toSql(IdentifierProcessing.ANSI) : this.name;