From a6eb7130d34c6d3afb8de7c69565a34ae5ba5927 Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Mon, 2 Dec 2019 14:13:31 +0100 Subject: [PATCH 1/6] DATAJDBC-386 - Prepare branch --- pom.xml | 2 +- spring-data-jdbc-distribution/pom.xml | 2 +- spring-data-jdbc/pom.xml | 4 ++-- spring-data-relational/pom.xml | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index c7d878511b..a248105651 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-relational-parent - 1.2.0.BUILD-SNAPSHOT + 1.2.0.DATAJDBC-386-SNAPSHOT pom Spring Data Relational Parent diff --git a/spring-data-jdbc-distribution/pom.xml b/spring-data-jdbc-distribution/pom.xml index f2bbb72319..a932f78c27 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 - 1.2.0.BUILD-SNAPSHOT + 1.2.0.DATAJDBC-386-SNAPSHOT ../pom.xml diff --git a/spring-data-jdbc/pom.xml b/spring-data-jdbc/pom.xml index 0904eb8136..f6d2cf9cb1 100644 --- a/spring-data-jdbc/pom.xml +++ b/spring-data-jdbc/pom.xml @@ -5,7 +5,7 @@ 4.0.0 spring-data-jdbc - 1.2.0.BUILD-SNAPSHOT + 1.2.0.DATAJDBC-386-SNAPSHOT Spring Data JDBC Spring Data module for JDBC repositories. @@ -14,7 +14,7 @@ org.springframework.data spring-data-relational-parent - 1.2.0.BUILD-SNAPSHOT + 1.2.0.DATAJDBC-386-SNAPSHOT diff --git a/spring-data-relational/pom.xml b/spring-data-relational/pom.xml index 1751c4244e..206a8c2628 100644 --- a/spring-data-relational/pom.xml +++ b/spring-data-relational/pom.xml @@ -5,7 +5,7 @@ 4.0.0 spring-data-relational - 1.2.0.BUILD-SNAPSHOT + 1.2.0.DATAJDBC-386-SNAPSHOT Spring Data Relational Spring Data Relational support @@ -13,7 +13,7 @@ org.springframework.data spring-data-relational-parent - 1.2.0.BUILD-SNAPSHOT + 1.2.0.DATAJDBC-386-SNAPSHOT From 1c45f0817bc7a029df0ca4838a6cc46fc6cf77b0 Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Mon, 2 Dec 2019 14:50:53 +0100 Subject: [PATCH 2/6] DATAJDBC-386 - Introduces quoting for all database identifier. All database indentifiers, i.e. table names, column names and so on, now get quoted. For most databases this means they get enclosed with double quotes. For some databases this makes the the identifiers case sensitive. In order to minimize the impact we convert identifiers their default letter casing. This should be upper case according to the SQL standard but isn't for some databases. The exact behavior regarding quoting and default letter casing gets controlled by a database specific `Dialect`. Future changes will make the quoting of annotated columns and the default quoting behavior configurable. --- .../jdbc/core/DefaultJdbcInterpreter.java | 2 +- .../jdbc/core/convert/BasicJdbcConverter.java | 9 +- .../convert/CascadingDataAccessStrategy.java | 3 +- .../jdbc/core/convert/DataAccessStrategy.java | 14 +- .../convert/DefaultDataAccessStrategy.java | 132 ++++--- .../convert/DelegatingDataAccessStrategy.java | 4 +- .../jdbc/core/convert/MapEntityRowMapper.java | 9 +- .../data/jdbc/core/convert/SqlContext.java | 27 +- .../data/jdbc/core/convert/SqlGenerator.java | 140 ++++--- .../jdbc/core/convert/SqlGeneratorSource.java | 13 +- .../convert/SqlIdentifierParameterSource.java | 84 ++++ .../mybatis/MyBatisDataAccessStrategy.java | 113 ++++-- .../config/AbstractJdbcConfiguration.java | 15 +- .../repository/config/JdbcConfiguration.java | 19 +- .../config/MyBatisJdbcConfiguration.java | 5 +- .../support/JdbcRepositoryFactoryBean.java | 11 +- .../core/DefaultJdbcInterpreterUnitTests.java | 23 +- ...JdbcAggregateTemplateIntegrationTests.java | 230 +++++------ ...sistentPropertyPathExtensionUnitTests.java | 74 ++-- .../DefaultDataAccessStrategyUnitTests.java | 30 +- .../convert/EntityRowMapperUnitTests.java | 69 ++-- .../JdbcIdentifierBuilderUnitTests.java | 15 +- ...orContextBasedNamingStrategyUnitTests.java | 20 +- .../SqlGeneratorEmbeddedUnitTests.java | 133 ++++--- ...GeneratorFixedNamingStrategyUnitTests.java | 46 ++- .../core/convert/SqlGeneratorUnitTests.java | 128 +++--- ...SqlIdentifierParameterSourceUnitTests.java | 118 ++++++ .../BasicJdbcPersistentPropertyUnitTests.java | 30 +- .../model/NamingStrategyUnitTests.java | 18 +- ...tomizingNamespaceHsqlIntegrationTests.java | 12 +- .../MyBatisDataAccessStrategyUnitTests.java | 23 +- .../mybatis/MyBatisHsqlIntegrationTests.java | 64 +-- ...epositoryIdGenerationIntegrationTests.java | 7 +- .../SimpleJdbcRepositoryEventsUnitTests.java | 3 +- ...nableJdbcAuditingHsqlIntegrationTests.java | 6 +- ...nableJdbcRepositoriesIntegrationTests.java | 7 +- .../JdbcRepositoryFactoryBeanUnitTests.java | 5 + .../testing/HsqlDataSourceConfiguration.java | 7 + .../MariaDBDataSourceConfiguration.java | 10 + .../testing/MySqlDataSourceConfiguration.java | 8 + .../PostgresDataSourceConfiguration.java | 8 + .../data/jdbc/testing/TestConfiguration.java | 7 +- ...ggregateTemplateIntegrationTests-mysql.sql | 361 ++++++++--------- ...egateTemplateIntegrationTests-postgres.sql | 369 +++++++++--------- .../data/relational/core/dialect/Dialect.java | 12 + .../core/dialect/HsqlDbDialect.java | 57 +++ .../core/dialect/MariaDbDialect.java | 29 ++ .../relational/core/dialect/MySqlDialect.java | 14 +- .../core/dialect/PostgresDialect.java | 11 + .../core/dialect/SqlServerDialect.java | 2 + .../BasicRelationalPersistentProperty.java | 35 +- .../core/mapping/CachingNamingStrategy.java | 28 +- .../core/mapping/NamingStrategy.java | 28 +- .../PersistentPropertyPathExtension.java | 43 +- .../mapping/RelationalPersistentEntity.java | 5 +- .../RelationalPersistentEntityImpl.java | 8 +- .../mapping/RelationalPersistentProperty.java | 10 +- .../data/relational/domain/Identifier.java | 20 +- .../domain/IdentifierProcessing.java | 151 +++++++ .../data/relational/domain/SqlIdentifier.java | 219 +++++++++++ .../query/RelationalEntityInformation.java | 3 +- .../query/RelationalEntityMetadata.java | 3 +- .../query/SimpleRelationalEntityMetadata.java | 3 +- .../MappingRelationalEntityInformation.java | 7 +- .../core/dialect/HsqlDbDialectUnitTests.java | 69 ++++ .../core/dialect/MariaDbDialectUnitTests.java | 69 ++++ .../core/dialect/MySqlDialectUnitTests.java | 8 + ...RelationalPersistentPropertyUnitTests.java | 20 +- .../core/mapping/NamingStrategyUnitTests.java | 28 +- ...lationalPersistentEntityImplUnitTests.java | 7 +- .../core/mapping/SqlIdentifierUnitTests.java | 123 ++++++ .../DefaultIdentifierProcessingUnitTests.java | 49 +++ .../domain/IdentifierUnitTests.java | 41 +- 73 files changed, 2416 insertions(+), 1117 deletions(-) create mode 100644 spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSource.java create mode 100644 spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSourceUnitTests.java create mode 100644 spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/HsqlDbDialect.java create mode 100644 spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/MariaDbDialect.java create mode 100644 spring-data-relational/src/main/java/org/springframework/data/relational/domain/IdentifierProcessing.java create mode 100644 spring-data-relational/src/main/java/org/springframework/data/relational/domain/SqlIdentifier.java create mode 100644 spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/HsqlDbDialectUnitTests.java create mode 100644 spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/MariaDbDialectUnitTests.java create mode 100644 spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/SqlIdentifierUnitTests.java create mode 100644 spring-data-relational/src/test/java/org/springframework/data/relational/domain/DefaultIdentifierProcessingUnitTests.java diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/DefaultJdbcInterpreter.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/DefaultJdbcInterpreter.java index 439724e3d8..0bc2a6e921 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/DefaultJdbcInterpreter.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/DefaultJdbcInterpreter.java @@ -266,7 +266,7 @@ private Object getIdFrom(DbAction.WithEntity idOwningAction) { .getRequiredPersistentEntity(idOwningAction.getEntityType()); Object identifier = persistentEntity.getIdentifierAccessor(idOwningAction.getEntity()).getIdentifier(); - Assert.state(identifier != null, "Couldn't get obtain a required id value"); + Assert.state(identifier != null, "Couldn't obtain a required id value"); return identifier; } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java index 703ec5c552..69c11faf33 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java @@ -37,12 +37,14 @@ import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.relational.core.conversion.BasicRelationalConverter; import org.springframework.data.relational.core.conversion.RelationalConverter; +import org.springframework.data.relational.core.dialect.HsqlDbDialect; import org.springframework.data.relational.core.mapping.Embedded; import org.springframework.data.relational.core.mapping.Embedded.OnEmpty; import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; import org.springframework.data.relational.domain.Identifier; +import org.springframework.data.relational.domain.IdentifierProcessing; import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; import org.springframework.lang.Nullable; @@ -69,6 +71,7 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc private static final Converter, Map> ITERABLE_OF_ENTRY_TO_MAP_CONVERTER = new IterableOfEntryToMapConverter(); private final JdbcTypeFactory typeFactory; + private final IdentifierProcessing identifierProcessing = HsqlDbDialect.INSTANCE.getIdentifierProcessing(); private RelationResolver relationResolver; @@ -374,7 +377,8 @@ private Object readFrom(RelationalPersistentProperty property) { return readEntityFrom(property, path); } - Object value = getObjectFromResultSet(path.extendBy(property).getColumnAlias()); + Object value = getObjectFromResultSet( + path.extendBy(property).getColumnAlias().toColumnName(identifierProcessing)); return readValue(value, property.getTypeInformation()); } @@ -428,7 +432,8 @@ private Object readEntityFrom(RelationalPersistentProperty property, PersistentP if (idProperty != null) { idValue = newContext.readFrom(idProperty); } else { - idValue = newContext.getObjectFromResultSet(path.extendBy(property).getReverseColumnNameAlias()); + idValue = newContext.getObjectFromResultSet( + path.extendBy(property).getReverseColumnNameAlias().toColumnName(identifierProcessing)); } if (idValue == null) { diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/CascadingDataAccessStrategy.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/CascadingDataAccessStrategy.java index dee263106a..0deff63fc1 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/CascadingDataAccessStrategy.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/CascadingDataAccessStrategy.java @@ -24,6 +24,7 @@ import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; import org.springframework.data.relational.domain.Identifier; +import org.springframework.data.relational.domain.SqlIdentifier; /** * Delegates each methods to the {@link DataAccessStrategy}s passed to the constructor in turn until the first that does @@ -47,7 +48,7 @@ public CascadingDataAccessStrategy(List strategies) { * @see org.springframework.data.jdbc.core.DataAccessStrategy#insert(java.lang.Object, java.lang.Class, java.util.Map) */ @Override - public Object insert(T instance, Class domainType, Map additionalParameters) { + public Object insert(T instance, Class domainType, Map additionalParameters) { return collect(das -> das.insert(instance, domainType, additionalParameters)); } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DataAccessStrategy.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DataAccessStrategy.java index fde16ad40c..dc612fc71d 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DataAccessStrategy.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DataAccessStrategy.java @@ -22,6 +22,7 @@ import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; import org.springframework.data.relational.domain.Identifier; +import org.springframework.data.relational.domain.SqlIdentifier; import org.springframework.lang.Nullable; /** @@ -46,7 +47,8 @@ public interface DataAccessStrategy extends RelationResolver { * @deprecated since 1.1, use {@link #insert(Object, Class, Identifier)} instead. */ @Deprecated - Object insert(T instance, Class domainType, Map additionalParameters); + @Nullable + Object insert(T instance, Class domainType, Map additionalParameters); /** * Inserts a the data of a single entity. Referenced entities don't get handled. @@ -76,8 +78,8 @@ default Object insert(T instance, Class domainType, Identifier identifier boolean update(T instance, Class domainType); /** - * Updates the data of a single entity in the database and enforce optimistic record locking using the {@code previousVersion} - * property. Referenced entities don't get handled. + * Updates the data of a single entity in the database and enforce optimistic record locking using the + * {@code previousVersion} property. Referenced entities don't get handled. *

* The statement will be of the form : {@code UPDATE … SET … WHERE ID = :id and VERSION_COLUMN = :previousVersion } * and throw an optimistic record locking exception if no rows have been updated. @@ -87,7 +89,8 @@ default Object insert(T instance, Class domainType, Identifier identifier * @param previousVersion The previous version assigned to the instance being saved. * @param the type of the instance to save. * @return whether the update actually updated a row. - * @throws OptimisticLockingFailureException if the update fails to update at least one row assuming the the optimistic locking version check failed. + * @throws OptimisticLockingFailureException if the update fails to update at least one row assuming the the + * optimistic locking version check failed. * @since 2.0 */ boolean updateWithVersion(T instance, Class domainType, Number previousVersion); @@ -113,7 +116,8 @@ default Object insert(T instance, Class domainType, Identifier identifier * @param domainType the type of entity to be deleted. Implicitly determines the table to operate on. Must not be * {@code null}. * @param previousVersion The previous version assigned to the instance being saved. - * @throws OptimisticLockingFailureException if the update fails to update at least one row assuming the the optimistic locking version check failed. + * @throws OptimisticLockingFailureException if the update fails to update at least one row assuming the the + * optimistic locking version check failed. * @since 2.0 */ void deleteWithVersion(Object id, Class domainType, Number previousVersion); diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategy.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategy.java index 298fd6ac6f..1860c8c945 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategy.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategy.java @@ -15,13 +15,11 @@ */ package org.springframework.data.jdbc.core.convert; -import static org.springframework.data.jdbc.core.convert.SqlGenerator.VERSION_SQL_PARAMETER_NAME; +import static org.springframework.data.jdbc.core.convert.SqlGenerator.*; import java.sql.JDBCType; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -36,15 +34,16 @@ import org.springframework.data.mapping.PersistentPropertyAccessor; import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.data.mapping.PropertyHandler; -import org.springframework.data.relational.core.conversion.RelationalEntityVersionUtils; import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; import org.springframework.data.relational.domain.Identifier; +import org.springframework.data.relational.domain.IdentifierProcessing; +import org.springframework.data.relational.domain.SqlIdentifier; import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; +import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.JdbcUtils; import org.springframework.jdbc.support.KeyHolder; @@ -98,7 +97,8 @@ public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, Relation * @see org.springframework.data.jdbc.core.DataAccessStrategy#insert(java.lang.Object, java.lang.Class, java.util.Map) */ @Override - public Object insert(T instance, Class domainType, Map additionalParameters) { + @Nullable + public Object insert(T instance, Class domainType, Map additionalParameters) { return insert(instance, domainType, Identifier.from(additionalParameters)); } @@ -109,11 +109,11 @@ public Object insert(T instance, Class domainType, Map ad @Override public Object insert(T instance, Class domainType, Identifier identifier) { - KeyHolder holder = new GeneratedKeyHolder(); + SqlGenerator sqlGenerator = sql(domainType); RelationalPersistentEntity persistentEntity = getRequiredPersistentEntity(domainType); - MapSqlParameterSource parameterSource = getParameterSource(instance, persistentEntity, "", - PersistentProperty::isIdProperty); + SqlIdentifierParameterSource parameterSource = getParameterSource(instance, persistentEntity, "", + PersistentProperty::isIdProperty, getIdentifierProcessing()); identifier.forEach((name, value, type) -> addConvertedPropertyValue(parameterSource, name, value, type)); @@ -124,8 +124,10 @@ public Object insert(T instance, Class domainType, Identifier identifier) addConvertedPropertyValue(parameterSource, idProperty, idValue, idProperty.getColumnName()); } + KeyHolder holder = new GeneratedKeyHolder(); + operations.update( // - sql(domainType).getInsert(new HashSet<>(Arrays.asList(parameterSource.getParameterNames()))), // + sqlGenerator.getInsert(new HashSet<>(parameterSource.getIdentifiers())), // parameterSource, // holder // ); @@ -142,7 +144,7 @@ public boolean update(S instance, Class domainType) { RelationalPersistentEntity persistentEntity = getRequiredPersistentEntity(domainType); return operations.update(sql(domainType).getUpdate(), - getParameterSource(instance, persistentEntity, "", Predicates.includeAll())) != 0; + getParameterSource(instance, persistentEntity, "", Predicates.includeAll(), getIdentifierProcessing())) != 0; } /* @@ -155,13 +157,14 @@ public boolean updateWithVersion(S instance, Class domainType, Number pre RelationalPersistentEntity persistentEntity = getRequiredPersistentEntity(domainType); // Adjust update statement to set the new version and use the old version in where clause. - MapSqlParameterSource parameterSource = getParameterSource(instance, persistentEntity, "", - Predicates.includeAll()); - parameterSource.addValue(VERSION_SQL_PARAMETER_NAME, previousVersion); + SqlIdentifierParameterSource parameterSource = getParameterSource(instance, persistentEntity, "", + Predicates.includeAll(), getIdentifierProcessing()); + parameterSource.addValue(VERSION_SQL_PARAMETER, previousVersion); int affectedRows = operations.update(sql(domainType).getUpdateWithVersion(), parameterSource); if (affectedRows == 0) { + throw new OptimisticLockingFailureException( String.format("Optimistic lock exception on saving entity of type %s.", persistentEntity.getName())); } @@ -177,7 +180,7 @@ public boolean updateWithVersion(S instance, Class domainType, Number pre public void delete(Object id, Class domainType) { String deleteByIdSql = sql(domainType).getDeleteById(); - MapSqlParameterSource parameter = createIdParameterSource(id, domainType); + SqlParameterSource parameter = createIdParameterSource(id, domainType); operations.update(deleteByIdSql, parameter); } @@ -193,8 +196,8 @@ public void deleteWithVersion(Object id, Class domainType, Number previou RelationalPersistentEntity persistentEntity = getRequiredPersistentEntity(domainType); - MapSqlParameterSource parameterSource = createIdParameterSource(id, domainType); - parameterSource.addValue(VERSION_SQL_PARAMETER_NAME, previousVersion); + SqlIdentifierParameterSource parameterSource = createIdParameterSource(id, domainType); + parameterSource.addValue(VERSION_SQL_PARAMETER, previousVersion); int affectedRows = operations.update(sql(domainType).getDeleteByIdAndVersion(), parameterSource); if (affectedRows == 0) { @@ -216,11 +219,11 @@ public void delete(Object rootId, PersistentPropertyPath parameters = new HashMap<>(); - parameters.put("rootId", rootId); - operations.update(format, parameters); + SqlIdentifierParameterSource parameters = new SqlIdentifierParameterSource(getIdentifierProcessing()); + parameters.addValue(ROOT_ID_PARAMETER, rootId); + operations.update(delete, parameters); } /* @@ -265,7 +268,7 @@ public long count(Class domainType) { public T findById(Object id, Class domainType) { String findOneSql = sql(domainType).getFindOne(); - MapSqlParameterSource parameter = createIdParameterSource(id, domainType); + SqlIdentifierParameterSource parameter = createIdParameterSource(id, domainType); try { return operations.queryForObject(findOneSql, parameter, (RowMapper) getEntityRowMapper(domainType)); @@ -297,9 +300,9 @@ public Iterable findAllById(Iterable ids, Class domainType) { } RelationalPersistentProperty idProperty = getRequiredPersistentEntity(domainType).getRequiredIdProperty(); - MapSqlParameterSource parameterSource = new MapSqlParameterSource(); + SqlIdentifierParameterSource parameterSource = new SqlIdentifierParameterSource(getIdentifierProcessing()); - addConvertedPropertyValuesAsList(parameterSource, idProperty, ids, "ids"); + addConvertedPropertyValuesAsList(parameterSource, idProperty, ids, IDS_SQL_PARAMETER); String findAllInListSql = sql(domainType).getFindAllInList(); @@ -324,12 +327,20 @@ public Iterable findAllByPath(Identifier identifier, String findAllByProperty = sql(actualType) // .getFindAllByProperty(identifier, path.getQualifierColumn(), path.isOrdered()); - MapSqlParameterSource parameters = new MapSqlParameterSource(identifier.toMap()); - RowMapper rowMapper = path.isMap() ? this.getMapEntityRowMapper(path, identifier) : this.getEntityRowMapper(path, identifier); - return operations.query(findAllByProperty, parameters, (RowMapper) rowMapper); + return operations.query(findAllByProperty, createParameterSource(identifier, getIdentifierProcessing()), + (RowMapper) rowMapper); + } + + private SqlParameterSource createParameterSource(Identifier identifier, IdentifierProcessing identifierProcessing) { + + SqlIdentifierParameterSource parameterSource = new SqlIdentifierParameterSource(identifierProcessing); + + identifier.toMap().forEach(parameterSource::addValue); + + return parameterSource; } /* @@ -355,7 +366,7 @@ public Iterable findAllByProperty(Object rootId, RelationalPersistentPro public boolean existsById(Object id, Class domainType) { String existsSql = sql(domainType).getExists(); - MapSqlParameterSource parameter = createIdParameterSource(id, domainType); + SqlParameterSource parameter = createIdParameterSource(id, domainType); Boolean result = operations.queryForObject(existsSql, parameter, Boolean.class); Assert.state(result != null, "The result of an exists query must not be null"); @@ -363,10 +374,11 @@ public boolean existsById(Object id, Class domainType) { return result; } - private MapSqlParameterSource getParameterSource(@Nullable S instance, RelationalPersistentEntity persistentEntity, - String prefix, Predicate skipProperty) { + private SqlIdentifierParameterSource getParameterSource(@Nullable S instance, + RelationalPersistentEntity persistentEntity, String prefix, + Predicate skipProperty, IdentifierProcessing identifierProcessing) { - MapSqlParameterSource parameters = new MapSqlParameterSource(); + SqlIdentifierParameterSource parameters = new SqlIdentifierParameterSource(identifierProcessing); PersistentPropertyAccessor propertyAccessor = instance != null ? persistentEntity.getPropertyAccessor(instance) : NoValuePropertyAccessor.instance(); @@ -384,13 +396,14 @@ private MapSqlParameterSource getParameterSource(@Nullable S instance, Re Object value = propertyAccessor.getProperty(property); RelationalPersistentEntity embeddedEntity = context.getPersistentEntity(property.getType()); - MapSqlParameterSource additionalParameters = getParameterSource((T) value, - (RelationalPersistentEntity) embeddedEntity, prefix + property.getEmbeddedPrefix(), skipProperty); - parameters.addValues(additionalParameters.getValues()); + SqlIdentifierParameterSource additionalParameters = getParameterSource((T) value, + (RelationalPersistentEntity) embeddedEntity, prefix + property.getEmbeddedPrefix(), skipProperty, + identifierProcessing); + parameters.addAll(additionalParameters); } else { Object value = propertyAccessor.getProperty(property); - String paramName = prefix + property.getColumnName(); + SqlIdentifier paramName = property.getColumnName().prefix(prefix); addConvertedPropertyValue(parameters, property, value, paramName); } @@ -434,7 +447,7 @@ private Object getIdFromHolder(KeyHolder holder, RelationalPersistentEntity< return null; } - return keys.get(persistentEntity.getIdColumn()); + return keys.get(persistentEntity.getIdColumn().toColumnName(getIdentifierProcessing())); } } @@ -448,55 +461,58 @@ private EntityRowMapper getEntityRowMapper(PersistentPropertyPathExtension pa private RowMapper getMapEntityRowMapper(PersistentPropertyPathExtension path, Identifier identifier) { - String keyColumn = path.getQualifierColumn(); + SqlIdentifier keyColumn = path.getQualifierColumn(); Assert.notNull(keyColumn, () -> "KeyColumn must not be null for " + path); - return new MapEntityRowMapper<>(path, converter, identifier, keyColumn); + return new MapEntityRowMapper<>(path, converter, identifier, keyColumn, getIdentifierProcessing()); } - private MapSqlParameterSource createIdParameterSource(Object id, Class domainType) { + private SqlIdentifierParameterSource createIdParameterSource(Object id, Class domainType) { - MapSqlParameterSource parameterSource = new MapSqlParameterSource(); + SqlIdentifierParameterSource parameterSource = new SqlIdentifierParameterSource(getIdentifierProcessing()); addConvertedPropertyValue( // parameterSource, // getRequiredPersistentEntity(domainType).getRequiredIdProperty(), // id, // - "id" // + ID_SQL_PARAMETER // ); return parameterSource; } - private void addConvertedPropertyValue(MapSqlParameterSource parameterSource, RelationalPersistentProperty property, - @Nullable Object value, String paramName) { + private IdentifierProcessing getIdentifierProcessing() { + return sqlGeneratorSource.getDialect().getIdentifierProcessing(); + } - JdbcValue jdbcValue = converter.writeJdbcValue( // - value, // - property.getColumnType(), // - property.getSqlType() // - ); + private void addConvertedPropertyValue(SqlIdentifierParameterSource parameterSource, + RelationalPersistentProperty property, @Nullable Object value, SqlIdentifier name) { - parameterSource.addValue(paramName, jdbcValue.getValue(), JdbcUtil.sqlTypeFor(jdbcValue.getJdbcType())); + addConvertedValue(parameterSource, value, name, property.getColumnType(), property.getSqlType()); } - private void addConvertedPropertyValue(MapSqlParameterSource parameterSource, String name, Object value, - Class type) { + private void addConvertedPropertyValue(SqlIdentifierParameterSource parameterSource, SqlIdentifier name, Object value, + Class javaType) { + + addConvertedValue(parameterSource, value, name, javaType, JdbcUtil.sqlTypeFor(javaType)); + } + + private void addConvertedValue(SqlIdentifierParameterSource parameterSource, @Nullable Object value, + SqlIdentifier paramName, Class javaType, int sqlType) { JdbcValue jdbcValue = converter.writeJdbcValue( // value, // - type, // - JdbcUtil.sqlTypeFor(type) // + javaType, // + sqlType // ); parameterSource.addValue( // - name, // + paramName, // jdbcValue.getValue(), // - JdbcUtil.sqlTypeFor(jdbcValue.getJdbcType()) // - ); + JdbcUtil.sqlTypeFor(jdbcValue.getJdbcType())); } - private void addConvertedPropertyValuesAsList(MapSqlParameterSource parameterSource, - RelationalPersistentProperty property, Iterable values, String paramName) { + private void addConvertedPropertyValuesAsList(SqlIdentifierParameterSource parameterSource, + RelationalPersistentProperty property, Iterable values, SqlIdentifier paramName) { List convertedIds = new ArrayList<>(); JdbcValue jdbcValue = null; diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DelegatingDataAccessStrategy.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DelegatingDataAccessStrategy.java index d98536aa05..2b3cd5754a 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DelegatingDataAccessStrategy.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DelegatingDataAccessStrategy.java @@ -20,6 +20,7 @@ import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; import org.springframework.data.relational.domain.Identifier; +import org.springframework.data.relational.domain.SqlIdentifier; import org.springframework.util.Assert; /** @@ -39,7 +40,7 @@ public class DelegatingDataAccessStrategy implements DataAccessStrategy { * @see org.springframework.data.jdbc.core.DataAccessStrategy#insert(java.lang.Object, java.lang.Class, java.util.Map) */ @Override - public Object insert(T instance, Class domainType, Map additionalParameters) { + public Object insert(T instance, Class domainType, Map additionalParameters) { return delegate.insert(instance, domainType, additionalParameters); } @@ -70,6 +71,7 @@ public boolean updateWithVersion(S instance, Class domainType, Number nex return delegate.updateWithVersion(instance, domainType, nextVersion); } + /* * (non-Javadoc) * @see org.springframework.data.jdbc.core.DataAccessStrategy#delete(java.lang.Object, org.springframework.data.mapping.PersistentPropertyPath) diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/MapEntityRowMapper.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/MapEntityRowMapper.java index 2125a1b2a5..62cc71748f 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/MapEntityRowMapper.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/MapEntityRowMapper.java @@ -24,6 +24,8 @@ import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension; import org.springframework.data.relational.domain.Identifier; +import org.springframework.data.relational.domain.IdentifierProcessing; +import org.springframework.data.relational.domain.SqlIdentifier; import org.springframework.jdbc.core.RowMapper; import org.springframework.lang.NonNull; @@ -40,13 +42,14 @@ class MapEntityRowMapper implements RowMapper> { private final PersistentPropertyPathExtension path; private final JdbcConverter converter; private final Identifier identifier; - - private final String keyColumn; + private final SqlIdentifier keyColumn; + private final IdentifierProcessing identifierProcessing; @NonNull @Override public Map.Entry mapRow(ResultSet rs, int rowNum) throws SQLException { - Object key = rs.getObject(keyColumn); + + Object key = rs.getObject(keyColumn.toColumnName(identifierProcessing)); return new HashMap.SimpleEntry<>(key, mapEntity(rs, key)); } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlContext.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlContext.java index 2a65c4b2e5..35673fb5c3 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlContext.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlContext.java @@ -20,6 +20,8 @@ import org.springframework.data.relational.core.sql.Column; import org.springframework.data.relational.core.sql.SQL; import org.springframework.data.relational.core.sql.Table; +import org.springframework.data.relational.domain.IdentifierProcessing; +import org.springframework.data.relational.domain.SqlIdentifier; /** * Utility to get from path to SQL DSL elements. @@ -33,36 +35,41 @@ class SqlContext { private final RelationalPersistentEntity entity; private final Table table; + private final IdentifierProcessing identifierProcessing; - SqlContext(RelationalPersistentEntity entity) { + SqlContext(RelationalPersistentEntity entity, IdentifierProcessing identifierProcessing) { + + this.identifierProcessing = identifierProcessing; this.entity = entity; - this.table = SQL.table(entity.getTableName()); + this.table = SQL.table(entity.getTableName().toSql(this.identifierProcessing)); } Column getIdColumn() { - return table.column(entity.getIdColumn()); + return table.column(entity.getIdColumn().toSql(identifierProcessing)); } Column getVersionColumn() { - return table.column(entity.getRequiredVersionProperty().getColumnName()); + return table.column(entity.getRequiredVersionProperty().getColumnName().toSql(identifierProcessing)); } - + Table getTable() { return table; } Table getTable(PersistentPropertyPathExtension path) { - String tableAlias = path.getTableAlias(); - Table table = SQL.table(path.getTableName()); - return tableAlias == null ? table : table.as(tableAlias); + SqlIdentifier tableAlias = path.getTableAlias(); + Table table = SQL.table(path.getTableName().toSql(identifierProcessing)); + return tableAlias == null ? table : table.as(tableAlias.toSql(identifierProcessing)); } Column getColumn(PersistentPropertyPathExtension path) { - return getTable(path).column(path.getColumnName()).as(path.getColumnAlias()); + return getTable(path).column(path.getColumnName().toSql(identifierProcessing)) + .as(path.getColumnAlias().toSql(identifierProcessing)); } Column getReverseColumn(PersistentPropertyPathExtension path) { - return getTable(path).column(path.getReverseColumnName()).as(path.getReverseColumnNameAlias()); + return getTable(path).column(path.getReverseColumnName().toSql(identifierProcessing)) + .as(path.getReverseColumnNameAlias().toSql(identifierProcessing)); } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java index 069fd457c6..a7ae237813 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java @@ -17,14 +17,7 @@ import lombok.Value; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.function.Function; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -40,6 +33,8 @@ import org.springframework.data.relational.core.sql.*; import org.springframework.data.relational.core.sql.render.SqlRenderer; import org.springframework.data.relational.domain.Identifier; +import org.springframework.data.relational.domain.IdentifierProcessing; +import org.springframework.data.relational.domain.SqlIdentifier; import org.springframework.data.util.Lazy; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -57,11 +52,15 @@ */ class SqlGenerator { - static final String VERSION_SQL_PARAMETER_NAME = "___oldOptimisticLockingVersion"; + static final SqlIdentifier VERSION_SQL_PARAMETER = SqlIdentifier.unquoted("___oldOptimisticLockingVersion"); + static final SqlIdentifier ID_SQL_PARAMETER = SqlIdentifier.unquoted("id"); + static final SqlIdentifier IDS_SQL_PARAMETER = SqlIdentifier.unquoted("ids"); + static final SqlIdentifier ROOT_ID_PARAMETER = SqlIdentifier.unquoted("rootId"); private static final Pattern parameterPattern = Pattern.compile("\\W"); private final RelationalPersistentEntity entity; private final MappingContext, RelationalPersistentProperty> mappingContext; + private final IdentifierProcessing identifierProcessing; private final SqlContext sqlContext; private final Columns columns; @@ -82,15 +81,18 @@ class SqlGenerator { /** * Create a new {@link SqlGenerator} given {@link RelationalMappingContext} and {@link RelationalPersistentEntity}. - * + * * @param mappingContext must not be {@literal null}. * @param entity must not be {@literal null}. + * @param identifierProcessing must not be {@literal null}. */ - SqlGenerator(RelationalMappingContext mappingContext, RelationalPersistentEntity entity) { + SqlGenerator(RelationalMappingContext mappingContext, RelationalPersistentEntity entity, + IdentifierProcessing identifierProcessing) { this.mappingContext = mappingContext; this.entity = entity; - this.sqlContext = new SqlContext(entity); + this.identifierProcessing = identifierProcessing; + this.sqlContext = new SqlContext(entity, identifierProcessing); this.columns = new Columns(entity, mappingContext); } @@ -103,7 +105,7 @@ class SqlGenerator { * @param filterColumn the column to apply the IN-condition to. * @return the IN condition */ - private static Condition getSubselectCondition(PersistentPropertyPathExtension path, + private Condition getSubselectCondition(PersistentPropertyPathExtension path, Function rootCondition, Column filterColumn) { PersistentPropertyPathExtension parentPath = path.getParentPath(); @@ -115,9 +117,10 @@ private static Condition getSubselectCondition(PersistentPropertyPathExtension p return rootCondition.apply(filterColumn); } - Table subSelectTable = SQL.table(parentPath.getTableName()); - Column idColumn = subSelectTable.column(parentPath.getIdColumnName()); - Column selectFilterColumn = subSelectTable.column(parentPath.getEffectiveIdColumnName()); + Table subSelectTable = SQL.table(parentPath.getTableName().toSql(identifierProcessing)); + Column idColumn = subSelectTable.column(parentPath.getIdColumnName().toSql(identifierProcessing)); + Column selectFilterColumn = subSelectTable + .column(parentPath.getEffectiveIdColumnName().toSql(identifierProcessing)); Condition innerCondition; @@ -139,8 +142,8 @@ private static Condition getSubselectCondition(PersistentPropertyPathExtension p return filterColumn.in(select); } - private static BindMarker getBindMarker(String columnName) { - return SQL.bindMarker(":" + parameterPattern.matcher(columnName).replaceAll("")); + private BindMarker getBindMarker(SqlIdentifier columnName) { + return SQL.bindMarker(":" + parameterPattern.matcher(columnName.toColumnName(identifierProcessing)).replaceAll("")); } /** @@ -174,7 +177,7 @@ String getFindAll() { * keyColumn must not be {@code null}. * @return a SQL String. */ - String getFindAllByProperty(Identifier parentIdentifier, @Nullable String keyColumn, boolean ordered) { + String getFindAllByProperty(Identifier parentIdentifier, @Nullable SqlIdentifier keyColumn, boolean ordered) { Assert.isTrue(keyColumn != null || !ordered, "If the SQL statement should be ordered a keyColumn to order by must be provided."); @@ -182,7 +185,7 @@ String getFindAllByProperty(Identifier parentIdentifier, @Nullable String keyCol SelectBuilder.SelectWhere builder = selectBuilder( // keyColumn == null // ? Collections.emptyList() // - : Collections.singleton(keyColumn) // + : Collections.singleton(keyColumn.toSql(identifierProcessing)) // ); Table table = getTable(); @@ -191,7 +194,9 @@ String getFindAllByProperty(Identifier parentIdentifier, @Nullable String keyCol SelectBuilder.SelectWhereAndOr withWhereClause = builder.where(condition); Select select = ordered // - ? withWhereClause.orderBy(table.column(keyColumn).as(keyColumn)).build() // + ? withWhereClause + .orderBy(table.column(keyColumn.toSql(identifierProcessing)).as(keyColumn.toSql(identifierProcessing))) + .build() // : withWhereClause.build(); return render(select); @@ -200,9 +205,10 @@ String getFindAllByProperty(Identifier parentIdentifier, @Nullable String keyCol private Condition buildConditionForBackReference(Identifier parentIdentifier, Table table) { Condition condition = null; - for (String backReferenceColumn : parentIdentifier.toMap().keySet()) { + for (SqlIdentifier backReferenceColumn : parentIdentifier.toMap().keySet()) { - Condition newCondition = table.column(backReferenceColumn).isEqualTo(getBindMarker(backReferenceColumn)); + Condition newCondition = table.column(backReferenceColumn.toSql(identifierProcessing)) + .isEqualTo(getBindMarker(backReferenceColumn)); condition = condition == null ? newCondition : condition.and(newCondition); } @@ -214,7 +220,7 @@ private Condition buildConditionForBackReference(Identifier parentIdentifier, Ta /** * Create a {@code SELECT COUNT(id) FROM … WHERE :id = …} statement. * - * @return + * @return the statement as a {@link String}. Guaranteed to be not {@literal null}. */ String getExists() { return existsSql.get(); @@ -223,7 +229,7 @@ String getExists() { /** * Create a {@code SELECT … FROM … WHERE :id = …} statement. * - * @return + * @return the statement as a {@link String}. Guaranteed to be not {@literal null}. */ String getFindOne() { return findOneSql.get(); @@ -232,16 +238,16 @@ String getFindOne() { /** * Create a {@code INSERT INTO … (…) VALUES(…)} statement. * - * @return + * @return the statement as a {@link String}. Guaranteed to be not {@literal null}. */ - String getInsert(Set additionalColumns) { + String getInsert(Set additionalColumns) { return createInsertSql(additionalColumns); } /** * Create a {@code UPDATE … SET …} statement. * - * @return + * @return the statement as a {@link String}. Guaranteed to be not {@literal null}. */ String getUpdate() { return updateSql.get(); @@ -250,7 +256,7 @@ String getUpdate() { /** * Create a {@code UPDATE … SET … WHERE ID = :id and VERSION_COLUMN = :___oldOptimisticLockingVersion } statement. * - * @return + * @return the statement as a {@link String}. Guaranteed to be not {@literal null}. */ String getUpdateWithVersion() { return updateWithVersionSql.get(); @@ -259,7 +265,7 @@ String getUpdateWithVersion() { /** * Create a {@code SELECT COUNT(*) FROM …} statement. * - * @return + * @return the statement as a {@link String}. Guaranteed to be not {@literal null}. */ String getCount() { return countSql.get(); @@ -268,7 +274,7 @@ String getCount() { /** * Create a {@code DELETE FROM … WHERE :id = …} statement. * - * @return + * @return the statement as a {@link String}. Guaranteed to be not {@literal null}. */ String getDeleteById() { return deleteByIdSql.get(); @@ -277,7 +283,7 @@ String getDeleteById() { /** * Create a {@code DELETE FROM … WHERE :id = … and :___oldOptimisticLockingVersion = ...} statement. * - * @return + * @return the statement as a {@link String}. Guaranteed to be not {@literal null}. */ String getDeleteByIdAndVersion() { return deleteByIdAndVersionSql.get(); @@ -286,7 +292,7 @@ String getDeleteByIdAndVersion() { /** * Create a {@code DELETE FROM … WHERE :ids in (…)} statement. * - * @return + * @return the statement as a {@link String}. Guaranteed to be not {@literal null}. */ String getDeleteByList() { return deleteByListSql.get(); @@ -296,7 +302,7 @@ String getDeleteByList() { * Create a {@code DELETE} query and optionally filter by {@link PersistentPropertyPath}. * * @param path can be {@literal null}. - * @return + * @return the statement as a {@link String}. Guaranteed to be not {@literal null}. */ String createDeleteAllSql(@Nullable PersistentPropertyPath path) { @@ -315,16 +321,16 @@ String createDeleteAllSql(@Nullable PersistentPropertyPath path) { return createDeleteByPathAndCriteria(new PersistentPropertyPathExtension(mappingContext, path), - filterColumn -> filterColumn.isEqualTo(getBindMarker("rootId"))); + filterColumn -> filterColumn.isEqualTo(getBindMarker(ROOT_ID_PARAMETER))); } private String createFindOneSql() { - Select select = selectBuilder().where(getIdColumn().isEqualTo(getBindMarker("id"))) // + Select select = selectBuilder().where(getIdColumn().isEqualTo(getBindMarker(ID_SQL_PARAMETER))) // .build(); return render(select); @@ -379,8 +385,8 @@ private SelectBuilder.SelectWhere selectBuilder(Collection keyColumns) { /** * Create a {@link Column} for {@link PersistentPropertyPathExtension}. * - * @param path - * @return + * @param path the path to the column in question. + * @return the statement as a {@link String}. Guaranteed to be not {@literal null}. */ @Nullable Column getColumn(PersistentPropertyPathExtension path) { @@ -425,14 +431,14 @@ Join getJoin(PersistentPropertyPathExtension path) { return new Join( // currentTable, // - currentTable.column(path.getReverseColumnName()), // - parentTable.column(idDefiningParentPath.getIdColumnName()) // + currentTable.column(path.getReverseColumnName().toSql(identifierProcessing)), // + parentTable.column(idDefiningParentPath.getIdColumnName().toSql(identifierProcessing)) // ); } private String createFindAllInListSql() { - Select select = selectBuilder().where(getIdColumn().in(getBindMarker("ids"))).build(); + Select select = selectBuilder().where(getIdColumn().in(getBindMarker(IDS_SQL_PARAMETER))).build(); return render(select); } @@ -444,7 +450,7 @@ private String createExistsSql() { Select select = StatementBuilder // .select(Functions.count(getIdColumn())) // .from(table) // - .where(getIdColumn().isEqualTo(getBindMarker("id"))) // + .where(getIdColumn().isEqualTo(getBindMarker(ID_SQL_PARAMETER))) // .build(); return render(select); @@ -462,21 +468,22 @@ private String createCountSql() { return render(select); } - private String createInsertSql(Set additionalColumns) { + private String createInsertSql(Set additionalColumns) { Table table = getTable(); - Set columnNamesForInsert = new LinkedHashSet<>(columns.getInsertableColumns()); + Set columnNamesForInsert = new TreeSet<>(Comparator.comparing(id -> id.toSql(identifierProcessing))); + columnNamesForInsert.addAll(columns.getInsertableColumns()); columnNamesForInsert.addAll(additionalColumns); InsertBuilder.InsertIntoColumnsAndValuesWithBuild insert = Insert.builder().into(table); - for (String cn : columnNamesForInsert) { - insert = insert.column(table.column(cn)); + for (SqlIdentifier cn : columnNamesForInsert) { + insert = insert.column(table.column(cn.toSql(identifierProcessing))); } InsertBuilder.InsertValuesWithBuild insertWithValues = null; - for (String cn : columnNamesForInsert) { + for (SqlIdentifier cn : columnNamesForInsert) { insertWithValues = (insertWithValues == null ? insert : insertWithValues).values(getBindMarker(cn)); } @@ -490,7 +497,8 @@ private String createUpdateSql() { private String createUpdateWithVersionSql() { Update update = createBaseUpdate() // - .and(getVersionColumn().isEqualTo(SQL.bindMarker(":" + VERSION_SQL_PARAMETER_NAME))) // + .and(getVersionColumn() + .isEqualTo(SQL.bindMarker(":" + VERSION_SQL_PARAMETER.toColumnName(identifierProcessing)))) // .build(); return render(update); @@ -503,7 +511,7 @@ private UpdateBuilder.UpdateWhereAndOr createBaseUpdate() { List assignments = columns.getUpdateableColumns() // .stream() // .map(columnName -> Assignments.value( // - table.column(columnName), // + table.column(columnName.toSql(identifierProcessing)), // getBindMarker(columnName))) // .collect(Collectors.toList()); @@ -520,7 +528,8 @@ private String createDeleteSql() { private String createDeleteByIdAndVersionSql() { Delete delete = createBaseDeleteById(getTable()) // - .and(getVersionColumn().isEqualTo(SQL.bindMarker(":" + VERSION_SQL_PARAMETER_NAME))) // + .and(getVersionColumn() + .isEqualTo(SQL.bindMarker(":" + VERSION_SQL_PARAMETER.toColumnName(identifierProcessing)))) // .build(); return render(delete); @@ -533,13 +542,13 @@ private DeleteBuilder.DeleteWhereAndOr createBaseDeleteById(Table table) { private String createDeleteByPathAndCriteria(PersistentPropertyPathExtension path, Function rootCondition) { - Table table = SQL.table(path.getTableName()); + Table table = SQL.table(path.getTableName().toSql(identifierProcessing)); DeleteBuilder.DeleteWhere builder = Delete.builder() // .from(table); Delete delete; - Column filterColumn = table.column(path.getReverseColumnName()); + Column filterColumn = table.column(path.getReverseColumnName().toSql(identifierProcessing)); if (path.getLength() == 1) { @@ -561,7 +570,7 @@ private String createDeleteByListSql() { Delete delete = Delete.builder() // .from(table) // - .where(getIdColumn().in(getBindMarker("ids"))) // + .where(getIdColumn().in(getBindMarker(IDS_SQL_PARAMETER))) // .build(); return render(delete); @@ -609,17 +618,18 @@ static class Join { * Value object encapsulating column name caches. * * @author Mark Paluch + * @author Jens Schauder */ static class Columns { private final MappingContext, RelationalPersistentProperty> mappingContext; - private final List columnNames = new ArrayList<>(); - private final List idColumnNames = new ArrayList<>(); - private final List nonIdColumnNames = new ArrayList<>(); - private final Set readOnlyColumnNames = new HashSet<>(); - private final Set insertableColumns; - private final Set updateableColumns; + private final List columnNames = new ArrayList<>(); + private final List idColumnNames = new ArrayList<>(); + private final List nonIdColumnNames = new ArrayList<>(); + private final Set readOnlyColumnNames = new HashSet<>(); + private final Set insertableColumns; + private final Set updateableColumns; Columns(RelationalPersistentEntity entity, MappingContext, RelationalPersistentProperty> mappingContext) { @@ -628,12 +638,12 @@ static class Columns { populateColumnNameCache(entity, ""); - Set insertable = new LinkedHashSet<>(nonIdColumnNames); + Set insertable = new LinkedHashSet<>(nonIdColumnNames); insertable.removeAll(readOnlyColumnNames); this.insertableColumns = Collections.unmodifiableSet(insertable); - Set updateable = new LinkedHashSet<>(columnNames); + Set updateable = new LinkedHashSet<>(columnNames); updateable.removeAll(idColumnNames); updateable.removeAll(readOnlyColumnNames); @@ -656,7 +666,7 @@ private void populateColumnNameCache(RelationalPersistentEntity entity, Strin private void initSimpleColumnName(RelationalPersistentProperty property, String prefix) { - String columnName = prefix + property.getColumnName(); + SqlIdentifier columnName = property.getColumnName().prefix(prefix); columnNames.add(columnName); @@ -684,14 +694,14 @@ private void initEmbeddedColumnNames(RelationalPersistentProperty property, Stri /** * @return Column names that can be used for {@code INSERT}. */ - Set getInsertableColumns() { + Set getInsertableColumns() { return insertableColumns; } /** * @return Column names that can be used for {@code UPDATE}. */ - Set getUpdateableColumns() { + Set getUpdateableColumns() { return updateableColumns; } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGeneratorSource.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGeneratorSource.java index de4aa6b4d0..3dae16b3ce 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGeneratorSource.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGeneratorSource.java @@ -19,7 +19,9 @@ import java.util.Map; +import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.data.relational.core.mapping.RelationalMappingContext; +import org.springframework.data.relational.domain.IdentifierProcessing; import org.springframework.util.ConcurrentReferenceHashMap; /** @@ -33,8 +35,17 @@ public class SqlGeneratorSource { private final Map, SqlGenerator> CACHE = new ConcurrentReferenceHashMap<>(); private final RelationalMappingContext context; + private final Dialect dialect; + + /** + * @return the {@link Dialect} used by the created {@link SqlGenerator} instances. Guaranteed to be not {@literal null}. + */ + public Dialect getDialect() { + return dialect; + } + SqlGenerator getSqlGenerator(Class domainType) { - return CACHE.computeIfAbsent(domainType, t -> new SqlGenerator(context, context.getRequiredPersistentEntity(t))); + return CACHE.computeIfAbsent(domainType, t -> new SqlGenerator(context, context.getRequiredPersistentEntity(t), dialect.getIdentifierProcessing())); } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSource.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSource.java new file mode 100644 index 0000000000..30dbf931b9 --- /dev/null +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSource.java @@ -0,0 +1,84 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.jdbc.core.convert; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.springframework.data.relational.domain.IdentifierProcessing; +import org.springframework.data.relational.domain.SqlIdentifier; +import org.springframework.jdbc.core.namedparam.AbstractSqlParameterSource; + +/** + * Implementation of the {@link org.springframework.jdbc.core.namedparam.SqlParameterSource} interface based on + * {@link SqlIdentifier} instead of {@link String} for names. + * + * @author Jens Schauder + * @since 2.0 + */ +class SqlIdentifierParameterSource extends AbstractSqlParameterSource { + + private final IdentifierProcessing identifierProcessing; + private final Set identifiers = new HashSet<>(); + private final Map namesToValues = new HashMap<>(); + + SqlIdentifierParameterSource(IdentifierProcessing identifierProcessing) { + this.identifierProcessing = identifierProcessing; + } + + @Override + public boolean hasValue(String paramName) { + return namesToValues.containsKey(paramName); + } + + @Override + public Object getValue(String paramName) throws IllegalArgumentException { + return namesToValues.get(paramName); + } + + @Override + public String[] getParameterNames() { + return namesToValues.keySet().toArray(new String[0]); + } + + Set getIdentifiers() { + return Collections.unmodifiableSet(identifiers); + } + + void addValue(SqlIdentifier name, Object value) { + addValue(name, value, Integer.MIN_VALUE); + } + + void addValue(SqlIdentifier identifier, Object value, int sqlType) { + + identifiers.add(identifier); + String name = identifier.toColumnName(identifierProcessing); + namesToValues.put(name, value); + registerSqlType(name, sqlType); + } + + void addAll(SqlIdentifierParameterSource others) { + + for (SqlIdentifier identifier : others.getIdentifiers()) { + + String name = identifier.toColumnName(identifierProcessing); + addValue(identifier, others.getValue(name), others.getSqlType(name)); + } + } +} diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategy.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategy.java index ea2b810445..69d134ec38 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategy.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategy.java @@ -15,11 +15,11 @@ */ package org.springframework.data.jdbc.mybatis; -import static java.util.Arrays.asList; +import static java.util.Arrays.*; import java.util.Collections; -import java.util.HashMap; import java.util.Map; +import java.util.stream.Collectors; import org.apache.ibatis.exceptions.PersistenceException; import org.apache.ibatis.session.SqlSession; @@ -34,9 +34,12 @@ import org.springframework.data.jdbc.core.convert.SqlGeneratorSource; import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.data.mapping.PropertyPath; +import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; import org.springframework.data.relational.domain.Identifier; +import org.springframework.data.relational.domain.IdentifierProcessing; +import org.springframework.data.relational.domain.SqlIdentifier; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.util.Assert; @@ -61,6 +64,7 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy { private static final String VERSION_SQL_PARAMETER_NAME_OLD = "___oldOptimisticLockingVersion"; private final SqlSession sqlSession; + private final IdentifierProcessing identifierProcessing; private NamespaceStrategy namespaceStrategy = NamespaceStrategy.DEFAULT_INSTANCE; /** @@ -68,8 +72,9 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy { * uses a {@link DefaultDataAccessStrategy} */ public static DataAccessStrategy createCombinedAccessStrategy(RelationalMappingContext context, - JdbcConverter converter, NamedParameterJdbcOperations operations, SqlSession sqlSession) { - return createCombinedAccessStrategy(context, converter, operations, sqlSession, NamespaceStrategy.DEFAULT_INSTANCE); + JdbcConverter converter, NamedParameterJdbcOperations operations, SqlSession sqlSession, Dialect dialect) { + return createCombinedAccessStrategy(context, converter, operations, sqlSession, NamespaceStrategy.DEFAULT_INSTANCE, + dialect); } /** @@ -78,19 +83,20 @@ public static DataAccessStrategy createCombinedAccessStrategy(RelationalMappingC */ public static DataAccessStrategy createCombinedAccessStrategy(RelationalMappingContext context, JdbcConverter converter, NamedParameterJdbcOperations operations, SqlSession sqlSession, - NamespaceStrategy namespaceStrategy) { + NamespaceStrategy namespaceStrategy, Dialect dialect) { // the DefaultDataAccessStrategy needs a reference to the returned DataAccessStrategy. This creates a dependency // cycle. In order to create it, we need something that allows to defer closing the cycle until all the elements are // created. That is the purpose of the DelegatingAccessStrategy. DelegatingDataAccessStrategy delegatingDataAccessStrategy = new DelegatingDataAccessStrategy(); - MyBatisDataAccessStrategy myBatisDataAccessStrategy = new MyBatisDataAccessStrategy(sqlSession, context, converter); + MyBatisDataAccessStrategy myBatisDataAccessStrategy = new MyBatisDataAccessStrategy(sqlSession, + dialect.getIdentifierProcessing()); myBatisDataAccessStrategy.setNamespaceStrategy(namespaceStrategy); CascadingDataAccessStrategy cascadingDataAccessStrategy = new CascadingDataAccessStrategy( asList(myBatisDataAccessStrategy, delegatingDataAccessStrategy)); - SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(context); + SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(context, dialect); DefaultDataAccessStrategy defaultDataAccessStrategy = new DefaultDataAccessStrategy( // sqlGeneratorSource, // context, // @@ -109,13 +115,17 @@ public static DataAccessStrategy createCombinedAccessStrategy(RelationalMappingC * Use a {@link SqlSessionTemplate} for {@link SqlSession} or a similar implementation tying the session to the proper * transaction. Note that the resulting {@link DataAccessStrategy} only handles MyBatis. It does not include the * functionality of the {@link DefaultDataAccessStrategy} which one normally still wants. Use - * {@link #createCombinedAccessStrategy(RelationalMappingContext, JdbcConverter, NamedParameterJdbcOperations, SqlSession, NamespaceStrategy)} + * {@link #createCombinedAccessStrategy(RelationalMappingContext, JdbcConverter, NamedParameterJdbcOperations, SqlSession, NamespaceStrategy, Dialect)} * to create such a {@link DataAccessStrategy}. * * @param sqlSession Must be non {@literal null}. + * @param identifierProcessing the {@link IdentifierProcessing} applied to {@link SqlIdentifier} instances in order to + * turn them into {@link String} */ - public MyBatisDataAccessStrategy(SqlSession sqlSession, RelationalMappingContext context, JdbcConverter converter) { + public MyBatisDataAccessStrategy(SqlSession sqlSession, IdentifierProcessing identifierProcessing) { + this.sqlSession = sqlSession; + this.identifierProcessing = identifierProcessing; } /** @@ -135,9 +145,10 @@ public void setNamespaceStrategy(NamespaceStrategy namespaceStrategy) { * @see org.springframework.data.jdbc.core.DataAccessStrategy#insert(java.lang.Object, java.lang.Class, java.util.Map) */ @Override - public Object insert(T instance, Class domainType, Map additionalParameters) { + public Object insert(T instance, Class domainType, Map additionalParameters) { - MyBatisContext myBatisContext = new MyBatisContext(null, instance, domainType, additionalParameters); + MyBatisContext myBatisContext = new MyBatisContext(null, instance, domainType, + convertToParameterMap(additionalParameters)); sqlSession().insert(namespace(domainType) + ".insert", myBatisContext); return myBatisContext.getId(); @@ -150,7 +161,8 @@ public Object insert(T instance, Class domainType, Map ad @Override public Object insert(T instance, Class domainType, Identifier identifier) { - MyBatisContext myBatisContext = new MyBatisContext(null, instance, domainType, identifier.toMap()); + MyBatisContext myBatisContext = new MyBatisContext(null, instance, domainType, + convertToParameterMap(identifier.toMap())); sqlSession().insert(namespace(domainType) + ".insert", myBatisContext); return myBatisContext.getId(); @@ -174,9 +186,10 @@ public boolean update(S instance, Class domainType) { @Override public boolean updateWithVersion(S instance, Class domainType, Number previousVersion) { - - return sqlSession().update(namespace(domainType) + ".updateWithVersion", - new MyBatisContext(null, instance, domainType, Collections.singletonMap(VERSION_SQL_PARAMETER_NAME_OLD, previousVersion))) != 0; + String statement = namespace(domainType) + ".updateWithVersion"; + MyBatisContext parameter = new MyBatisContext(null, instance, domainType, + Collections.singletonMap(VERSION_SQL_PARAMETER_NAME_OLD, previousVersion)); + return sqlSession().update(statement, parameter) != 0; } /* @@ -186,8 +199,9 @@ public boolean updateWithVersion(S instance, Class domainType, Number pre @Override public void delete(Object id, Class domainType) { - sqlSession().delete(namespace(domainType) + ".delete", - new MyBatisContext(id, null, domainType, Collections.emptyMap())); + String statement = namespace(domainType) + ".delete"; + MyBatisContext parameter = new MyBatisContext(id, null, domainType, Collections.emptyMap()); + sqlSession().delete(statement, parameter); } /* @@ -197,8 +211,10 @@ public void delete(Object id, Class domainType) { @Override public void deleteWithVersion(Object id, Class domainType, Number previousVersion) { - sqlSession().delete(namespace(domainType) + ".deleteWithVersion", - new MyBatisContext(id, null, domainType, Collections.singletonMap(VERSION_SQL_PARAMETER_NAME_OLD, previousVersion))); + String statement = namespace(domainType) + ".deleteWithVersion"; + MyBatisContext parameter = new MyBatisContext(id, null, domainType, + Collections.singletonMap(VERSION_SQL_PARAMETER_NAME_OLD, previousVersion)); + sqlSession().delete(statement, parameter); } /* @@ -208,10 +224,12 @@ public void deleteWithVersion(Object id, Class domainType, Number previou @Override public void delete(Object rootId, PersistentPropertyPath propertyPath) { - sqlSession().delete( - namespace(propertyPath.getBaseProperty().getOwner().getType()) + ".delete-" + toDashPath(propertyPath), - new MyBatisContext(rootId, null, propertyPath.getRequiredLeafProperty().getTypeInformation().getType(), - Collections.emptyMap())); + Class ownerType = propertyPath.getBaseProperty().getOwner().getType(); + String statement = namespace(ownerType) + ".delete-" + toDashPath(propertyPath); + Class leafType = propertyPath.getRequiredLeafProperty().getTypeInformation().getType(); + MyBatisContext parameter = new MyBatisContext(rootId, null, leafType, Collections.emptyMap()); + + sqlSession().delete(statement, parameter); } /* @@ -221,10 +239,9 @@ public void delete(Object rootId, PersistentPropertyPath void deleteAll(Class domainType) { - sqlSession().delete( // - namespace(domainType) + ".deleteAll", // - new MyBatisContext(null, null, domainType, Collections.emptyMap()) // - ); + String statement = namespace(domainType) + ".deleteAll"; + MyBatisContext parameter = new MyBatisContext(null, null, domainType, Collections.emptyMap()); + sqlSession().delete(statement, parameter); } /* @@ -237,10 +254,9 @@ public void deleteAll(PersistentPropertyPath prope Class baseType = propertyPath.getBaseProperty().getOwner().getType(); Class leafType = propertyPath.getRequiredLeafProperty().getTypeInformation().getType(); - sqlSession().delete( // - namespace(baseType) + ".deleteAll-" + toDashPath(propertyPath), // - new MyBatisContext(null, null, leafType, Collections.emptyMap()) // - ); + String statement = namespace(baseType) + ".deleteAll-" + toDashPath(propertyPath); + MyBatisContext parameter = new MyBatisContext(null, null, leafType, Collections.emptyMap()); + sqlSession().delete(statement, parameter); } /* @@ -249,8 +265,10 @@ public void deleteAll(PersistentPropertyPath prope */ @Override public T findById(Object id, Class domainType) { - return sqlSession().selectOne(namespace(domainType) + ".findById", - new MyBatisContext(id, null, domainType, Collections.emptyMap())); + + String statement = namespace(domainType) + ".findById"; + MyBatisContext parameter = new MyBatisContext(id, null, domainType, Collections.emptyMap()); + return sqlSession().selectOne(statement, parameter); } /* @@ -259,8 +277,10 @@ public T findById(Object id, Class domainType) { */ @Override public Iterable findAll(Class domainType) { - return sqlSession().selectList(namespace(domainType) + ".findAll", - new MyBatisContext(null, null, domainType, Collections.emptyMap())); + + String statement = namespace(domainType) + ".findAll"; + MyBatisContext parameter = new MyBatisContext(null, null, domainType, Collections.emptyMap()); + return sqlSession().selectList(statement, parameter); } /* @@ -299,9 +319,9 @@ public Iterable findAllByPath(Identifier identifier, @Override public Iterable findAllByProperty(Object rootId, RelationalPersistentProperty property) { - return sqlSession().selectList( - namespace(property.getOwner().getType()) + ".findAllByProperty-" + property.getName(), - new MyBatisContext(rootId, null, property.getType(), Collections.emptyMap())); + String statement = namespace(property.getOwner().getType()) + ".findAllByProperty-" + property.getName(); + MyBatisContext parameter = new MyBatisContext(rootId, null, property.getType(), Collections.emptyMap()); + return sqlSession().selectList(statement, parameter); } /* @@ -311,8 +331,9 @@ public Iterable findAllByProperty(Object rootId, RelationalPersistentProp @Override public boolean existsById(Object id, Class domainType) { - return sqlSession().selectOne(namespace(domainType) + ".existsById", - new MyBatisContext(id, null, domainType, Collections.emptyMap())); + String statement = namespace(domainType) + ".existsById"; + MyBatisContext parameter = new MyBatisContext(id, null, domainType, Collections.emptyMap()); + return sqlSession().selectOne(statement, parameter); } /* @@ -321,8 +342,16 @@ public boolean existsById(Object id, Class domainType) { */ @Override public long count(Class domainType) { - return sqlSession().selectOne(namespace(domainType) + ".count", - new MyBatisContext(null, null, domainType, Collections.emptyMap())); + + String statement = namespace(domainType) + ".count"; + MyBatisContext parameter = new MyBatisContext(null, null, domainType, Collections.emptyMap()); + return sqlSession().selectOne(statement, parameter); + } + + private Map convertToParameterMap(Map additionalParameters) { + + return additionalParameters.entrySet().stream() // + .collect(Collectors.toMap(e -> e.getKey().toSql(identifierProcessing), Map.Entry::getValue)); } private String namespace(Class domainType) { 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 08148fb7e3..983ac4c150 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 @@ -34,6 +34,8 @@ import org.springframework.data.jdbc.core.convert.SqlGeneratorSource; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.relational.core.conversion.RelationalConverter; +import org.springframework.data.relational.core.dialect.Dialect; +import org.springframework.data.relational.core.dialect.HsqlDbDialect; import org.springframework.data.relational.core.mapping.NamingStrategy; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; @@ -71,8 +73,8 @@ public JdbcMappingContext jdbcMappingContext(Optional namingStra } /** - * Creates a {@link RelationalConverter} using the configured {@link #jdbcMappingContext(Optional)}. Will get - * {@link #jdbcCustomConversions()} applied. + * Creates a {@link RelationalConverter} using the configured + * {@link #jdbcMappingContext(Optional, JdbcCustomConversions)}. Will get {@link #jdbcCustomConversions()} applied. * * @see #jdbcMappingContext(Optional, JdbcCustomConversions) * @see #jdbcCustomConversions() @@ -125,7 +127,12 @@ public JdbcAggregateTemplate jdbcAggregateTemplate(ApplicationContext applicatio */ @Bean public DataAccessStrategy dataAccessStrategyBean(NamedParameterJdbcOperations operations, JdbcConverter jdbcConverter, - RelationalMappingContext context) { - return new DefaultDataAccessStrategy(new SqlGeneratorSource(context), context, jdbcConverter, operations); + RelationalMappingContext context, Dialect dialect) { + return new DefaultDataAccessStrategy(new SqlGeneratorSource(context, dialect), context, jdbcConverter, operations); + } + + @Bean + Dialect dialect() { + return HsqlDbDialect.INSTANCE; } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/JdbcConfiguration.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/JdbcConfiguration.java index 6bd600565f..7d8125b7d7 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/JdbcConfiguration.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/JdbcConfiguration.java @@ -34,6 +34,8 @@ import org.springframework.data.jdbc.core.convert.SqlGeneratorSource; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.relational.core.conversion.RelationalConverter; +import org.springframework.data.relational.core.dialect.Dialect; +import org.springframework.data.relational.core.dialect.HsqlDbDialect; import org.springframework.data.relational.core.mapping.NamingStrategy; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; @@ -102,12 +104,15 @@ public JdbcCustomConversions jdbcCustomConversions() { * @param context * @param converter * @param operations + * @param dialect * @return */ @Bean public JdbcAggregateOperations jdbcAggregateOperations(ApplicationEventPublisher publisher, - RelationalMappingContext context, JdbcConverter converter, NamedParameterJdbcOperations operations) { - return new JdbcAggregateTemplate(publisher, context, converter, dataAccessStrategy(context, converter, operations)); + RelationalMappingContext context, JdbcConverter converter, NamedParameterJdbcOperations operations, + Dialect dialect) { + return new JdbcAggregateTemplate(publisher, context, converter, + dataAccessStrategy(context, converter, operations, dialect)); } /** @@ -117,11 +122,17 @@ public JdbcAggregateOperations jdbcAggregateOperations(ApplicationEventPublisher * @param context * @param converter * @param operations + * @param dialect * @return */ @Bean public DataAccessStrategy dataAccessStrategy(RelationalMappingContext context, JdbcConverter converter, - NamedParameterJdbcOperations operations) { - return new DefaultDataAccessStrategy(new SqlGeneratorSource(context), context, converter, operations); + NamedParameterJdbcOperations operations, Dialect dialect) { + return new DefaultDataAccessStrategy(new SqlGeneratorSource(context, dialect), context, converter, operations); + } + + @Bean + public Dialect dialect() { + return HsqlDbDialect.INSTANCE; } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/MyBatisJdbcConfiguration.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/MyBatisJdbcConfiguration.java index b840977fff..c5cc23d52d 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/MyBatisJdbcConfiguration.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/MyBatisJdbcConfiguration.java @@ -22,6 +22,7 @@ import org.springframework.data.jdbc.core.convert.DataAccessStrategy; import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.mybatis.MyBatisDataAccessStrategy; +import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; @@ -43,8 +44,8 @@ public class MyBatisJdbcConfiguration extends AbstractJdbcConfiguration { @Bean @Override public DataAccessStrategy dataAccessStrategyBean(NamedParameterJdbcOperations operations, JdbcConverter jdbcConverter, - RelationalMappingContext context) { + RelationalMappingContext context, Dialect dialect) { - return MyBatisDataAccessStrategy.createCombinedAccessStrategy(context, jdbcConverter, operations, session); + return MyBatisDataAccessStrategy.createCombinedAccessStrategy(context, jdbcConverter, operations, session, dialect); } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java index bbaf86ea0a..efe66fb60c 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java @@ -28,6 +28,7 @@ import org.springframework.data.jdbc.repository.QueryMappingConfiguration; import org.springframework.data.jdbc.repository.RowMapperMap; import org.springframework.data.mapping.callback.EntityCallbacks; +import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.repository.Repository; import org.springframework.data.repository.core.support.RepositoryFactorySupport; @@ -56,6 +57,7 @@ public class JdbcRepositoryFactoryBean, S, ID extend private QueryMappingConfiguration queryMappingConfiguration = QueryMappingConfiguration.EMPTY; private NamedParameterJdbcOperations operations; private EntityCallbacks entityCallbacks; + private Dialect dialect; /** * Creates a new {@link JdbcRepositoryFactoryBean} for the given repository interface. @@ -99,6 +101,11 @@ protected void setMappingContext(RelationalMappingContext mappingContext) { this.mappingContext = mappingContext; } + @Autowired + protected void setDialect(Dialect dialect) { + this.dialect = dialect; + } + /** * @param dataAccessStrategy can be {@literal null}. */ @@ -167,7 +174,9 @@ public void afterPropertiesSet() { this.dataAccessStrategy = this.beanFactory.getBeanProvider(DataAccessStrategy.class) // .getIfAvailable(() -> { - SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(this.mappingContext); + Assert.state(this.dialect != null, "Dialect is required and must not be null!"); + + SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(this.mappingContext, this.dialect); return new DefaultDataAccessStrategy(sqlGeneratorSource, this.mappingContext, this.converter, this.operations); }); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/DefaultJdbcInterpreterUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/DefaultJdbcInterpreterUnitTests.java index 9bfdf98e30..9c5315851a 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/DefaultJdbcInterpreterUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/DefaultJdbcInterpreterUnitTests.java @@ -15,14 +15,11 @@ */ package org.springframework.data.jdbc.core; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.tuple; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.springframework.data.jdbc.core.PropertyPathTestingUtils.toPath; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; +import static org.springframework.data.jdbc.core.PropertyPathTestingUtils.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; import java.util.List; @@ -52,9 +49,8 @@ */ public class DefaultJdbcInterpreterUnitTests { + public static final SimpleSqlIdentifier BACK_REFERENCE = quoted("container"); static final long CONTAINER_ID = 23L; - static final String BACK_REFERENCE = "container"; - RelationalMappingContext context = new JdbcMappingContext(); JdbcConverter converter = new BasicJdbcConverter(context, (Identifier, path) -> null); DataAccessStrategy dataAccessStrategy = mock(DataAccessStrategy.class); @@ -156,9 +152,10 @@ public void generateCascadingIds() { assertThat(argumentCaptor.getValue().getParts()) // .extracting("name", "value", "targetType") // - .containsOnly(tuple("root_with_list", CONTAINER_ID, Long.class), // the top level id - tuple("root_with_list_key", 3, Integer.class), // midlevel key - tuple("with_list_key", 6, Integer.class) // lowlevel key + .containsOnly(tuple(quoted("root_with_list"), CONTAINER_ID, Long.class), // the top + // level id + tuple(quoted("root_with_list_key"), 3, Integer.class), // midlevel key + tuple(quoted("with_list_key"), 6, Integer.class) // lowlevel key ); } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java index b7e1e49f21..f35ff0a1f4 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java @@ -89,6 +89,109 @@ public class JdbcAggregateTemplateIntegrationTests { @Autowired NamedParameterJdbcOperations jdbcTemplate; LegoSet legoSet = createLegoSet(); + /** + * creates an instance of {@link NoIdListChain4} with the following properties: + *
    + *
  • Each element has two children with indices 0 and 1.
  • + *
  • the xxxValue of each element is a {@literal v} followed by the indices used to navigate to the given instance. + *
  • + *
+ */ + private static NoIdListChain4 createNoIdTree() { + + NoIdListChain4 chain4 = new NoIdListChain4(); + chain4.fourValue = "v"; + + IntStream.of(0, 1).forEach(i -> { + + NoIdListChain3 c3 = new NoIdListChain3(); + c3.threeValue = chain4.fourValue + i; + chain4.chain3.add(c3); + + IntStream.of(0, 1).forEach(j -> { + + NoIdListChain2 c2 = new NoIdListChain2(); + c2.twoValue = c3.threeValue + j; + c3.chain2.add(c2); + + IntStream.of(0, 1).forEach(k -> { + + NoIdListChain1 c1 = new NoIdListChain1(); + c1.oneValue = c2.twoValue + k; + c2.chain1.add(c1); + + IntStream.of(0, 1).forEach(m -> { + + NoIdListChain0 c0 = new NoIdListChain0(); + c0.zeroValue = c1.oneValue + m; + c1.chain0.add(c0); + }); + }); + }); + }); + + return chain4; + } + + private static NoIdMapChain4 createNoIdMapTree() { + + NoIdMapChain4 chain4 = new NoIdMapChain4(); + chain4.fourValue = "v"; + + IntStream.of(0, 1).forEach(i -> { + + NoIdMapChain3 c3 = new NoIdMapChain3(); + c3.threeValue = chain4.fourValue + i; + chain4.chain3.put(asString(i), c3); + + IntStream.of(0, 1).forEach(j -> { + + NoIdMapChain2 c2 = new NoIdMapChain2(); + c2.twoValue = c3.threeValue + j; + c3.chain2.put(asString(j), c2); + + IntStream.of(0, 1).forEach(k -> { + + NoIdMapChain1 c1 = new NoIdMapChain1(); + c1.oneValue = c2.twoValue + k; + c2.chain1.put(asString(k), c1); + + IntStream.of(0, 1).forEach(it -> { + + NoIdMapChain0 c0 = new NoIdMapChain0(); + c0.zeroValue = c1.oneValue + it; + c1.chain0.put(asString(it), c0); + }); + }); + }); + }); + + return chain4; + } + + private static String asString(int i) { + return "_" + i; + } + + private static void assumeNot(String dbProfileName) { + + Assume.assumeTrue("true" + .equalsIgnoreCase(ProfileValueUtils.retrieveProfileValueSource(JdbcAggregateTemplateIntegrationTests.class) + .get("current.database.is.not." + dbProfileName))); + } + + private static LegoSet createLegoSet() { + + LegoSet entity = new LegoSet(); + entity.setName("Star Destroyer"); + + Manual manual = new Manual(); + manual.setContent("Accelerates to 99% of light speed. Destroys almost everything. See https://what-if.xkcd.com/1/"); + entity.setManual(manual); + + return entity; + } + @Test // DATAJDBC-112 public void saveAndLoadAnEntityWithReferencedEntityById() { @@ -550,50 +653,6 @@ public void shouldDeleteChainOfListsWithoutIds() { }); } - /** - * creates an instance of {@link NoIdListChain4} with the following properties: - *
    - *
  • Each element has two children with indices 0 and 1.
  • - *
  • the xxxValue of each element is a {@literal v} followed by the indices used to navigate to the given instance. - *
  • - *
- */ - private static NoIdListChain4 createNoIdTree() { - - NoIdListChain4 chain4 = new NoIdListChain4(); - chain4.fourValue = "v"; - - IntStream.of(0, 1).forEach(i -> { - - NoIdListChain3 c3 = new NoIdListChain3(); - c3.threeValue = chain4.fourValue + i; - chain4.chain3.add(c3); - - IntStream.of(0, 1).forEach(j -> { - - NoIdListChain2 c2 = new NoIdListChain2(); - c2.twoValue = c3.threeValue + j; - c3.chain2.add(c2); - - IntStream.of(0, 1).forEach(k -> { - - NoIdListChain1 c1 = new NoIdListChain1(); - c1.oneValue = c2.twoValue + k; - c2.chain1.add(c1); - - IntStream.of(0, 1).forEach(m -> { - - NoIdListChain0 c0 = new NoIdListChain0(); - c0.zeroValue = c1.oneValue + m; - c1.chain0.add(c0); - }); - }); - }); - }); - - return chain4; - } - @Test // DATAJDBC-223 public void saveAndLoadLongChainOfMapsWithoutIds() { @@ -758,57 +817,10 @@ private void saveAndUpdateAggregateWithVersion(VersionedAggre .withFailMessage("saving an aggregate with a future version should raise an exception"); } - private static NoIdMapChain4 createNoIdMapTree() { - - NoIdMapChain4 chain4 = new NoIdMapChain4(); - chain4.fourValue = "v"; - - IntStream.of(0, 1).forEach(i -> { - - NoIdMapChain3 c3 = new NoIdMapChain3(); - c3.threeValue = chain4.fourValue + i; - chain4.chain3.put(asString(i), c3); - - IntStream.of(0, 1).forEach(j -> { - - NoIdMapChain2 c2 = new NoIdMapChain2(); - c2.twoValue = c3.threeValue + j; - c3.chain2.put(asString(j), c2); - - IntStream.of(0, 1).forEach(k -> { - - NoIdMapChain1 c1 = new NoIdMapChain1(); - c1.oneValue = c2.twoValue + k; - c2.chain1.put(asString(k), c1); - - IntStream.of(0, 1).forEach(it -> { - - NoIdMapChain0 c0 = new NoIdMapChain0(); - c0.zeroValue = c1.oneValue + it; - c1.chain0.put(asString(it), c0); - }); - }); - }); - }); - - return chain4; - } - - private static String asString(int i) { - return "_" + i; - } - private Long count(String tableName) { return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM " + tableName, emptyMap(), Long.class); } - private static void assumeNot(String dbProfileName) { - - Assume.assumeTrue("true" - .equalsIgnoreCase(ProfileValueUtils.retrieveProfileValueSource(JdbcAggregateTemplateIntegrationTests.class) - .get("current.database.is.not." + dbProfileName))); - } - private static class ArrayOwner { @Id Long id; @@ -836,18 +848,6 @@ private static class SetOwner { Set digits = new HashSet<>(); } - private static LegoSet createLegoSet() { - - LegoSet entity = new LegoSet(); - entity.setName("Star Destroyer"); - - Manual manual = new Manual(); - manual.setContent("Accelerates to 99% of light speed. Destroys almost everything. See https://what-if.xkcd.com/1/"); - entity.setManual(manual); - - return entity; - } - @Data static class LegoSet { @@ -1060,13 +1060,13 @@ static class AggregateWithPrimitiveLongVersion extends VersionedAggregate { @Version private long version; @Override - void setVersion(Number newVersion) { - this.version = (long) newVersion; + Number getVersion() { + return this.version; } @Override - Number getVersion() { - return this.version; + void setVersion(Number newVersion) { + this.version = (long) newVersion; } } @@ -1088,13 +1088,13 @@ static class AggregateWithPrimitiveIntegerVersion extends VersionedAggregate { @Version private int version; @Override - void setVersion(Number newVersion) { - this.version = (int) newVersion; + Number getVersion() { + return this.version; } @Override - Number getVersion() { - return this.version; + void setVersion(Number newVersion) { + this.version = (int) newVersion; } } @@ -1116,13 +1116,13 @@ static class AggregateWithPrimitiveShortVersion extends VersionedAggregate { @Version private short version; @Override - void setVersion(Number newVersion) { - this.version = (short) newVersion; + Number getVersion() { + return this.version; } @Override - Number getVersion() { - return this.version; + void setVersion(Number newVersion) { + this.version = (short) newVersion; } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/PersistentPropertyPathExtensionUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/PersistentPropertyPathExtensionUnitTests.java index a8f616b3db..f7e6b5ae9f 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/PersistentPropertyPathExtensionUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/PersistentPropertyPathExtensionUnitTests.java @@ -15,9 +15,11 @@ */ package org.springframework.data.jdbc.core; +import static org.assertj.core.api.SoftAssertions.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; + import java.util.List; -import org.jetbrains.annotations.NotNull; import org.junit.Test; import org.springframework.data.annotation.Id; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; @@ -28,8 +30,6 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; -import static org.assertj.core.api.SoftAssertions.*; - /** * @author Jens Schauder */ @@ -99,13 +99,13 @@ public void getTableName() { assertSoftly(softly -> { - softly.assertThat(extPath(entity).getTableName()).isEqualTo("dummy_entity"); - softly.assertThat(extPath("second").getTableName()).isEqualTo("second"); - softly.assertThat(extPath("second.third2").getTableName()).isEqualTo("second"); - softly.assertThat(extPath("second.third2.value").getTableName()).isEqualTo("second"); - softly.assertThat(extPath("secondList.third2").getTableName()).isEqualTo("second"); - softly.assertThat(extPath("secondList.third2.value").getTableName()).isEqualTo("second"); - softly.assertThat(extPath("secondList").getTableName()).isEqualTo("second"); + softly.assertThat(extPath(entity).getTableName()).isEqualTo(quoted("dummy_entity")); + softly.assertThat(extPath("second").getTableName()).isEqualTo(quoted("second")); + softly.assertThat(extPath("second.third2").getTableName()).isEqualTo(quoted("second")); + softly.assertThat(extPath("second.third2.value").getTableName()).isEqualTo(quoted("second")); + softly.assertThat(extPath("secondList.third2").getTableName()).isEqualTo(quoted("second")); + softly.assertThat(extPath("secondList.third2.value").getTableName()).isEqualTo(quoted("second")); + softly.assertThat(extPath("secondList").getTableName()).isEqualTo(quoted("second")); }); } @@ -115,17 +115,17 @@ public void getTableAlias() { assertSoftly(softly -> { softly.assertThat(extPath(entity).getTableAlias()).isEqualTo(null); - softly.assertThat(extPath("second").getTableAlias()).isEqualTo("second"); - softly.assertThat(extPath("second.third2").getTableAlias()).isEqualTo("second"); - softly.assertThat(extPath("second.third2.value").getTableAlias()).isEqualTo("second"); - softly.assertThat(extPath("second.third").getTableAlias()).isEqualTo("second_third"); - softly.assertThat(extPath("second.third.value").getTableAlias()).isEqualTo("second_third"); - softly.assertThat(extPath("secondList.third2").getTableAlias()).isEqualTo("secondList"); - softly.assertThat(extPath("secondList.third2.value").getTableAlias()).isEqualTo("secondList"); - softly.assertThat(extPath("secondList.third").getTableAlias()).isEqualTo("secondList_third"); - softly.assertThat(extPath("secondList.third.value").getTableAlias()).isEqualTo("secondList_third"); - softly.assertThat(extPath("secondList").getTableAlias()).isEqualTo("secondList"); - softly.assertThat(extPath("second2.third").getTableAlias()).isEqualTo("secthird"); + softly.assertThat(extPath("second").getTableAlias()).isEqualTo(quoted("second")); + softly.assertThat(extPath("second.third2").getTableAlias()).isEqualTo(quoted("second")); + softly.assertThat(extPath("second.third2.value").getTableAlias()).isEqualTo(quoted("second")); + softly.assertThat(extPath("second.third").getTableAlias()).isEqualTo(quoted("second_third")); + softly.assertThat(extPath("second.third.value").getTableAlias()).isEqualTo(quoted("second_third")); + softly.assertThat(extPath("secondList.third2").getTableAlias()).isEqualTo(quoted("secondList")); + softly.assertThat(extPath("secondList.third2.value").getTableAlias()).isEqualTo(quoted("secondList")); + softly.assertThat(extPath("secondList.third").getTableAlias()).isEqualTo(quoted("secondList_third")); + softly.assertThat(extPath("secondList.third.value").getTableAlias()).isEqualTo(quoted("secondList_third")); + softly.assertThat(extPath("secondList").getTableAlias()).isEqualTo(quoted("secondList")); + softly.assertThat(extPath("second2.third").getTableAlias()).isEqualTo(quoted("secthird")); }); } @@ -134,12 +134,12 @@ public void getColumnName() { assertSoftly(softly -> { - softly.assertThat(extPath("second.third2.value").getColumnName()).isEqualTo("thrdvalue"); - softly.assertThat(extPath("second.third.value").getColumnName()).isEqualTo("value"); - softly.assertThat(extPath("secondList.third2.value").getColumnName()).isEqualTo("thrdvalue"); - softly.assertThat(extPath("secondList.third.value").getColumnName()).isEqualTo("value"); - softly.assertThat(extPath("second2.third2.value").getColumnName()).isEqualTo("secthrdvalue"); - softly.assertThat(extPath("second2.third.value").getColumnName()).isEqualTo("value"); + softly.assertThat(extPath("second.third2.value").getColumnName()).isEqualTo(quoted("thrdvalue")); + softly.assertThat(extPath("second.third.value").getColumnName()).isEqualTo(quoted("value")); + softly.assertThat(extPath("secondList.third2.value").getColumnName()).isEqualTo(quoted("thrdvalue")); + softly.assertThat(extPath("secondList.third.value").getColumnName()).isEqualTo(quoted("value")); + softly.assertThat(extPath("second2.third2.value").getColumnName()).isEqualTo(quoted("secthrdvalue")); + softly.assertThat(extPath("second2.third.value").getColumnName()).isEqualTo(quoted("value")); }); } @@ -164,15 +164,15 @@ public void reverseColumnName() { assertSoftly(softly -> { - softly.assertThat(extPath("second.third2").getReverseColumnName()).isEqualTo("dummy_entity"); - softly.assertThat(extPath("second.third").getReverseColumnName()).isEqualTo("dummy_entity"); - softly.assertThat(extPath("secondList.third2").getReverseColumnName()).isEqualTo("dummy_entity"); - softly.assertThat(extPath("secondList.third").getReverseColumnName()).isEqualTo("dummy_entity"); - softly.assertThat(extPath("second2.third2").getReverseColumnName()).isEqualTo("dummy_entity"); - softly.assertThat(extPath("second2.third").getReverseColumnName()).isEqualTo("dummy_entity"); - softly.assertThat(extPath("withId.second.third2.value").getReverseColumnName()).isEqualTo("with_id"); - softly.assertThat(extPath("withId.second.third").getReverseColumnName()).isEqualTo("with_id"); - softly.assertThat(extPath("withId.second2.third").getReverseColumnName()).isEqualTo("with_id"); + softly.assertThat(extPath("second.third2").getReverseColumnName()).isEqualTo(quoted("dummy_entity")); + softly.assertThat(extPath("second.third").getReverseColumnName()).isEqualTo(quoted("dummy_entity")); + softly.assertThat(extPath("secondList.third2").getReverseColumnName()).isEqualTo(quoted("dummy_entity")); + softly.assertThat(extPath("secondList.third").getReverseColumnName()).isEqualTo(quoted("dummy_entity")); + softly.assertThat(extPath("second2.third2").getReverseColumnName()).isEqualTo(quoted("dummy_entity")); + softly.assertThat(extPath("second2.third").getReverseColumnName()).isEqualTo(quoted("dummy_entity")); + softly.assertThat(extPath("withId.second.third2.value").getReverseColumnName()).isEqualTo(quoted("with_id")); + softly.assertThat(extPath("withId.second.third").getReverseColumnName()).isEqualTo(quoted("with_id")); + softly.assertThat(extPath("withId.second2.third").getReverseColumnName()).isEqualTo(quoted("with_id")); }); } @@ -200,12 +200,10 @@ public void extendBy() { }); } - @NotNull private PersistentPropertyPathExtension extPath(RelationalPersistentEntity entity) { return new PersistentPropertyPathExtension(context, entity); } - @NotNull private PersistentPropertyPathExtension extPath(String path) { return new PersistentPropertyPathExtension(context, createSimplePath(path)); } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java index fa42af0c61..932aaee2d4 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java @@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor; @@ -33,7 +34,10 @@ import org.springframework.data.convert.ReadingConverter; import org.springframework.data.convert.WritingConverter; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; +import org.springframework.data.relational.core.dialect.Dialect; +import org.springframework.data.relational.core.dialect.HsqlDbDialect; import org.springframework.data.relational.core.mapping.RelationalMappingContext; +import org.springframework.data.relational.domain.SqlIdentifier; import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.core.namedparam.SqlParameterSource; @@ -54,7 +58,7 @@ public class DefaultDataAccessStrategyUnitTests { JdbcOperations jdbcOperations = mock(JdbcOperations.class); RelationalMappingContext context = new JdbcMappingContext(); - HashMap additionalParameters = new HashMap<>(); + HashMap additionalParameters = new HashMap<>(); ArgumentCaptor paramSourceCaptor = ArgumentCaptor.forClass(SqlParameterSource.class); JdbcConverter converter; @@ -62,12 +66,14 @@ public class DefaultDataAccessStrategyUnitTests { @Before public void before() { + DelegatingDataAccessStrategy relationResolver = new DelegatingDataAccessStrategy(); + Dialect dialect = HsqlDbDialect.INSTANCE; converter = new BasicJdbcConverter(context, relationResolver, new JdbcCustomConversions(), new DefaultJdbcTypeFactory(jdbcOperations)); accessStrategy = new DefaultDataAccessStrategy( // - new SqlGeneratorSource(context), // + new SqlGeneratorSource(context, dialect), // context, // converter, // namedJdbcOperations); @@ -78,12 +84,12 @@ public void before() { @Test // DATAJDBC-146 public void additionalParameterForIdDoesNotLeadToDuplicateParameters() { - additionalParameters.put("id", ID_FROM_ADDITIONAL_VALUES); + additionalParameters.put(SqlIdentifier.quoted("ID"), ID_FROM_ADDITIONAL_VALUES); accessStrategy.insert(new DummyEntity(ORIGINAL_ID), DummyEntity.class, additionalParameters); - verify(namedJdbcOperations).update(eq("INSERT INTO dummy_entity (id) VALUES (:id)"), paramSourceCaptor.capture(), - any(KeyHolder.class)); + verify(namedJdbcOperations).update(eq("INSERT INTO \"DUMMY_ENTITY\" (\"ID\") VALUES (:ID)"), + paramSourceCaptor.capture(), any(KeyHolder.class)); } @Test // DATAJDBC-146 @@ -91,16 +97,16 @@ public void additionalParametersGetAddedToStatement() { ArgumentCaptor sqlCaptor = ArgumentCaptor.forClass(String.class); - additionalParameters.put("reference", ID_FROM_ADDITIONAL_VALUES); + additionalParameters.put(unquoted("reference"), ID_FROM_ADDITIONAL_VALUES); accessStrategy.insert(new DummyEntity(ORIGINAL_ID), DummyEntity.class, additionalParameters); verify(namedJdbcOperations).update(sqlCaptor.capture(), paramSourceCaptor.capture(), any(KeyHolder.class)); assertThat(sqlCaptor.getValue()) // - .containsSequence("INSERT INTO dummy_entity (", "id", ") VALUES (", ":id", ")") // - .containsSequence("INSERT INTO dummy_entity (", "reference", ") VALUES (", ":reference", ")"); - assertThat(paramSourceCaptor.getValue().getValue("id")).isEqualTo(ORIGINAL_ID); + .containsSequence("INSERT INTO \"DUMMY_ENTITY\" (", "\"ID\"", ") VALUES (", ":ID", ")") // + .containsSequence("INSERT INTO \"DUMMY_ENTITY\" (", "reference", ") VALUES (", ":reference", ")"); + assertThat(paramSourceCaptor.getValue().getValue("ID")).isEqualTo(ORIGINAL_ID); } @Test // DATAJDBC-235 @@ -113,7 +119,7 @@ public void considersConfiguredWriteConverter() { new DefaultJdbcTypeFactory(jdbcOperations)); DefaultDataAccessStrategy accessStrategy = new DefaultDataAccessStrategy( // - new SqlGeneratorSource(context), // + new SqlGeneratorSource(context, HsqlDbDialect.INSTANCE), // context, // converter, // namedJdbcOperations); @@ -128,8 +134,8 @@ public void considersConfiguredWriteConverter() { verify(namedJdbcOperations).update(sqlCaptor.capture(), paramSourceCaptor.capture(), any(KeyHolder.class)); - assertThat(paramSourceCaptor.getValue().getValue("id")).isEqualTo(ORIGINAL_ID); - assertThat(paramSourceCaptor.getValue().getValue("flag")).isEqualTo("T"); + assertThat(paramSourceCaptor.getValue().getValue("ID")).isEqualTo(ORIGINAL_ID); + assertThat(paramSourceCaptor.getValue().getValue("FLAG")).isEqualTo("T"); } @RequiredArgsConstructor 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 bc47a266e5..83ea1154c5 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 @@ -60,6 +60,7 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; import org.springframework.data.relational.domain.Identifier; +import org.springframework.data.relational.domain.SqlIdentifier.SimpleSqlIdentifier; import org.springframework.data.repository.query.Param; import org.springframework.util.Assert; @@ -80,15 +81,15 @@ public class EntityRowMapperUnitTests { public static final long ID_FOR_ENTITY_NOT_REFERENCING_MAP = 23L; public static final NamingStrategy X_APPENDING_NAMINGSTRATEGY = new NamingStrategy() { @Override - public String getColumnName(RelationalPersistentProperty property) { - return NamingStrategy.super.getColumnName(property) + "x"; + public SimpleSqlIdentifier getColumnName(RelationalPersistentProperty property) { + return NamingStrategy.super.getColumnName(property).suffix("x"); } }; @Test // DATAJDBC-113 public void simpleEntitiesGetProperlyExtracted() throws SQLException { - ResultSet rs = mockResultSet(asList("id", "name"), // + ResultSet rs = mockResultSet(asList("ID", "NAME"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha"); rs.next(); @@ -103,7 +104,7 @@ public void simpleEntitiesGetProperlyExtracted() throws SQLException { @Test // DATAJDBC-181 public void namingStrategyGetsHonored() throws SQLException { - ResultSet rs = mockResultSet(asList("idx", "namex"), // + ResultSet rs = mockResultSet(asList("IDX", "NAMEX"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha"); rs.next(); @@ -118,7 +119,7 @@ public void namingStrategyGetsHonored() throws SQLException { @Test // DATAJDBC-181 public void namingStrategyGetsHonoredForConstructor() throws SQLException { - ResultSet rs = mockResultSet(asList("idx", "namex"), // + ResultSet rs = mockResultSet(asList("IDX", "NAMEX"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha"); rs.next(); @@ -133,7 +134,7 @@ public void namingStrategyGetsHonoredForConstructor() throws SQLException { @Test // DATAJDBC-427 public void simpleWithReferenceGetProperlyExtracted() throws SQLException { - ResultSet rs = mockResultSet(asList("id", "name", "trivial_id"), // + ResultSet rs = mockResultSet(asList("ID", "NAME", "TRIVIAL_ID"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", 100L); rs.next(); @@ -148,7 +149,7 @@ public void simpleWithReferenceGetProperlyExtracted() throws SQLException { @Test // DATAJDBC-113 public void simpleOneToOneGetsProperlyExtracted() throws SQLException { - ResultSet rs = mockResultSet(asList("id", "name", "child_id", "child_name"), // + ResultSet rs = mockResultSet(asList("ID", "NAME", "CHILD_ID", "CHILD_NAME"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", 24L, "beta"); rs.next(); @@ -163,7 +164,7 @@ public void simpleOneToOneGetsProperlyExtracted() throws SQLException { @Test // DATAJDBC-286 public void immutableOneToOneGetsProperlyExtracted() throws SQLException { - ResultSet rs = mockResultSet(asList("id", "name", "child_id", "child_name"), // + ResultSet rs = mockResultSet(asList("ID", "NAME", "CHILD_ID", "CHILD_NAME"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", 24L, "beta"); rs.next(); @@ -178,7 +179,7 @@ public void immutableOneToOneGetsProperlyExtracted() throws SQLException { @Test // DATAJDBC-427 public void immutableWithReferenceGetsProperlyExtracted() throws SQLException { - ResultSet rs = mockResultSet(asList("id", "name", "trivial_id"), // + ResultSet rs = mockResultSet(asList("ID", "NAME", "TRIVIAL_ID"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", 100L); rs.next(); @@ -194,7 +195,7 @@ public void immutableWithReferenceGetsProperlyExtracted() throws SQLException { @Test // DATAJDBC-111 public void simpleEmbeddedGetsProperlyExtracted() throws SQLException { - ResultSet rs = mockResultSet(asList("id", "name", "prefix_id", "prefix_name"), // + ResultSet rs = mockResultSet(asList("ID", "NAME", "PREFIX_ID", "PREFIX_NAME"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", 24L, "beta"); rs.next(); @@ -209,7 +210,7 @@ public void simpleEmbeddedGetsProperlyExtracted() throws SQLException { @Test // DATAJDBC-113 public void collectionReferenceGetsLoadedWithAdditionalSelect() throws SQLException { - ResultSet rs = mockResultSet(asList("id", "name"), // + ResultSet rs = mockResultSet(asList("ID", "NAME"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha"); rs.next(); @@ -224,7 +225,7 @@ public void collectionReferenceGetsLoadedWithAdditionalSelect() throws SQLExcept @Test // DATAJDBC-131 public void mapReferenceGetsLoadedWithAdditionalSelect() throws SQLException { - ResultSet rs = mockResultSet(asList("id", "name"), // + ResultSet rs = mockResultSet(asList("ID", "NAME"), // ID_FOR_ENTITY_REFERENCING_MAP, "alpha"); rs.next(); @@ -239,7 +240,7 @@ public void mapReferenceGetsLoadedWithAdditionalSelect() throws SQLException { @Test // DATAJDBC-130 public void listReferenceGetsLoadedWithAdditionalSelect() throws SQLException { - ResultSet rs = mockResultSet(asList("id", "name"), // + ResultSet rs = mockResultSet(asList("ID", "NAME"), // ID_FOR_ENTITY_REFERENCING_LIST, "alpha"); rs.next(); @@ -254,7 +255,7 @@ public void listReferenceGetsLoadedWithAdditionalSelect() throws SQLException { @Test // DATAJDBC-252 public void doesNotTryToSetPropertiesThatAreSetViaConstructor() throws SQLException { - ResultSet rs = mockResultSet(singletonList("value"), // + ResultSet rs = mockResultSet(singletonList("VALUE"), // "value-from-resultSet"); rs.next(); @@ -267,7 +268,7 @@ public void doesNotTryToSetPropertiesThatAreSetViaConstructor() throws SQLExcept @Test // DATAJDBC-252 public void handlesMixedProperties() throws SQLException { - ResultSet rs = mockResultSet(asList("one", "two", "three"), // + ResultSet rs = mockResultSet(asList("ONE", "TWO", "THREE"), // "111", "222", "333"); rs.next(); @@ -281,7 +282,7 @@ public void handlesMixedProperties() throws SQLException { @Test // DATAJDBC-273 public void handlesNonSimplePropertyInConstructor() throws SQLException { - ResultSet rs = mockResultSet(singletonList("id"), // + ResultSet rs = mockResultSet(singletonList("ID"), // ID_FOR_ENTITY_REFERENCING_LIST); rs.next(); @@ -297,22 +298,22 @@ public void chainedEntitiesWithoutId() throws SQLException { Fixture fixture = this. buildFixture() // // Id of the aggregate root and backreference to it from // the various aggregate members. - .value(4L).inColumns("four", // - "chain3_no_id_chain4", // - "chain3_chain2_no_id_chain4", // - "chain3_chain2_chain1_no_id_chain4", // - "chain3_chain2_chain1_chain0_no_id_chain4") // + .value(4L).inColumns("FOUR", // + "CHAIN3_NO_ID_CHAIN4", // + "CHAIN3_CHAIN2_NO_ID_CHAIN4", // + "CHAIN3_CHAIN2_CHAIN1_NO_ID_CHAIN4", // + "CHAIN3_CHAIN2_CHAIN1_CHAIN0_NO_ID_CHAIN4") // .endUpIn(e -> e.four) // values for the different entities - .value("four_value").inColumns("four_value").endUpIn(e -> e.fourValue) // + .value("four_value").inColumns("FOUR_VALUE").endUpIn(e -> e.fourValue) // - .value("three_value").inColumns("chain3_three_value").endUpIn(e -> e.chain3.threeValue) // + .value("three_value").inColumns("CHAIN3_THREE_VALUE").endUpIn(e -> e.chain3.threeValue) // - .value("two_value").inColumns("chain3_chain2_two_value").endUpIn(e -> e.chain3.chain2.twoValue) // + .value("two_value").inColumns("CHAIN3_CHAIN2_TWO_VALUE").endUpIn(e -> e.chain3.chain2.twoValue) // - .value("one_value").inColumns("chain3_chain2_chain1_one_value").endUpIn(e -> e.chain3.chain2.chain1.oneValue) // + .value("one_value").inColumns("CHAIN3_CHAIN2_CHAIN1_ONE_VALUE").endUpIn(e -> e.chain3.chain2.chain1.oneValue) // - .value("zero_value").inColumns("chain3_chain2_chain1_chain0_zero_value") + .value("zero_value").inColumns("CHAIN3_CHAIN2_CHAIN1_CHAIN0_ZERO_VALUE") .endUpIn(e -> e.chain3.chain2.chain1.chain0.zeroValue) // .build(); // @formatter:on @@ -329,7 +330,7 @@ public void chainedEntitiesWithoutId() throws SQLException { @Test // DATAJDBC-370 public void simpleNullableImmutableEmbeddedGetsProperlyExtracted() throws SQLException { - ResultSet rs = mockResultSet(asList("id", "value"), // + ResultSet rs = mockResultSet(asList("ID", "VALUE"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, "ru'Ha'"); rs.next(); @@ -345,7 +346,7 @@ public void simpleNullableImmutableEmbeddedGetsProperlyExtracted() throws SQLExc @Test // DATAJDBC-374 public void simpleEmptyImmutableEmbeddedGetsProperlyExtracted() throws SQLException { - ResultSet rs = mockResultSet(asList("id", "value"), // + ResultSet rs = mockResultSet(asList("ID", "VALUE"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, null); rs.next(); @@ -361,7 +362,7 @@ public void simpleEmptyImmutableEmbeddedGetsProperlyExtracted() throws SQLExcept @SneakyThrows public void simplePrimitiveImmutableEmbeddedGetsProperlyExtracted() { - ResultSet rs = mockResultSet(asList("id", "value"), // + ResultSet rs = mockResultSet(asList("ID", "VALUE"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, 24); rs.next(); @@ -377,7 +378,7 @@ public void simplePrimitiveImmutableEmbeddedGetsProperlyExtracted() { @Test // DATAJDBC-370 public void simpleImmutableEmbeddedShouldBeNullIfAllOfTheEmbeddableAreNull() throws SQLException { - ResultSet rs = mockResultSet(asList("id", "value"), // + ResultSet rs = mockResultSet(asList("ID", "VALUE"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, null); rs.next(); @@ -394,7 +395,7 @@ public void simpleImmutableEmbeddedShouldBeNullIfAllOfTheEmbeddableAreNull() thr @SneakyThrows public void embeddedShouldBeNullWhenFieldsAreNull() { - ResultSet rs = mockResultSet(asList("id", "name", "prefix_id", "prefix_name"), // + ResultSet rs = mockResultSet(asList("ID", "NAME", "PREFIX_ID", "PREFIX_NAME"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", null, null); rs.next(); @@ -410,7 +411,7 @@ public void embeddedShouldBeNullWhenFieldsAreNull() { @SneakyThrows public void embeddedShouldNotBeNullWhenAtLeastOneFieldIsNotNull() { - ResultSet rs = mockResultSet(asList("id", "name", "prefix_id", "prefix_name"), // + ResultSet rs = mockResultSet(asList("ID", "NAME", "PREFIX_ID", "PREFIX_NAME"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", 24, null); rs.next(); @@ -426,7 +427,7 @@ public void embeddedShouldNotBeNullWhenAtLeastOneFieldIsNotNull() { @SneakyThrows public void primitiveEmbeddedShouldBeNullWhenNoValuePresent() { - ResultSet rs = mockResultSet(asList("id", "value"), // + ResultSet rs = mockResultSet(asList("ID", "VALUE"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, null); rs.next(); @@ -443,7 +444,7 @@ public void primitiveEmbeddedShouldBeNullWhenNoValuePresent() { @SneakyThrows public void deepNestedEmbeddable() { - ResultSet rs = mockResultSet(asList("id", "level0", "level1_value", "level1_level2_value"), // + ResultSet rs = mockResultSet(asList("ID", "LEVEL0", "LEVEL1_VALUE", "LEVEL1_LEVEL2_VALUE"), // ID_FOR_ENTITY_NOT_REFERENCING_MAP, "0", "1", "2"); rs.next(); 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 0bf2879d4a..68a4f5898f 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 @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.*; import static org.springframework.data.jdbc.core.PropertyPathTestingUtils.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; import java.util.List; import java.util.Map; @@ -46,7 +47,7 @@ public void parametersWithPropertyKeysUseTheParentPropertyJdbcType() { assertThat(identifier.getParts()) // .extracting("name", "value", "targetType") // .containsExactly( // - tuple("dummy_entity", "eins", UUID.class) // + tuple(quoted("dummy_entity"), "eins", UUID.class) // ); } @@ -63,8 +64,8 @@ public void qualifiersForMaps() { assertThat(identifier.getParts()) // .extracting("name", "value", "targetType") // .containsExactlyInAnyOrder( // - tuple("dummy_entity", "parent-eins", UUID.class), // - tuple("dummy_entity_key", "map-key-eins", String.class) // + tuple(quoted("dummy_entity"), "parent-eins", UUID.class), // + tuple(quoted("dummy_entity_key"), "map-key-eins", String.class) // ); } @@ -81,8 +82,8 @@ public void qualifiersForLists() { assertThat(identifier.getParts()) // .extracting("name", "value", "targetType") // .containsExactlyInAnyOrder( // - tuple("dummy_entity", "parent-eins", UUID.class), // - tuple("dummy_entity_key", "list-index-eins", Integer.class) // + tuple(quoted("dummy_entity"), "parent-eins", UUID.class), // + tuple(quoted("dummy_entity_key"), "list-index-eins", Integer.class) // ); } @@ -96,7 +97,7 @@ public void backreferenceAcrossEmbeddable() { assertThat(identifier.getParts()) // .extracting("name", "value", "targetType") // .containsExactly( // - tuple("dummy_entity", "parent-eins", UUID.class) // + tuple(quoted("dummy_entity"), "parent-eins", UUID.class) // ); } @@ -110,7 +111,7 @@ public void backreferenceAcrossNoId() { assertThat(identifier.getParts()) // .extracting("name", "value", "targetType") // .containsExactly( // - tuple("dummy_entity", "parent-eins", UUID.class) // + tuple(quoted("dummy_entity"), "parent-eins", UUID.class) // ); } 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 ce65d661b4..3e9e9f46c6 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 @@ -16,6 +16,7 @@ package org.springframework.data.jdbc.core.convert; import static org.assertj.core.api.Assertions.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -25,7 +26,6 @@ import org.assertj.core.api.SoftAssertions; import org.junit.Test; import org.springframework.data.annotation.Id; -import org.springframework.data.jdbc.core.convert.SqlGenerator; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.core.mapping.PersistentPropertyPathTestUtils; import org.springframework.data.mapping.PersistentPropertyPath; @@ -33,6 +33,10 @@ import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; +import org.springframework.data.relational.domain.IdentifierProcessing.DefaultIdentifierProcessing; +import org.springframework.data.relational.domain.IdentifierProcessing.LetterCasing; +import org.springframework.data.relational.domain.IdentifierProcessing.Quoting; +import org.springframework.data.relational.domain.SqlIdentifier; /** * Unit tests to verify a contextual {@link NamingStrategy} implementation that customizes using a user-centric @@ -52,8 +56,8 @@ public class SqlGeneratorContextBasedNamingStrategyUnitTests { private final NamingStrategy contextualNamingStrategy = new NamingStrategy() { @Override - public String getSchema() { - return userHandler.get(); + public SqlIdentifier getSchema() { + return unquoted(userHandler.get()); } }; @@ -87,8 +91,11 @@ public void cascadingDeleteFirstLevel() { String sql = sqlGenerator.createDeleteByPath(getPath("ref")); - assertThat(sql).isEqualTo( - "DELETE FROM " + user + ".referenced_entity WHERE " + user + ".referenced_entity.dummy_entity = :rootId"); + assertThat(sql).isEqualTo( // + "DELETE FROM " // + + user + ".referenced_entity WHERE " // + + user + ".referenced_entity.dummy_entity = :rootId" // + ); }); } @@ -213,7 +220,8 @@ private SqlGenerator configureSqlGenerator(NamingStrategy namingStrategy) { RelationalMappingContext context = new JdbcMappingContext(namingStrategy); RelationalPersistentEntity persistentEntity = context.getRequiredPersistentEntity(DummyEntity.class); - return new SqlGenerator(context, persistentEntity); + return new SqlGenerator(context, persistentEntity, + new DefaultIdentifierProcessing(new Quoting(""), LetterCasing.AS_IS)); } @SuppressWarnings("unused") 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 85bbc3ff24..2309942d65 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 @@ -32,6 +32,9 @@ import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.sql.Aliased; +import org.springframework.data.relational.domain.IdentifierProcessing.DefaultIdentifierProcessing; +import org.springframework.data.relational.domain.IdentifierProcessing.LetterCasing; +import org.springframework.data.relational.domain.IdentifierProcessing.Quoting; /** * Unit tests for the {@link SqlGenerator} in a context of the {@link Embedded} annotation. @@ -50,81 +53,121 @@ public void setUp() { SqlGenerator createSqlGenerator(Class type) { RelationalPersistentEntity persistentEntity = context.getRequiredPersistentEntity(type); - return new SqlGenerator(context, persistentEntity); + return new SqlGenerator(context, persistentEntity, + new DefaultIdentifierProcessing(new Quoting(""), LetterCasing.AS_IS)); } @Test // DATAJDBC-111 public void findOne() { final String sql = sqlGenerator.getFindOne(); - SoftAssertions softAssertions = new SoftAssertions(); - softAssertions.assertThat(sql).startsWith("SELECT").contains("dummy_entity.id1 AS id1") - .contains("dummy_entity.test AS test").contains("dummy_entity.attr1 AS attr1") - .contains("dummy_entity.attr2 AS attr2").contains("dummy_entity.prefix2_attr1 AS prefix2_attr1") - .contains("dummy_entity.prefix2_attr2 AS prefix2_attr2").contains("dummy_entity.prefix_test AS prefix_test") - .contains("dummy_entity.prefix_attr1 AS prefix_attr1").contains("dummy_entity.prefix_attr2 AS prefix_attr2") - .contains("dummy_entity.prefix_prefix2_attr1 AS prefix_prefix2_attr1") - .contains("dummy_entity.prefix_prefix2_attr2 AS prefix_prefix2_attr2").contains("WHERE dummy_entity.id1 = :id") - .doesNotContain("JOIN").doesNotContain("embeddable"); - softAssertions.assertAll(); + SoftAssertions.assertSoftly(softly -> { + + softly.assertThat(sql).startsWith("SELECT") // + .contains("dummy_entity.id1 AS id1") // + .contains("dummy_entity.test AS test") // + .contains("dummy_entity.attr1 AS attr1") // + .contains("dummy_entity.attr2 AS attr2") // + .contains("dummy_entity.prefix2_attr1 AS prefix2_attr1") // + .contains("dummy_entity.prefix2_attr2 AS prefix2_attr2") // + .contains("dummy_entity.prefix_test AS prefix_test") // + .contains("dummy_entity.prefix_attr1 AS prefix_attr1") // + .contains("dummy_entity.prefix_attr2 AS prefix_attr2") // + .contains("dummy_entity.prefix_prefix2_attr1 AS prefix_prefix2_attr1") // + .contains("dummy_entity.prefix_prefix2_attr2 AS prefix_prefix2_attr2") // + .contains("WHERE dummy_entity.id1 = :id") // + .doesNotContain("JOIN").doesNotContain("embeddable"); // + }); } @Test // DATAJDBC-111 public void findAll() { final String sql = sqlGenerator.getFindAll(); - SoftAssertions softAssertions = new SoftAssertions(); - softAssertions.assertThat(sql).startsWith("SELECT").contains("dummy_entity.id1 AS id1") - .contains("dummy_entity.test AS test").contains("dummy_entity.attr1 AS attr1") - .contains("dummy_entity.attr2 AS attr2").contains("dummy_entity.prefix2_attr1 AS prefix2_attr1") - .contains("dummy_entity.prefix2_attr2 AS prefix2_attr2").contains("dummy_entity.prefix_test AS prefix_test") - .contains("dummy_entity.prefix_attr1 AS prefix_attr1").contains("dummy_entity.prefix_attr2 AS prefix_attr2") - .contains("dummy_entity.prefix_prefix2_attr1 AS prefix_prefix2_attr1") - .contains("dummy_entity.prefix_prefix2_attr2 AS prefix_prefix2_attr2").doesNotContain("JOIN") - .doesNotContain("embeddable"); - softAssertions.assertAll(); + SoftAssertions.assertSoftly(softly -> { + + softly.assertThat(sql).startsWith("SELECT") // + .contains("dummy_entity.id1 AS id1") // + .contains("dummy_entity.test AS test") // + .contains("dummy_entity.attr1 AS attr1") // + .contains("dummy_entity.attr2 AS attr2") // + .contains("dummy_entity.prefix2_attr1 AS prefix2_attr1") // + .contains("dummy_entity.prefix2_attr2 AS prefix2_attr2") // + .contains("dummy_entity.prefix_test AS prefix_test") // + .contains("dummy_entity.prefix_attr1 AS prefix_attr1") // + .contains("dummy_entity.prefix_attr2 AS prefix_attr2") // + .contains("dummy_entity.prefix_prefix2_attr1 AS prefix_prefix2_attr1") // + .contains("dummy_entity.prefix_prefix2_attr2 AS prefix_prefix2_attr2") // + .doesNotContain("JOIN") // + .doesNotContain("embeddable"); + }); } @Test // DATAJDBC-111 public void findAllInList() { final String sql = sqlGenerator.getFindAllInList(); - SoftAssertions softAssertions = new SoftAssertions(); - softAssertions.assertThat(sql).startsWith("SELECT").contains("dummy_entity.id1 AS id1") - .contains("dummy_entity.test AS test").contains("dummy_entity.attr1 AS attr1") - .contains("dummy_entity.attr2 AS attr2").contains("dummy_entity.prefix2_attr1 AS prefix2_attr1") - .contains("dummy_entity.prefix2_attr2 AS prefix2_attr2").contains("dummy_entity.prefix_test AS prefix_test") - .contains("dummy_entity.prefix_attr1 AS prefix_attr1").contains("dummy_entity.prefix_attr2 AS prefix_attr2") - .contains("dummy_entity.prefix_prefix2_attr1 AS prefix_prefix2_attr1") - .contains("dummy_entity.prefix_prefix2_attr2 AS prefix_prefix2_attr2") - .contains("WHERE dummy_entity.id1 IN (:ids)").doesNotContain("JOIN").doesNotContain("embeddable"); - softAssertions.assertAll(); + SoftAssertions.assertSoftly(softly -> { + + softly.assertThat(sql).startsWith("SELECT") // + .contains("dummy_entity.id1 AS id1") // + .contains("dummy_entity.test AS test") // + .contains("dummy_entity.attr1 AS attr1") // + .contains("dummy_entity.attr2 AS attr2").contains("dummy_entity.prefix2_attr1 AS prefix2_attr1") // + .contains("dummy_entity.prefix2_attr2 AS prefix2_attr2") // + .contains("dummy_entity.prefix_test AS prefix_test") // + .contains("dummy_entity.prefix_attr1 AS prefix_attr1") // + .contains("dummy_entity.prefix_attr2 AS prefix_attr2") // + .contains("dummy_entity.prefix_prefix2_attr1 AS prefix_prefix2_attr1") // + .contains("dummy_entity.prefix_prefix2_attr2 AS prefix_prefix2_attr2") // + .contains("WHERE dummy_entity.id1 IN (:ids)") // + .doesNotContain("JOIN") // + .doesNotContain("embeddable"); + }); } @Test // DATAJDBC-111 public void insert() { final String sql = sqlGenerator.getInsert(emptySet()); - SoftAssertions softAssertions = new SoftAssertions(); - softAssertions.assertThat(sql).startsWith("INSERT INTO").contains("dummy_entity").contains(":test") - .contains(":attr1").contains(":attr2").contains(":prefix2_attr1").contains(":prefix2_attr2") - .contains(":prefix_test").contains(":prefix_attr1").contains(":prefix_attr2").contains(":prefix_prefix2_attr1") - .contains(":prefix_prefix2_attr2"); - softAssertions.assertAll(); + SoftAssertions.assertSoftly(softly -> { + + softly.assertThat(sql) // + .startsWith("INSERT INTO") // + .contains("dummy_entity") // + .contains(":test") // + .contains(":attr1") // + .contains(":attr2") // + .contains(":prefix2_attr1") // + .contains(":prefix2_attr2") // + .contains(":prefix_test") // + .contains(":prefix_attr1") // + .contains(":prefix_attr2") // + .contains(":prefix_prefix2_attr1") // + .contains(":prefix_prefix2_attr2"); + }); } @Test // DATAJDBC-111 public void update() { final String sql = sqlGenerator.getUpdate(); - SoftAssertions softAssertions = new SoftAssertions(); - softAssertions.assertThat(sql).startsWith("UPDATE").contains("dummy_entity").contains("test = :test") - .contains("attr1 = :attr1").contains("attr2 = :attr2").contains("prefix2_attr1 = :prefix2_attr1") - .contains("prefix2_attr2 = :prefix2_attr2").contains("prefix_test = :prefix_test") - .contains("prefix_attr1 = :prefix_attr1").contains("prefix_attr2 = :prefix_attr2") - .contains("prefix_prefix2_attr1 = :prefix_prefix2_attr1") - .contains("prefix_prefix2_attr2 = :prefix_prefix2_attr2"); - softAssertions.assertAll(); + SoftAssertions.assertSoftly(softly -> { + + softly.assertThat(sql) // + .startsWith("UPDATE") // + .contains("dummy_entity") // + .contains("test = :test") // + .contains("attr1 = :attr1") // + .contains("attr2 = :attr2") // + .contains("prefix2_attr1 = :prefix2_attr1") // + .contains("prefix2_attr2 = :prefix2_attr2") // + .contains("prefix_test = :prefix_test") // + .contains("prefix_attr1 = :prefix_attr1") // + .contains("prefix_attr2 = :prefix_attr2") // + .contains("prefix_prefix2_attr1 = :prefix_prefix2_attr1") // + .contains("prefix_prefix2_attr2 = :prefix_prefix2_attr2"); + }); } @Test // DATAJDBC-340 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 f361312cd8..eb7071e1c0 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 @@ -16,6 +16,7 @@ package org.springframework.data.jdbc.core.convert; import static org.assertj.core.api.Assertions.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; import org.assertj.core.api.SoftAssertions; import org.junit.Test; @@ -23,10 +24,13 @@ import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.core.mapping.PersistentPropertyPathTestUtils; import org.springframework.data.mapping.PersistentPropertyPath; +import org.springframework.data.relational.domain.IdentifierProcessing; +import org.springframework.data.relational.domain.SqlIdentifier; 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.core.mapping.RelationalPersistentProperty; +import org.springframework.data.relational.domain.SqlIdentifier.SimpleSqlIdentifier; /** * Unit tests the {@link SqlGenerator} with a fixed {@link NamingStrategy} implementation containing a hard wired @@ -39,31 +43,31 @@ public class SqlGeneratorFixedNamingStrategyUnitTests { final NamingStrategy fixedCustomTablePrefixStrategy = new NamingStrategy() { @Override - public String getSchema() { - return "FixedCustomSchema"; + public SqlIdentifier getSchema() { + return unquoted("FixedCustomSchema"); } @Override - public String getTableName(Class type) { - return "FixedCustomTablePrefix_" + type.getSimpleName(); + public SqlIdentifier getTableName(Class type) { + return unquoted("FixedCustomTablePrefix_" + type.getSimpleName()); } @Override - public String getColumnName(RelationalPersistentProperty property) { - return "FixedCustomPropertyPrefix_" + property.getName(); + public SimpleSqlIdentifier getColumnName(RelationalPersistentProperty property) { + return unquoted("FixedCustomPropertyPrefix_" + property.getName()); } }; final NamingStrategy upperCaseLowerCaseStrategy = new NamingStrategy() { @Override - public String getTableName(Class type) { - return type.getSimpleName().toUpperCase(); + public SqlIdentifier getTableName(Class type) { + return unquoted(type.getSimpleName().toUpperCase()); } @Override - public String getColumnName(RelationalPersistentProperty property) { - return property.getName().toLowerCase(); + public SimpleSqlIdentifier getColumnName(RelationalPersistentProperty property) { + return unquoted(property.getName().toLowerCase()); } }; @@ -83,8 +87,8 @@ public void findOneWithOverriddenFixedTableName() { "FixedCustomSchema.FixedCustomTablePrefix_DummyEntity.FixedCustomPropertyPrefix_id AS FixedCustomPropertyPrefix_id,") // .contains( "FixedCustomSchema.FixedCustomTablePrefix_DummyEntity.FixedCustomPropertyPrefix_name AS FixedCustomPropertyPrefix_name,") // - .contains("ref.FixedCustomPropertyPrefix_l1id AS ref_FixedCustomPropertyPrefix_l1id") // - .contains("ref.FixedCustomPropertyPrefix_content AS ref_FixedCustomPropertyPrefix_content") // + .contains("\"REF\".FixedCustomPropertyPrefix_l1id AS ref_FixedCustomPropertyPrefix_l1id") // + .contains("\"REF\".FixedCustomPropertyPrefix_content AS ref_FixedCustomPropertyPrefix_content") // .contains("FROM FixedCustomSchema.FixedCustomTablePrefix_DummyEntity"); softAssertions.assertAll(); } @@ -101,8 +105,8 @@ public void findOneWithUppercasedTablesAndLowercasedColumns() { .startsWith("SELECT") // .contains("DUMMYENTITY.id AS id,") // .contains("DUMMYENTITY.name AS name,") // - .contains("ref.l1id AS ref_l1id") // - .contains("ref.content AS ref_content") // + .contains("\"REF\".l1id AS ref_l1id") // + .contains("\"REF\".content AS ref_content") // .contains("FROM DUMMYENTITY"); softAssertions.assertAll(); } @@ -115,7 +119,7 @@ public void cascadingDeleteFirstLevel() { String sql = sqlGenerator.createDeleteByPath(getPath("ref")); assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity " - + "WHERE FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity.dummy_entity = :rootId"); + + "WHERE FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity.\"DUMMY_ENTITY\" = :rootId"); } @Test // DATAJDBC-107 @@ -126,10 +130,10 @@ public void cascadingDeleteAllSecondLevel() { String sql = sqlGenerator.createDeleteByPath(getPath("ref.further")); assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_SecondLevelReferencedEntity " - + "WHERE FixedCustomSchema.FixedCustomTablePrefix_SecondLevelReferencedEntity.referenced_entity IN " + + "WHERE FixedCustomSchema.FixedCustomTablePrefix_SecondLevelReferencedEntity.\"REFERENCED_ENTITY\" IN " + "(SELECT FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity.FixedCustomPropertyPrefix_l1id " + "FROM FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity " - + "WHERE FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity.dummy_entity = :rootId)"); + + "WHERE FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity.\"DUMMY_ENTITY\" = :rootId)"); } @Test // DATAJDBC-107 @@ -150,7 +154,7 @@ public void cascadingDeleteAllFirstLevel() { String sql = sqlGenerator.createDeleteAllSql(getPath("ref")); assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity " - + "WHERE FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity.dummy_entity IS NOT NULL"); + + "WHERE FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity.\"DUMMY_ENTITY\" IS NOT NULL"); } @Test // DATAJDBC-107 @@ -161,10 +165,10 @@ public void cascadingDeleteSecondLevel() { String sql = sqlGenerator.createDeleteAllSql(getPath("ref.further")); assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_SecondLevelReferencedEntity " - + "WHERE FixedCustomSchema.FixedCustomTablePrefix_SecondLevelReferencedEntity.referenced_entity IN " + + "WHERE FixedCustomSchema.FixedCustomTablePrefix_SecondLevelReferencedEntity.\"REFERENCED_ENTITY\" IN " + "(SELECT FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity.FixedCustomPropertyPrefix_l1id " + "FROM FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity " - + "WHERE FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity.dummy_entity IS NOT NULL)"); + + "WHERE FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity.\"DUMMY_ENTITY\" IS NOT NULL)"); } @Test // DATAJDBC-113 @@ -189,7 +193,7 @@ private SqlGenerator configureSqlGenerator(NamingStrategy namingStrategy) { RelationalMappingContext context = new JdbcMappingContext(namingStrategy); RelationalPersistentEntity persistentEntity = context.getRequiredPersistentEntity(DummyEntity.class); - return new SqlGenerator(context, persistentEntity); + return new SqlGenerator(context, persistentEntity, IdentifierProcessing.ANSI); } @SuppressWarnings("unused") 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 5fa155f863..c5abe3a05f 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 @@ -17,6 +17,7 @@ import static java.util.Collections.*; import static org.assertj.core.api.Assertions.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; import java.util.Map; import java.util.Set; @@ -41,6 +42,11 @@ import org.springframework.data.relational.core.sql.Aliased; import org.springframework.data.relational.core.sql.Table; import org.springframework.data.relational.domain.Identifier; +import org.springframework.data.relational.domain.IdentifierProcessing; +import org.springframework.data.relational.domain.IdentifierProcessing.DefaultIdentifierProcessing; +import org.springframework.data.relational.domain.IdentifierProcessing.LetterCasing; +import org.springframework.data.relational.domain.IdentifierProcessing.Quoting; +import org.springframework.data.relational.domain.SqlIdentifier.*; /** * Unit tests for the {@link SqlGenerator}. @@ -54,7 +60,7 @@ */ public class SqlGeneratorUnitTests { - static final Identifier BACKREF = Identifier.of("backref", "some-value", String.class); + static final Identifier BACKREF = Identifier.of(unquoted("backref"), "some-value", String.class); SqlGenerator sqlGenerator; NamingStrategy namingStrategy = new PrefixingNamingStrategy(); @@ -67,9 +73,14 @@ public void setUp() { SqlGenerator createSqlGenerator(Class type) { + return createSqlGenerator(type, new DefaultIdentifierProcessing(new Quoting(""), LetterCasing.AS_IS)); + } + + SqlGenerator createSqlGenerator(Class type, IdentifierProcessing identifierProcessing) { + RelationalPersistentEntity persistentEntity = context.getRequiredPersistentEntity(type); - return new SqlGenerator(context, persistentEntity); + return new SqlGenerator(context, persistentEntity, identifierProcessing); } @Test // DATAJDBC-112 @@ -174,8 +185,8 @@ public void findAllByProperty() { public void findAllByPropertyWithMultipartIdentifier() { // this would get called when ListParent is the element type of a Set - Identifier parentIdentifier = Identifier.of("backref", "some-value", String.class) // - .withPart("backref_key", "key-value", Object.class); + Identifier parentIdentifier = Identifier.of(unquoted("backref"), "some-value", String.class) // + .withPart(unquoted("backref_key"), "key-value", Object.class); String sql = sqlGenerator.getFindAllByProperty(parentIdentifier, null, false); assertThat(sql).contains("SELECT", // @@ -197,7 +208,7 @@ public void findAllByPropertyWithMultipartIdentifier() { public void findAllByPropertyWithKey() { // this would get called when ListParent is th element type of a Map - String sql = sqlGenerator.getFindAllByProperty(BACKREF, "key-column", false); + String sql = sqlGenerator.getFindAllByProperty(BACKREF, unquoted("key-column"), false); assertThat(sql).isEqualTo("SELECT dummy_entity.id1 AS id1, dummy_entity.x_name AS x_name, " // + "dummy_entity.x_other AS x_other, " // @@ -219,7 +230,7 @@ public void findAllByPropertyOrderedWithoutKey() { public void findAllByPropertyWithKeyOrdered() { // this would get called when ListParent is th element type of a Map - String sql = sqlGenerator.getFindAllByProperty(BACKREF, "key-column", true); + String sql = sqlGenerator.getFindAllByProperty(BACKREF, unquoted("key-column"), true); assertThat(sql).isEqualTo("SELECT dummy_entity.id1 AS id1, dummy_entity.x_name AS x_name, " // + "dummy_entity.x_other AS x_other, " // @@ -235,16 +246,16 @@ public void findAllByPropertyWithKeyOrdered() { @Test // DATAJDBC-219 public void updateWithVersion() { - SqlGenerator sqlGenerator = createSqlGenerator(VersionedEntity.class); + SqlGenerator sqlGenerator = createSqlGenerator(VersionedEntity.class, IdentifierProcessing.ANSI); assertThat(sqlGenerator.getUpdateWithVersion()).containsSequence( // "UPDATE", // - "versioned_entity", // + "\"VERSIONED_ENTITY\"", // "SET", // "WHERE", // - "id1 = :id", // + "\"ID1\" = :ID1", // "AND", // - "version = :___oldOptimisticLockingVersion"); + "\"X_VERSION\" = :___oldOptimisticLockingVersion"); } @Test // DATAJDBC-264 @@ -260,66 +271,69 @@ public void getInsertForEmptyColumnList() { @Test // DATAJDBC-334 public void getInsertForQuotedColumnName() { - SqlGenerator sqlGenerator = createSqlGenerator(EntityWithQuotedColumnName.class); + SqlGenerator sqlGenerator = createSqlGenerator(EntityWithQuotedColumnName.class, IdentifierProcessing.ANSI); String insert = sqlGenerator.getInsert(emptySet()); - assertThat(insert) - .isEqualTo("INSERT INTO entity_with_quoted_column_name " + "(\"test_@123\") " + "VALUES (:test_123)"); + assertThat(insert).isEqualTo("INSERT INTO \"ENTITY_WITH_QUOTED_COLUMN_NAME\" " // + + "(\"TEST\"\"_@123\") " + "VALUES (:TEST_123)"); } @Test // DATAJDBC-266 public void joinForOneToOneWithoutIdIncludesTheBackReferenceOfTheOuterJoin() { - SqlGenerator sqlGenerator = createSqlGenerator(ParentOfNoIdChild.class); + SqlGenerator sqlGenerator = createSqlGenerator(ParentOfNoIdChild.class, IdentifierProcessing.ANSI); String findAll = sqlGenerator.getFindAll(); - assertThat(findAll).containsSequence("SELECT", "child.parent_of_no_id_child AS child_parent_of_no_id_child", - "FROM"); + assertThat(findAll).containsSequence("SELECT", + "\"CHILD\".\"PARENT_OF_NO_ID_CHILD\" AS \"CHILD_PARENT_OF_NO_ID_CHILD\"", "FROM"); } @Test // DATAJDBC-262 public void update() { + SqlGenerator sqlGenerator = createSqlGenerator(DummyEntity.class, IdentifierProcessing.ANSI); + assertThat(sqlGenerator.getUpdate()).containsSequence( // "UPDATE", // - "dummy_entity", // + "\"DUMMY_ENTITY\"", // "SET", // "WHERE", // - "id1 = :id"); + "\"ID1\" = :ID"); } @Test // DATAJDBC-324 public void readOnlyPropertyExcludedFromQuery_when_generateUpdateSql() { - final SqlGenerator sqlGenerator = createSqlGenerator(EntityWithReadOnlyProperty.class); + final SqlGenerator sqlGenerator = createSqlGenerator(EntityWithReadOnlyProperty.class, IdentifierProcessing.ANSI); assertThat(sqlGenerator.getUpdate()).isEqualToIgnoringCase( // - "UPDATE entity_with_read_only_property " // - + "SET x_name = :x_name " // - + "WHERE entity_with_read_only_property.x_id = :x_id" // + "UPDATE \"ENTITY_WITH_READ_ONLY_PROPERTY\" " // + + "SET \"X_NAME\" = :X_NAME " // + + "WHERE \"ENTITY_WITH_READ_ONLY_PROPERTY\".\"X_ID\" = :X_ID" // ); } @Test // DATAJDBC-334 public void getUpdateForQuotedColumnName() { - SqlGenerator sqlGenerator = createSqlGenerator(EntityWithQuotedColumnName.class); + SqlGenerator sqlGenerator = createSqlGenerator(EntityWithQuotedColumnName.class, IdentifierProcessing.ANSI); String update = sqlGenerator.getUpdate(); - assertThat(update).isEqualTo("UPDATE entity_with_quoted_column_name " + "SET \"test_@123\" = :test_123 " - + "WHERE entity_with_quoted_column_name.\"test_@id\" = :test_id"); + assertThat(update).isEqualTo("UPDATE \"ENTITY_WITH_QUOTED_COLUMN_NAME\" " // + + "SET \"TEST\"\"_@123\" = :TEST_123 " // + + "WHERE \"ENTITY_WITH_QUOTED_COLUMN_NAME\".\"TEST\"\"_@ID\" = :TEST_ID"); } @Test // DATAJDBC-324 public void readOnlyPropertyExcludedFromQuery_when_generateInsertSql() { - final SqlGenerator sqlGenerator = createSqlGenerator(EntityWithReadOnlyProperty.class); + final SqlGenerator sqlGenerator = createSqlGenerator(EntityWithReadOnlyProperty.class, IdentifierProcessing.ANSI); assertThat(sqlGenerator.getInsert(emptySet())).isEqualToIgnoringCase( // - "INSERT INTO entity_with_read_only_property (x_name) " // + "INSERT INTO \"ENTITY_WITH_READ_ONLY_PROPERTY\" (\"X_NAME\") " // + "VALUES (:x_name)" // ); } @@ -340,7 +354,7 @@ public void readOnlyPropertyIncludedIntoQuery_when_generateFindAllByPropertySql( final SqlGenerator sqlGenerator = createSqlGenerator(EntityWithReadOnlyProperty.class); - assertThat(sqlGenerator.getFindAllByProperty(BACKREF, "key-column", true)).isEqualToIgnoringCase( // + assertThat(sqlGenerator.getFindAllByProperty(BACKREF, unquoted("key-column"), true)).isEqualToIgnoringCase( // "SELECT " // + "entity_with_read_only_property.x_id AS x_id, " // + "entity_with_read_only_property.x_name AS x_name, " // @@ -434,14 +448,15 @@ public void noJoinForSimpleColumn() { @Test // DATAJDBC-340 public void joinForSimpleReference() { + SqlGenerator.Join join = generateJoin("ref", DummyEntity.class); + SoftAssertions.assertSoftly(softly -> { - SqlGenerator.Join join = generateJoin("ref", DummyEntity.class); - softly.assertThat(join.getJoinTable().getName()).isEqualTo("referenced_entity"); + softly.assertThat(join.getJoinTable().getName()).isEqualTo("\"REFERENCED_ENTITY\""); softly.assertThat(join.getJoinColumn().getTable()).isEqualTo(join.getJoinTable()); - softly.assertThat(join.getJoinColumn().getName()).isEqualTo("dummy_entity"); - softly.assertThat(join.getParentId().getName()).isEqualTo("id1"); - softly.assertThat(join.getParentId().getTable().getName()).isEqualTo("dummy_entity"); + softly.assertThat(join.getJoinColumn().getName()).isEqualTo("\"DUMMY_ENTITY\""); + softly.assertThat(join.getParentId().getName()).isEqualTo("\"ID1\""); + softly.assertThat(join.getParentId().getTable().getName()).isEqualTo("\"DUMMY_ENTITY\""); }); } @@ -465,37 +480,39 @@ public void noJoinForMappedReference() { @Test // DATAJDBC-340 public void joinForSecondLevelReference() { + SqlGenerator.Join join = generateJoin("ref.further", DummyEntity.class); + SoftAssertions.assertSoftly(softly -> { - SqlGenerator.Join join = generateJoin("ref.further", DummyEntity.class); - softly.assertThat(join.getJoinTable().getName()).isEqualTo("second_level_referenced_entity"); + softly.assertThat(join.getJoinTable().getName()).isEqualTo("\"SECOND_LEVEL_REFERENCED_ENTITY\""); softly.assertThat(join.getJoinColumn().getTable()).isEqualTo(join.getJoinTable()); - softly.assertThat(join.getJoinColumn().getName()).isEqualTo("referenced_entity"); - softly.assertThat(join.getParentId().getName()).isEqualTo("x_l1id"); - softly.assertThat(join.getParentId().getTable().getName()).isEqualTo("referenced_entity"); + softly.assertThat(join.getJoinColumn().getName()).isEqualTo("\"REFERENCED_ENTITY\""); + softly.assertThat(join.getParentId().getName()).isEqualTo("\"X_L1ID\""); + softly.assertThat(join.getParentId().getTable().getName()).isEqualTo("\"REFERENCED_ENTITY\""); }); } @Test // DATAJDBC-340 public void joinForOneToOneWithoutId() { + SqlGenerator.Join join = generateJoin("child", ParentOfNoIdChild.class); + Table joinTable = join.getJoinTable(); + SoftAssertions.assertSoftly(softly -> { - SqlGenerator.Join join = generateJoin("child", ParentOfNoIdChild.class); - Table joinTable = join.getJoinTable(); - softly.assertThat(joinTable.getName()).isEqualTo("no_id_child"); + softly.assertThat(joinTable.getName()).isEqualTo("\"NO_ID_CHILD\""); softly.assertThat(joinTable).isInstanceOf(Aliased.class); - softly.assertThat(((Aliased) joinTable).getAlias()).isEqualTo("child"); + softly.assertThat(((Aliased) joinTable).getAlias()).isEqualTo("\"CHILD\""); softly.assertThat(join.getJoinColumn().getTable()).isEqualTo(joinTable); - softly.assertThat(join.getJoinColumn().getName()).isEqualTo("parent_of_no_id_child"); - softly.assertThat(join.getParentId().getName()).isEqualTo("x_id"); - softly.assertThat(join.getParentId().getTable().getName()).isEqualTo("parent_of_no_id_child"); + softly.assertThat(join.getJoinColumn().getName()).isEqualTo("\"PARENT_OF_NO_ID_CHILD\""); + softly.assertThat(join.getParentId().getName()).isEqualTo("\"X_ID\""); + softly.assertThat(join.getParentId().getTable().getName()).isEqualTo("\"PARENT_OF_NO_ID_CHILD\""); }); } private SqlGenerator.Join generateJoin(String path, Class type) { - return createSqlGenerator(type) + return createSqlGenerator(type, IdentifierProcessing.ANSI) .getJoin(new PersistentPropertyPathExtension(context, PropertyPathTestingUtils.toPath(path, type, context))); } @@ -504,7 +521,7 @@ public void simpleColumn() { assertThat(generatedColumn("id", DummyEntity.class)) // .extracting(c -> c.getName(), c -> c.getTable().getName(), c -> getAlias(c.getTable()), this::getAlias) - .containsExactly("id1", "dummy_entity", null, "id1"); + .containsExactly("\"ID1\"", "\"DUMMY_ENTITY\"", null, "\"ID1\""); } @Test // DATAJDBC-340 @@ -512,7 +529,7 @@ public void columnForIndirectProperty() { assertThat(generatedColumn("ref.l1id", DummyEntity.class)) // .extracting(c -> c.getName(), c -> c.getTable().getName(), c -> getAlias(c.getTable()), this::getAlias) // - .containsExactly("x_l1id", "referenced_entity", "ref", "ref_x_l1id"); + .containsExactly("\"X_L1ID\"", "\"REFERENCED_ENTITY\"", "\"REF\"", "\"REF_X_L1ID\""); } @Test // DATAJDBC-340 @@ -526,7 +543,8 @@ public void columnForReferencedEntityWithoutId() { assertThat(generatedColumn("child", ParentOfNoIdChild.class)) // .extracting(c -> c.getName(), c -> c.getTable().getName(), c -> getAlias(c.getTable()), this::getAlias) // - .containsExactly("parent_of_no_id_child", "no_id_child", "child", "child_parent_of_no_id_child"); + .containsExactly("\"PARENT_OF_NO_ID_CHILD\"", "\"NO_ID_CHILD\"", "\"CHILD\"", + "\"CHILD_PARENT_OF_NO_ID_CHILD\""); } private String getAlias(Object maybeAliased) { @@ -539,7 +557,7 @@ private String getAlias(Object maybeAliased) { private org.springframework.data.relational.core.sql.Column generatedColumn(String path, Class type) { - return createSqlGenerator(type) + return createSqlGenerator(type, IdentifierProcessing.ANSI) .getColumn(new PersistentPropertyPathExtension(context, PropertyPathTestingUtils.toPath(path, type, context))); } @@ -599,8 +617,8 @@ static class OtherAggregate { private static class PrefixingNamingStrategy implements NamingStrategy { @Override - public String getColumnName(RelationalPersistentProperty property) { - return "x_" + NamingStrategy.super.getColumnName(property); + public SimpleSqlIdentifier getColumnName(RelationalPersistentProperty property) { + return NamingStrategy.super.getColumnName(property).prefix("x_"); } } @@ -621,8 +639,10 @@ static class EntityWithReadOnlyProperty { static class EntityWithQuotedColumnName { - @Id @Column("\"test_@id\"") Long id; - @Column("\"test_@123\"") String name; + // these column names behave like single double quote in the name since the get quoted and then doubling the double + // quote escapes it. + @Id @Column("test\"\"_@id") Long id; + @Column("test\"\"_@123") String name; } @SuppressWarnings("unused") diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSourceUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSourceUnitTests.java new file mode 100644 index 0000000000..f4aaed9bde --- /dev/null +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSourceUnitTests.java @@ -0,0 +1,118 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.jdbc.core.convert; + +import org.assertj.core.api.SoftAssertions; +import org.junit.Test; +import org.springframework.data.relational.domain.IdentifierProcessing; +import org.springframework.data.relational.domain.SqlIdentifier; + +/** + * Tests for {@link SqlIdentifierParameterSource}. + * + * @author Jens Schauder + */ +public class SqlIdentifierParameterSourceUnitTests { + + private IdentifierProcessing identifierProcessing = IdentifierProcessing.ANSI; + + @Test // DATAJDBC-386 + public void empty() { + + SqlIdentifierParameterSource parameters = new SqlIdentifierParameterSource(identifierProcessing); + + SoftAssertions.assertSoftly(softly -> { + + softly.assertThat(parameters.getParameterNames()).isEmpty(); + softly.assertThat(parameters.getValue("blah")).isNull(); + softly.assertThat(parameters.hasValue("blah")).isFalse(); + softly.assertThat(parameters.getSqlType("blah")).isEqualTo(Integer.MIN_VALUE); + }); + } + + @Test // DATAJDBC-386 + public void addSingleValue() { + + SqlIdentifierParameterSource parameters = new SqlIdentifierParameterSource(identifierProcessing); + + parameters.addValue(SqlIdentifier.unquoted("key"), 23); + + SoftAssertions.assertSoftly(softly -> { + + softly.assertThat(parameters.getParameterNames()).isEqualTo(new String[] { "key" }); + softly.assertThat(parameters.getValue("key")).isEqualTo(23); + softly.assertThat(parameters.hasValue("key")).isTrue(); + + softly.assertThat(parameters.getValue("blah")).isNull(); + softly.assertThat(parameters.hasValue("blah")).isFalse(); + softly.assertThat(parameters.getSqlType("blah")).isEqualTo(Integer.MIN_VALUE); + }); + } + + @Test // DATAJDBC-386 + public void addSingleValueWithType() { + + SqlIdentifierParameterSource parameters = new SqlIdentifierParameterSource(identifierProcessing); + + parameters.addValue(SqlIdentifier.unquoted("key"), 23, 42); + + SoftAssertions.assertSoftly(softly -> { + + softly.assertThat(parameters.getParameterNames()).isEqualTo(new String[] { "key" }); + softly.assertThat(parameters.getValue("key")).isEqualTo(23); + softly.assertThat(parameters.hasValue("key")).isTrue(); + softly.assertThat(parameters.getSqlType("key")).isEqualTo(42); + + softly.assertThat(parameters.getValue("blah")).isNull(); + softly.assertThat(parameters.hasValue("blah")).isFalse(); + softly.assertThat(parameters.getSqlType("blah")).isEqualTo(Integer.MIN_VALUE); + }); + } + + @Test // DATAJDBC-386 + public void addOtherDatabaseObjectIdentifierParameterSource() { + + SqlIdentifierParameterSource parameters = new SqlIdentifierParameterSource(identifierProcessing); + parameters.addValue(SqlIdentifier.unquoted("key1"), 111, 11); + parameters.addValue(SqlIdentifier.unquoted("key2"), 111); + + SqlIdentifierParameterSource parameters2 = new SqlIdentifierParameterSource(identifierProcessing); + parameters2.addValue(SqlIdentifier.unquoted("key2"), 222, 22); + parameters2.addValue(SqlIdentifier.unquoted("key3"), 222); + + parameters.addAll(parameters2); + + SoftAssertions.assertSoftly(softly -> { + + softly.assertThat(parameters.getParameterNames()).isEqualTo(new String[] { "key1", "key2", "key3" }); + softly.assertThat(parameters.getValue("key1")).isEqualTo(111); + softly.assertThat(parameters.hasValue("key1")).isTrue(); + softly.assertThat(parameters.getSqlType("key1")).isEqualTo(11); + + softly.assertThat(parameters.getValue("key2")).isEqualTo(222); + softly.assertThat(parameters.hasValue("key2")).isTrue(); + softly.assertThat(parameters.getSqlType("key2")).isEqualTo(22); + + softly.assertThat(parameters.getValue("key3")).isEqualTo(222); + softly.assertThat(parameters.hasValue("key3")).isTrue(); + softly.assertThat(parameters.getSqlType("key3")).isEqualTo(Integer.MIN_VALUE); + + softly.assertThat(parameters.getValue("blah")).isNull(); + softly.assertThat(parameters.hasValue("blah")).isFalse(); + softly.assertThat(parameters.getSqlType("blah")).isEqualTo(Integer.MIN_VALUE); + }); + } +} diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/mapping/BasicJdbcPersistentPropertyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/mapping/BasicJdbcPersistentPropertyUnitTests.java index d3eefe2327..05816debf2 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/mapping/BasicJdbcPersistentPropertyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/mapping/BasicJdbcPersistentPropertyUnitTests.java @@ -15,7 +15,8 @@ */ package org.springframework.data.jdbc.core.mapping; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; import lombok.Data; @@ -27,7 +28,6 @@ import org.assertj.core.api.SoftAssertions; import org.junit.Test; - import org.springframework.data.annotation.Id; import org.springframework.data.mapping.PropertyHandler; import org.springframework.data.relational.core.mapping.BasicRelationalPersistentProperty; @@ -89,9 +89,9 @@ public void detectsAnnotatedColumnName() { RelationalPersistentEntity entity = context.getRequiredPersistentEntity(DummyEntity.class); - assertThat(entity.getRequiredPersistentProperty("name").getColumnName()).isEqualTo("dummy_name"); + assertThat(entity.getRequiredPersistentProperty("name").getColumnName()).isEqualTo(quoted("dummy_name")); assertThat(entity.getRequiredPersistentProperty("localDateTime").getColumnName()) - .isEqualTo("dummy_last_updated_at"); + .isEqualTo(quoted("dummy_last_updated_at")); } @Test // DATAJDBC-218 @@ -101,8 +101,8 @@ public void detectsAnnotatedColumnAndKeyName() { .getRequiredPersistentEntity(DummyEntity.class) // .getRequiredPersistentProperty("someList"); - assertThat(listProperty.getReverseColumnName()).isEqualTo("dummy_column_name"); - assertThat(listProperty.getKeyColumn()).isEqualTo("dummy_key_column_name"); + assertThat(listProperty.getReverseColumnName()).isEqualTo(quoted("dummy_column_name")); + assertThat(listProperty.getKeyColumn()).isEqualTo(quoted("dummy_key_column_name")); } @Test // DATAJDBC-221 @@ -125,8 +125,8 @@ public void detectsKeyColumnNameFromColumnAnnotation() { .getRequiredPersistentEntity(WithCollections.class) // .getRequiredPersistentProperty("someList"); - assertThat(listProperty.getKeyColumn()).isEqualTo("some_key"); - assertThat(listProperty.getReverseColumnName()).isEqualTo("some_value"); + assertThat(listProperty.getKeyColumn()).isEqualTo(quoted("some_key")); + assertThat(listProperty.getReverseColumnName()).isEqualTo(quoted("some_value")); } @Test // DATAJDBC-331 @@ -136,8 +136,8 @@ public void detectsKeyColumnOverrideNameFromMappedCollectionAnnotation() { .getRequiredPersistentEntity(WithCollections.class) // .getRequiredPersistentProperty("overrideList"); - assertThat(listProperty.getKeyColumn()).isEqualTo("override_key"); - assertThat(listProperty.getReverseColumnName()).isEqualTo("override_id"); + assertThat(listProperty.getKeyColumn()).isEqualTo(quoted("override_key")); + assertThat(listProperty.getReverseColumnName()).isEqualTo(quoted("override_id")); } private void checkTargetType(SoftAssertions softly, RelationalPersistentEntity persistentEntity, @@ -148,6 +148,11 @@ private void checkTargetType(SoftAssertions softly, RelationalPersistentEntity overrideList; } - - @SuppressWarnings("unused") - private enum SomeEnum { - ALPHA - } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mapping/model/NamingStrategyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mapping/model/NamingStrategyUnitTests.java index bdb79273e0..cad4b3d27e 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mapping/model/NamingStrategyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mapping/model/NamingStrategyUnitTests.java @@ -16,6 +16,7 @@ package org.springframework.data.jdbc.mapping.model; import static org.assertj.core.api.Assertions.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; import lombok.Data; @@ -27,6 +28,7 @@ import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.relational.core.mapping.NamingStrategy; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; +import org.springframework.data.relational.domain.SqlIdentifier; /** * Unit tests for the default {@link NamingStrategy}. @@ -44,42 +46,42 @@ public class NamingStrategyUnitTests { @Test // DATAJDBC-184 public void getTableName() { - assertThat(target.getTableName(persistentEntity.getType())).isEqualTo("dummy_entity"); + assertThat(target.getTableName(persistentEntity.getType())).isEqualTo(quoted("dummy_entity")); } @Test // DATAJDBC-184 public void getColumnName() { assertThat(target.getColumnName(persistentEntity.getPersistentProperty("id"))) // - .isEqualTo("id"); + .isEqualTo(quoted("id")); assertThat(target.getColumnName(persistentEntity.getPersistentProperty("createdAt"))) // - .isEqualTo("created_at"); + .isEqualTo(quoted("created_at")); assertThat(target.getColumnName(persistentEntity.getPersistentProperty("dummySubEntities"))) // - .isEqualTo("dummy_sub_entities"); + .isEqualTo(quoted("dummy_sub_entities")); } @Test // DATAJDBC-184 public void getReverseColumnName() { assertThat(target.getReverseColumnName(persistentEntity.getPersistentProperty("dummySubEntities"))) - .isEqualTo("dummy_entity"); + .isEqualTo(quoted("dummy_entity")); } @Test // DATAJDBC-184 public void getKeyColumn() { assertThat(target.getKeyColumn(persistentEntity.getPersistentProperty("dummySubEntities"))) // - .isEqualTo("dummy_entity_key"); + .isEqualTo(quoted("dummy_entity_key")); } @Test // DATAJDBC-184 public void getSchema() { - assertThat(target.getSchema()).isEmpty(); + assertThat(target.getSchema()).isEqualTo(SqlIdentifier.EMPTY); } @Test // DATAJDBC-184 public void getQualifiedTableName() { - assertThat(target.getQualifiedTableName(persistentEntity.getType())).isEqualTo("dummy_entity"); + assertThat(target.getQualifiedTableName(persistentEntity.getType())).isEqualTo(quoted("dummy_entity")); } @Data diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisCustomizingNamespaceHsqlIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisCustomizingNamespaceHsqlIntegrationTests.java index 2de583ad6c..be8c18e437 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisCustomizingNamespaceHsqlIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisCustomizingNamespaceHsqlIntegrationTests.java @@ -15,7 +15,7 @@ */ package org.springframework.data.jdbc.mybatis; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.*; import junit.framework.AssertionFailedError; @@ -39,6 +39,7 @@ import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories; import org.springframework.data.jdbc.testing.TestConfiguration; +import org.springframework.data.relational.core.dialect.HsqlDbDialect; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.repository.CrudRepository; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; @@ -79,6 +80,8 @@ public void myBatisGetsUsedForInsertAndSelect() { assertThat(reloaded.name).isEqualTo("name " + saved.id); } + interface DummyEntityRepository extends CrudRepository {} + @org.springframework.context.annotation.Configuration @Import(TestConfiguration.class) @EnableJdbcRepositories(considerNestedRepositories = true) @@ -116,8 +119,9 @@ MyBatisDataAccessStrategy dataAccessStrategy(SqlSession sqlSession) { RelationalMappingContext context = new JdbcMappingContext(); JdbcConverter converter = new BasicJdbcConverter(context, (Identifier, path) -> null); - - MyBatisDataAccessStrategy strategy = new MyBatisDataAccessStrategy(sqlSession, context, converter); + + MyBatisDataAccessStrategy strategy = new MyBatisDataAccessStrategy(sqlSession, + HsqlDbDialect.INSTANCE.getIdentifierProcessing()); strategy.setNamespaceStrategy(new NamespaceStrategy() { @Override @@ -129,6 +133,4 @@ public String getNamespace(Class domainType) { return strategy; } } - - interface DummyEntityRepository extends CrudRepository {} } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategyUnitTests.java index 2c048f6375..aa729cc851 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategyUnitTests.java @@ -15,18 +15,12 @@ */ package org.springframework.data.jdbc.mybatis; -import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.RETURNS_DEEP_STUBS; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static java.util.Arrays.*; +import static java.util.Collections.*; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; import java.util.Collections; @@ -44,6 +38,7 @@ import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; import org.springframework.data.relational.domain.Identifier; +import org.springframework.data.relational.domain.IdentifierProcessing; /** * Unit tests for the {@link MyBatisDataAccessStrategy}, mainly ensuring that the correct statements get's looked up. @@ -60,7 +55,7 @@ public class MyBatisDataAccessStrategyUnitTests { SqlSession session = mock(SqlSession.class); ArgumentCaptor captor = ArgumentCaptor.forClass(MyBatisContext.class); - MyBatisDataAccessStrategy accessStrategy = new MyBatisDataAccessStrategy(session, context, converter); + MyBatisDataAccessStrategy accessStrategy = new MyBatisDataAccessStrategy(session, IdentifierProcessing.ANSI); PersistentPropertyPath path = PropertyPathTestingUtils.toPath("one.two", DummyEntity.class, context); @@ -74,7 +69,7 @@ public void before() { @Test // DATAJDBC-123 public void insert() { - accessStrategy.insert("x", String.class, Collections.singletonMap("key", "value")); + accessStrategy.insert("x", String.class, Collections.singletonMap(unquoted("key"), "value")); verify(session).insert(eq("java.lang.StringMapper.insert"), captor.capture()); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisHsqlIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisHsqlIntegrationTests.java index 2014ac1856..a6f7d88454 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisHsqlIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisHsqlIntegrationTests.java @@ -35,6 +35,7 @@ import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories; import org.springframework.data.jdbc.testing.TestConfiguration; +import org.springframework.data.relational.core.dialect.HsqlDbDialect; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.repository.CrudRepository; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @@ -57,6 +58,36 @@ @Transactional public class MyBatisHsqlIntegrationTests { + @ClassRule public static final SpringClassRule classRule = new SpringClassRule(); + @Rule public SpringMethodRule methodRule = new SpringMethodRule(); + @Autowired SqlSessionFactory sqlSessionFactory; + @Autowired DummyEntityRepository repository; + + @Test // DATAJDBC-123 + public void mybatisSelfTest() { + + SqlSession session = sqlSessionFactory.openSession(); + + session.selectList("org.springframework.data.jdbc.mybatis.DummyEntityMapper.findById"); + } + + @Test // DATAJDBC-123 + public void myBatisGetsUsedForInsertAndSelect() { + + DummyEntity entity = new DummyEntity(null, "some name"); + DummyEntity saved = repository.save(entity); + + assertThat(saved.id).isNotNull(); + + DummyEntity reloaded = repository.findById(saved.id).orElseThrow(AssertionFailedError::new); + + assertThat(reloaded).isNotNull().extracting(e -> e.id, e -> e.name); + } + + interface DummyEntityRepository extends CrudRepository { + + } + @org.springframework.context.annotation.Configuration @Import(TestConfiguration.class) @EnableJdbcRepositories(considerNestedRepositories = true) @@ -94,38 +125,7 @@ DataAccessStrategy dataAccessStrategy(RelationalMappingContext context, JdbcConv SqlSession sqlSession, EmbeddedDatabase db) { return MyBatisDataAccessStrategy.createCombinedAccessStrategy(context, converter, - new NamedParameterJdbcTemplate(db), sqlSession); + new NamedParameterJdbcTemplate(db), sqlSession, HsqlDbDialect.INSTANCE); } } - - @ClassRule public static final SpringClassRule classRule = new SpringClassRule(); - @Rule public SpringMethodRule methodRule = new SpringMethodRule(); - - @Autowired SqlSessionFactory sqlSessionFactory; - @Autowired DummyEntityRepository repository; - - @Test // DATAJDBC-123 - public void mybatisSelfTest() { - - SqlSession session = sqlSessionFactory.openSession(); - - session.selectList("org.springframework.data.jdbc.mybatis.DummyEntityMapper.findById"); - } - - @Test // DATAJDBC-123 - public void myBatisGetsUsedForInsertAndSelect() { - - DummyEntity entity = new DummyEntity(null, "some name"); - DummyEntity saved = repository.save(entity); - - assertThat(saved.id).isNotNull(); - - DummyEntity reloaded = repository.findById(saved.id).orElseThrow(AssertionFailedError::new); - - assertThat(reloaded).isNotNull().extracting(e -> e.id, e -> e.name); - } - - interface DummyEntityRepository extends CrudRepository { - - } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java index 12a77ef485..e50f6e2d1a 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java @@ -16,6 +16,7 @@ package org.springframework.data.jdbc.repository; import static org.assertj.core.api.Assertions.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; import lombok.Data; import lombok.Value; @@ -27,7 +28,6 @@ import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; @@ -39,6 +39,7 @@ import org.springframework.data.jdbc.repository.support.SimpleJdbcRepository; import org.springframework.data.relational.core.mapping.NamingStrategy; import org.springframework.data.relational.core.mapping.event.BeforeConvertCallback; +import org.springframework.data.relational.domain.SqlIdentifier; import org.springframework.data.repository.CrudRepository; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.test.context.ContextConfiguration; @@ -166,8 +167,8 @@ NamingStrategy namingStrategy() { return new NamingStrategy() { @Override - public String getTableName(Class type) { - return type.getSimpleName().toUpperCase(); + public SqlIdentifier getTableName(Class type) { + return unquoted(type.getSimpleName().toUpperCase()); } }; } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java index dac687929d..1329178c3a 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java @@ -45,6 +45,7 @@ import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory; import org.springframework.data.jdbc.repository.support.SimpleJdbcRepository; +import org.springframework.data.relational.core.dialect.HsqlDbDialect; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.event.AfterDeleteEvent; import org.springframework.data.relational.core.mapping.event.AfterLoadEvent; @@ -82,7 +83,7 @@ public void before() { DelegatingDataAccessStrategy delegatingDataAccessStrategy = new DelegatingDataAccessStrategy(); JdbcConverter converter = new BasicJdbcConverter(context, delegatingDataAccessStrategy, new JdbcCustomConversions(), new DefaultJdbcTypeFactory(operations.getJdbcOperations())); - SqlGeneratorSource generatorSource = new SqlGeneratorSource(context); + SqlGeneratorSource generatorSource = new SqlGeneratorSource(context, HsqlDbDialect.INSTANCE); this.dataAccessStrategy = spy(new DefaultDataAccessStrategy(generatorSource, context, converter, operations)); delegatingDataAccessStrategy.setDelegate(dataAccessStrategy); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcAuditingHsqlIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcAuditingHsqlIntegrationTests.java index 352839967e..3f5fd83f5b 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcAuditingHsqlIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcAuditingHsqlIntegrationTests.java @@ -16,6 +16,7 @@ package org.springframework.data.jdbc.repository.config; import static org.assertj.core.api.Assertions.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; import lombok.Data; @@ -44,6 +45,7 @@ import org.springframework.data.relational.core.mapping.NamingStrategy; import org.springframework.data.relational.core.mapping.event.BeforeConvertCallback; import org.springframework.data.relational.core.mapping.event.BeforeSaveEvent; +import org.springframework.data.relational.domain.SqlIdentifier; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Component; import org.springframework.test.context.ActiveProfiles; @@ -271,8 +273,8 @@ NamingStrategy namingStrategy() { return new NamingStrategy() { - public String getTableName(@NotNull Class type) { - return "DummyEntity"; + public SqlIdentifier getTableName(@NotNull Class type) { + return unquoted("DummyEntity"); } }; } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositoriesIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositoriesIntegrationTests.java index 45aa3c420e..13a0ab6db3 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositoriesIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositoriesIntegrationTests.java @@ -40,9 +40,9 @@ import org.springframework.data.jdbc.repository.QueryMappingConfiguration; import org.springframework.data.jdbc.repository.config.EnableJdbcRepositoriesIntegrationTests.TestConfiguration; import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactoryBean; +import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.repository.CrudRepository; -import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @@ -69,7 +69,6 @@ public class EnableJdbcRepositoriesIntegrationTests { "dataAccessStrategy"); public static final RowMapper DUMMY_ENTITY_ROW_MAPPER = mock(RowMapper.class); public static final RowMapper STRING_ROW_MAPPER = mock(RowMapper.class); - public static final ResultSetExtractor INTEGER_RESULT_SET_EXTRACTOR = mock(ResultSetExtractor.class); @Autowired JdbcRepositoryFactoryBean factoryBean; @Autowired DummyRepository repository; @@ -153,8 +152,8 @@ NamedParameterJdbcOperations qualifierJdbcOperations(DataSource dataSource) { @Bean("qualifierDataAccessStrategy") DataAccessStrategy defaultDataAccessStrategy( @Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations template, - RelationalMappingContext context, JdbcConverter converter) { - return new DefaultDataAccessStrategy(new SqlGeneratorSource(context), context, converter, template); + RelationalMappingContext context, JdbcConverter converter, Dialect dialect) { + return new DefaultDataAccessStrategy(new SqlGeneratorSource(context, dialect), context, converter, template); } } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBeanUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBeanUnitTests.java index f479ac1521..43403b5cf9 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBeanUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBeanUnitTests.java @@ -37,6 +37,7 @@ import org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.repository.QueryMappingConfiguration; +import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.repository.CrudRepository; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; @@ -60,6 +61,8 @@ public class JdbcRepositoryFactoryBeanUnitTests { @Mock DataAccessStrategy dataAccessStrategy; @Mock ApplicationEventPublisher publisher; @Mock(answer = Answers.RETURNS_DEEP_STUBS) ListableBeanFactory beanFactory; + @Mock + Dialect dialect; RelationalMappingContext mappingContext; @@ -86,6 +89,7 @@ public void setsUpBasicInstanceCorrectly() { factoryBean.setConverter(new BasicJdbcConverter(mappingContext, dataAccessStrategy)); factoryBean.setApplicationEventPublisher(publisher); factoryBean.setBeanFactory(beanFactory); + factoryBean.setDialect(dialect); factoryBean.afterPropertiesSet(); assertThat(factoryBean.getObject()).isNotNull(); @@ -113,6 +117,7 @@ public void afterPropertiesSetDefaultsNullablePropertiesCorrectly() { factoryBean.setConverter(new BasicJdbcConverter(mappingContext, dataAccessStrategy)); factoryBean.setApplicationEventPublisher(publisher); factoryBean.setBeanFactory(beanFactory); + factoryBean.setDialect(dialect); factoryBean.afterPropertiesSet(); assertThat(factoryBean.getObject()).isNotNull(); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/HsqlDataSourceConfiguration.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/HsqlDataSourceConfiguration.java index 9d4b71374f..3be5ef4128 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/HsqlDataSourceConfiguration.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/HsqlDataSourceConfiguration.java @@ -21,6 +21,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; +import org.springframework.data.relational.core.dialect.Dialect; +import org.springframework.data.relational.core.dialect.HsqlDbDialect; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; @@ -47,4 +49,9 @@ DataSource dataSource() { .addScript(TestUtils.createScriptName(context, "hsql")) // .build(); } + + @Bean + Dialect dialect() { + return HsqlDbDialect.INSTANCE; + } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/MariaDBDataSourceConfiguration.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/MariaDBDataSourceConfiguration.java index 8a0b8a709a..385c0a561c 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/MariaDBDataSourceConfiguration.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/MariaDBDataSourceConfiguration.java @@ -22,8 +22,11 @@ import javax.sql.DataSource; import org.mariadb.jdbc.MariaDbDataSource; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; +import org.springframework.data.relational.core.dialect.Dialect; +import org.springframework.data.relational.core.dialect.MariaDbDialect; import org.testcontainers.containers.MariaDBContainer; import org.testcontainers.jdbc.ext.ScriptUtils; @@ -48,7 +51,9 @@ class MariaDBDataSourceConfiguration extends DataSourceConfiguration { */ @Override protected DataSource createDataSource() { + try { + MariaDbDataSource dataSource = new MariaDbDataSource(); dataSource.setUrl(MARIADB_CONTAINER.getJdbcUrl()); dataSource.setUser(MARIADB_CONTAINER.getUsername()); @@ -59,6 +64,11 @@ protected DataSource createDataSource() { } } + @Bean + Dialect dialect() { + return MariaDbDialect.INSTANCE; + } + @PostConstruct public void initDatabase() throws SQLException, ScriptException { ScriptUtils.executeSqlScript(createDataSource().getConnection(), null, "DROP DATABASE test;CREATE DATABASE test;"); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/MySqlDataSourceConfiguration.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/MySqlDataSourceConfiguration.java index 94ce8ea45c..f62872bab6 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/MySqlDataSourceConfiguration.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/MySqlDataSourceConfiguration.java @@ -21,8 +21,11 @@ import javax.script.ScriptException; import javax.sql.DataSource; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; +import org.springframework.data.relational.core.dialect.Dialect; +import org.springframework.data.relational.core.dialect.MySqlDialect; import org.testcontainers.containers.MySQLContainer; import org.testcontainers.jdbc.ext.ScriptUtils; @@ -62,6 +65,11 @@ protected DataSource createDataSource() { return dataSource; } + @Bean + Dialect dialect() { + return MySqlDialect.INSTANCE; + } + @PostConstruct public void initDatabase() throws SQLException, ScriptException { ScriptUtils.executeSqlScript(createDataSource().getConnection(), null, "DROP DATABASE test;CREATE DATABASE test;"); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/PostgresDataSourceConfiguration.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/PostgresDataSourceConfiguration.java index f9b4cb71e3..46f238afa0 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/PostgresDataSourceConfiguration.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/PostgresDataSourceConfiguration.java @@ -18,8 +18,11 @@ import javax.sql.DataSource; import org.postgresql.ds.PGSimpleDataSource; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; +import org.springframework.data.relational.core.dialect.Dialect; +import org.springframework.data.relational.core.dialect.PostgresDialect; import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; import org.testcontainers.containers.PostgreSQLContainer; @@ -55,6 +58,11 @@ protected DataSource createDataSource() { return dataSource; } + @Bean + Dialect dialect() { + return PostgresDialect.INSTANCE; + } + /* * (non-Javadoc) * @see org.springframework.data.jdbc.testing.DataSourceFactoryBean#customizePopulator(org.springframework.jdbc.datasource.init.ResourceDatabasePopulator) 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 66803880ba..e134a86486 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 @@ -38,6 +38,7 @@ import org.springframework.data.jdbc.core.convert.SqlGeneratorSource; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory; +import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.data.relational.core.mapping.NamingStrategy; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.repository.core.NamedQueries; @@ -86,10 +87,10 @@ PlatformTransactionManager transactionManager() { @Bean DataAccessStrategy defaultDataAccessStrategy( @Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations template, RelationalMappingContext context, - JdbcConverter converter) { + JdbcConverter converter, Dialect dialect) { - DefaultDataAccessStrategy defaultDataAccessStrategy = new DefaultDataAccessStrategy(new SqlGeneratorSource(context), - context, converter, template); + DefaultDataAccessStrategy defaultDataAccessStrategy = new DefaultDataAccessStrategy( + new SqlGeneratorSource(context, dialect), context, converter, template); return defaultDataAccessStrategy; } diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-mysql.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-mysql.sql index db71d7a10f..1ea550facf 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-mysql.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-mysql.sql @@ -1,292 +1,297 @@ CREATE TABLE LEGO_SET ( - id1 BIGINT AUTO_INCREMENT PRIMARY KEY, - NAME VARCHAR(30) + id1 BIGINT AUTO_INCREMENT PRIMARY KEY, + NAME VARCHAR(30) ); CREATE TABLE MANUAL ( - id2 BIGINT AUTO_INCREMENT PRIMARY KEY, - LEGO_SET BIGINT, - ALTERNATIVE BIGINT, - CONTENT VARCHAR(2000) + id2 BIGINT AUTO_INCREMENT PRIMARY KEY, + LEGO_SET BIGINT, + ALTERNATIVE BIGINT, + CONTENT VARCHAR(2000) ); ALTER TABLE MANUAL - ADD FOREIGN KEY (LEGO_SET) - REFERENCES LEGO_SET (id1); + ADD FOREIGN KEY (LEGO_SET) + REFERENCES LEGO_SET (id1); CREATE TABLE ONE_TO_ONE_PARENT ( - id3 BIGINT AUTO_INCREMENT PRIMARY KEY, - content VARCHAR(30) + id3 BIGINT AUTO_INCREMENT PRIMARY KEY, + content VARCHAR(30) ); CREATE TABLE Child_No_Id ( - ONE_TO_ONE_PARENT INTEGER PRIMARY KEY, - content VARCHAR(30) + ONE_TO_ONE_PARENT INTEGER PRIMARY KEY, + content VARCHAR(30) ); CREATE TABLE LIST_PARENT ( - id4 BIGINT AUTO_INCREMENT PRIMARY KEY, - NAME VARCHAR(100) + id4 BIGINT AUTO_INCREMENT PRIMARY KEY, + NAME VARCHAR(100) ); CREATE TABLE element_no_id ( - content VARCHAR(100), - LIST_PARENT_key BIGINT, - LIST_PARENT BIGINT + content VARCHAR(100), + LIST_PARENT_key BIGINT, + LIST_PARENT BIGINT ); CREATE TABLE BYTE_ARRAY_OWNER ( - ID BIGINT AUTO_INCREMENT PRIMARY KEY, - BINARY_DATA VARBINARY(20) NOT NULL + ID BIGINT AUTO_INCREMENT PRIMARY KEY, + BINARY_DATA VARBINARY(20) NOT NULL ); CREATE TABLE CHAIN4 ( - FOUR BIGINT AUTO_INCREMENT PRIMARY KEY, - FOUR_VALUE VARCHAR(20) + FOUR BIGINT AUTO_INCREMENT PRIMARY KEY, + FOUR_VALUE VARCHAR(20) ); CREATE TABLE CHAIN3 ( - THREE BIGINT AUTO_INCREMENT PRIMARY KEY, - THREE_VALUE VARCHAR(20), - CHAIN4 BIGINT, - FOREIGN KEY (CHAIN4) REFERENCES CHAIN4(FOUR) + THREE BIGINT AUTO_INCREMENT PRIMARY KEY, + THREE_VALUE VARCHAR(20), + CHAIN4 BIGINT, + FOREIGN KEY (CHAIN4) REFERENCES CHAIN4 (FOUR) ); CREATE TABLE CHAIN2 ( - TWO BIGINT AUTO_INCREMENT PRIMARY KEY, - TWO_VALUE VARCHAR(20), - CHAIN3 BIGINT, - FOREIGN KEY (CHAIN3) REFERENCES CHAIN3(THREE) + TWO BIGINT AUTO_INCREMENT PRIMARY KEY, + TWO_VALUE VARCHAR(20), + CHAIN3 BIGINT, + FOREIGN KEY (CHAIN3) REFERENCES CHAIN3 (THREE) ); CREATE TABLE CHAIN1 ( - ONE BIGINT AUTO_INCREMENT PRIMARY KEY, - ONE_VALUE VARCHAR(20), - CHAIN2 BIGINT, - FOREIGN KEY (CHAIN2) REFERENCES CHAIN2(TWO) + ONE BIGINT AUTO_INCREMENT PRIMARY KEY, + ONE_VALUE VARCHAR(20), + CHAIN2 BIGINT, + FOREIGN KEY (CHAIN2) REFERENCES CHAIN2 (TWO) ); CREATE TABLE CHAIN0 ( - ZERO BIGINT AUTO_INCREMENT PRIMARY KEY, - ZERO_VALUE VARCHAR(20), - CHAIN1 BIGINT, - FOREIGN KEY (CHAIN1) REFERENCES CHAIN1(ONE) + ZERO BIGINT AUTO_INCREMENT PRIMARY KEY, + ZERO_VALUE VARCHAR(20), + CHAIN1 BIGINT, + FOREIGN KEY (CHAIN1) REFERENCES CHAIN1 (ONE) ); CREATE TABLE NO_ID_CHAIN4 ( - FOUR BIGINT AUTO_INCREMENT PRIMARY KEY, - FOUR_VALUE VARCHAR(20) + FOUR BIGINT AUTO_INCREMENT PRIMARY KEY, + FOUR_VALUE VARCHAR(20) ); CREATE TABLE NO_ID_CHAIN3 ( - THREE_VALUE VARCHAR(20), - NO_ID_CHAIN4 BIGINT, - FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR) + THREE_VALUE VARCHAR(20), + NO_ID_CHAIN4 BIGINT, + FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR) ); CREATE TABLE NO_ID_CHAIN2 ( - TWO_VALUE VARCHAR(20), - NO_ID_CHAIN4 BIGINT, - FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR) + TWO_VALUE VARCHAR(20), + NO_ID_CHAIN4 BIGINT, + FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR) ); CREATE TABLE NO_ID_CHAIN1 ( - ONE_VALUE VARCHAR(20), - NO_ID_CHAIN4 BIGINT, - FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR) + ONE_VALUE VARCHAR(20), + NO_ID_CHAIN4 BIGINT, + FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR) ); CREATE TABLE NO_ID_CHAIN0 ( - ZERO_VALUE VARCHAR(20), - NO_ID_CHAIN4 BIGINT, - FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR) + ZERO_VALUE VARCHAR(20), + NO_ID_CHAIN4 BIGINT, + FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR) ); CREATE TABLE NO_ID_LIST_CHAIN4 ( - FOUR BIGINT AUTO_INCREMENT PRIMARY KEY, - FOUR_VALUE VARCHAR(20) + FOUR BIGINT AUTO_INCREMENT PRIMARY KEY, + FOUR_VALUE VARCHAR(20) ); CREATE TABLE NO_ID_LIST_CHAIN3 ( - THREE_VALUE VARCHAR(20), - NO_ID_LIST_CHAIN4 BIGINT, - NO_ID_LIST_CHAIN4_KEY BIGINT, - PRIMARY KEY (NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY), - FOREIGN KEY (NO_ID_LIST_CHAIN4) REFERENCES NO_ID_LIST_CHAIN4 (FOUR) + THREE_VALUE VARCHAR(20), + NO_ID_LIST_CHAIN4 BIGINT, + NO_ID_LIST_CHAIN4_KEY BIGINT, + PRIMARY KEY (NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY), + FOREIGN KEY (NO_ID_LIST_CHAIN4) REFERENCES NO_ID_LIST_CHAIN4 (FOUR) ); CREATE TABLE NO_ID_LIST_CHAIN2 ( - TWO_VALUE VARCHAR(20), - NO_ID_LIST_CHAIN4 BIGINT, - NO_ID_LIST_CHAIN4_KEY BIGINT, - NO_ID_LIST_CHAIN3_KEY BIGINT, - PRIMARY KEY (NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY, - NO_ID_LIST_CHAIN3_KEY), - FOREIGN KEY ( - NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY - ) REFERENCES NO_ID_LIST_CHAIN3 ( - NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY - ) + TWO_VALUE VARCHAR(20), + NO_ID_LIST_CHAIN4 BIGINT, + NO_ID_LIST_CHAIN4_KEY BIGINT, + NO_ID_LIST_CHAIN3_KEY BIGINT, + PRIMARY KEY (NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY, + NO_ID_LIST_CHAIN3_KEY), + FOREIGN KEY ( + NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY + ) REFERENCES NO_ID_LIST_CHAIN3 ( + NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY + ) ); CREATE TABLE NO_ID_LIST_CHAIN1 ( - ONE_VALUE VARCHAR(20), - NO_ID_LIST_CHAIN4 BIGINT, - NO_ID_LIST_CHAIN4_KEY BIGINT, - NO_ID_LIST_CHAIN3_KEY BIGINT, - NO_ID_LIST_CHAIN2_KEY BIGINT, - PRIMARY KEY (NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY, - NO_ID_LIST_CHAIN3_KEY, - NO_ID_LIST_CHAIN2_KEY), - FOREIGN KEY ( - NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY, - NO_ID_LIST_CHAIN3_KEY - ) REFERENCES NO_ID_LIST_CHAIN2 ( - NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY, - NO_ID_LIST_CHAIN3_KEY - ) + ONE_VALUE VARCHAR(20), + NO_ID_LIST_CHAIN4 BIGINT, + NO_ID_LIST_CHAIN4_KEY BIGINT, + NO_ID_LIST_CHAIN3_KEY BIGINT, + NO_ID_LIST_CHAIN2_KEY BIGINT, + PRIMARY KEY (NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY, + NO_ID_LIST_CHAIN3_KEY, + NO_ID_LIST_CHAIN2_KEY), + FOREIGN KEY ( + NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY, + NO_ID_LIST_CHAIN3_KEY + ) REFERENCES NO_ID_LIST_CHAIN2 ( + NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY, + NO_ID_LIST_CHAIN3_KEY + ) ); CREATE TABLE NO_ID_LIST_CHAIN0 ( - ZERO_VALUE VARCHAR(20), - NO_ID_LIST_CHAIN4 BIGINT, - NO_ID_LIST_CHAIN4_KEY BIGINT, - NO_ID_LIST_CHAIN3_KEY BIGINT, - NO_ID_LIST_CHAIN2_KEY BIGINT, - NO_ID_LIST_CHAIN1_KEY BIGINT, - PRIMARY KEY (NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY, - NO_ID_LIST_CHAIN3_KEY, - NO_ID_LIST_CHAIN2_KEY, - NO_ID_LIST_CHAIN1_KEY), - FOREIGN KEY ( - NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY, - NO_ID_LIST_CHAIN3_KEY, - NO_ID_LIST_CHAIN2_KEY - ) REFERENCES NO_ID_LIST_CHAIN1 ( - NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY, - NO_ID_LIST_CHAIN3_KEY, - NO_ID_LIST_CHAIN2_KEY - ) + ZERO_VALUE VARCHAR(20), + NO_ID_LIST_CHAIN4 BIGINT, + NO_ID_LIST_CHAIN4_KEY BIGINT, + NO_ID_LIST_CHAIN3_KEY BIGINT, + NO_ID_LIST_CHAIN2_KEY BIGINT, + NO_ID_LIST_CHAIN1_KEY BIGINT, + PRIMARY KEY (NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY, + NO_ID_LIST_CHAIN3_KEY, + NO_ID_LIST_CHAIN2_KEY, + NO_ID_LIST_CHAIN1_KEY), + FOREIGN KEY ( + NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY, + NO_ID_LIST_CHAIN3_KEY, + NO_ID_LIST_CHAIN2_KEY + ) REFERENCES NO_ID_LIST_CHAIN1 ( + NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY, + NO_ID_LIST_CHAIN3_KEY, + NO_ID_LIST_CHAIN2_KEY + ) ); - CREATE TABLE NO_ID_MAP_CHAIN4 ( - FOUR BIGINT AUTO_INCREMENT PRIMARY KEY, - FOUR_VALUE VARCHAR(20) + FOUR BIGINT AUTO_INCREMENT PRIMARY KEY, + FOUR_VALUE VARCHAR(20) ); CREATE TABLE NO_ID_MAP_CHAIN3 ( - THREE_VALUE VARCHAR(20), - NO_ID_MAP_CHAIN4 BIGINT, - NO_ID_MAP_CHAIN4_KEY VARCHAR(20), - PRIMARY KEY (NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY), - FOREIGN KEY (NO_ID_MAP_CHAIN4) REFERENCES NO_ID_MAP_CHAIN4 (FOUR) + THREE_VALUE VARCHAR(20), + NO_ID_MAP_CHAIN4 BIGINT, + NO_ID_MAP_CHAIN4_KEY VARCHAR(20), + PRIMARY KEY (NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY), + FOREIGN KEY (NO_ID_MAP_CHAIN4) REFERENCES NO_ID_MAP_CHAIN4 (FOUR) ); CREATE TABLE NO_ID_MAP_CHAIN2 ( - TWO_VALUE VARCHAR(20), - NO_ID_MAP_CHAIN4 BIGINT, - NO_ID_MAP_CHAIN4_KEY VARCHAR(20), - NO_ID_MAP_CHAIN3_KEY VARCHAR(20), - PRIMARY KEY (NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY, - NO_ID_MAP_CHAIN3_KEY), - FOREIGN KEY ( - NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY - ) REFERENCES NO_ID_MAP_CHAIN3 ( - NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY - ) + TWO_VALUE VARCHAR(20), + NO_ID_MAP_CHAIN4 BIGINT, + NO_ID_MAP_CHAIN4_KEY VARCHAR(20), + NO_ID_MAP_CHAIN3_KEY VARCHAR(20), + PRIMARY KEY (NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY, + NO_ID_MAP_CHAIN3_KEY), + FOREIGN KEY ( + NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY + ) REFERENCES NO_ID_MAP_CHAIN3 ( + NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY + ) ); CREATE TABLE NO_ID_MAP_CHAIN1 ( - ONE_VALUE VARCHAR(20), - NO_ID_MAP_CHAIN4 BIGINT, - NO_ID_MAP_CHAIN4_KEY VARCHAR(20), - NO_ID_MAP_CHAIN3_KEY VARCHAR(20), - NO_ID_MAP_CHAIN2_KEY VARCHAR(20), - PRIMARY KEY (NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY, - NO_ID_MAP_CHAIN3_KEY, - NO_ID_MAP_CHAIN2_KEY), - FOREIGN KEY ( - NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY, - NO_ID_MAP_CHAIN3_KEY - ) REFERENCES NO_ID_MAP_CHAIN2 ( - NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY, - NO_ID_MAP_CHAIN3_KEY - ) + ONE_VALUE VARCHAR(20), + NO_ID_MAP_CHAIN4 BIGINT, + NO_ID_MAP_CHAIN4_KEY VARCHAR(20), + NO_ID_MAP_CHAIN3_KEY VARCHAR(20), + NO_ID_MAP_CHAIN2_KEY VARCHAR(20), + PRIMARY KEY (NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY, + NO_ID_MAP_CHAIN3_KEY, + NO_ID_MAP_CHAIN2_KEY), + FOREIGN KEY ( + NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY, + NO_ID_MAP_CHAIN3_KEY + ) REFERENCES NO_ID_MAP_CHAIN2 ( + NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY, + NO_ID_MAP_CHAIN3_KEY + ) ); CREATE TABLE NO_ID_MAP_CHAIN0 ( - ZERO_VALUE VARCHAR(20), - NO_ID_MAP_CHAIN4 BIGINT, - NO_ID_MAP_CHAIN4_KEY VARCHAR(20), - NO_ID_MAP_CHAIN3_KEY VARCHAR(20), - NO_ID_MAP_CHAIN2_KEY VARCHAR(20), - NO_ID_MAP_CHAIN1_KEY VARCHAR(20), - PRIMARY KEY (NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY, - NO_ID_MAP_CHAIN3_KEY, - NO_ID_MAP_CHAIN2_KEY, - NO_ID_MAP_CHAIN1_KEY), - FOREIGN KEY ( - NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY, - NO_ID_MAP_CHAIN3_KEY, - NO_ID_MAP_CHAIN2_KEY - ) REFERENCES NO_ID_MAP_CHAIN1 ( - NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY, - NO_ID_MAP_CHAIN3_KEY, - NO_ID_MAP_CHAIN2_KEY - ) + ZERO_VALUE VARCHAR(20), + NO_ID_MAP_CHAIN4 BIGINT, + NO_ID_MAP_CHAIN4_KEY VARCHAR(20), + NO_ID_MAP_CHAIN3_KEY VARCHAR(20), + NO_ID_MAP_CHAIN2_KEY VARCHAR(20), + NO_ID_MAP_CHAIN1_KEY VARCHAR(20), + PRIMARY KEY (NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY, + NO_ID_MAP_CHAIN3_KEY, + NO_ID_MAP_CHAIN2_KEY, + NO_ID_MAP_CHAIN1_KEY), + FOREIGN KEY ( + NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY, + NO_ID_MAP_CHAIN3_KEY, + NO_ID_MAP_CHAIN2_KEY + ) REFERENCES NO_ID_MAP_CHAIN1 ( + NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY, + NO_ID_MAP_CHAIN3_KEY, + NO_ID_MAP_CHAIN2_KEY + ) ); CREATE TABLE VERSIONED_AGGREGATE ( - ID BIGINT AUTO_INCREMENT PRIMARY KEY, - VERSION BIGINT + ID BIGINT AUTO_INCREMENT PRIMARY KEY, + VERSION BIGINT ); +CREATE TABLE WITH_READ_ONLY +( + ID BIGINT AUTO_INCREMENT PRIMARY KEY, + NAME VARCHAR(200), + READ_ONLY VARCHAR(200) DEFAULT 'from-db' +); \ No newline at end of file diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-postgres.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-postgres.sql index 9ac303a0ed..3e9396f743 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-postgres.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-postgres.sql @@ -11,302 +11,309 @@ DROP TABLE CHAIN3; DROP TABLE CHAIN2; DROP TABLE CHAIN1; DROP TABLE CHAIN0; +DROP TABLE WITH_READ_ONLY; CREATE TABLE LEGO_SET ( - id1 SERIAL PRIMARY KEY, - NAME VARCHAR(30) + id1 SERIAL PRIMARY KEY, + NAME VARCHAR(30) ); CREATE TABLE MANUAL ( - id2 SERIAL PRIMARY KEY, - LEGO_SET BIGINT, - ALTERNATIVE BIGINT, - CONTENT VARCHAR(2000) + id2 SERIAL PRIMARY KEY, + LEGO_SET BIGINT, + ALTERNATIVE BIGINT, + CONTENT VARCHAR(2000) ); ALTER TABLE MANUAL - ADD FOREIGN KEY (LEGO_SET) - REFERENCES LEGO_SET (id1); + ADD FOREIGN KEY (LEGO_SET) + REFERENCES LEGO_SET (id1); CREATE TABLE ONE_TO_ONE_PARENT ( - id3 SERIAL PRIMARY KEY, - content VARCHAR(30) + id3 SERIAL PRIMARY KEY, + content VARCHAR(30) ); CREATE TABLE Child_No_Id ( - ONE_TO_ONE_PARENT INTEGER PRIMARY KEY, - content VARCHAR(30) + ONE_TO_ONE_PARENT INTEGER PRIMARY KEY, + content VARCHAR(30) ); CREATE TABLE LIST_PARENT ( - id4 SERIAL PRIMARY KEY, - NAME VARCHAR(100) + id4 SERIAL PRIMARY KEY, + NAME VARCHAR(100) ); CREATE TABLE element_no_id ( - content VARCHAR(100), - LIST_PARENT_key BIGINT, - LIST_PARENT INTEGER + content VARCHAR(100), + LIST_PARENT_key BIGINT, + LIST_PARENT INTEGER ); CREATE TABLE ARRAY_OWNER ( - ID SERIAL PRIMARY KEY, - DIGITS VARCHAR(20)[10], - MULTIDIMENSIONAL VARCHAR(20)[10][10] + ID SERIAL PRIMARY KEY, + DIGITS VARCHAR(20)[10], + MULTIDIMENSIONAL VARCHAR(20)[10][10] ); CREATE TABLE BYTE_ARRAY_OWNER ( - ID SERIAL PRIMARY KEY, - BINARY_DATA BYTEA NOT NULL + ID SERIAL PRIMARY KEY, + BINARY_DATA BYTEA NOT NULL ); CREATE TABLE CHAIN4 ( - FOUR SERIAL PRIMARY KEY, - FOUR_VALUE VARCHAR(20) + FOUR SERIAL PRIMARY KEY, + FOUR_VALUE VARCHAR(20) ); CREATE TABLE CHAIN3 ( - THREE SERIAL PRIMARY KEY, - THREE_VALUE VARCHAR(20), - CHAIN4 BIGINT, - FOREIGN KEY (CHAIN4) REFERENCES CHAIN4 (FOUR) + THREE SERIAL PRIMARY KEY, + THREE_VALUE VARCHAR(20), + CHAIN4 BIGINT, + FOREIGN KEY (CHAIN4) REFERENCES CHAIN4 (FOUR) ); CREATE TABLE CHAIN2 ( - TWO SERIAL PRIMARY KEY, - TWO_VALUE VARCHAR(20), - CHAIN3 BIGINT, - FOREIGN KEY (CHAIN3) REFERENCES CHAIN3 (THREE) + TWO SERIAL PRIMARY KEY, + TWO_VALUE VARCHAR(20), + CHAIN3 BIGINT, + FOREIGN KEY (CHAIN3) REFERENCES CHAIN3 (THREE) ); CREATE TABLE CHAIN1 ( - ONE SERIAL PRIMARY KEY, - ONE_VALUE VARCHAR(20), - CHAIN2 BIGINT, - FOREIGN KEY (CHAIN2) REFERENCES CHAIN2 (TWO) + ONE SERIAL PRIMARY KEY, + ONE_VALUE VARCHAR(20), + CHAIN2 BIGINT, + FOREIGN KEY (CHAIN2) REFERENCES CHAIN2 (TWO) ); CREATE TABLE CHAIN0 ( - ZERO SERIAL PRIMARY KEY, - ZERO_VALUE VARCHAR(20), - CHAIN1 BIGINT, - FOREIGN KEY (CHAIN1) REFERENCES CHAIN1 (ONE) + ZERO SERIAL PRIMARY KEY, + ZERO_VALUE VARCHAR(20), + CHAIN1 BIGINT, + FOREIGN KEY (CHAIN1) REFERENCES CHAIN1 (ONE) ); CREATE TABLE NO_ID_CHAIN4 ( - FOUR SERIAL PRIMARY KEY, - FOUR_VALUE VARCHAR(20) + FOUR SERIAL PRIMARY KEY, + FOUR_VALUE VARCHAR(20) ); CREATE TABLE NO_ID_CHAIN3 ( - THREE_VALUE VARCHAR(20), - NO_ID_CHAIN4 BIGINT, - FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR) + THREE_VALUE VARCHAR(20), + NO_ID_CHAIN4 BIGINT, + FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR) ); CREATE TABLE NO_ID_CHAIN2 ( - TWO_VALUE VARCHAR(20), - NO_ID_CHAIN4 BIGINT, - FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR) + TWO_VALUE VARCHAR(20), + NO_ID_CHAIN4 BIGINT, + FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR) ); CREATE TABLE NO_ID_CHAIN1 ( - ONE_VALUE VARCHAR(20), - NO_ID_CHAIN4 BIGINT, - FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR) + ONE_VALUE VARCHAR(20), + NO_ID_CHAIN4 BIGINT, + FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR) ); CREATE TABLE NO_ID_CHAIN0 ( - ZERO_VALUE VARCHAR(20), - NO_ID_CHAIN4 BIGINT, - FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR) + ZERO_VALUE VARCHAR(20), + NO_ID_CHAIN4 BIGINT, + FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR) ); CREATE TABLE NO_ID_LIST_CHAIN4 ( - FOUR SERIAL PRIMARY KEY, - FOUR_VALUE VARCHAR(20) + FOUR SERIAL PRIMARY KEY, + FOUR_VALUE VARCHAR(20) ); CREATE TABLE NO_ID_LIST_CHAIN3 ( - THREE_VALUE VARCHAR(20), - NO_ID_LIST_CHAIN4 BIGINT, - NO_ID_LIST_CHAIN4_KEY BIGINT, - PRIMARY KEY (NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY), - FOREIGN KEY (NO_ID_LIST_CHAIN4) REFERENCES NO_ID_LIST_CHAIN4 (FOUR) + THREE_VALUE VARCHAR(20), + NO_ID_LIST_CHAIN4 BIGINT, + NO_ID_LIST_CHAIN4_KEY BIGINT, + PRIMARY KEY (NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY), + FOREIGN KEY (NO_ID_LIST_CHAIN4) REFERENCES NO_ID_LIST_CHAIN4 (FOUR) ); CREATE TABLE NO_ID_LIST_CHAIN2 ( - TWO_VALUE VARCHAR(20), - NO_ID_LIST_CHAIN4 BIGINT, - NO_ID_LIST_CHAIN4_KEY BIGINT, - NO_ID_LIST_CHAIN3_KEY BIGINT, - PRIMARY KEY (NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY, - NO_ID_LIST_CHAIN3_KEY), - FOREIGN KEY ( - NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY - ) REFERENCES NO_ID_LIST_CHAIN3 ( - NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY - ) + TWO_VALUE VARCHAR(20), + NO_ID_LIST_CHAIN4 BIGINT, + NO_ID_LIST_CHAIN4_KEY BIGINT, + NO_ID_LIST_CHAIN3_KEY BIGINT, + PRIMARY KEY (NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY, + NO_ID_LIST_CHAIN3_KEY), + FOREIGN KEY ( + NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY + ) REFERENCES NO_ID_LIST_CHAIN3 ( + NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY + ) ); CREATE TABLE NO_ID_LIST_CHAIN1 ( - ONE_VALUE VARCHAR(20), - NO_ID_LIST_CHAIN4 BIGINT, - NO_ID_LIST_CHAIN4_KEY BIGINT, - NO_ID_LIST_CHAIN3_KEY BIGINT, - NO_ID_LIST_CHAIN2_KEY BIGINT, - PRIMARY KEY (NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY, - NO_ID_LIST_CHAIN3_KEY, - NO_ID_LIST_CHAIN2_KEY), - FOREIGN KEY ( - NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY, - NO_ID_LIST_CHAIN3_KEY - ) REFERENCES NO_ID_LIST_CHAIN2 ( - NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY, - NO_ID_LIST_CHAIN3_KEY - ) + ONE_VALUE VARCHAR(20), + NO_ID_LIST_CHAIN4 BIGINT, + NO_ID_LIST_CHAIN4_KEY BIGINT, + NO_ID_LIST_CHAIN3_KEY BIGINT, + NO_ID_LIST_CHAIN2_KEY BIGINT, + PRIMARY KEY (NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY, + NO_ID_LIST_CHAIN3_KEY, + NO_ID_LIST_CHAIN2_KEY), + FOREIGN KEY ( + NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY, + NO_ID_LIST_CHAIN3_KEY + ) REFERENCES NO_ID_LIST_CHAIN2 ( + NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY, + NO_ID_LIST_CHAIN3_KEY + ) ); CREATE TABLE NO_ID_LIST_CHAIN0 ( - ZERO_VALUE VARCHAR(20), - NO_ID_LIST_CHAIN4 BIGINT, - NO_ID_LIST_CHAIN4_KEY BIGINT, - NO_ID_LIST_CHAIN3_KEY BIGINT, - NO_ID_LIST_CHAIN2_KEY BIGINT, - NO_ID_LIST_CHAIN1_KEY BIGINT, - PRIMARY KEY (NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY, - NO_ID_LIST_CHAIN3_KEY, - NO_ID_LIST_CHAIN2_KEY, - NO_ID_LIST_CHAIN1_KEY), - FOREIGN KEY ( - NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY, - NO_ID_LIST_CHAIN3_KEY, - NO_ID_LIST_CHAIN2_KEY - ) REFERENCES NO_ID_LIST_CHAIN1 ( - NO_ID_LIST_CHAIN4, - NO_ID_LIST_CHAIN4_KEY, - NO_ID_LIST_CHAIN3_KEY, - NO_ID_LIST_CHAIN2_KEY - ) + ZERO_VALUE VARCHAR(20), + NO_ID_LIST_CHAIN4 BIGINT, + NO_ID_LIST_CHAIN4_KEY BIGINT, + NO_ID_LIST_CHAIN3_KEY BIGINT, + NO_ID_LIST_CHAIN2_KEY BIGINT, + NO_ID_LIST_CHAIN1_KEY BIGINT, + PRIMARY KEY (NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY, + NO_ID_LIST_CHAIN3_KEY, + NO_ID_LIST_CHAIN2_KEY, + NO_ID_LIST_CHAIN1_KEY), + FOREIGN KEY ( + NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY, + NO_ID_LIST_CHAIN3_KEY, + NO_ID_LIST_CHAIN2_KEY + ) REFERENCES NO_ID_LIST_CHAIN1 ( + NO_ID_LIST_CHAIN4, + NO_ID_LIST_CHAIN4_KEY, + NO_ID_LIST_CHAIN3_KEY, + NO_ID_LIST_CHAIN2_KEY + ) ); - CREATE TABLE NO_ID_MAP_CHAIN4 ( - FOUR SERIAL PRIMARY KEY, - FOUR_VALUE VARCHAR(20) + FOUR SERIAL PRIMARY KEY, + FOUR_VALUE VARCHAR(20) ); CREATE TABLE NO_ID_MAP_CHAIN3 ( - THREE_VALUE VARCHAR(20), - NO_ID_MAP_CHAIN4 BIGINT, - NO_ID_MAP_CHAIN4_KEY VARCHAR(20), - PRIMARY KEY (NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY), - FOREIGN KEY (NO_ID_MAP_CHAIN4) REFERENCES NO_ID_MAP_CHAIN4 (FOUR) + THREE_VALUE VARCHAR(20), + NO_ID_MAP_CHAIN4 BIGINT, + NO_ID_MAP_CHAIN4_KEY VARCHAR(20), + PRIMARY KEY (NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY), + FOREIGN KEY (NO_ID_MAP_CHAIN4) REFERENCES NO_ID_MAP_CHAIN4 (FOUR) ); CREATE TABLE NO_ID_MAP_CHAIN2 ( - TWO_VALUE VARCHAR(20), - NO_ID_MAP_CHAIN4 BIGINT, - NO_ID_MAP_CHAIN4_KEY VARCHAR(20), - NO_ID_MAP_CHAIN3_KEY VARCHAR(20), - PRIMARY KEY (NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY, - NO_ID_MAP_CHAIN3_KEY), - FOREIGN KEY ( - NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY - ) REFERENCES NO_ID_MAP_CHAIN3 ( - NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY - ) + TWO_VALUE VARCHAR(20), + NO_ID_MAP_CHAIN4 BIGINT, + NO_ID_MAP_CHAIN4_KEY VARCHAR(20), + NO_ID_MAP_CHAIN3_KEY VARCHAR(20), + PRIMARY KEY (NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY, + NO_ID_MAP_CHAIN3_KEY), + FOREIGN KEY ( + NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY + ) REFERENCES NO_ID_MAP_CHAIN3 ( + NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY + ) ); CREATE TABLE NO_ID_MAP_CHAIN1 ( - ONE_VALUE VARCHAR(20), - NO_ID_MAP_CHAIN4 BIGINT, - NO_ID_MAP_CHAIN4_KEY VARCHAR(20), - NO_ID_MAP_CHAIN3_KEY VARCHAR(20), - NO_ID_MAP_CHAIN2_KEY VARCHAR(20), - PRIMARY KEY (NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY, - NO_ID_MAP_CHAIN3_KEY, - NO_ID_MAP_CHAIN2_KEY), - FOREIGN KEY ( - NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY, - NO_ID_MAP_CHAIN3_KEY - ) REFERENCES NO_ID_MAP_CHAIN2 ( - NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY, - NO_ID_MAP_CHAIN3_KEY - ) + ONE_VALUE VARCHAR(20), + NO_ID_MAP_CHAIN4 BIGINT, + NO_ID_MAP_CHAIN4_KEY VARCHAR(20), + NO_ID_MAP_CHAIN3_KEY VARCHAR(20), + NO_ID_MAP_CHAIN2_KEY VARCHAR(20), + PRIMARY KEY (NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY, + NO_ID_MAP_CHAIN3_KEY, + NO_ID_MAP_CHAIN2_KEY), + FOREIGN KEY ( + NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY, + NO_ID_MAP_CHAIN3_KEY + ) REFERENCES NO_ID_MAP_CHAIN2 ( + NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY, + NO_ID_MAP_CHAIN3_KEY + ) ); CREATE TABLE NO_ID_MAP_CHAIN0 ( - ZERO_VALUE VARCHAR(20), - NO_ID_MAP_CHAIN4 BIGINT, - NO_ID_MAP_CHAIN4_KEY VARCHAR(20), - NO_ID_MAP_CHAIN3_KEY VARCHAR(20), - NO_ID_MAP_CHAIN2_KEY VARCHAR(20), - NO_ID_MAP_CHAIN1_KEY VARCHAR(20), - PRIMARY KEY (NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY, - NO_ID_MAP_CHAIN3_KEY, - NO_ID_MAP_CHAIN2_KEY, - NO_ID_MAP_CHAIN1_KEY), - FOREIGN KEY ( - NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY, - NO_ID_MAP_CHAIN3_KEY, - NO_ID_MAP_CHAIN2_KEY - ) REFERENCES NO_ID_MAP_CHAIN1 ( - NO_ID_MAP_CHAIN4, - NO_ID_MAP_CHAIN4_KEY, - NO_ID_MAP_CHAIN3_KEY, - NO_ID_MAP_CHAIN2_KEY - ) + ZERO_VALUE VARCHAR(20), + NO_ID_MAP_CHAIN4 BIGINT, + NO_ID_MAP_CHAIN4_KEY VARCHAR(20), + NO_ID_MAP_CHAIN3_KEY VARCHAR(20), + NO_ID_MAP_CHAIN2_KEY VARCHAR(20), + NO_ID_MAP_CHAIN1_KEY VARCHAR(20), + PRIMARY KEY (NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY, + NO_ID_MAP_CHAIN3_KEY, + NO_ID_MAP_CHAIN2_KEY, + NO_ID_MAP_CHAIN1_KEY), + FOREIGN KEY ( + NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY, + NO_ID_MAP_CHAIN3_KEY, + NO_ID_MAP_CHAIN2_KEY + ) REFERENCES NO_ID_MAP_CHAIN1 ( + NO_ID_MAP_CHAIN4, + NO_ID_MAP_CHAIN4_KEY, + NO_ID_MAP_CHAIN3_KEY, + NO_ID_MAP_CHAIN2_KEY + ) ); CREATE TABLE VERSIONED_AGGREGATE ( - ID SERIAL PRIMARY KEY, - VERSION BIGINT + ID SERIAL PRIMARY KEY, + VERSION BIGINT +); + +CREATE TABLE WITH_READ_ONLY +( + ID SERIAL PRIMARY KEY, + NAME VARCHAR(200), + READ_ONLY VARCHAR(200) DEFAULT 'from-db' ); \ No newline at end of file diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/Dialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/Dialect.java index 8f6f45d9d2..21c1634e63 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/Dialect.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/Dialect.java @@ -16,6 +16,8 @@ package org.springframework.data.relational.core.dialect; import org.springframework.data.relational.core.sql.render.SelectRenderContext; +import org.springframework.data.relational.domain.IdentifierProcessing; +import org.springframework.data.relational.domain.SqlIdentifier; /** * Represents a dialect that is implemented by a particular database. Please note that not all features are supported by @@ -50,4 +52,14 @@ default ArrayColumns getArraySupport() { * @return the {@link SelectRenderContext}. */ SelectRenderContext getSelectContext(); + + /** + * Returns the {@link IdentifierProcessing} used for processing {@link SqlIdentifier} when converting them to SQL snippets or parameter names. + * + * @return the {@link IdentifierProcessing}. Guaranteed to be not {@literal null}. + * @since 2.0 + */ + default IdentifierProcessing getIdentifierProcessing() { + return IdentifierProcessing.ANSI; + } } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/HsqlDbDialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/HsqlDbDialect.java new file mode 100644 index 0000000000..94e2184b12 --- /dev/null +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/HsqlDbDialect.java @@ -0,0 +1,57 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.relational.core.dialect; + +/** + * A {@link Dialect} for HsqlDb. + * + * @author Jens Schauder + */ +public class HsqlDbDialect extends AbstractDialect { + + public static final HsqlDbDialect INSTANCE = new HsqlDbDialect(); + + protected HsqlDbDialect() { } + + @Override + public LimitClause limit() { + return LIMIT_CLAUSE; + } + + private static final LimitClause LIMIT_CLAUSE = new LimitClause() { + + @Override + public String getLimit(long limit) { + return "LIMIT " + limit; + } + + @Override + public String getOffset(long offset) { + return "OFFSET " + offset; + } + + @Override + public String getLimitOffset(long limit, long offset) { + return getOffset(offset) + " " + getLimit(limit); + } + + @Override + public Position getClausePosition() { + return Position.AFTER_ORDER_BY; + } + }; + +} diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/MariaDbDialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/MariaDbDialect.java new file mode 100644 index 0000000000..dd42bb2eda --- /dev/null +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/MariaDbDialect.java @@ -0,0 +1,29 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.relational.core.dialect; + +/** + * The {@link Dialect} to be used with MariaDb. Since we haven't encountered any significant differences between MariaDb + * and Mysql its instance is actually {@link MySqlDialect#INSTANCE}, although that might change at any time. + * + * @author Jens Schauder + */ +public class MariaDbDialect extends MySqlDialect{ + + public static final Dialect INSTANCE = MySqlDialect.INSTANCE; + + protected MariaDbDialect() { } +} diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/MySqlDialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/MySqlDialect.java index 50f6ff9efb..e19b9c7e7a 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/MySqlDialect.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/MySqlDialect.java @@ -15,8 +15,13 @@ */ package org.springframework.data.relational.core.dialect; +import org.springframework.data.relational.domain.IdentifierProcessing; +import org.springframework.data.relational.domain.IdentifierProcessing.DefaultIdentifierProcessing; +import org.springframework.data.relational.domain.IdentifierProcessing.LetterCasing; +import org.springframework.data.relational.domain.IdentifierProcessing.Quoting; + /** - * An SQL dialect for MySQL. + * A SQL dialect for MySQL. * * @author Mark Paluch * @author Jens Schauder @@ -29,6 +34,8 @@ public class MySqlDialect extends AbstractDialect { */ public static final MySqlDialect INSTANCE = new MySqlDialect(); + protected MySqlDialect() { } + private static final LimitClause LIMIT_CLAUSE = new LimitClause() { /* @@ -80,4 +87,9 @@ public Position getClausePosition() { public LimitClause limit() { return LIMIT_CLAUSE; } + + @Override + public IdentifierProcessing getIdentifierProcessing() { + return new DefaultIdentifierProcessing(new Quoting("`"), LetterCasing.LOWER_CASE); + } } 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 25e398df14..435fe2d7f2 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 @@ -17,6 +17,10 @@ import lombok.RequiredArgsConstructor; +import org.springframework.data.relational.domain.IdentifierProcessing; +import org.springframework.data.relational.domain.IdentifierProcessing.DefaultIdentifierProcessing; +import org.springframework.data.relational.domain.IdentifierProcessing.LetterCasing; +import org.springframework.data.relational.domain.IdentifierProcessing.Quoting; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -33,6 +37,8 @@ public class PostgresDialect extends AbstractDialect { */ public static final PostgresDialect INSTANCE = new PostgresDialect(); + protected PostgresDialect() {} + private static final LimitClause LIMIT_CLAUSE = new LimitClause() { /* @@ -116,4 +122,9 @@ public Class getArrayType(Class userType) { return ClassUtils.resolvePrimitiveIfNecessary(userType); } } + + @Override + public IdentifierProcessing getIdentifierProcessing() { + return new DefaultIdentifierProcessing(Quoting.ANSI, LetterCasing.LOWER_CASE); + } } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/SqlServerDialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/SqlServerDialect.java index b7ea294640..9242d4a0af 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/SqlServerDialect.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/SqlServerDialect.java @@ -31,6 +31,8 @@ public class SqlServerDialect extends AbstractDialect { */ public static final SqlServerDialect INSTANCE = new SqlServerDialect(); + protected SqlServerDialect() { } + private static final LimitClause LIMIT_CLAUSE = new LimitClause() { /* diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java index c0aa4b6fdb..2ae5a096fb 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java @@ -30,6 +30,8 @@ import org.springframework.data.mapping.model.Property; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.relational.core.mapping.Embedded.OnEmpty; +import org.springframework.data.relational.domain.SqlIdentifier; +import org.springframework.data.relational.domain.SqlIdentifier.SimpleSqlIdentifier; import org.springframework.data.util.Lazy; import org.springframework.data.util.Optionals; import org.springframework.lang.Nullable; @@ -58,9 +60,9 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent } private final RelationalMappingContext context; - private final Lazy columnName; - private final Lazy> collectionIdColumnName; - private final Lazy collectionKeyColumnName; + private final Lazy columnName; + private final Lazy> collectionIdColumnName; + private final Lazy collectionKeyColumnName; private final Lazy isEmbedded; private final Lazy embeddedPrefix; private final Lazy> columnType = Lazy.of(this::doGetColumnType); @@ -91,17 +93,24 @@ public BasicRelationalPersistentProperty(Property property, PersistentEntity Optional.ofNullable(findAnnotation(Column.class)) // .map(Column::value) // .filter(StringUtils::hasText) // + .map(name -> SqlIdentifier.quoted(name).withAdjustableLetterCasing()) // .orElseGet(() -> context.getNamingStrategy().getColumnName(this))); this.collectionIdColumnName = Lazy.of(() -> Optionals - .toStream(Optional.ofNullable(findAnnotation(MappedCollection.class)).map(MappedCollection::idColumn), - Optional.ofNullable(findAnnotation(Column.class)).map(Column::value)) // - .filter(StringUtils::hasText).findFirst()); + .toStream(Optional.ofNullable(findAnnotation(MappedCollection.class)) // + .map(MappedCollection::idColumn), // + Optional.ofNullable(findAnnotation(Column.class)) // + .map(Column::value)) // + .filter(StringUtils::hasText) // + .findFirst() // + .map(name -> SqlIdentifier.quoted(name).withAdjustableLetterCasing())); // - this.collectionKeyColumnName = Lazy.of(() -> Optionals - .toStream(Optional.ofNullable(findAnnotation(MappedCollection.class)).map(MappedCollection::keyColumn), + this.collectionKeyColumnName = Lazy.of(() -> Optionals // + .toStream(Optional.ofNullable(findAnnotation(MappedCollection.class)).map(MappedCollection::keyColumn), // Optional.ofNullable(findAnnotation(Column.class)).map(Column::keyColumn)) // - .filter(StringUtils::hasText).findFirst().orElseGet(() -> context.getNamingStrategy().getKeyColumn(this))); + .filter(StringUtils::hasText).findFirst() // + .map(name -> (SqlIdentifier) SqlIdentifier.quoted(name).withAdjustableLetterCasing()) // + .orElseGet(() -> context.getNamingStrategy().getKeyColumn(this))); } /* @@ -128,7 +137,7 @@ public boolean isReference() { * @see org.springframework.data.jdbc.core.mapping.model.JdbcPersistentProperty#getColumnName() */ @Override - public String getColumnName() { + public SimpleSqlIdentifier getColumnName() { return columnName.get(); } @@ -178,18 +187,18 @@ public RelationalPersistentEntity getOwner() { } @Override - public String getReverseColumnName() { + public SqlIdentifier getReverseColumnName() { return collectionIdColumnName.get().orElseGet(() -> context.getNamingStrategy().getReverseColumnName(this)); } @Override - public String getReverseColumnName(PersistentPropertyPathExtension path) { + public SqlIdentifier getReverseColumnName(PersistentPropertyPathExtension path) { return collectionIdColumnName.get().orElseGet(() -> context.getNamingStrategy().getReverseColumnName(path)); } @Override - public String getKeyColumn() { + public SqlIdentifier getKeyColumn() { return isQualified() ? collectionKeyColumnName.get() : null; } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/CachingNamingStrategy.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/CachingNamingStrategy.java index 79b053696d..8069ad5691 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/CachingNamingStrategy.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/CachingNamingStrategy.java @@ -18,6 +18,8 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.springframework.data.relational.domain.SqlIdentifier; +import org.springframework.data.relational.domain.SqlIdentifier.SimpleSqlIdentifier; import org.springframework.data.util.Lazy; import org.springframework.util.Assert; import org.springframework.util.ConcurrentReferenceHashMap; @@ -32,19 +34,19 @@ class CachingNamingStrategy implements NamingStrategy { private final NamingStrategy delegate; - private final Map columnNames = new ConcurrentHashMap<>(); - private final Map keyColumns = new ConcurrentHashMap<>(); - private final Map, String> qualifiedTableNames = new ConcurrentReferenceHashMap<>(); - private final Map, String> tableNames = new ConcurrentReferenceHashMap<>(); + private final Map columnNames = new ConcurrentHashMap<>(); + private final Map keyColumns = new ConcurrentHashMap<>(); + private final Map, SqlIdentifier> qualifiedTableNames = new ConcurrentReferenceHashMap<>(); + private final Map, SqlIdentifier> tableNames = new ConcurrentReferenceHashMap<>(); - private final Lazy schema; + private final Lazy schema; /** * Creates a new {@link CachingNamingStrategy} with the given delegate {@link NamingStrategy}. * * @param delegate must not be {@literal null}. */ - public CachingNamingStrategy(NamingStrategy delegate) { + CachingNamingStrategy(NamingStrategy delegate) { Assert.notNull(delegate, "Delegate must not be null!"); @@ -57,7 +59,7 @@ public CachingNamingStrategy(NamingStrategy delegate) { * @see org.springframework.data.relational.core.mapping.NamingStrategy#getKeyColumn(org.springframework.data.relational.core.mapping.RelationalPersistentProperty) */ @Override - public String getKeyColumn(RelationalPersistentProperty property) { + public SqlIdentifier getKeyColumn(RelationalPersistentProperty property) { return keyColumns.computeIfAbsent(property, delegate::getKeyColumn); } @@ -66,7 +68,7 @@ public String getKeyColumn(RelationalPersistentProperty property) { * @see org.springframework.data.relational.core.mapping.NamingStrategy#getQualifiedTableName(java.lang.Class) */ @Override - public String getQualifiedTableName(Class type) { + public SqlIdentifier getQualifiedTableName(Class type) { return qualifiedTableNames.computeIfAbsent(type, delegate::getQualifiedTableName); } @@ -75,7 +77,7 @@ public String getQualifiedTableName(Class type) { * @see org.springframework.data.relational.core.mapping.NamingStrategy#getTableName(java.lang.Class) */ @Override - public String getTableName(Class type) { + public SqlIdentifier getTableName(Class type) { return tableNames.computeIfAbsent(type, delegate::getTableName); } @@ -84,7 +86,7 @@ public String getTableName(Class type) { * @see org.springframework.data.relational.core.mapping.NamingStrategy#getReverseColumnName(org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension) */ @Override - public String getReverseColumnName(PersistentPropertyPathExtension path) { + public SqlIdentifier getReverseColumnName(PersistentPropertyPathExtension path) { return delegate.getReverseColumnName(path); } @@ -93,7 +95,7 @@ public String getReverseColumnName(PersistentPropertyPathExtension path) { * @see org.springframework.data.relational.core.mapping.NamingStrategy#getReverseColumnName(org.springframework.data.relational.core.mapping.RelationalPersistentProperty) */ @Override - public String getReverseColumnName(RelationalPersistentProperty property) { + public SqlIdentifier getReverseColumnName(RelationalPersistentProperty property) { return delegate.getReverseColumnName(property); } @@ -102,7 +104,7 @@ public String getReverseColumnName(RelationalPersistentProperty property) { * @see org.springframework.data.relational.core.mapping.NamingStrategy#getSchema() */ @Override - public String getSchema() { + public SqlIdentifier getSchema() { return schema.get(); } @@ -111,7 +113,7 @@ public String getSchema() { * @see org.springframework.data.relational.core.mapping.NamingStrategy#getColumnName(org.springframework.data.relational.core.mapping.RelationalPersistentProperty) */ @Override - public String getColumnName(RelationalPersistentProperty property) { + public SimpleSqlIdentifier getColumnName(RelationalPersistentProperty property) { return columnNames.computeIfAbsent(property, delegate::getColumnName); } } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/NamingStrategy.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/NamingStrategy.java index be5ee64d45..c0618dc0c2 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/NamingStrategy.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/NamingStrategy.java @@ -15,6 +15,10 @@ */ package org.springframework.data.relational.core.mapping; +import static org.springframework.data.relational.domain.SqlIdentifier.*; + +import org.springframework.data.relational.domain.SqlIdentifier; +import org.springframework.data.relational.domain.SqlIdentifier.*; import org.springframework.data.util.ParsingUtils; import org.springframework.util.Assert; @@ -45,34 +49,34 @@ public interface NamingStrategy { * * @return Empty String representing no schema */ - default String getSchema() { - return ""; + default SqlIdentifier getSchema() { + return SqlIdentifier.EMPTY; } /** * The name of the table to be used for persisting entities having the type passed as an argument. The default * implementation takes the {@code type.getSimpleName()} and separates camel case parts with '_'. */ - default String getTableName(Class type) { + default SqlIdentifier getTableName(Class type) { Assert.notNull(type, "Type must not be null."); - return ParsingUtils.reconcatenateCamelCase(type.getSimpleName(), "_"); + return quoted(ParsingUtils.reconcatenateCamelCase(type.getSimpleName(), "_")).withAdjustableLetterCasing(); } /** * Defaults to return the given {@link RelationalPersistentProperty}'s name with the parts of a camel case name * separated by '_'; */ - default String getColumnName(RelationalPersistentProperty property) { + default SimpleSqlIdentifier getColumnName(RelationalPersistentProperty property) { Assert.notNull(property, "Property must not be null."); - return ParsingUtils.reconcatenateCamelCase(property.getName(), "_"); + return quoted(ParsingUtils.reconcatenateCamelCase(property.getName(), "_")).withAdjustableLetterCasing(); } - default String getQualifiedTableName(Class type) { - return this.getSchema() + (this.getSchema().equals("") ? "" : ".") + this.getTableName(type); + default SqlIdentifier getQualifiedTableName(Class type) { + return this.getSchema().concat(this.getTableName(type)); } /** @@ -81,14 +85,14 @@ default String getQualifiedTableName(Class type) { * @param property The property who's column name in the owner table is required * @return a column name. Must not be {@code null}. */ - default String getReverseColumnName(RelationalPersistentProperty property) { + default SqlIdentifier getReverseColumnName(RelationalPersistentProperty property) { Assert.notNull(property, "Property must not be null."); return property.getOwner().getTableName(); } - default String getReverseColumnName(PersistentPropertyPathExtension path) { + default SqlIdentifier getReverseColumnName(PersistentPropertyPathExtension path) { return getTableName(path.getIdDefiningParentPath().getLeafEntity().getType()); } @@ -99,10 +103,10 @@ default String getReverseColumnName(PersistentPropertyPathExtension path) { * * @return name of the key column. Must not be {@code null}. */ - default String getKeyColumn(RelationalPersistentProperty property) { + default SqlIdentifier getKeyColumn(RelationalPersistentProperty property) { Assert.notNull(property, "Property must not be null."); - return getReverseColumnName(property) + "_key"; + return getReverseColumnName(property).suffix("_key"); } } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/PersistentPropertyPathExtension.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/PersistentPropertyPathExtension.java index 01901488cc..d233a32447 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/PersistentPropertyPathExtension.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/PersistentPropertyPathExtension.java @@ -20,6 +20,8 @@ import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.data.mapping.context.MappingContext; +import org.springframework.data.relational.domain.SqlIdentifier; +import org.springframework.data.relational.domain.SqlIdentifier.SimpleSqlIdentifier; import org.springframework.data.util.Lazy; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -38,7 +40,7 @@ public class PersistentPropertyPathExtension { private final @Nullable PersistentPropertyPath path; private final MappingContext, RelationalPersistentProperty> context; - private final Lazy columnAlias = Lazy.of(() -> prefixWithTableAlias(getColumnName())); + private final Lazy columnAlias = Lazy.of(() -> prefixWithTableAlias(getColumnName())); /** * Creates the empty path referencing the root itself. @@ -156,10 +158,9 @@ public boolean isCollectionLike() { * * @throws IllegalStateException when called on an empty path. */ - public String getReverseColumnName() { + public SqlIdentifier getReverseColumnName() { Assert.state(path != null, "Empty paths don't have a reverse column name"); - return path.getRequiredLeafProperty().getReverseColumnName(this); } @@ -168,7 +169,7 @@ public String getReverseColumnName() { * * @throws IllegalStateException when called on an empty path. */ - public String getReverseColumnNameAlias() { + public SqlIdentifier getReverseColumnNameAlias() { return prefixWithTableAlias(getReverseColumnName()); } @@ -178,7 +179,7 @@ public String getReverseColumnNameAlias() { * * @throws IllegalStateException when called on an empty path. */ - public String getColumnName() { + public SqlIdentifier getColumnName() { Assert.state(path != null, "Path is null"); @@ -190,7 +191,7 @@ public String getColumnName() { * * @throws IllegalStateException when called on an empty path. */ - public String getColumnAlias() { + public SqlIdentifier getColumnAlias() { return columnAlias.get(); } @@ -228,7 +229,7 @@ public PersistentPropertyPathExtension getIdDefiningParentPath() { * * @return the name of the table. Guaranteed to be not {@literal null}. */ - public String getTableName() { + public SqlIdentifier getTableName() { return getTableOwningAncestor().getRequiredLeafEntity().getTableName(); } @@ -238,7 +239,7 @@ public String getTableName() { * @return a table alias, {@literal null} if the table owning path is the empty path. */ @Nullable - public String getTableAlias() { + public SqlIdentifier getTableAlias() { PersistentPropertyPathExtension tableOwner = getTableOwningAncestor(); @@ -249,7 +250,7 @@ public String getTableAlias() { /** * The column name of the id column of the ancestor path that represents an actual table. */ - public String getIdColumnName() { + public SqlIdentifier getIdColumnName() { return getTableOwningAncestor().getRequiredLeafEntity().getIdColumn(); } @@ -257,7 +258,7 @@ public String getIdColumnName() { * If the table owning ancestor has an id the column name of that id property is returned. Otherwise the reverse * column is returned. */ - public String getEffectiveIdColumnName() { + public SqlIdentifier getEffectiveIdColumnName() { PersistentPropertyPathExtension owner = getTableOwningAncestor(); return owner.path == null ? owner.getRequiredLeafEntity().getIdColumn() : owner.getReverseColumnName(); @@ -296,8 +297,8 @@ public RelationalPersistentProperty getRequiredIdProperty() { * @return May be {@literal null}. */ @Nullable - public String getQualifierColumn() { - return path == null ? "" : path.getRequiredLeafProperty().getKeyColumn(); + public SqlIdentifier getQualifierColumn() { + return path == null ? SqlIdentifier.EMPTY : path.getRequiredLeafProperty().getKeyColumn(); } /** @@ -384,7 +385,7 @@ private PersistentPropertyPathExtension getTableOwningAncestor() { return isEntity() && !isEmbedded() ? this : getParentPath().getTableOwningAncestor(); } - private String assembleTableAlias() { + private SqlIdentifier assembleTableAlias() { Assert.state(path != null, "Path is null"); @@ -393,15 +394,15 @@ private String assembleTableAlias() { if (path.getLength() == 1) { Assert.notNull(prefix, "Prefix mus not be null."); - return prefix; + return SqlIdentifier.quoted(prefix).withAdjustableLetterCasing(); } PersistentPropertyPathExtension parentPath = getParentPath(); - return parentPath.isEmbedded() ? parentPath.assembleTableAlias() + prefix - : parentPath.assembleTableAlias() + "_" + prefix; + return parentPath.isEmbedded() ? parentPath.assembleTableAlias().suffix(prefix) + : parentPath.assembleTableAlias().suffix("_" + prefix); } - private String assembleColumnName(String suffix) { + private SqlIdentifier assembleColumnName(SimpleSqlIdentifier suffix) { Assert.state(path != null, "Path is null"); @@ -418,17 +419,17 @@ private String assembleColumnName(String suffix) { String embeddedPrefix = parentLeaf.getEmbeddedPrefix(); - return getParentPath().assembleColumnName(embeddedPrefix + suffix); + return getParentPath().assembleColumnName(suffix.prefix(embeddedPrefix)); } private RelationalPersistentEntity getRequiredLeafEntity() { return path == null ? entity : context.getRequiredPersistentEntity(path.getRequiredLeafProperty().getActualType()); } - private String prefixWithTableAlias(String columnName) { + private SqlIdentifier prefixWithTableAlias(SqlIdentifier columnName) { - String tableAlias = getTableAlias(); - return tableAlias == null ? columnName : tableAlias + "_" + columnName; + SqlIdentifier tableAlias = getTableAlias(); + return tableAlias == null ? columnName : columnName.prefix(tableAlias, "_"); } } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntity.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntity.java index 6009aefa85..04ba5dd91f 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntity.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntity.java @@ -16,6 +16,7 @@ package org.springframework.data.relational.core.mapping; import org.springframework.data.mapping.model.MutablePersistentEntity; +import org.springframework.data.relational.domain.SqlIdentifier; /** * A {@link org.springframework.data.mapping.PersistentEntity} interface with additional methods for JDBC/RDBMS related @@ -31,12 +32,12 @@ public interface RelationalPersistentEntity extends MutablePersistentEntity extends BasicPersistentEntity { private final NamingStrategy namingStrategy; - private final Lazy> tableName; + private final Lazy> tableName; /** * Creates a new {@link RelationalPersistentEntityImpl} for the given {@link TypeInformation}. @@ -50,6 +51,7 @@ class RelationalPersistentEntityImpl extends BasicPersistentEntity SqlIdentifier.quoted(name).withAdjustableLetterCasing()) // ); } @@ -58,7 +60,7 @@ class RelationalPersistentEntityImpl extends BasicPersistentEntity namingStrategy.getQualifiedTableName(getType())); } @@ -67,7 +69,7 @@ public String getTableName() { * @see org.springframework.data.jdbc.core.mapping.model.JdbcPersistentEntity#getIdColumn() */ @Override - public String getIdColumn() { + public SqlIdentifier getIdColumn() { return getRequiredIdProperty().getColumnName(); } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java index c829358e4c..767a447949 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java @@ -16,6 +16,8 @@ package org.springframework.data.relational.core.mapping; import org.springframework.data.mapping.PersistentProperty; +import org.springframework.data.relational.domain.SqlIdentifier; +import org.springframework.data.relational.domain.SqlIdentifier.SimpleSqlIdentifier; import org.springframework.lang.Nullable; /** @@ -34,7 +36,7 @@ public interface RelationalPersistentProperty extends PersistentProperty targetType) { + public static Identifier of(SqlIdentifier name, Object value, Class targetType) { - Assert.hasText(name, "Name must not be empty!"); + Assert.notNull(name, "Name must not be empty!"); Assert.notNull(targetType, "Target type must not be null!"); return new Identifier(Collections.singletonList(new SingleIdentifierValue(name, value, targetType))); @@ -83,7 +83,7 @@ public static Identifier of(String name, Object value, Class targetType) { * @param map must not be {@literal null}. * @return the {@link Identifier} from a {@link Map} of name to value tuples. */ - public static Identifier from(Map map) { + public static Identifier from(Map map) { Assert.notNull(map, "Map must not be null!"); @@ -111,9 +111,9 @@ public static Identifier from(Map map) { * @return the {@link Identifier} containing all existing keys and the key part for {@code name}, {@code value}, and a * {@link Class target type}. */ - public Identifier withPart(String name, Object value, Class targetType) { + public Identifier withPart(SqlIdentifier name, Object value, Class targetType) { - Assert.hasText(name, "Name must not be empty!"); + Assert.notNull(name, "Name must not be null!"); Assert.notNull(targetType, "Target type must not be null!"); boolean overwritten = false; @@ -141,9 +141,9 @@ public Identifier withPart(String name, Object value, Class targetType) { * * @return a {@link Map} containing the identifier name to value tuples. */ - public Map toMap() { + public Map toMap() { - Map result = new LinkedHashMap<>(); + Map result = new LinkedHashMap<>(); forEach((name, value, type) -> result.put(name, value)); return result; } @@ -188,7 +188,7 @@ public int size() { @AllArgsConstructor(access = AccessLevel.PRIVATE) static class SingleIdentifierValue { - String name; + SqlIdentifier name; Object value; Class targetType; } @@ -204,11 +204,11 @@ public interface IdentifierConsumer { /** * Performs this operation on the given arguments. - * + * * @param name * @param value * @param targetType */ - void accept(String name, Object value, Class targetType); + void accept(SqlIdentifier name, Object value, Class targetType); } } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/domain/IdentifierProcessing.java b/spring-data-relational/src/main/java/org/springframework/data/relational/domain/IdentifierProcessing.java new file mode 100644 index 0000000000..78dccb89fe --- /dev/null +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/domain/IdentifierProcessing.java @@ -0,0 +1,151 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.relational.domain; + +/** + * An interface describing the processing steps for the conversion of {@link SqlIdentifier} to SQL snippets or column + * names. + * + * @author Jens Schauder + * @since 2.0 + */ +public interface IdentifierProcessing { + + /** + * An {@link IdentifierProcessing} that can be used for databases adhering to the SQL standard which uses double + * quotes ({@literal "}) for quoting and makes unquoted literals equivalent to upper case. + */ + IdentifierProcessing ANSI = new DefaultIdentifierProcessing(Quoting.ANSI, LetterCasing.UPPER_CASE); + + /** + * Converts a {@link String} representing a bare name of an identifier to a {@link String} with proper quoting + * applied. + * + * @param identifier the name of an identifier. Must not be {@literal null}. + * @return a quoted name of an identifier. Guaranteed to be not {@literal null}. + */ + String quote(String identifier); + + /** + * Standardizes the use of upper and lower case letters in an identifier in such a way that semantically the same + * identifier results from the quoted and the unquoted version. If this is not possible use of + * {@link LetterCasing#AS_IS} is recommended. + * + * @param identifier an identifier with arbitrary upper and lower cases. must not be {@literal null}. + * @return an identifier with standardized use of upper and lower case letter. Guaranteed to be not {@literal null}. + */ + String standardizeLetterCase(String identifier); + + /** + * An {@link IdentifierProcessing} implementation based on two implementations for the quoting and for the letter case + * standardization. + */ + class DefaultIdentifierProcessing implements IdentifierProcessing { + + private final Quoting quoting; + private final LetterCasing letterCasing; + + public DefaultIdentifierProcessing(Quoting quoting, LetterCasing letterCasing) { + this.quoting = quoting; + this.letterCasing = letterCasing; + } + + @Override + public String quote(String identifier) { + return quoting.apply(identifier); + } + + @Override + public String standardizeLetterCase(String identifier) { + return letterCasing.apply(identifier); + } + } + + /** + * A conversion from unquoted identifiers to quoted identifiers. + * + * @author Jens Schauder + * @since 2.0 + */ + class Quoting { + + public static final Quoting ANSI = new Quoting("\""); + + private final String prefix; + private final String suffix; + + /** + * Constructs a {@literal Quoting} with potential different prefix and suffix used for quoting. + * + * @param prefix a {@literal String} prefixed before the name for quoting it. + * @param suffix a {@literal String} suffixed at the end of the name for quoting it. + */ + public Quoting(String prefix, String suffix) { + + this.prefix = prefix; + this.suffix = suffix; + } + + /** + * Constructs a {@literal Quoting} with the same {@literal String} appended in front and end of an identifier. + * + * @param quoteCharacter the value appended at the beginning and the end of a name in order to quote it. + */ + public Quoting(String quoteCharacter) { + this(quoteCharacter, quoteCharacter); + } + + public String apply(String identifier) { + return prefix + identifier + suffix; + } + } + + /** + * Encapsulates the three kinds of letter casing supported. + * + * @author Jens Schauder + * @since 2.0 + */ + enum LetterCasing { + + UPPER_CASE { + + @Override + public String apply(String identifier) { + return identifier.toUpperCase(); + } + }, + + LOWER_CASE { + + @Override + public String apply(String identifier) { + return identifier.toLowerCase(); + } + }, + + AS_IS { + + @Override + public String apply(String identifier) { + return identifier; + } + }; + + abstract String apply(String identifier); + } + +} diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/domain/SqlIdentifier.java b/spring-data-relational/src/main/java/org/springframework/data/relational/domain/SqlIdentifier.java new file mode 100644 index 0000000000..d40f11cdcd --- /dev/null +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/domain/SqlIdentifier.java @@ -0,0 +1,219 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.relational.domain; + +import java.util.Arrays; +import java.util.Objects; +import java.util.StringJoiner; + +import org.springframework.util.Assert; + +/** + * Represents a named object that exists in the database like a table name or a column name + * + * @author Jens Schauder + * @since 2.0 + */ +public interface SqlIdentifier { + + SimpleSqlIdentifier prefix(SqlIdentifier prefix, String separator); + + SqlIdentifier suffix(String suffix); + + SqlIdentifier concat(SqlIdentifier second); + + String toSql(IdentifierProcessing processing); + + String toColumnName(IdentifierProcessing processing); + + static SimpleSqlIdentifier quoted(String name) { + return new SimpleSqlIdentifier(name, true, true); + } + + static SimpleSqlIdentifier unquoted(String name) { + return new SimpleSqlIdentifier(name, false, true); + } + + SqlIdentifier EMPTY = new SqlIdentifier() { + + @Override + public SimpleSqlIdentifier prefix(SqlIdentifier prefix, String separator) { + throw new UnsupportedOperationException("We can't prefix an empty DatabaseObjectIdentifier"); + } + + @Override + public SqlIdentifier suffix(String suffix) { + throw new UnsupportedOperationException("We can't suffix an empty DatabaseObjectIdentifier"); + } + + @Override + public SqlIdentifier concat(SqlIdentifier second) { + return second; + } + + @Override + public String toSql(IdentifierProcessing processing) { + throw new UnsupportedOperationException("An empty SqlIdentifier can't be used in to create SQL snippets"); + } + + @Override + public String toColumnName(IdentifierProcessing processing) { + throw new UnsupportedOperationException("An empty SqlIdentifier can't be used in to create column names"); + } + + public String toString() { + return ""; + } + }; + + final class SimpleSqlIdentifier implements SqlIdentifier { + + private final String name; + private final boolean quoted; + private final boolean fixedLetterCasing; + + private SimpleSqlIdentifier(String name, boolean quoted, boolean fixedLetterCasing) { + + Assert.hasText(name, "A database object must have at least on name part."); + + this.name = name; + this.quoted = quoted; + this.fixedLetterCasing = fixedLetterCasing; + } + + public SimpleSqlIdentifier withAdjustableLetterCasing() { + return new SimpleSqlIdentifier(name, quoted, false); + } + + public SimpleSqlIdentifier prefix(String prefix) { + return new SimpleSqlIdentifier(prefix + name, quoted, fixedLetterCasing); + } + + @Override + public SimpleSqlIdentifier prefix(SqlIdentifier prefix, String separator) { + + Assert.isInstanceOf(SimpleSqlIdentifier.class, prefix, "Prefixing is only supported for simple SqlIdentifier"); + + return new SimpleSqlIdentifier(((SimpleSqlIdentifier) prefix).name + separator + name, quoted, fixedLetterCasing); + } + + public SimpleSqlIdentifier suffix(String suffix) { + return new SimpleSqlIdentifier(name + suffix, quoted, fixedLetterCasing); + } + + @Override + public boolean equals(Object o) { + + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + SimpleSqlIdentifier that = (SimpleSqlIdentifier) o; + return quoted == that.quoted && Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + + int result = Objects.hash(quoted); + result = 31 * result + name.hashCode(); + return result; + } + + @Override + public String toString() { + return "DatabaseObjectIdentifier{" + "name=" + name + ", quoted=" + quoted + '}'; + } + + @Override + public SqlIdentifier concat(SqlIdentifier second) { + // TODO: this is completely broken and needs fixing. + return new CombinedSqlIdentifier(this, (SimpleSqlIdentifier) second); + } + + @Override + public String toSql(IdentifierProcessing processing) { + + return quoted ? processing.quote(toColumnName(processing)) : toColumnName(processing); + } + + @Override + public String toColumnName(IdentifierProcessing processing) { + return fixedLetterCasing ? name : processing.standardizeLetterCase(name); + } + } + + final class CombinedSqlIdentifier implements SqlIdentifier { + + private final SimpleSqlIdentifier[] parts; + + private CombinedSqlIdentifier(SimpleSqlIdentifier... parts) { + this.parts = parts; + } + + @Override + public SqlIdentifier concat(SqlIdentifier second) { + throw new UnsupportedOperationException(); + } + + @Override + public SimpleSqlIdentifier prefix(SqlIdentifier prefix, String separator) { + throw new UnsupportedOperationException(); + } + + @Override + public SqlIdentifier suffix(String suffix) { + throw new UnsupportedOperationException(); + } + + @Override + public String toSql(IdentifierProcessing processing) { + + StringJoiner stringJoiner = new StringJoiner("."); + + for (SimpleSqlIdentifier namePart : parts) { + stringJoiner.add(namePart.toSql(processing)); + } + + return stringJoiner.toString(); + } + + @Override + public String toColumnName(IdentifierProcessing processing) { + throw new UnsupportedOperationException("A CombinedSqlIdentifier can't be used as a column name"); + } + + @Override + public String toString() { + return "CombinedDatabaseObjectIdentifier{" + "parts=" + Arrays.toString(parts) + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + CombinedSqlIdentifier that = (CombinedSqlIdentifier) o; + return Arrays.equals(parts, that.parts); + } + + @Override + public int hashCode() { + return Arrays.hashCode(parts); + } + } +} diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/RelationalEntityInformation.java b/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/RelationalEntityInformation.java index 55620b4b9f..049fc1b8fe 100755 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/RelationalEntityInformation.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/RelationalEntityInformation.java @@ -15,6 +15,7 @@ */ package org.springframework.data.relational.repository.query; +import org.springframework.data.relational.domain.SqlIdentifier; import org.springframework.data.repository.core.EntityInformation; /** @@ -29,5 +30,5 @@ public interface RelationalEntityInformation extends EntityInformation extends EntityMetadata { * * @return */ - String getTableName(); + SqlIdentifier getTableName(); /** * Returns the {@link RelationalPersistentEntity} that supposed to determine the table to be queried. diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/SimpleRelationalEntityMetadata.java b/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/SimpleRelationalEntityMetadata.java index 36fec02061..4635f966a7 100755 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/SimpleRelationalEntityMetadata.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/SimpleRelationalEntityMetadata.java @@ -18,6 +18,7 @@ import lombok.Getter; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; +import org.springframework.data.relational.domain.SqlIdentifier; import org.springframework.util.Assert; /** @@ -56,7 +57,7 @@ public Class getJavaType() { /* (non-Javadoc) * @see org.springframework.data.relational.repository.query.RelationalEntityMetadata#getTableName() */ - public String getTableName() { + public SqlIdentifier getTableName() { return tableEntity.getTableName(); } } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/repository/support/MappingRelationalEntityInformation.java b/spring-data-relational/src/main/java/org/springframework/data/relational/repository/support/MappingRelationalEntityInformation.java index 9ec5a9baff..39b583b507 100755 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/repository/support/MappingRelationalEntityInformation.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/repository/support/MappingRelationalEntityInformation.java @@ -16,6 +16,7 @@ package org.springframework.data.relational.repository.support; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; +import org.springframework.data.relational.domain.SqlIdentifier; import org.springframework.data.relational.repository.query.RelationalEntityInformation; import org.springframework.data.repository.core.support.PersistentEntityInformation; import org.springframework.lang.Nullable; @@ -32,7 +33,7 @@ public class MappingRelationalEntityInformation extends PersistentEntityI implements RelationalEntityInformation { private final RelationalPersistentEntity entityMetadata; - private final @Nullable String customTableName; + private final @Nullable SqlIdentifier customTableName; private final Class fallbackIdType; /** @@ -81,14 +82,14 @@ private MappingRelationalEntityInformation(RelationalPersistentEntity entity, super(entity); this.entityMetadata = entity; - this.customTableName = customTableName; + this.customTableName = customTableName == null ? null : SqlIdentifier.quoted(customTableName); this.fallbackIdType = idType != null ? idType : (Class) Long.class; } /* (non-Javadoc) * @see org.springframework.data.relational.repository.query.RelationalEntityInformation#getTableName() */ - public String getTableName() { + public SqlIdentifier getTableName() { return customTableName == null ? entityMetadata.getTableName() : customTableName; } diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/HsqlDbDialectUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/HsqlDbDialectUnitTests.java new file mode 100644 index 0000000000..818bf406ae --- /dev/null +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/HsqlDbDialectUnitTests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.relational.core.dialect; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.Test; + +/** + * Unit tests for the {@link HsqlDbDialect}. + * + * @author Jens Schauder + */ +public class HsqlDbDialectUnitTests { + + @Test // DATAJDBC-386 + public void shouldNotSupportArrays() { + + ArrayColumns arrayColumns = HsqlDbDialect.INSTANCE.getArraySupport(); + + assertThat(arrayColumns.isSupported()).isFalse(); + } + + @Test // DATAJDBC-386 + public void shouldRenderLimit() { + + LimitClause limit = HsqlDbDialect.INSTANCE.limit(); + + assertThat(limit.getClausePosition()).isEqualTo(LimitClause.Position.AFTER_ORDER_BY); + assertThat(limit.getLimit(10)).isEqualTo("LIMIT 10"); + } + + @Test // DATAJDBC-386 + public void shouldRenderOffset() { + + LimitClause limit = HsqlDbDialect.INSTANCE.limit(); + + assertThat(limit.getOffset(10)).isEqualTo("OFFSET 10"); + } + + @Test // DATAJDBC-386 + public void shouldRenderLimitOffset() { + + LimitClause limit = HsqlDbDialect.INSTANCE.limit(); + + assertThat(limit.getLimitOffset(20, 10)).isEqualTo("OFFSET 10 LIMIT 20"); + } + + @Test // DATAJDBC-386 + public void shouldQuoteIdentifiersUsingBackticks() { + + String abcQuoted = HsqlDbDialect.INSTANCE.getIdentifierProcessing().quote("abc"); + + assertThat(abcQuoted).isEqualTo("\"abc\""); + } +} diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/MariaDbDialectUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/MariaDbDialectUnitTests.java new file mode 100644 index 0000000000..4a2e97053b --- /dev/null +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/MariaDbDialectUnitTests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.relational.core.dialect; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.Test; + +/** + * Unit tests for {@link MariaDbDialect}. + * + * @author Jens Schauder + */ +public class MariaDbDialectUnitTests { + + @Test // DATAJDBC-278 + public void shouldNotSupportArrays() { + + ArrayColumns arrayColumns = MariaDbDialect.INSTANCE.getArraySupport(); + + assertThat(arrayColumns.isSupported()).isFalse(); + } + + @Test // DATAJDBC-278 + public void shouldRenderLimit() { + + LimitClause limit = MariaDbDialect.INSTANCE.limit(); + + assertThat(limit.getClausePosition()).isEqualTo(LimitClause.Position.AFTER_ORDER_BY); + assertThat(limit.getLimit(10)).isEqualTo("LIMIT 10"); + } + + @Test // DATAJDBC-278 + public void shouldRenderOffset() { + + LimitClause limit = MariaDbDialect.INSTANCE.limit(); + + assertThat(limit.getOffset(10)).isEqualTo("LIMIT 10, 18446744073709551615"); + } + + @Test // DATAJDBC-278 + public void shouldRenderLimitOffset() { + + LimitClause limit = MariaDbDialect.INSTANCE.limit(); + + assertThat(limit.getLimitOffset(20, 10)).isEqualTo("LIMIT 10, 20"); + } + + @Test // DATAJDBC-386 + public void shouldQuoteIdentifiersUsingBackticks() { + + String abcQuoted = MariaDbDialect.INSTANCE.getIdentifierProcessing().quote("abc"); + + assertThat(abcQuoted).isEqualTo("`abc`"); + } +} diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/MySqlDialectUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/MySqlDialectUnitTests.java index 4bb6b5ee9d..5e6d94ac44 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/MySqlDialectUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/MySqlDialectUnitTests.java @@ -59,4 +59,12 @@ public void shouldRenderLimitOffset() { assertThat(limit.getLimitOffset(20, 10)).isEqualTo("LIMIT 10, 20"); } + + @Test // DATAJDBC-386 + public void shouldQuoteIdentifiersUsingBackticks() { + + String abcQuoted = MySqlDialect.INSTANCE.getIdentifierProcessing().quote("abc"); + + assertThat(abcQuoted).isEqualTo("`abc`"); + } } diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentPropertyUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentPropertyUnitTests.java index c9855910f4..b727339272 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentPropertyUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentPropertyUnitTests.java @@ -16,6 +16,7 @@ package org.springframework.data.relational.core.mapping; import static org.assertj.core.api.Assertions.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; import lombok.Data; @@ -82,9 +83,9 @@ public void testTargetTypesForPropertyType() { @Test // DATAJDBC-106 public void detectsAnnotatedColumnName() { - assertThat(entity.getRequiredPersistentProperty("name").getColumnName()).isEqualTo("dummy_name"); + assertThat(entity.getRequiredPersistentProperty("name").getColumnName()).isEqualTo(quoted("dummy_name")); assertThat(entity.getRequiredPersistentProperty("localDateTime").getColumnName()) - .isEqualTo("dummy_last_updated_at"); + .isEqualTo(quoted("dummy_last_updated_at")); } @Test // DATAJDBC-218 @@ -92,8 +93,8 @@ public void detectsAnnotatedColumnAndKeyName() { RelationalPersistentProperty listProperty = entity.getRequiredPersistentProperty("someList"); - assertThat(listProperty.getReverseColumnName()).isEqualTo("dummy_column_name"); - assertThat(listProperty.getKeyColumn()).isEqualTo("dummy_key_column_name"); + assertThat(listProperty.getReverseColumnName()).isEqualTo(quoted("dummy_column_name")); + assertThat(listProperty.getKeyColumn()).isEqualTo(quoted("dummy_key_column_name")); } @Test // DATAJDBC-111 @@ -148,10 +149,10 @@ public void classificationOfCollectionLikeProperties() { .assertThat(p.isCollectionLike() && !p.isEntity()).describedAs(s + " contains either simple types or entities") .isNotEqualTo(p.isCollectionLike() && p.isEntity()); - checkEitherOr.accept(listOfString,"listOfString"); - checkEitherOr.accept(arrayOfString,"arrayOfString"); - checkEitherOr.accept(listOfEntity,"listOfEntity"); - checkEitherOr.accept(arrayOfEntity,"arrayOfEntity"); + checkEitherOr.accept(listOfString, "listOfString"); + checkEitherOr.accept(arrayOfString, "arrayOfString"); + checkEitherOr.accept(listOfEntity, "listOfEntity"); + checkEitherOr.accept(arrayOfEntity, "arrayOfEntity"); softly.assertThat(arrayOfString.getColumnType()).isEqualTo(String[].class); softly.assertThat(listOfString.getColumnType()).isEqualTo(String[].class); @@ -183,7 +184,8 @@ private static class DummyEntity { private final List listOfEntity; private final OtherEntity[] arrayOfEntity; - @MappedCollection(idColumn = "dummy_column_name", keyColumn = "dummy_key_column_name") private List someList; + @MappedCollection(idColumn = "dummy_column_name", + keyColumn = "dummy_key_column_name") private List someList; // DATACMNS-106 private @Column("dummy_name") String name; diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/NamingStrategyUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/NamingStrategyUnitTests.java index 852b982605..2599dbd461 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/NamingStrategyUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/NamingStrategyUnitTests.java @@ -16,6 +16,7 @@ package org.springframework.data.relational.core.mapping; import static org.assertj.core.api.Assertions.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; import java.time.LocalDateTime; import java.util.List; @@ -23,6 +24,7 @@ import org.junit.Test; import org.springframework.data.annotation.Id; import org.springframework.data.relational.core.mapping.RelationalPersistentEntityImplUnitTests.DummySubEntity; +import org.springframework.data.relational.domain.SqlIdentifier; /** * Unit tests for the {@link NamingStrategy}. @@ -40,51 +42,53 @@ public class NamingStrategyUnitTests { @Test public void getTableName() { - assertThat(target.getTableName(persistentEntity.getType())).isEqualTo("dummy_entity"); - assertThat(target.getTableName(DummySubEntity.class)).isEqualTo("dummy_sub_entity"); + assertThat(target.getTableName(persistentEntity.getType())).isEqualTo(quoted("dummy_entity")); + assertThat(target.getTableName(DummySubEntity.class)).isEqualTo(quoted("dummy_sub_entity")); } @Test public void getColumnName() { - assertThat(target.getColumnName(persistentEntity.getPersistentProperty("id"))).isEqualTo("id"); - assertThat(target.getColumnName(persistentEntity.getPersistentProperty("createdAt"))).isEqualTo("created_at"); + assertThat(target.getColumnName(persistentEntity.getPersistentProperty("id"))).isEqualTo(quoted("id")); + assertThat(target.getColumnName(persistentEntity.getPersistentProperty("createdAt"))) + .isEqualTo(quoted("created_at")); assertThat(target.getColumnName(persistentEntity.getPersistentProperty("dummySubEntities"))) - .isEqualTo("dummy_sub_entities"); + .isEqualTo(quoted("dummy_sub_entities")); } @Test public void getReverseColumnName() { assertThat(target.getReverseColumnName(persistentEntity.getPersistentProperty("dummySubEntities"))) - .isEqualTo("dummy_entity"); + .isEqualTo(quoted("dummy_entity")); } @Test public void getKeyColumn() { assertThat(target.getKeyColumn(persistentEntity.getPersistentProperty("dummySubEntities"))) - .isEqualTo("dummy_entity_key"); + .isEqualTo(quoted("dummy_entity_key")); } @Test public void getSchema() { - assertThat(target.getSchema()).isEmpty(); + assertThat(target.getSchema()).isEqualTo(SqlIdentifier.EMPTY); } @Test public void getQualifiedTableName() { - assertThat(target.getQualifiedTableName(persistentEntity.getType())).isEqualTo("dummy_entity"); + assertThat(target.getQualifiedTableName(persistentEntity.getType())).isEqualTo(quoted("dummy_entity")); NamingStrategy strategy = new NamingStrategy() { @Override - public String getSchema() { - return "schema"; + public SqlIdentifier getSchema() { + return quoted("schema"); } }; - assertThat(strategy.getQualifiedTableName(persistentEntity.getType())).isEqualTo("schema.dummy_entity"); + assertThat(strategy.getQualifiedTableName(persistentEntity.getType())) + .isEqualTo(quoted("schema").concat(quoted("dummy_entity"))); } static class DummyEntity { diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImplUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImplUnitTests.java index 74b644b38a..e3fcd4f3dc 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImplUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImplUnitTests.java @@ -16,6 +16,7 @@ package org.springframework.data.relational.core.mapping; import static org.assertj.core.api.Assertions.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; import org.junit.Test; import org.springframework.data.annotation.Id; @@ -36,7 +37,7 @@ public void discoversAnnotatedTableName() { RelationalPersistentEntity entity = mappingContext.getPersistentEntity(DummySubEntity.class); - assertThat(entity.getTableName()).isEqualTo("dummy_sub_entity"); + assertThat(entity.getTableName()).isEqualTo(quoted("dummy_sub_entity")); } @Test // DATAJDBC-294 @@ -44,7 +45,7 @@ public void considerIdColumnName() { RelationalPersistentEntity entity = mappingContext.getPersistentEntity(DummySubEntity.class); - assertThat(entity.getIdColumn()).isEqualTo("renamedId"); + assertThat(entity.getIdColumn()).isEqualTo(quoted("renamedId")); } @Test // DATAJDBC-296 @@ -52,7 +53,7 @@ public void emptyTableAnnotationFallsBackToNamingStrategy() { RelationalPersistentEntity entity = mappingContext.getPersistentEntity(DummyEntityWithEmptyAnnotation.class); - assertThat(entity.getTableName()).isEqualTo("dummy_entity_with_empty_annotation"); + assertThat(entity.getTableName()).isEqualTo(quoted("dummy_entity_with_empty_annotation")); } @Table("dummy_sub_entity") diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/SqlIdentifierUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/SqlIdentifierUnitTests.java new file mode 100644 index 0000000000..909cef124c --- /dev/null +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/SqlIdentifierUnitTests.java @@ -0,0 +1,123 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.relational.core.mapping; + +import static org.assertj.core.api.Assertions.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; + +import org.assertj.core.api.SoftAssertions; +import org.junit.Test; +import org.springframework.data.relational.domain.IdentifierProcessing; +import org.springframework.data.relational.domain.IdentifierProcessing.DefaultIdentifierProcessing; +import org.springframework.data.relational.domain.IdentifierProcessing.LetterCasing; +import org.springframework.data.relational.domain.IdentifierProcessing.Quoting; +import org.springframework.data.relational.domain.SqlIdentifier; + +/** + * Unit tests for SqlIdentifier. + * + * @author Jens Schauder + */ +public class SqlIdentifierUnitTests { + + public static final DefaultIdentifierProcessing BRACKETS_LOWER_CASE = new DefaultIdentifierProcessing( + new Quoting("[", "]"), LetterCasing.LOWER_CASE); + + @Test // DATAJDBC-386 + public void quotedSimpleObjectIdentifier() { + + SimpleSqlIdentifier identifier = quoted("someName"); + + assertThat(identifier.toSql(BRACKETS_LOWER_CASE)).isEqualTo("[someName]"); + assertThat(identifier.toColumnName(BRACKETS_LOWER_CASE)).isEqualTo("someName"); + + } + + @Test // DATAJDBC-386 + public void unquotedSimpleObjectIdentifier() { + + SimpleSqlIdentifier identifier = unquoted("someName"); + String sql = identifier.toSql(BRACKETS_LOWER_CASE); + + assertThat(sql).isEqualTo("someName"); + assertThat(identifier.toColumnName(BRACKETS_LOWER_CASE)).isEqualTo("someName"); + } + + @Test // DATAJDBC-386 + public void quotedSimpleObjectIdentifierWithAdjustableLetterCasing() { + + SimpleSqlIdentifier identifier = quoted("someName").withAdjustableLetterCasing(); + + assertThat(identifier.toSql(BRACKETS_LOWER_CASE)).isEqualTo("[somename]"); + assertThat(identifier.toColumnName(BRACKETS_LOWER_CASE)).isEqualTo("somename"); + + } + + @Test // DATAJDBC-386 + public void unquotedSimpleObjectIdentifierWithAdjustableLetterCasing() { + + SimpleSqlIdentifier identifier = unquoted("someName").withAdjustableLetterCasing(); + String sql = identifier.toSql(BRACKETS_LOWER_CASE); + + assertThat(sql).isEqualTo("somename"); + assertThat(identifier.toColumnName(BRACKETS_LOWER_CASE)).isEqualTo("somename"); + } + + @Test // DATAJDBC-386 + public void quotedMultipartObjectIdentifierWithAdjustableLetterCase() { + + SqlIdentifier identifier = quoted("some").withAdjustableLetterCasing() + .concat(quoted("name").withAdjustableLetterCasing()); + String sql = identifier.toSql(IdentifierProcessing.ANSI); + + assertThat(sql).isEqualTo("\"SOME\".\"NAME\""); + } + + @Test // DATAJDBC-386 + public void quotedMultipartObjectIdentifier() { + + SqlIdentifier identifier = quoted("some").concat(quoted("name")); + String sql = identifier.toSql(IdentifierProcessing.ANSI); + + assertThat(sql).isEqualTo("\"some\".\"name\""); + } + + @Test // DATAJDBC-386 + public void unquotedMultipartObjectIdentifier() { + + SqlIdentifier identifier = unquoted("some").concat(unquoted("name")); + String sql = identifier.toSql(IdentifierProcessing.ANSI); + + assertThat(sql).isEqualTo("some.name"); + } + + @Test // DATAJDBC-386 + public void equality() { + + SqlIdentifier basis = SqlIdentifier.unquoted("simple"); + SqlIdentifier equal = SqlIdentifier.unquoted("simple"); + SqlIdentifier quoted = quoted("simple"); + SqlIdentifier notSimple = SqlIdentifier.unquoted("simple").concat(unquoted("not")); + + SoftAssertions.assertSoftly(softly -> { + + softly.assertThat(basis).isEqualTo(equal); + softly.assertThat(equal).isEqualTo(basis); + softly.assertThat(basis).isNotEqualTo(quoted); + softly.assertThat(basis).isNotEqualTo(notSimple); + }); + } +} diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/domain/DefaultIdentifierProcessingUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/domain/DefaultIdentifierProcessingUnitTests.java new file mode 100644 index 0000000000..e153abd2ac --- /dev/null +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/domain/DefaultIdentifierProcessingUnitTests.java @@ -0,0 +1,49 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.relational.domain; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.Test; +import org.springframework.data.relational.domain.IdentifierProcessing.DefaultIdentifierProcessing; +import org.springframework.data.relational.domain.IdentifierProcessing.LetterCasing; +import org.springframework.data.relational.domain.IdentifierProcessing.Quoting; + +/** + * unit tests for {@link DefaultIdentifierProcessing}. + * + * @author Jens Schauder + */ +public class DefaultIdentifierProcessingUnitTests { + + @Test // DATAJDBC-386 + public void ansiConformProcessing() { + + DefaultIdentifierProcessing processing = new DefaultIdentifierProcessing(Quoting.ANSI, LetterCasing.UPPER_CASE); + + assertThat(processing.quote("something")).isEqualTo("\"something\""); + assertThat(processing.standardizeLetterCase("aBc")).isEqualTo("ABC"); + } + + @Test // DATAJDBC-386 + public void twoCharacterAsIs() { + + DefaultIdentifierProcessing processing = new DefaultIdentifierProcessing(new Quoting("[", "]"), LetterCasing.AS_IS); + + assertThat(processing.quote("something")).isEqualTo("[something]"); + assertThat(processing.standardizeLetterCase("aBc")).isEqualTo("aBc"); + } +} diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/domain/IdentifierUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/domain/IdentifierUnitTests.java index c9363f239a..340187bede 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/domain/IdentifierUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/domain/IdentifierUnitTests.java @@ -16,6 +16,7 @@ package org.springframework.data.relational.domain; import static org.assertj.core.api.Assertions.*; +import static org.springframework.data.relational.domain.SqlIdentifier.*; import java.util.ArrayList; import java.util.Collections; @@ -35,50 +36,55 @@ public class IdentifierUnitTests { @Test // DATAJDBC-326 public void getParametersByName() { - Identifier identifier = Identifier.of("aName", "aValue", String.class); + Identifier identifier = Identifier.of(unquoted("aName"), "aValue", String.class); - assertThat(identifier.toMap()).hasSize(1).containsEntry("aName", "aValue"); + assertThat(identifier.toMap()).hasSize(1).containsEntry(unquoted("aName"), "aValue"); } @Test // DATAJDBC-326 public void parametersWithStringKeysUseObjectAsTypeForNull() { - HashMap parameters = new HashMap<>(); - parameters.put("one", null); + HashMap parameters = new HashMap<>(); + parameters.put(unquoted("one"), null); Identifier identifier = Identifier.from(parameters); assertThat(identifier.getParts()) // .extracting("name", "value", "targetType") // .containsExactly( // - tuple("one", null, Object.class) // + tuple(unquoted("one"), null, Object.class) // ); } @Test // DATAJDBC-326 public void createsIdentifierFromMap() { - Identifier identifier = Identifier.from(Collections.singletonMap("aName", "aValue")); + Identifier identifier = Identifier.from(Collections.singletonMap(unquoted("aName"), "aValue")); - assertThat(identifier.toMap()).hasSize(1).containsEntry("aName", "aValue"); + assertThat(identifier.toMap()).hasSize(1).containsEntry(unquoted("aName"), "aValue"); } @Test // DATAJDBC-326 public void withAddsNewEntries() { - Identifier identifier = Identifier.from(Collections.singletonMap("aName", "aValue")).withPart("foo", "bar", - String.class); + Identifier identifier = Identifier.from(Collections.singletonMap(unquoted("aName"), "aValue")) + .withPart(unquoted("foo"), "bar", String.class); - assertThat(identifier.toMap()).hasSize(2).containsEntry("aName", "aValue").containsEntry("foo", "bar"); + assertThat(identifier.toMap()) // + .hasSize(2) // + .containsEntry(unquoted("aName"), "aValue") // + .containsEntry(unquoted("foo"), "bar"); } @Test // DATAJDBC-326 public void withOverridesExistingEntries() { - Identifier identifier = Identifier.from(Collections.singletonMap("aName", "aValue")).withPart("aName", "bar", - String.class); + Identifier identifier = Identifier.from(Collections.singletonMap(unquoted("aName"), "aValue")) + .withPart(unquoted("aName"), "bar", String.class); - assertThat(identifier.toMap()).hasSize(1).containsEntry("aName", "bar"); + assertThat(identifier.toMap()) // + .hasSize(1) // + .containsEntry(unquoted("aName"), "bar"); } @Test // DATAJDBC-326 @@ -86,7 +92,8 @@ public void forEachIteratesOverKeys() { List keys = new ArrayList<>(); - Identifier.from(Collections.singletonMap("aName", "aValue")).forEach((name, value, targetType) -> keys.add(name)); + Identifier.from(Collections.singletonMap(unquoted("aName"), "aValue")) + .forEach((name, value, targetType) -> keys.add(name.toSql(IdentifierProcessing.ANSI))); assertThat(keys).containsOnly("aName"); } @@ -94,9 +101,9 @@ public void forEachIteratesOverKeys() { @Test // DATAJDBC-326 public void equalsConsidersEquality() { - Identifier one = Identifier.from(Collections.singletonMap("aName", "aValue")); - Identifier two = Identifier.from(Collections.singletonMap("aName", "aValue")); - Identifier three = Identifier.from(Collections.singletonMap("aName", "different")); + Identifier one = Identifier.from(Collections.singletonMap(unquoted("aName"), "aValue")); + Identifier two = Identifier.from(Collections.singletonMap(unquoted("aName"), "aValue")); + Identifier three = Identifier.from(Collections.singletonMap(unquoted("aName"), "different")); assertThat(one).isEqualTo(two); assertThat(one).isNotEqualTo(three); From e5280f856829ce4f53c4792ac6f9a04633136434 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 9 Jan 2020 10:22:54 +0100 Subject: [PATCH 3/6] DATAJDBC-386 - Fix bind marker rendering for delete by Id. --- .../springframework/data/jdbc/core/convert/SqlGenerator.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java index a7ae237813..86ccdabfa7 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java @@ -81,7 +81,7 @@ class SqlGenerator { /** * Create a new {@link SqlGenerator} given {@link RelationalMappingContext} and {@link RelationalPersistentEntity}. - * + * * @param mappingContext must not be {@literal null}. * @param entity must not be {@literal null}. * @param identifierProcessing must not be {@literal null}. @@ -536,7 +536,8 @@ private String createDeleteByIdAndVersionSql() { } private DeleteBuilder.DeleteWhereAndOr createBaseDeleteById(Table table) { - return Delete.builder().from(table).where(getIdColumn().isEqualTo(SQL.bindMarker(":id"))); + return Delete.builder().from(table) + .where(getIdColumn().isEqualTo(SQL.bindMarker(":" + ID_SQL_PARAMETER.toColumnName(identifierProcessing)))); } private String createDeleteByPathAndCriteria(PersistentPropertyPathExtension path, From db484f61abb4401167cce559dffa37753976b38f Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 9 Jan 2020 16:09:37 +0100 Subject: [PATCH 4/6] DATAJDBC-386 - Refactor SqlIdentifier. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SqlIdentifier provides now a transform(…) method to transform its content instead of exposing prefix(…) and suffix(…) methods. Composite identifiers are created through SqlIdentifier.from(…) instead of exposing a concat(…) method. We also now apply identifier normalization only to derived identifiers instead of applying normalization to annotated column and table names. This change requires references to derived field names to honor the appropriate letter casing. Identifier quotation can be disabled globally, via RelationalMappingContext.setForceQuote(false). --- .../jdbc/core/convert/BasicJdbcConverter.java | 4 +- .../convert/DefaultDataAccessStrategy.java | 4 +- .../jdbc/core/convert/MapEntityRowMapper.java | 2 +- .../data/jdbc/core/convert/SqlGenerator.java | 21 +- .../convert/SqlIdentifierParameterSource.java | 6 +- ...eChangeIdGenerationImmutableUnitTests.java | 8 +- .../core/DefaultJdbcInterpreterUnitTests.java | 9 +- ...sistentPropertyPathExtensionUnitTests.java | 44 ++-- .../DefaultDataAccessStrategyUnitTests.java | 2 + .../convert/EntityRowMapperUnitTests.java | 5 +- .../JdbcIdentifierBuilderUnitTests.java | 14 +- ...orContextBasedNamingStrategyUnitTests.java | 8 +- .../SqlGeneratorEmbeddedUnitTests.java | 4 +- ...GeneratorFixedNamingStrategyUnitTests.java | 91 +++---- .../core/convert/SqlGeneratorUnitTests.java | 31 ++- ...SqlIdentifierParameterSourceUnitTests.java | 1 + .../model/NamingStrategyUnitTests.java | 18 +- .../MyBatisDataAccessStrategyUnitTests.java | 2 + ...toryEmbeddedImmutableIntegrationTests.java | 2 +- ...dbcRepositoryEmbeddedIntegrationTests.java | 4 +- ...dedNotInAggregateRootIntegrationTests.java | 2 +- ...mbeddedWithCollectionIntegrationTests.java | 4 +- ...EmbeddedWithReferenceIntegrationTests.java | 4 +- ...epositoryIdGenerationIntegrationTests.java | 4 +- ...nableJdbcAuditingHsqlIntegrationTests.java | 4 +- ...AggregateTemplateIntegrationTests-hsql.sql | 16 +- ...regateTemplateIntegrationTests-mariadb.sql | 16 +- ...ggregateTemplateIntegrationTests-mssql.sql | 14 +- ...ggregateTemplateIntegrationTests-mysql.sql | 16 +- ...egateTemplateIntegrationTests-postgres.sql | 14 +- .../core/dialect/HsqlDbDialect.java | 3 +- .../relational/core/dialect/MySqlDialect.java | 3 +- .../core/dialect/PostgresDialect.java | 3 +- .../BasicRelationalPersistentProperty.java | 38 ++- .../core/mapping/CachingNamingStrategy.java | 26 +- .../core/mapping/DerivedSqlIdentifier.java | 105 ++++++++ .../core/mapping/NamingStrategy.java | 31 +-- .../PersistentPropertyPathExtension.java | 18 +- .../mapping/RelationalMappingContext.java | 34 ++- .../RelationalPersistentEntityImpl.java | 25 +- .../mapping/RelationalPersistentProperty.java | 3 +- .../domain/CompositeSqlIdentifier.java | 108 ++++++++ .../domain/DefaultIdentifierProcessing.java | 52 ++++ .../domain/DefaultSqlIdentifier.java | 104 ++++++++ .../domain/IdentifierProcessing.java | 55 ++-- .../data/relational/domain/SqlIdentifier.java | 244 ++++++------------ .../DerivedSqlIdentifierUnitTests.java | 86 ++++++ .../core/mapping/NamingStrategyUnitTests.java | 28 +- ...lationalPersistentEntityImplUnitTests.java | 4 +- .../DefaultIdentifierProcessingUnitTests.java | 8 +- .../domain/IdentifierUnitTests.java | 2 + .../SqlIdentifierUnitTests.java | 60 +---- 52 files changed, 909 insertions(+), 505 deletions(-) create mode 100644 spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/DerivedSqlIdentifier.java create mode 100644 spring-data-relational/src/main/java/org/springframework/data/relational/domain/CompositeSqlIdentifier.java create mode 100644 spring-data-relational/src/main/java/org/springframework/data/relational/domain/DefaultIdentifierProcessing.java create mode 100644 spring-data-relational/src/main/java/org/springframework/data/relational/domain/DefaultSqlIdentifier.java create mode 100644 spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/DerivedSqlIdentifierUnitTests.java rename spring-data-relational/src/test/java/org/springframework/data/relational/{core/mapping => domain}/SqlIdentifierUnitTests.java (52%) diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java index 69c11faf33..4512c40f9d 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java @@ -378,7 +378,7 @@ private Object readFrom(RelationalPersistentProperty property) { } Object value = getObjectFromResultSet( - path.extendBy(property).getColumnAlias().toColumnName(identifierProcessing)); + path.extendBy(property).getColumnAlias().getReference(identifierProcessing)); return readValue(value, property.getTypeInformation()); } @@ -433,7 +433,7 @@ private Object readEntityFrom(RelationalPersistentProperty property, PersistentP idValue = newContext.readFrom(idProperty); } else { idValue = newContext.getObjectFromResultSet( - path.extendBy(property).getReverseColumnNameAlias().toColumnName(identifierProcessing)); + path.extendBy(property).getReverseColumnNameAlias().getReference(identifierProcessing)); } if (idValue == null) { diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategy.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategy.java index 1860c8c945..12179bd1f1 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategy.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategy.java @@ -403,7 +403,7 @@ private SqlIdentifierParameterSource getParameterSource(@Nullable S insta } else { Object value = propertyAccessor.getProperty(property); - SqlIdentifier paramName = property.getColumnName().prefix(prefix); + SqlIdentifier paramName = property.getColumnName().transform(prefix::concat); addConvertedPropertyValue(parameters, property, value, paramName); } @@ -447,7 +447,7 @@ private Object getIdFromHolder(KeyHolder holder, RelationalPersistentEntity< return null; } - return keys.get(persistentEntity.getIdColumn().toColumnName(getIdentifierProcessing())); + return keys.get(persistentEntity.getIdColumn().getReference(getIdentifierProcessing())); } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/MapEntityRowMapper.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/MapEntityRowMapper.java index 62cc71748f..27dc8b755b 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/MapEntityRowMapper.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/MapEntityRowMapper.java @@ -49,7 +49,7 @@ class MapEntityRowMapper implements RowMapper> { @Override public Map.Entry mapRow(ResultSet rs, int rowNum) throws SQLException { - Object key = rs.getObject(keyColumn.toColumnName(identifierProcessing)); + Object key = rs.getObject(keyColumn.getReference(identifierProcessing)); return new HashMap.SimpleEntry<>(key, mapEntity(rs, key)); } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java index 86ccdabfa7..facc15822e 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java @@ -17,7 +17,16 @@ import lombok.Value; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; import java.util.function.Function; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -143,7 +152,7 @@ private Condition getSubselectCondition(PersistentPropertyPathExtension path, } private BindMarker getBindMarker(SqlIdentifier columnName) { - return SQL.bindMarker(":" + parameterPattern.matcher(columnName.toColumnName(identifierProcessing)).replaceAll("")); + return SQL.bindMarker(":" + parameterPattern.matcher(columnName.getReference(identifierProcessing)).replaceAll("")); } /** @@ -498,7 +507,7 @@ private String createUpdateWithVersionSql() { Update update = createBaseUpdate() // .and(getVersionColumn() - .isEqualTo(SQL.bindMarker(":" + VERSION_SQL_PARAMETER.toColumnName(identifierProcessing)))) // + .isEqualTo(SQL.bindMarker(":" + VERSION_SQL_PARAMETER.getReference(identifierProcessing)))) // .build(); return render(update); @@ -529,7 +538,7 @@ private String createDeleteByIdAndVersionSql() { Delete delete = createBaseDeleteById(getTable()) // .and(getVersionColumn() - .isEqualTo(SQL.bindMarker(":" + VERSION_SQL_PARAMETER.toColumnName(identifierProcessing)))) // + .isEqualTo(SQL.bindMarker(":" + VERSION_SQL_PARAMETER.getReference(identifierProcessing)))) // .build(); return render(delete); @@ -537,7 +546,7 @@ private String createDeleteByIdAndVersionSql() { private DeleteBuilder.DeleteWhereAndOr createBaseDeleteById(Table table) { return Delete.builder().from(table) - .where(getIdColumn().isEqualTo(SQL.bindMarker(":" + ID_SQL_PARAMETER.toColumnName(identifierProcessing)))); + .where(getIdColumn().isEqualTo(SQL.bindMarker(":" + ID_SQL_PARAMETER.getReference(identifierProcessing)))); } private String createDeleteByPathAndCriteria(PersistentPropertyPathExtension path, @@ -667,7 +676,7 @@ private void populateColumnNameCache(RelationalPersistentEntity entity, Strin private void initSimpleColumnName(RelationalPersistentProperty property, String prefix) { - SqlIdentifier columnName = property.getColumnName().prefix(prefix); + SqlIdentifier columnName = property.getColumnName().transform(prefix::concat); columnNames.add(columnName); diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSource.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSource.java index 30dbf931b9..d38ccc17aa 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSource.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSource.java @@ -28,7 +28,7 @@ /** * Implementation of the {@link org.springframework.jdbc.core.namedparam.SqlParameterSource} interface based on * {@link SqlIdentifier} instead of {@link String} for names. - * + * * @author Jens Schauder * @since 2.0 */ @@ -68,7 +68,7 @@ void addValue(SqlIdentifier name, Object value) { void addValue(SqlIdentifier identifier, Object value, int sqlType) { identifiers.add(identifier); - String name = identifier.toColumnName(identifierProcessing); + String name = identifier.getReference(identifierProcessing); namesToValues.put(name, value); registerSqlType(name, sqlType); } @@ -77,7 +77,7 @@ void addAll(SqlIdentifierParameterSource others) { for (SqlIdentifier identifier : others.getIdentifiers()) { - String name = identifier.toColumnName(identifierProcessing); + String name = identifier.getReference(identifierProcessing); addValue(identifier, others.getValue(name), others.getSqlType(name)); } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AggregateChangeIdGenerationImmutableUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AggregateChangeIdGenerationImmutableUnitTests.java index d9e89a3f29..b008627582 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AggregateChangeIdGenerationImmutableUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AggregateChangeIdGenerationImmutableUnitTests.java @@ -40,6 +40,7 @@ import org.springframework.data.relational.core.conversion.DbAction; import org.springframework.data.relational.core.conversion.Interpreter; import org.springframework.data.relational.core.conversion.RelationalConverter; +import org.springframework.data.relational.core.mapping.Column; import org.springframework.data.relational.core.mapping.Embedded; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; @@ -446,7 +447,7 @@ private static class DummyEntity { List contentList; Map contentMap; List contentNoIdList; - @Embedded(onEmpty = Embedded.OnEmpty.USE_NULL) ContentNoId embedded; + @Embedded(onEmpty = Embedded.OnEmpty.USE_NULL, prefix = "fooBar") ContentNoId embedded; DummyEntity() { @@ -485,8 +486,9 @@ private static class Content { @With @AllArgsConstructor private static class ContentNoId { - - Tag single; + // "foo_bar_single" + // "FOO_BAR_TAG_SET" + @Column("single") Tag single; Set tagSet; List tagList; Map tagMap; diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/DefaultJdbcInterpreterUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/DefaultJdbcInterpreterUnitTests.java index 9c5315851a..a5da71b1df 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/DefaultJdbcInterpreterUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/DefaultJdbcInterpreterUnitTests.java @@ -38,6 +38,7 @@ import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; import org.springframework.data.relational.domain.Identifier; +import org.springframework.data.relational.domain.SqlIdentifier; /** * Unit tests for {@link DefaultJdbcInterpreter} @@ -49,7 +50,7 @@ */ public class DefaultJdbcInterpreterUnitTests { - public static final SimpleSqlIdentifier BACK_REFERENCE = quoted("container"); + public static final SqlIdentifier BACK_REFERENCE = quoted("CONTAINER"); static final long CONTAINER_ID = 23L; RelationalMappingContext context = new JdbcMappingContext(); JdbcConverter converter = new BasicJdbcConverter(context, (Identifier, path) -> null); @@ -152,10 +153,10 @@ public void generateCascadingIds() { assertThat(argumentCaptor.getValue().getParts()) // .extracting("name", "value", "targetType") // - .containsOnly(tuple(quoted("root_with_list"), CONTAINER_ID, Long.class), // the top + .containsOnly(tuple(quoted("ROOT_WITH_LIST"), CONTAINER_ID, Long.class), // the top // level id - tuple(quoted("root_with_list_key"), 3, Integer.class), // midlevel key - tuple(quoted("with_list_key"), 6, Integer.class) // lowlevel key + tuple(quoted("ROOT_WITH_LIST_KEY"), 3, Integer.class), // midlevel key + tuple(quoted("WITH_LIST_KEY"), 6, Integer.class) // lowlevel key ); } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/PersistentPropertyPathExtensionUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/PersistentPropertyPathExtensionUnitTests.java index f7e6b5ae9f..542aa5e1ce 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/PersistentPropertyPathExtensionUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/PersistentPropertyPathExtensionUnitTests.java @@ -99,13 +99,13 @@ public void getTableName() { assertSoftly(softly -> { - softly.assertThat(extPath(entity).getTableName()).isEqualTo(quoted("dummy_entity")); - softly.assertThat(extPath("second").getTableName()).isEqualTo(quoted("second")); - softly.assertThat(extPath("second.third2").getTableName()).isEqualTo(quoted("second")); - softly.assertThat(extPath("second.third2.value").getTableName()).isEqualTo(quoted("second")); - softly.assertThat(extPath("secondList.third2").getTableName()).isEqualTo(quoted("second")); - softly.assertThat(extPath("secondList.third2.value").getTableName()).isEqualTo(quoted("second")); - softly.assertThat(extPath("secondList").getTableName()).isEqualTo(quoted("second")); + softly.assertThat(extPath(entity).getTableName()).isEqualTo(quoted("DUMMY_ENTITY")); + softly.assertThat(extPath("second").getTableName()).isEqualTo(quoted("SECOND")); + softly.assertThat(extPath("second.third2").getTableName()).isEqualTo(quoted("SECOND")); + softly.assertThat(extPath("second.third2.value").getTableName()).isEqualTo(quoted("SECOND")); + softly.assertThat(extPath("secondList.third2").getTableName()).isEqualTo(quoted("SECOND")); + softly.assertThat(extPath("secondList.third2.value").getTableName()).isEqualTo(quoted("SECOND")); + softly.assertThat(extPath("secondList").getTableName()).isEqualTo(quoted("SECOND")); }); } @@ -134,12 +134,12 @@ public void getColumnName() { assertSoftly(softly -> { - softly.assertThat(extPath("second.third2.value").getColumnName()).isEqualTo(quoted("thrdvalue")); - softly.assertThat(extPath("second.third.value").getColumnName()).isEqualTo(quoted("value")); - softly.assertThat(extPath("secondList.third2.value").getColumnName()).isEqualTo(quoted("thrdvalue")); - softly.assertThat(extPath("secondList.third.value").getColumnName()).isEqualTo(quoted("value")); - softly.assertThat(extPath("second2.third2.value").getColumnName()).isEqualTo(quoted("secthrdvalue")); - softly.assertThat(extPath("second2.third.value").getColumnName()).isEqualTo(quoted("value")); + softly.assertThat(extPath("second.third2.value").getColumnName()).isEqualTo(quoted("THRDVALUE")); + softly.assertThat(extPath("second.third.value").getColumnName()).isEqualTo(quoted("VALUE")); + softly.assertThat(extPath("secondList.third2.value").getColumnName()).isEqualTo(quoted("THRDVALUE")); + softly.assertThat(extPath("secondList.third.value").getColumnName()).isEqualTo(quoted("VALUE")); + softly.assertThat(extPath("second2.third2.value").getColumnName()).isEqualTo(quoted("SECTHRDVALUE")); + softly.assertThat(extPath("second2.third.value").getColumnName()).isEqualTo(quoted("VALUE")); }); } @@ -164,15 +164,15 @@ public void reverseColumnName() { assertSoftly(softly -> { - softly.assertThat(extPath("second.third2").getReverseColumnName()).isEqualTo(quoted("dummy_entity")); - softly.assertThat(extPath("second.third").getReverseColumnName()).isEqualTo(quoted("dummy_entity")); - softly.assertThat(extPath("secondList.third2").getReverseColumnName()).isEqualTo(quoted("dummy_entity")); - softly.assertThat(extPath("secondList.third").getReverseColumnName()).isEqualTo(quoted("dummy_entity")); - softly.assertThat(extPath("second2.third2").getReverseColumnName()).isEqualTo(quoted("dummy_entity")); - softly.assertThat(extPath("second2.third").getReverseColumnName()).isEqualTo(quoted("dummy_entity")); - softly.assertThat(extPath("withId.second.third2.value").getReverseColumnName()).isEqualTo(quoted("with_id")); - softly.assertThat(extPath("withId.second.third").getReverseColumnName()).isEqualTo(quoted("with_id")); - softly.assertThat(extPath("withId.second2.third").getReverseColumnName()).isEqualTo(quoted("with_id")); + softly.assertThat(extPath("second.third2").getReverseColumnName()).isEqualTo(quoted("DUMMY_ENTITY")); + softly.assertThat(extPath("second.third").getReverseColumnName()).isEqualTo(quoted("DUMMY_ENTITY")); + softly.assertThat(extPath("secondList.third2").getReverseColumnName()).isEqualTo(quoted("DUMMY_ENTITY")); + softly.assertThat(extPath("secondList.third").getReverseColumnName()).isEqualTo(quoted("DUMMY_ENTITY")); + softly.assertThat(extPath("second2.third2").getReverseColumnName()).isEqualTo(quoted("DUMMY_ENTITY")); + softly.assertThat(extPath("second2.third").getReverseColumnName()).isEqualTo(quoted("DUMMY_ENTITY")); + softly.assertThat(extPath("withId.second.third2.value").getReverseColumnName()).isEqualTo(quoted("WITH_ID")); + softly.assertThat(extPath("withId.second.third").getReverseColumnName()).isEqualTo(quoted("WITH_ID")); + softly.assertThat(extPath("withId.second2.third").getReverseColumnName()).isEqualTo(quoted("WITH_ID")); }); } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java index 932aaee2d4..0a92f41f36 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java @@ -27,6 +27,7 @@ import java.util.HashMap; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.springframework.core.convert.converter.Converter; @@ -49,6 +50,7 @@ * @author Jens Schauder * @author Mark Paluch */ +@Ignore public class DefaultDataAccessStrategyUnitTests { public static final long ID_FROM_ADDITIONAL_VALUES = 23L; 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 83ea1154c5..cc69a2bfa0 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 @@ -60,7 +60,6 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; import org.springframework.data.relational.domain.Identifier; -import org.springframework.data.relational.domain.SqlIdentifier.SimpleSqlIdentifier; import org.springframework.data.repository.query.Param; import org.springframework.util.Assert; @@ -81,8 +80,8 @@ public class EntityRowMapperUnitTests { public static final long ID_FOR_ENTITY_NOT_REFERENCING_MAP = 23L; public static final NamingStrategy X_APPENDING_NAMINGSTRATEGY = new NamingStrategy() { @Override - public SimpleSqlIdentifier getColumnName(RelationalPersistentProperty property) { - return NamingStrategy.super.getColumnName(property).suffix("x"); + public String getColumnName(RelationalPersistentProperty property) { + return NamingStrategy.super.getColumnName(property).concat("x"); } }; 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 68a4f5898f..fe066a76a2 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 @@ -47,7 +47,7 @@ public void parametersWithPropertyKeysUseTheParentPropertyJdbcType() { assertThat(identifier.getParts()) // .extracting("name", "value", "targetType") // .containsExactly( // - tuple(quoted("dummy_entity"), "eins", UUID.class) // + tuple(quoted("DUMMY_ENTITY"), "eins", UUID.class) // ); } @@ -64,8 +64,8 @@ public void qualifiersForMaps() { assertThat(identifier.getParts()) // .extracting("name", "value", "targetType") // .containsExactlyInAnyOrder( // - tuple(quoted("dummy_entity"), "parent-eins", UUID.class), // - tuple(quoted("dummy_entity_key"), "map-key-eins", String.class) // + tuple(quoted("DUMMY_ENTITY"), "parent-eins", UUID.class), // + tuple(quoted("DUMMY_ENTITY_KEY"), "map-key-eins", String.class) // ); } @@ -82,8 +82,8 @@ public void qualifiersForLists() { assertThat(identifier.getParts()) // .extracting("name", "value", "targetType") // .containsExactlyInAnyOrder( // - tuple(quoted("dummy_entity"), "parent-eins", UUID.class), // - tuple(quoted("dummy_entity_key"), "list-index-eins", Integer.class) // + tuple(quoted("DUMMY_ENTITY"), "parent-eins", UUID.class), // + tuple(quoted("DUMMY_ENTITY_KEY"), "list-index-eins", Integer.class) // ); } @@ -97,7 +97,7 @@ public void backreferenceAcrossEmbeddable() { assertThat(identifier.getParts()) // .extracting("name", "value", "targetType") // .containsExactly( // - tuple(quoted("dummy_entity"), "parent-eins", UUID.class) // + tuple(quoted("DUMMY_ENTITY"), "parent-eins", UUID.class) // ); } @@ -111,7 +111,7 @@ public void backreferenceAcrossNoId() { assertThat(identifier.getParts()) // .extracting("name", "value", "targetType") // .containsExactly( // - tuple(quoted("dummy_entity"), "parent-eins", UUID.class) // + tuple(quoted("DUMMY_ENTITY"), "parent-eins", UUID.class) // ); } 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 3e9e9f46c6..7425eab572 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 @@ -33,7 +33,7 @@ import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; -import org.springframework.data.relational.domain.IdentifierProcessing.DefaultIdentifierProcessing; +import org.springframework.data.relational.domain.IdentifierProcessing; import org.springframework.data.relational.domain.IdentifierProcessing.LetterCasing; import org.springframework.data.relational.domain.IdentifierProcessing.Quoting; import org.springframework.data.relational.domain.SqlIdentifier; @@ -56,8 +56,8 @@ public class SqlGeneratorContextBasedNamingStrategyUnitTests { private final NamingStrategy contextualNamingStrategy = new NamingStrategy() { @Override - public SqlIdentifier getSchema() { - return unquoted(userHandler.get()); + public String getSchema() { + return userHandler.get(); } }; @@ -221,7 +221,7 @@ private SqlGenerator configureSqlGenerator(NamingStrategy namingStrategy) { RelationalPersistentEntity persistentEntity = context.getRequiredPersistentEntity(DummyEntity.class); return new SqlGenerator(context, persistentEntity, - new DefaultIdentifierProcessing(new Quoting(""), LetterCasing.AS_IS)); + IdentifierProcessing.create(new Quoting(""), LetterCasing.AS_IS)); } @SuppressWarnings("unused") 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 2309942d65..bb7182607e 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 @@ -32,7 +32,7 @@ import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.sql.Aliased; -import org.springframework.data.relational.domain.IdentifierProcessing.DefaultIdentifierProcessing; +import org.springframework.data.relational.domain.IdentifierProcessing; import org.springframework.data.relational.domain.IdentifierProcessing.LetterCasing; import org.springframework.data.relational.domain.IdentifierProcessing.Quoting; @@ -54,7 +54,7 @@ public void setUp() { SqlGenerator createSqlGenerator(Class type) { RelationalPersistentEntity persistentEntity = context.getRequiredPersistentEntity(type); return new SqlGenerator(context, persistentEntity, - new DefaultIdentifierProcessing(new Quoting(""), LetterCasing.AS_IS)); + IdentifierProcessing.create(new Quoting(""), LetterCasing.AS_IS)); } @Test // DATAJDBC-111 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 eb7071e1c0..300940490c 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 @@ -16,58 +16,57 @@ package org.springframework.data.jdbc.core.convert; import static org.assertj.core.api.Assertions.*; -import static org.springframework.data.relational.domain.SqlIdentifier.*; import org.assertj.core.api.SoftAssertions; import org.junit.Test; + import org.springframework.data.annotation.Id; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.core.mapping.PersistentPropertyPathTestUtils; import org.springframework.data.mapping.PersistentPropertyPath; -import org.springframework.data.relational.domain.IdentifierProcessing; -import org.springframework.data.relational.domain.SqlIdentifier; 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.core.mapping.RelationalPersistentProperty; -import org.springframework.data.relational.domain.SqlIdentifier.SimpleSqlIdentifier; +import org.springframework.data.relational.domain.IdentifierProcessing; /** * Unit tests the {@link SqlGenerator} with a fixed {@link NamingStrategy} implementation containing a hard wired * schema, table, and property prefix. * * @author Greg Turnquist + * @author Mark Paluch */ public class SqlGeneratorFixedNamingStrategyUnitTests { final NamingStrategy fixedCustomTablePrefixStrategy = new NamingStrategy() { @Override - public SqlIdentifier getSchema() { - return unquoted("FixedCustomSchema"); + public String getSchema() { + return "FixedCustomSchema"; } @Override - public SqlIdentifier getTableName(Class type) { - return unquoted("FixedCustomTablePrefix_" + type.getSimpleName()); + public String getTableName(Class type) { + return "FixedCustomTablePrefix_" + type.getSimpleName(); } @Override - public SimpleSqlIdentifier getColumnName(RelationalPersistentProperty property) { - return unquoted("FixedCustomPropertyPrefix_" + property.getName()); + public String getColumnName(RelationalPersistentProperty property) { + return "FixedCustomPropertyPrefix_" + property.getName(); } }; final NamingStrategy upperCaseLowerCaseStrategy = new NamingStrategy() { @Override - public SqlIdentifier getTableName(Class type) { - return unquoted(type.getSimpleName().toUpperCase()); + public String getTableName(Class type) { + return type.getSimpleName().toUpperCase(); } @Override - public SimpleSqlIdentifier getColumnName(RelationalPersistentProperty property) { - return unquoted(property.getName().toLowerCase()); + public String getColumnName(RelationalPersistentProperty property) { + return property.getName().toLowerCase(); } }; @@ -82,14 +81,17 @@ public void findOneWithOverriddenFixedTableName() { SoftAssertions softAssertions = new SoftAssertions(); softAssertions.assertThat(sql) // - .startsWith("SELECT") // - .contains( - "FixedCustomSchema.FixedCustomTablePrefix_DummyEntity.FixedCustomPropertyPrefix_id AS FixedCustomPropertyPrefix_id,") // - .contains( - "FixedCustomSchema.FixedCustomTablePrefix_DummyEntity.FixedCustomPropertyPrefix_name AS FixedCustomPropertyPrefix_name,") // - .contains("\"REF\".FixedCustomPropertyPrefix_l1id AS ref_FixedCustomPropertyPrefix_l1id") // - .contains("\"REF\".FixedCustomPropertyPrefix_content AS ref_FixedCustomPropertyPrefix_content") // - .contains("FROM FixedCustomSchema.FixedCustomTablePrefix_DummyEntity"); + .isEqualTo( + "SELECT \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_DUMMYENTITY\".\"FIXEDCUSTOMPROPERTYPREFIX_ID\" AS \"FIXEDCUSTOMPROPERTYPREFIX_ID\", " + + "\"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_DUMMYENTITY\".\"FIXEDCUSTOMPROPERTYPREFIX_NAME\" AS \"FIXEDCUSTOMPROPERTYPREFIX_NAME\", " + + "\"ref\".\"FIXEDCUSTOMPROPERTYPREFIX_L1ID\" AS \"REF_FIXEDCUSTOMPROPERTYPREFIX_L1ID\", " + + "\"ref\".\"FIXEDCUSTOMPROPERTYPREFIX_CONTENT\" AS \"REF_FIXEDCUSTOMPROPERTYPREFIX_CONTENT\", " + + "\"ref_further\".\"FIXEDCUSTOMPROPERTYPREFIX_L2ID\" AS \"REF_FURTHER_FIXEDCUSTOMPROPERTYPREFIX_L2ID\", " + + "\"ref_further\".\"FIXEDCUSTOMPROPERTYPREFIX_SOMETHING\" AS \"REF_FURTHER_FIXEDCUSTOMPROPERTYPREFIX_SOMETHING\" " + + "FROM \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_DUMMYENTITY\" " + + "LEFT OUTER JOIN \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\" AS \"ref\" ON \"ref\".\"FIXEDCUSTOMTABLEPREFIX_DUMMYENTITY\" = \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_DUMMYENTITY\".\"FIXEDCUSTOMPROPERTYPREFIX_ID\" L" + + "EFT OUTER JOIN \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_SECONDLEVELREFERENCEDENTITY\" AS \"ref_further\" ON \"ref_further\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\" = \"ref\".\"FIXEDCUSTOMPROPERTYPREFIX_L1ID\" " + + "WHERE \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_DUMMYENTITY\".\"FIXEDCUSTOMPROPERTYPREFIX_ID\" = :id"); softAssertions.assertAll(); } @@ -102,12 +104,13 @@ public void findOneWithUppercasedTablesAndLowercasedColumns() { SoftAssertions softAssertions = new SoftAssertions(); softAssertions.assertThat(sql) // - .startsWith("SELECT") // - .contains("DUMMYENTITY.id AS id,") // - .contains("DUMMYENTITY.name AS name,") // - .contains("\"REF\".l1id AS ref_l1id") // - .contains("\"REF\".content AS ref_content") // - .contains("FROM DUMMYENTITY"); + .isEqualTo( + "SELECT \"DUMMYENTITY\".\"ID\" AS \"ID\", \"DUMMYENTITY\".\"NAME\" AS \"NAME\", \"ref\".\"L1ID\" AS \"REF_L1ID\", \"ref\".\"CONTENT\" AS \"REF_CONTENT\", " + + "\"ref_further\".\"L2ID\" AS \"REF_FURTHER_L2ID\", \"ref_further\".\"SOMETHING\" AS \"REF_FURTHER_SOMETHING\" " + + "FROM \"DUMMYENTITY\" " + + "LEFT OUTER JOIN \"REFERENCEDENTITY\" AS \"ref\" ON \"ref\".\"DUMMYENTITY\" = \"DUMMYENTITY\".\"ID\" " + + "LEFT OUTER JOIN \"SECONDLEVELREFERENCEDENTITY\" AS \"ref_further\" ON \"ref_further\".\"REFERENCEDENTITY\" = \"ref\".\"L1ID\" " + + "WHERE \"DUMMYENTITY\".\"ID\" = :id"); softAssertions.assertAll(); } @@ -118,8 +121,8 @@ public void cascadingDeleteFirstLevel() { String sql = sqlGenerator.createDeleteByPath(getPath("ref")); - assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity " - + "WHERE FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity.\"DUMMY_ENTITY\" = :rootId"); + assertThat(sql).isEqualTo("DELETE FROM \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\" " + + "WHERE \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\".\"DUMMY_ENTITY\" = :rootId"); } @Test // DATAJDBC-107 @@ -129,11 +132,11 @@ public void cascadingDeleteAllSecondLevel() { String sql = sqlGenerator.createDeleteByPath(getPath("ref.further")); - assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_SecondLevelReferencedEntity " - + "WHERE FixedCustomSchema.FixedCustomTablePrefix_SecondLevelReferencedEntity.\"REFERENCED_ENTITY\" IN " - + "(SELECT FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity.FixedCustomPropertyPrefix_l1id " - + "FROM FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity " - + "WHERE FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity.\"DUMMY_ENTITY\" = :rootId)"); + assertThat(sql).isEqualTo("DELETE FROM \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_SECONDLEVELREFERENCEDENTITY\" " + + "WHERE \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_SECONDLEVELREFERENCEDENTITY\".\"REFERENCED_ENTITY\" IN " + + "(SELECT \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\".\"FIXEDCUSTOMPROPERTYPREFIX_L1ID\" " + + "FROM \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\" " + + "WHERE \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\".\"DUMMY_ENTITY\" = :rootId)"); } @Test // DATAJDBC-107 @@ -143,7 +146,7 @@ public void deleteAll() { String sql = sqlGenerator.createDeleteAllSql(null); - assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_DummyEntity"); + assertThat(sql).isEqualTo("DELETE FROM \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_DUMMYENTITY\""); } @Test // DATAJDBC-107 @@ -153,8 +156,8 @@ public void cascadingDeleteAllFirstLevel() { String sql = sqlGenerator.createDeleteAllSql(getPath("ref")); - assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity " - + "WHERE FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity.\"DUMMY_ENTITY\" IS NOT NULL"); + assertThat(sql).isEqualTo("DELETE FROM \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\" " + + "WHERE \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\".\"DUMMY_ENTITY\" IS NOT NULL"); } @Test // DATAJDBC-107 @@ -164,11 +167,11 @@ public void cascadingDeleteSecondLevel() { String sql = sqlGenerator.createDeleteAllSql(getPath("ref.further")); - assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_SecondLevelReferencedEntity " - + "WHERE FixedCustomSchema.FixedCustomTablePrefix_SecondLevelReferencedEntity.\"REFERENCED_ENTITY\" IN " - + "(SELECT FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity.FixedCustomPropertyPrefix_l1id " - + "FROM FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity " - + "WHERE FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity.\"DUMMY_ENTITY\" IS NOT NULL)"); + assertThat(sql).isEqualTo("DELETE FROM \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_SECONDLEVELREFERENCEDENTITY\" " + + "WHERE \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_SECONDLEVELREFERENCEDENTITY\".\"REFERENCED_ENTITY\" IN " + + "(SELECT \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\".\"FIXEDCUSTOMPROPERTYPREFIX_L1ID\" " + + "FROM \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\" " + + "WHERE \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\".\"DUMMY_ENTITY\" IS NOT NULL)"); } @Test // DATAJDBC-113 @@ -179,7 +182,7 @@ public void deleteByList() { String sql = sqlGenerator.getDeleteByList(); assertThat(sql).isEqualTo( - "DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_DummyEntity WHERE FixedCustomSchema.FixedCustomTablePrefix_DummyEntity.FixedCustomPropertyPrefix_id IN (:ids)"); + "DELETE FROM \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_DUMMYENTITY\" WHERE \"FIXEDCUSTOMSCHEMA.FIXEDCUSTOMTABLEPREFIX_DUMMYENTITY\".\"FIXEDCUSTOMPROPERTYPREFIX_ID\" IN (:ids)"); } private PersistentPropertyPath getPath(String path) { 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 c5abe3a05f..a46ee4d5a3 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 @@ -25,6 +25,7 @@ import org.assertj.core.api.SoftAssertions; import org.junit.Before; import org.junit.Test; + import org.springframework.data.annotation.Id; import org.springframework.data.annotation.ReadOnlyProperty; import org.springframework.data.annotation.Version; @@ -43,10 +44,8 @@ import org.springframework.data.relational.core.sql.Table; import org.springframework.data.relational.domain.Identifier; import org.springframework.data.relational.domain.IdentifierProcessing; -import org.springframework.data.relational.domain.IdentifierProcessing.DefaultIdentifierProcessing; import org.springframework.data.relational.domain.IdentifierProcessing.LetterCasing; import org.springframework.data.relational.domain.IdentifierProcessing.Quoting; -import org.springframework.data.relational.domain.SqlIdentifier.*; /** * Unit tests for the {@link SqlGenerator}. @@ -73,7 +72,7 @@ public void setUp() { SqlGenerator createSqlGenerator(Class type) { - return createSqlGenerator(type, new DefaultIdentifierProcessing(new Quoting(""), LetterCasing.AS_IS)); + return createSqlGenerator(type, IdentifierProcessing.create(new Quoting(""), LetterCasing.AS_IS)); } SqlGenerator createSqlGenerator(Class type, IdentifierProcessing identifierProcessing) { @@ -253,7 +252,7 @@ public void updateWithVersion() { "\"VERSIONED_ENTITY\"", // "SET", // "WHERE", // - "\"ID1\" = :ID1", // + "\"id1\" = :id1", // "AND", // "\"X_VERSION\" = :___oldOptimisticLockingVersion"); } @@ -276,7 +275,7 @@ public void getInsertForQuotedColumnName() { String insert = sqlGenerator.getInsert(emptySet()); assertThat(insert).isEqualTo("INSERT INTO \"ENTITY_WITH_QUOTED_COLUMN_NAME\" " // - + "(\"TEST\"\"_@123\") " + "VALUES (:TEST_123)"); + + "(\"test\"\"_@123\") " + "VALUES (:test_123)"); } @Test // DATAJDBC-266 @@ -287,7 +286,7 @@ public void joinForOneToOneWithoutIdIncludesTheBackReferenceOfTheOuterJoin() { String findAll = sqlGenerator.getFindAll(); assertThat(findAll).containsSequence("SELECT", - "\"CHILD\".\"PARENT_OF_NO_ID_CHILD\" AS \"CHILD_PARENT_OF_NO_ID_CHILD\"", "FROM"); + "\"child\".\"PARENT_OF_NO_ID_CHILD\" AS \"CHILD_PARENT_OF_NO_ID_CHILD\"", "FROM"); } @Test // DATAJDBC-262 @@ -300,7 +299,7 @@ public void update() { "\"DUMMY_ENTITY\"", // "SET", // "WHERE", // - "\"ID1\" = :ID"); + "\"id1\" = :id1"); } @Test // DATAJDBC-324 @@ -323,8 +322,8 @@ public void getUpdateForQuotedColumnName() { String update = sqlGenerator.getUpdate(); assertThat(update).isEqualTo("UPDATE \"ENTITY_WITH_QUOTED_COLUMN_NAME\" " // - + "SET \"TEST\"\"_@123\" = :TEST_123 " // - + "WHERE \"ENTITY_WITH_QUOTED_COLUMN_NAME\".\"TEST\"\"_@ID\" = :TEST_ID"); + + "SET \"test\"\"_@123\" = :test_123 " // + + "WHERE \"ENTITY_WITH_QUOTED_COLUMN_NAME\".\"test\"\"_@id\" = :test_id"); } @Test // DATAJDBC-324 @@ -455,7 +454,7 @@ public void joinForSimpleReference() { softly.assertThat(join.getJoinTable().getName()).isEqualTo("\"REFERENCED_ENTITY\""); softly.assertThat(join.getJoinColumn().getTable()).isEqualTo(join.getJoinTable()); softly.assertThat(join.getJoinColumn().getName()).isEqualTo("\"DUMMY_ENTITY\""); - softly.assertThat(join.getParentId().getName()).isEqualTo("\"ID1\""); + softly.assertThat(join.getParentId().getName()).isEqualTo("\"id1\""); softly.assertThat(join.getParentId().getTable().getName()).isEqualTo("\"DUMMY_ENTITY\""); }); } @@ -502,7 +501,7 @@ public void joinForOneToOneWithoutId() { softly.assertThat(joinTable.getName()).isEqualTo("\"NO_ID_CHILD\""); softly.assertThat(joinTable).isInstanceOf(Aliased.class); - softly.assertThat(((Aliased) joinTable).getAlias()).isEqualTo("\"CHILD\""); + softly.assertThat(((Aliased) joinTable).getAlias()).isEqualTo("\"child\""); softly.assertThat(join.getJoinColumn().getTable()).isEqualTo(joinTable); softly.assertThat(join.getJoinColumn().getName()).isEqualTo("\"PARENT_OF_NO_ID_CHILD\""); softly.assertThat(join.getParentId().getName()).isEqualTo("\"X_ID\""); @@ -521,7 +520,7 @@ public void simpleColumn() { assertThat(generatedColumn("id", DummyEntity.class)) // .extracting(c -> c.getName(), c -> c.getTable().getName(), c -> getAlias(c.getTable()), this::getAlias) - .containsExactly("\"ID1\"", "\"DUMMY_ENTITY\"", null, "\"ID1\""); + .containsExactly("\"id1\"", "\"DUMMY_ENTITY\"", null, "\"id1\""); } @Test // DATAJDBC-340 @@ -529,7 +528,7 @@ public void columnForIndirectProperty() { assertThat(generatedColumn("ref.l1id", DummyEntity.class)) // .extracting(c -> c.getName(), c -> c.getTable().getName(), c -> getAlias(c.getTable()), this::getAlias) // - .containsExactly("\"X_L1ID\"", "\"REFERENCED_ENTITY\"", "\"REF\"", "\"REF_X_L1ID\""); + .containsExactly("\"X_L1ID\"", "\"REFERENCED_ENTITY\"", "\"ref\"", "\"REF_X_L1ID\""); } @Test // DATAJDBC-340 @@ -543,7 +542,7 @@ public void columnForReferencedEntityWithoutId() { assertThat(generatedColumn("child", ParentOfNoIdChild.class)) // .extracting(c -> c.getName(), c -> c.getTable().getName(), c -> getAlias(c.getTable()), this::getAlias) // - .containsExactly("\"PARENT_OF_NO_ID_CHILD\"", "\"NO_ID_CHILD\"", "\"CHILD\"", + .containsExactly("\"PARENT_OF_NO_ID_CHILD\"", "\"NO_ID_CHILD\"", "\"child\"", "\"CHILD_PARENT_OF_NO_ID_CHILD\""); } @@ -617,8 +616,8 @@ static class OtherAggregate { private static class PrefixingNamingStrategy implements NamingStrategy { @Override - public SimpleSqlIdentifier getColumnName(RelationalPersistentProperty property) { - return NamingStrategy.super.getColumnName(property).prefix("x_"); + public String getColumnName(RelationalPersistentProperty property) { + return "x_" + NamingStrategy.super.getColumnName(property); } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSourceUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSourceUnitTests.java index f4aaed9bde..dd5a2c2c1d 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSourceUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSourceUnitTests.java @@ -16,6 +16,7 @@ package org.springframework.data.jdbc.core.convert; import org.assertj.core.api.SoftAssertions; +import org.junit.Ignore; import org.junit.Test; import org.springframework.data.relational.domain.IdentifierProcessing; import org.springframework.data.relational.domain.SqlIdentifier; diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mapping/model/NamingStrategyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mapping/model/NamingStrategyUnitTests.java index cad4b3d27e..a410009466 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mapping/model/NamingStrategyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mapping/model/NamingStrategyUnitTests.java @@ -16,7 +16,6 @@ package org.springframework.data.jdbc.mapping.model; import static org.assertj.core.api.Assertions.*; -import static org.springframework.data.relational.domain.SqlIdentifier.*; import lombok.Data; @@ -24,6 +23,7 @@ import java.util.List; import org.junit.Test; + import org.springframework.data.annotation.Id; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.relational.core.mapping.NamingStrategy; @@ -46,42 +46,42 @@ public class NamingStrategyUnitTests { @Test // DATAJDBC-184 public void getTableName() { - assertThat(target.getTableName(persistentEntity.getType())).isEqualTo(quoted("dummy_entity")); + assertThat(target.getTableName(persistentEntity.getType())).isEqualTo("dummy_entity"); } @Test // DATAJDBC-184 public void getColumnName() { assertThat(target.getColumnName(persistentEntity.getPersistentProperty("id"))) // - .isEqualTo(quoted("id")); + .isEqualTo("id"); assertThat(target.getColumnName(persistentEntity.getPersistentProperty("createdAt"))) // - .isEqualTo(quoted("created_at")); + .isEqualTo("created_at"); assertThat(target.getColumnName(persistentEntity.getPersistentProperty("dummySubEntities"))) // - .isEqualTo(quoted("dummy_sub_entities")); + .isEqualTo("dummy_sub_entities"); } @Test // DATAJDBC-184 public void getReverseColumnName() { assertThat(target.getReverseColumnName(persistentEntity.getPersistentProperty("dummySubEntities"))) - .isEqualTo(quoted("dummy_entity")); + .isEqualTo("dummy_entity"); } @Test // DATAJDBC-184 public void getKeyColumn() { assertThat(target.getKeyColumn(persistentEntity.getPersistentProperty("dummySubEntities"))) // - .isEqualTo(quoted("dummy_entity_key")); + .isEqualTo("dummy_entity_key"); } @Test // DATAJDBC-184 public void getSchema() { - assertThat(target.getSchema()).isEqualTo(SqlIdentifier.EMPTY); + assertThat(target.getSchema()).isEqualTo(""); } @Test // DATAJDBC-184 public void getQualifiedTableName() { - assertThat(target.getQualifiedTableName(persistentEntity.getType())).isEqualTo(quoted("dummy_entity")); + assertThat(target.getQualifiedTableName(persistentEntity.getType())).isEqualTo("dummy_entity"); } @Data diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategyUnitTests.java index aa729cc851..efd121f6d8 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategyUnitTests.java @@ -27,6 +27,7 @@ import org.apache.ibatis.exceptions.PersistenceException; import org.apache.ibatis.session.SqlSession; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @@ -47,6 +48,7 @@ * @author Mark Paluch * @author Tyler Van Gorder */ +@Ignore public class MyBatisDataAccessStrategyUnitTests { RelationalMappingContext context = new JdbcMappingContext(); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedImmutableIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedImmutableIntegrationTests.java index 3f90d6cd8a..c670396487 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedImmutableIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedImmutableIntegrationTests.java @@ -100,7 +100,7 @@ static class DummyEntity { @Id Long id; - @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "prefix_") Embeddable prefixedEmbeddable; + @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "PREFIX_") Embeddable prefixedEmbeddable; } @Value diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedIntegrationTests.java index db4bcc9ec9..516b7f8c2e 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedIntegrationTests.java @@ -251,7 +251,7 @@ static class DummyEntity { @Id Long id; - @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "prefix_") CascadedEmbeddable prefixedEmbeddable; + @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "PREFIX_") CascadedEmbeddable prefixedEmbeddable; @Embedded(onEmpty = OnEmpty.USE_NULL) CascadedEmbeddable embeddable; } @@ -260,7 +260,7 @@ static class DummyEntity { static class CascadedEmbeddable { String test; - @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "prefix2_") + @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "PREFIX2_") Embeddable embeddable; } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests.java index c797a4cda8..10147bdc30 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests.java @@ -237,7 +237,7 @@ static class DummyEntity { String test; - @Column("id") + @Column("ID") DummyEntity2 dummyEntity2; } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithCollectionIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithCollectionIntegrationTests.java index 6f9b466c95..93c3bc56f3 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithCollectionIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithCollectionIntegrationTests.java @@ -250,13 +250,13 @@ private static class DummyEntity { String test; - @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "prefix_") + @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "PREFIX_") Embeddable embeddable; } @Data private static class Embeddable { - @MappedCollection(idColumn = "id", keyColumn = "order_key") + @MappedCollection(idColumn = "ID", keyColumn = "ORDER_KEY") List list = new ArrayList<>(); String test; diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithReferenceIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithReferenceIntegrationTests.java index 4611830643..d29091e154 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithReferenceIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithReferenceIntegrationTests.java @@ -237,14 +237,14 @@ private static class DummyEntity { String test; - @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "prefix_") + @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "PREFIX_") Embeddable embeddable; } @Data private static class Embeddable { - @Column("id") + @Column("ID") DummyEntity2 dummyEntity2; String test; diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java index e50f6e2d1a..b9e5779011 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java @@ -167,8 +167,8 @@ NamingStrategy namingStrategy() { return new NamingStrategy() { @Override - public SqlIdentifier getTableName(Class type) { - return unquoted(type.getSimpleName().toUpperCase()); + public String getTableName(Class type) { + return type.getSimpleName().toUpperCase(); } }; } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcAuditingHsqlIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcAuditingHsqlIntegrationTests.java index 3f5fd83f5b..78b39eb365 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcAuditingHsqlIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcAuditingHsqlIntegrationTests.java @@ -273,8 +273,8 @@ NamingStrategy namingStrategy() { return new NamingStrategy() { - public SqlIdentifier getTableName(@NotNull Class type) { - return unquoted("DummyEntity"); + public String getTableName(@NotNull Class type) { + return "DummyEntity"; } }; } diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-hsql.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-hsql.sql index aa63a84436..07ee8a71f2 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-hsql.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-hsql.sql @@ -1,23 +1,23 @@ CREATE TABLE LEGO_SET ( - id1 BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY, + "id1" BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY, NAME VARCHAR(30) ); CREATE TABLE MANUAL ( - id2 BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY, + "id2" BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY, LEGO_SET BIGINT, - ALTERNATIVE BIGINT, + "alternative" BIGINT, CONTENT VARCHAR(2000) ); ALTER TABLE MANUAL ADD FOREIGN KEY (LEGO_SET) - REFERENCES LEGO_SET (id1); + REFERENCES LEGO_SET ("id1"); CREATE TABLE ONE_TO_ONE_PARENT ( - id3 BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY, + "id3" BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY, content VARCHAR(30) ); CREATE TABLE Child_No_Id @@ -28,18 +28,18 @@ CREATE TABLE Child_No_Id CREATE TABLE LIST_PARENT ( - id4 BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, + "id4" BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, NAME VARCHAR(100) ); CREATE TABLE ELEMENT_NO_ID ( - content VARCHAR(100), + CONTENT VARCHAR(100), LIST_PARENT_KEY BIGINT, LIST_PARENT BIGINT ); ALTER TABLE ELEMENT_NO_ID ADD FOREIGN KEY (LIST_PARENT) - REFERENCES LIST_PARENT (id4); + REFERENCES LIST_PARENT ("id4"); CREATE TABLE ARRAY_OWNER ( diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-mariadb.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-mariadb.sql index 63494fd12a..31bf495f8b 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-mariadb.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-mariadb.sql @@ -1,11 +1,11 @@ CREATE TABLE LEGO_SET ( - id1 BIGINT AUTO_INCREMENT PRIMARY KEY, + `id1` BIGINT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR(30) ); CREATE TABLE MANUAL ( - id2 BIGINT AUTO_INCREMENT PRIMARY KEY, + `id2` BIGINT AUTO_INCREMENT PRIMARY KEY, LEGO_SET BIGINT, ALTERNATIVE BIGINT, CONTENT VARCHAR(2000) @@ -13,27 +13,27 @@ CREATE TABLE MANUAL ALTER TABLE MANUAL ADD FOREIGN KEY (LEGO_SET) - REFERENCES LEGO_SET (id1); + REFERENCES LEGO_SET (`id1`); CREATE TABLE ONE_TO_ONE_PARENT ( - id3 BIGINT AUTO_INCREMENT PRIMARY KEY, - content VARCHAR(30) + `id3` BIGINT AUTO_INCREMENT PRIMARY KEY, + `content` VARCHAR(30) ); CREATE TABLE Child_No_Id ( ONE_TO_ONE_PARENT INTEGER PRIMARY KEY, - content VARCHAR(30) + `content` VARCHAR(30) ); CREATE TABLE LIST_PARENT ( - id4 BIGINT AUTO_INCREMENT PRIMARY KEY, + `id4` BIGINT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR(100) ); CREATE TABLE element_no_id ( - content VARCHAR(100), + CONTENT VARCHAR(100), LIST_PARENT_key BIGINT, LIST_PARENT BIGINT ); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-mssql.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-mssql.sql index 1edfd32f00..b22766e0fd 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-mssql.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-mssql.sql @@ -2,12 +2,12 @@ DROP TABLE IF EXISTS MANUAL; DROP TABLE IF EXISTS LEGO_SET; CREATE TABLE LEGO_SET ( - id1 BIGINT IDENTITY PRIMARY KEY, + [id1] BIGINT IDENTITY PRIMARY KEY, NAME VARCHAR(30) ); CREATE TABLE MANUAL ( - id2 BIGINT IDENTITY PRIMARY KEY, + [id2] BIGINT IDENTITY PRIMARY KEY, LEGO_SET BIGINT, ALTERNATIVE BIGINT, CONTENT VARCHAR(2000) @@ -19,25 +19,25 @@ DROP TABLE IF EXISTS Child_No_Id; DROP TABLE IF EXISTS ONE_TO_ONE_PARENT; CREATE TABLE ONE_TO_ONE_PARENT ( - id3 BIGINT IDENTITY PRIMARY KEY, + [id3] BIGINT IDENTITY PRIMARY KEY, content VARCHAR(30) ); CREATE TABLE Child_No_Id ( ONE_TO_ONE_PARENT BIGINT PRIMARY KEY, - content VARCHAR(30) + [content] VARCHAR(30) ); DROP TABLE IF EXISTS element_no_id; DROP TABLE IF EXISTS LIST_PARENT; CREATE TABLE LIST_PARENT ( - id4 BIGINT IDENTITY PRIMARY KEY, + [id4] BIGINT IDENTITY PRIMARY KEY, NAME VARCHAR(100) ); CREATE TABLE element_no_id ( - content VARCHAR(100), + CONTENT VARCHAR(100), LIST_PARENT_key BIGINT, LIST_PARENT BIGINT ); @@ -297,4 +297,4 @@ CREATE TABLE VERSIONED_AGGREGATE ( ID BIGINT IDENTITY PRIMARY KEY, VERSION BIGINT -); \ No newline at end of file +); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-mysql.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-mysql.sql index 1ea550facf..9d8ba80f35 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-mysql.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-mysql.sql @@ -1,11 +1,11 @@ CREATE TABLE LEGO_SET ( - id1 BIGINT AUTO_INCREMENT PRIMARY KEY, + `id1` BIGINT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR(30) ); CREATE TABLE MANUAL ( - id2 BIGINT AUTO_INCREMENT PRIMARY KEY, + `id2` BIGINT AUTO_INCREMENT PRIMARY KEY, LEGO_SET BIGINT, ALTERNATIVE BIGINT, CONTENT VARCHAR(2000) @@ -13,27 +13,27 @@ CREATE TABLE MANUAL ALTER TABLE MANUAL ADD FOREIGN KEY (LEGO_SET) - REFERENCES LEGO_SET (id1); + REFERENCES LEGO_SET (`id1`); CREATE TABLE ONE_TO_ONE_PARENT ( - id3 BIGINT AUTO_INCREMENT PRIMARY KEY, + `id3` BIGINT AUTO_INCREMENT PRIMARY KEY, content VARCHAR(30) ); CREATE TABLE Child_No_Id ( ONE_TO_ONE_PARENT INTEGER PRIMARY KEY, - content VARCHAR(30) + `content` VARCHAR(30) ); CREATE TABLE LIST_PARENT ( - id4 BIGINT AUTO_INCREMENT PRIMARY KEY, + `id4` BIGINT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR(100) ); CREATE TABLE element_no_id ( - content VARCHAR(100), + CONTENT VARCHAR(100), LIST_PARENT_key BIGINT, LIST_PARENT BIGINT ); @@ -294,4 +294,4 @@ CREATE TABLE WITH_READ_ONLY ID BIGINT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR(200), READ_ONLY VARCHAR(200) DEFAULT 'from-db' -); \ No newline at end of file +); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-postgres.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-postgres.sql index 3e9396f743..ee8c090c43 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-postgres.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-postgres.sql @@ -15,12 +15,12 @@ DROP TABLE WITH_READ_ONLY; CREATE TABLE LEGO_SET ( - id1 SERIAL PRIMARY KEY, + "id1" SERIAL PRIMARY KEY, NAME VARCHAR(30) ); CREATE TABLE MANUAL ( - id2 SERIAL PRIMARY KEY, + "id2" SERIAL PRIMARY KEY, LEGO_SET BIGINT, ALTERNATIVE BIGINT, CONTENT VARCHAR(2000) @@ -28,11 +28,11 @@ CREATE TABLE MANUAL ALTER TABLE MANUAL ADD FOREIGN KEY (LEGO_SET) - REFERENCES LEGO_SET (id1); + REFERENCES LEGO_SET ("id1"); CREATE TABLE ONE_TO_ONE_PARENT ( - id3 SERIAL PRIMARY KEY, + "id3" SERIAL PRIMARY KEY, content VARCHAR(30) ); CREATE TABLE Child_No_Id @@ -43,7 +43,7 @@ CREATE TABLE Child_No_Id CREATE TABLE LIST_PARENT ( - id4 SERIAL PRIMARY KEY, + "id4" SERIAL PRIMARY KEY, NAME VARCHAR(100) ); CREATE TABLE element_no_id @@ -60,7 +60,7 @@ CREATE TABLE ARRAY_OWNER MULTIDIMENSIONAL VARCHAR(20)[10][10] ); -CREATE TABLE BYTE_ARRAY_OWNER +CREATE TABLE BYTE_ARRAY_OWNER RelationalPersistentEntityImplUnitTests. ( ID SERIAL PRIMARY KEY, BINARY_DATA BYTEA NOT NULL @@ -316,4 +316,4 @@ CREATE TABLE WITH_READ_ONLY ID SERIAL PRIMARY KEY, NAME VARCHAR(200), READ_ONLY VARCHAR(200) DEFAULT 'from-db' -); \ No newline at end of file +); diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/HsqlDbDialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/HsqlDbDialect.java index 94e2184b12..11ae9c8a6e 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/HsqlDbDialect.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/HsqlDbDialect.java @@ -15,6 +15,8 @@ */ package org.springframework.data.relational.core.dialect; +import org.springframework.data.relational.domain.IdentifierProcessing; + /** * A {@link Dialect} for HsqlDb. * @@ -53,5 +55,4 @@ public Position getClausePosition() { return Position.AFTER_ORDER_BY; } }; - } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/MySqlDialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/MySqlDialect.java index e19b9c7e7a..e03e5e5820 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/MySqlDialect.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/MySqlDialect.java @@ -16,7 +16,6 @@ package org.springframework.data.relational.core.dialect; import org.springframework.data.relational.domain.IdentifierProcessing; -import org.springframework.data.relational.domain.IdentifierProcessing.DefaultIdentifierProcessing; import org.springframework.data.relational.domain.IdentifierProcessing.LetterCasing; import org.springframework.data.relational.domain.IdentifierProcessing.Quoting; @@ -90,6 +89,6 @@ public LimitClause limit() { @Override public IdentifierProcessing getIdentifierProcessing() { - return new DefaultIdentifierProcessing(new Quoting("`"), LetterCasing.LOWER_CASE); + return IdentifierProcessing.create(new Quoting("`"), LetterCasing.LOWER_CASE); } } 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 435fe2d7f2..d81cc6e2ad 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 @@ -18,7 +18,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.data.relational.domain.IdentifierProcessing; -import org.springframework.data.relational.domain.IdentifierProcessing.DefaultIdentifierProcessing; import org.springframework.data.relational.domain.IdentifierProcessing.LetterCasing; import org.springframework.data.relational.domain.IdentifierProcessing.Quoting; import org.springframework.util.Assert; @@ -125,6 +124,6 @@ public Class getArrayType(Class userType) { @Override public IdentifierProcessing getIdentifierProcessing() { - return new DefaultIdentifierProcessing(Quoting.ANSI, LetterCasing.LOWER_CASE); + return IdentifierProcessing.create(Quoting.ANSI, LetterCasing.LOWER_CASE); } } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java index 2ae5a096fb..24ea2585c1 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java @@ -31,7 +31,6 @@ import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.relational.core.mapping.Embedded.OnEmpty; import org.springframework.data.relational.domain.SqlIdentifier; -import org.springframework.data.relational.domain.SqlIdentifier.SimpleSqlIdentifier; import org.springframework.data.util.Lazy; import org.springframework.data.util.Optionals; import org.springframework.lang.Nullable; @@ -60,12 +59,13 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent } private final RelationalMappingContext context; - private final Lazy columnName; + private final Lazy columnName; private final Lazy> collectionIdColumnName; private final Lazy collectionKeyColumnName; private final Lazy isEmbedded; private final Lazy embeddedPrefix; private final Lazy> columnType = Lazy.of(this::doGetColumnType); + private boolean forceQuote = true; /** * Creates a new {@link AnnotationBasedPersistentProperty}. @@ -93,8 +93,8 @@ public BasicRelationalPersistentProperty(Property property, PersistentEntity Optional.ofNullable(findAnnotation(Column.class)) // .map(Column::value) // .filter(StringUtils::hasText) // - .map(name -> SqlIdentifier.quoted(name).withAdjustableLetterCasing()) // - .orElseGet(() -> context.getNamingStrategy().getColumnName(this))); + .map(this::createSqlIdentifier) // + .orElseGet(() -> createDerivedSqlIdentifier(context.getNamingStrategy().getColumnName(this)))); this.collectionIdColumnName = Lazy.of(() -> Optionals .toStream(Optional.ofNullable(findAnnotation(MappedCollection.class)) // @@ -103,14 +103,22 @@ public BasicRelationalPersistentProperty(Property property, PersistentEntity SqlIdentifier.quoted(name).withAdjustableLetterCasing())); // + .map(this::createSqlIdentifier)); // this.collectionKeyColumnName = Lazy.of(() -> Optionals // .toStream(Optional.ofNullable(findAnnotation(MappedCollection.class)).map(MappedCollection::keyColumn), // Optional.ofNullable(findAnnotation(Column.class)).map(Column::keyColumn)) // .filter(StringUtils::hasText).findFirst() // - .map(name -> (SqlIdentifier) SqlIdentifier.quoted(name).withAdjustableLetterCasing()) // - .orElseGet(() -> context.getNamingStrategy().getKeyColumn(this))); + .map(this::createSqlIdentifier) // + .orElseGet(() -> createDerivedSqlIdentifier(context.getNamingStrategy().getKeyColumn(this)))); + } + + private SqlIdentifier createSqlIdentifier(String name) { + return isForceQuote() ? SqlIdentifier.quoted(name) : SqlIdentifier.unquoted(name); + } + + private SqlIdentifier createDerivedSqlIdentifier(String name) { + return new DerivedSqlIdentifier(name, isForceQuote()); } /* @@ -122,6 +130,14 @@ protected Association createAssociation() { throw new UnsupportedOperationException(); } + boolean isForceQuote() { + return forceQuote; + } + + void setForceQuote(boolean forceQuote) { + this.forceQuote = forceQuote; + } + @Override public boolean isEntity() { return super.isEntity() && !isReference(); @@ -137,7 +153,7 @@ public boolean isReference() { * @see org.springframework.data.jdbc.core.mapping.model.JdbcPersistentProperty#getColumnName() */ @Override - public SimpleSqlIdentifier getColumnName() { + public SqlIdentifier getColumnName() { return columnName.get(); } @@ -188,13 +204,15 @@ public RelationalPersistentEntity getOwner() { @Override public SqlIdentifier getReverseColumnName() { - return collectionIdColumnName.get().orElseGet(() -> context.getNamingStrategy().getReverseColumnName(this)); + return collectionIdColumnName.get() + .orElseGet(() -> createDerivedSqlIdentifier(context.getNamingStrategy().getReverseColumnName(this))); } @Override public SqlIdentifier getReverseColumnName(PersistentPropertyPathExtension path) { - return collectionIdColumnName.get().orElseGet(() -> context.getNamingStrategy().getReverseColumnName(path)); + return collectionIdColumnName.get() + .orElseGet(() -> createDerivedSqlIdentifier(context.getNamingStrategy().getReverseColumnName(path))); } @Override diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/CachingNamingStrategy.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/CachingNamingStrategy.java index 8069ad5691..c58f8ad193 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/CachingNamingStrategy.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/CachingNamingStrategy.java @@ -18,8 +18,6 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.springframework.data.relational.domain.SqlIdentifier; -import org.springframework.data.relational.domain.SqlIdentifier.SimpleSqlIdentifier; import org.springframework.data.util.Lazy; import org.springframework.util.Assert; import org.springframework.util.ConcurrentReferenceHashMap; @@ -34,12 +32,12 @@ class CachingNamingStrategy implements NamingStrategy { private final NamingStrategy delegate; - private final Map columnNames = new ConcurrentHashMap<>(); - private final Map keyColumns = new ConcurrentHashMap<>(); - private final Map, SqlIdentifier> qualifiedTableNames = new ConcurrentReferenceHashMap<>(); - private final Map, SqlIdentifier> tableNames = new ConcurrentReferenceHashMap<>(); + private final Map columnNames = new ConcurrentHashMap<>(); + private final Map keyColumns = new ConcurrentHashMap<>(); + private final Map, String> qualifiedTableNames = new ConcurrentReferenceHashMap<>(); + private final Map, String> tableNames = new ConcurrentReferenceHashMap<>(); - private final Lazy schema; + private final Lazy schema; /** * Creates a new {@link CachingNamingStrategy} with the given delegate {@link NamingStrategy}. @@ -59,7 +57,7 @@ class CachingNamingStrategy implements NamingStrategy { * @see org.springframework.data.relational.core.mapping.NamingStrategy#getKeyColumn(org.springframework.data.relational.core.mapping.RelationalPersistentProperty) */ @Override - public SqlIdentifier getKeyColumn(RelationalPersistentProperty property) { + public String getKeyColumn(RelationalPersistentProperty property) { return keyColumns.computeIfAbsent(property, delegate::getKeyColumn); } @@ -68,7 +66,7 @@ public SqlIdentifier getKeyColumn(RelationalPersistentProperty property) { * @see org.springframework.data.relational.core.mapping.NamingStrategy#getQualifiedTableName(java.lang.Class) */ @Override - public SqlIdentifier getQualifiedTableName(Class type) { + public String getQualifiedTableName(Class type) { return qualifiedTableNames.computeIfAbsent(type, delegate::getQualifiedTableName); } @@ -77,7 +75,7 @@ public SqlIdentifier getQualifiedTableName(Class type) { * @see org.springframework.data.relational.core.mapping.NamingStrategy#getTableName(java.lang.Class) */ @Override - public SqlIdentifier getTableName(Class type) { + public String getTableName(Class type) { return tableNames.computeIfAbsent(type, delegate::getTableName); } @@ -86,7 +84,7 @@ public SqlIdentifier getTableName(Class type) { * @see org.springframework.data.relational.core.mapping.NamingStrategy#getReverseColumnName(org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension) */ @Override - public SqlIdentifier getReverseColumnName(PersistentPropertyPathExtension path) { + public String getReverseColumnName(PersistentPropertyPathExtension path) { return delegate.getReverseColumnName(path); } @@ -95,7 +93,7 @@ public SqlIdentifier getReverseColumnName(PersistentPropertyPathExtension path) * @see org.springframework.data.relational.core.mapping.NamingStrategy#getReverseColumnName(org.springframework.data.relational.core.mapping.RelationalPersistentProperty) */ @Override - public SqlIdentifier getReverseColumnName(RelationalPersistentProperty property) { + public String getReverseColumnName(RelationalPersistentProperty property) { return delegate.getReverseColumnName(property); } @@ -104,7 +102,7 @@ public SqlIdentifier getReverseColumnName(RelationalPersistentProperty property) * @see org.springframework.data.relational.core.mapping.NamingStrategy#getSchema() */ @Override - public SqlIdentifier getSchema() { + public String getSchema() { return schema.get(); } @@ -113,7 +111,7 @@ public SqlIdentifier getSchema() { * @see org.springframework.data.relational.core.mapping.NamingStrategy#getColumnName(org.springframework.data.relational.core.mapping.RelationalPersistentProperty) */ @Override - public SimpleSqlIdentifier getColumnName(RelationalPersistentProperty property) { + public String getColumnName(RelationalPersistentProperty property) { return columnNames.computeIfAbsent(property, delegate::getColumnName); } } 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 new file mode 100644 index 0000000000..1f42835eb5 --- /dev/null +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/DerivedSqlIdentifier.java @@ -0,0 +1,105 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.relational.core.mapping; + +import java.util.function.UnaryOperator; + +import org.springframework.data.relational.domain.IdentifierProcessing; +import org.springframework.data.relational.domain.SqlIdentifier; +import org.springframework.util.Assert; + +/** + * {@link SqlIdentifier} that is derived from a property name or class name to infer the defaults provided by a + * {@link NamingStrategy}. + * + * @author Mark Paluch + * @since 2.0 + */ +class DerivedSqlIdentifier implements SqlIdentifier { + + private final String name; + private final boolean quoted; + + DerivedSqlIdentifier(String name, boolean quoted) { + + Assert.hasText(name, "A database object must have at least on name part."); + this.name = name; + this.quoted = quoted; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.relational.domain.SqlIdentifier#transform(java.util.function.UnaryOperator) + */ + @Override + public SqlIdentifier transform(UnaryOperator transformationFunction) { + + Assert.notNull(transformationFunction, "Transformation function must not be null"); + + return new DerivedSqlIdentifier(transformationFunction.apply(name), quoted); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.relational.domain.SqlIdentifier#toSql(org.springframework.data.relational.domain.IdentifierProcessing) + */ + @Override + public String toSql(IdentifierProcessing processing) { + return quoted ? processing.quote(getReference(processing)) : getReference(processing); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.relational.domain.SqlIdentifier#getReference(org.springframework.data.relational.domain.IdentifierProcessing) + */ + @Override + public String getReference(IdentifierProcessing processing) { + return processing.standardizeLetterCase(name); + } + + /* + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object o) { + + if (this == o) + return true; + if (o instanceof SqlIdentifier) { + return toString().equals(o.toString()); + } + return false; + } + + /* + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return toString().hashCode(); + } + + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return toSql(IdentifierProcessing.ANSI); + } +} diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/NamingStrategy.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/NamingStrategy.java index c0618dc0c2..e43dfdeff6 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/NamingStrategy.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/NamingStrategy.java @@ -17,6 +17,7 @@ import static org.springframework.data.relational.domain.SqlIdentifier.*; +import org.springframework.data.relational.domain.IdentifierProcessing; import org.springframework.data.relational.domain.SqlIdentifier; import org.springframework.data.relational.domain.SqlIdentifier.*; import org.springframework.data.util.ParsingUtils; @@ -28,7 +29,7 @@ *

* NOTE: Can also be used as an adapter. Create a lambda or an anonymous subclass and override any settings to implement * a different strategy on the fly. - * + * * @author Greg Turnquist * @author Michael Simons * @author Kazuki Shimizu @@ -49,34 +50,34 @@ public interface NamingStrategy { * * @return Empty String representing no schema */ - default SqlIdentifier getSchema() { - return SqlIdentifier.EMPTY; + default String getSchema() { + return ""; } /** * The name of the table to be used for persisting entities having the type passed as an argument. The default * implementation takes the {@code type.getSimpleName()} and separates camel case parts with '_'. */ - default SqlIdentifier getTableName(Class type) { + default String getTableName(Class type) { Assert.notNull(type, "Type must not be null."); - return quoted(ParsingUtils.reconcatenateCamelCase(type.getSimpleName(), "_")).withAdjustableLetterCasing(); + return ParsingUtils.reconcatenateCamelCase(type.getSimpleName(), "_"); } /** * Defaults to return the given {@link RelationalPersistentProperty}'s name with the parts of a camel case name * separated by '_'; */ - default SimpleSqlIdentifier getColumnName(RelationalPersistentProperty property) { + default String getColumnName(RelationalPersistentProperty property) { Assert.notNull(property, "Property must not be null."); - return quoted(ParsingUtils.reconcatenateCamelCase(property.getName(), "_")).withAdjustableLetterCasing(); + return ParsingUtils.reconcatenateCamelCase(property.getName(), "_"); } - default SqlIdentifier getQualifiedTableName(Class type) { - return this.getSchema().concat(this.getTableName(type)); + default String getQualifiedTableName(Class type) { + return this.getSchema() + (this.getSchema().equals("") ? "" : ".") + this.getTableName(type); } /** @@ -85,14 +86,14 @@ default SqlIdentifier getQualifiedTableName(Class type) { * @param property The property who's column name in the owner table is required * @return a column name. Must not be {@code null}. */ - default SqlIdentifier getReverseColumnName(RelationalPersistentProperty property) { + default String getReverseColumnName(RelationalPersistentProperty property) { Assert.notNull(property, "Property must not be null."); - return property.getOwner().getTableName(); + return property.getOwner().getTableName().getReference(IdentifierProcessing.NONE); } - default SqlIdentifier getReverseColumnName(PersistentPropertyPathExtension path) { + default String getReverseColumnName(PersistentPropertyPathExtension path) { return getTableName(path.getIdDefiningParentPath().getLeafEntity().getType()); } @@ -100,13 +101,13 @@ default SqlIdentifier getReverseColumnName(PersistentPropertyPathExtension path) /** * For a map valued reference A -> Map>X,B< this is the name of the column in the table for B holding the key of * the map. - * + * * @return name of the key column. Must not be {@code null}. */ - default SqlIdentifier getKeyColumn(RelationalPersistentProperty property) { + default String getKeyColumn(RelationalPersistentProperty property) { Assert.notNull(property, "Property must not be null."); - return getReverseColumnName(property).suffix("_key"); + return getReverseColumnName(property) + "_key"; } } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/PersistentPropertyPathExtension.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/PersistentPropertyPathExtension.java index d233a32447..db9ecda72b 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/PersistentPropertyPathExtension.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/PersistentPropertyPathExtension.java @@ -20,8 +20,8 @@ import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.data.mapping.context.MappingContext; +import org.springframework.data.relational.domain.IdentifierProcessing; import org.springframework.data.relational.domain.SqlIdentifier; -import org.springframework.data.relational.domain.SqlIdentifier.SimpleSqlIdentifier; import org.springframework.data.util.Lazy; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -394,15 +394,18 @@ private SqlIdentifier assembleTableAlias() { if (path.getLength() == 1) { Assert.notNull(prefix, "Prefix mus not be null."); - return SqlIdentifier.quoted(prefix).withAdjustableLetterCasing(); + return SqlIdentifier.quoted(prefix); } PersistentPropertyPathExtension parentPath = getParentPath(); - return parentPath.isEmbedded() ? parentPath.assembleTableAlias().suffix(prefix) - : parentPath.assembleTableAlias().suffix("_" + prefix); + SqlIdentifier sqlIdentifier = parentPath.assembleTableAlias(); + + return parentPath.isEmbedded() ? sqlIdentifier.transform(name -> name.concat(prefix)) + : sqlIdentifier.transform(name -> name + "_" + prefix); + } - private SqlIdentifier assembleColumnName(SimpleSqlIdentifier suffix) { + private SqlIdentifier assembleColumnName(SqlIdentifier suffix) { Assert.state(path != null, "Path is null"); @@ -419,7 +422,7 @@ private SqlIdentifier assembleColumnName(SimpleSqlIdentifier suffix) { String embeddedPrefix = parentLeaf.getEmbeddedPrefix(); - return getParentPath().assembleColumnName(suffix.prefix(embeddedPrefix)); + return getParentPath().assembleColumnName(suffix.transform(embeddedPrefix::concat)); } private RelationalPersistentEntity getRequiredLeafEntity() { @@ -429,7 +432,8 @@ private RelationalPersistentEntity getRequiredLeafEntity() { private SqlIdentifier prefixWithTableAlias(SqlIdentifier columnName) { SqlIdentifier tableAlias = getTableAlias(); - return tableAlias == null ? columnName : columnName.prefix(tableAlias, "_"); + return tableAlias == null ? columnName + : columnName.transform(name -> tableAlias.getReference(IdentifierProcessing.NONE) + "_" + name); } } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalMappingContext.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalMappingContext.java index 9a01c3d745..56080fd239 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalMappingContext.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalMappingContext.java @@ -37,6 +37,7 @@ public class RelationalMappingContext extends AbstractMappingContext, RelationalPersistentProperty> { @Getter private final NamingStrategy namingStrategy; + private boolean forceQuote = true; /** * Creates a new {@link RelationalMappingContext}. @@ -59,13 +60,37 @@ public RelationalMappingContext(NamingStrategy namingStrategy) { setSimpleTypeHolder(SimpleTypeHolder.DEFAULT); } + /** + * Return whether quoting should be enabled for all table and column names. Quoting is enabled by default. + * + * @return + * @since 2.0 + */ + public boolean isForceQuote() { + return forceQuote; + } + + /** + * Enable/disable quoting for all tables and column names. + * + * @param forceQuote + */ + public void setForceQuote(boolean forceQuote) { + this.forceQuote = forceQuote; + } + /* * (non-Javadoc) * @see org.springframework.data.mapping.context.AbstractMappingContext#createPersistentEntity(org.springframework.data.util.TypeInformation) */ @Override protected RelationalPersistentEntity createPersistentEntity(TypeInformation typeInformation) { - return new RelationalPersistentEntityImpl<>(typeInformation, this.namingStrategy); + + RelationalPersistentEntityImpl entity = new RelationalPersistentEntityImpl<>(typeInformation, + this.namingStrategy); + entity.setForceQuote(isForceQuote()); + + return entity; } /* @@ -75,6 +100,11 @@ protected RelationalPersistentEntity createPersistentEntity(TypeInformati @Override protected RelationalPersistentProperty createPersistentProperty(Property property, RelationalPersistentEntity owner, SimpleTypeHolder simpleTypeHolder) { - return new BasicRelationalPersistentProperty(property, owner, simpleTypeHolder, this); + + BasicRelationalPersistentProperty persistentProperty = new BasicRelationalPersistentProperty(property, owner, + simpleTypeHolder, this); + persistentProperty.setForceQuote(isForceQuote()); + + return persistentProperty; } } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImpl.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImpl.java index 9f91d47e31..92ccb30cd0 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImpl.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImpl.java @@ -36,6 +36,7 @@ class RelationalPersistentEntityImpl extends BasicPersistentEntity> tableName; + private boolean forceQuote = true; /** * Creates a new {@link RelationalPersistentEntityImpl} for the given {@link TypeInformation}. @@ -51,17 +52,33 @@ class RelationalPersistentEntityImpl extends BasicPersistentEntity SqlIdentifier.quoted(name).withAdjustableLetterCasing()) // + .map(this::createSqlIdentifier) // ); } - /* + private SqlIdentifier createSqlIdentifier(String name) { + return isForceQuote() ? SqlIdentifier.quoted(name) : SqlIdentifier.unquoted(name); + } + + private SqlIdentifier createDerivedSqlIdentifier(String name) { + return new DerivedSqlIdentifier(name, isForceQuote()); + } + + boolean isForceQuote() { + return forceQuote; + } + + void setForceQuote(boolean forceQuote) { + this.forceQuote = forceQuote; + } + + /* * (non-Javadoc) * @see org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity#getTableName() */ @Override public SqlIdentifier getTableName() { - return tableName.get().orElseGet(() -> namingStrategy.getQualifiedTableName(getType())); + return tableName.get().orElseGet(() -> createDerivedSqlIdentifier(namingStrategy.getQualifiedTableName(getType()))); } /* @@ -82,7 +99,7 @@ public String toString() { return String.format("JdbcPersistentEntityImpl<%s>", getType()); } - /* + /* * (non-Javadoc) * @see org.springframework.data.mapping.model.BasicPersistentEntity#setPersistentPropertyAccessorFactory(org.springframework.data.mapping.model.PersistentPropertyAccessorFactory) */ diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java index 767a447949..484eabf228 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java @@ -17,7 +17,6 @@ import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.relational.domain.SqlIdentifier; -import org.springframework.data.relational.domain.SqlIdentifier.SimpleSqlIdentifier; import org.springframework.lang.Nullable; /** @@ -36,7 +35,7 @@ public interface RelationalPersistentProperty extends PersistentProperty 0, "SqlIdentifier parts must not be empty"); + + this.parts = parts; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.relational.domain.SqlIdentifier#transform(java.util.function.UnaryOperator) + */ + @Override + public SqlIdentifier transform(UnaryOperator transformationFunction) { + throw new UnsupportedOperationException("Composite SQL Identifiers cannot be transformed"); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.relational.domain.SqlIdentifier#toSql(org.springframework.data.relational.domain.IdentifierProcessing) + */ + @Override + public String toSql(IdentifierProcessing processing) { + + StringJoiner stringJoiner = new StringJoiner("."); + + for (SqlIdentifier namePart : parts) { + stringJoiner.add(namePart.toSql(processing)); + } + + return stringJoiner.toString(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.relational.domain.SqlIdentifier#getReference(org.springframework.data.relational.domain.IdentifierProcessing) + */ + @Override + public String getReference(IdentifierProcessing processing) { + throw new UnsupportedOperationException("A Composite SQL Identifiers can't be used as a reference name"); + } + + /* + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object o) { + + if (this == o) + return true; + if (o instanceof SqlIdentifier) { + return toString().equals(o.toString()); + } + return false; + } + + /* + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return toString().hashCode(); + } + + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return toSql(IdentifierProcessing.ANSI); + } +} diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/domain/DefaultIdentifierProcessing.java b/spring-data-relational/src/main/java/org/springframework/data/relational/domain/DefaultIdentifierProcessing.java new file mode 100644 index 0000000000..7e22257716 --- /dev/null +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/domain/DefaultIdentifierProcessing.java @@ -0,0 +1,52 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.relational.domain; + +/** + * An {@link IdentifierProcessing} implementation based on two implementations for the quoting and for the letter case + * standardization. + * + * @author Jens Schauder + * @since 2.0 + */ +class DefaultIdentifierProcessing implements IdentifierProcessing { + + private final Quoting quoting; + private final LetterCasing letterCasing; + + DefaultIdentifierProcessing(Quoting quoting, LetterCasing letterCasing) { + this.quoting = quoting; + this.letterCasing = letterCasing; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.relational.domain.IdentifierProcessing#quote(java.lang.String) + */ + @Override + public String quote(String identifier) { + return quoting.apply(identifier); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.relational.domain.IdentifierProcessing#standardizeLetterCase(java.lang.String) + */ + @Override + public String standardizeLetterCase(String identifier) { + return letterCasing.apply(identifier); + } +} diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/domain/DefaultSqlIdentifier.java b/spring-data-relational/src/main/java/org/springframework/data/relational/domain/DefaultSqlIdentifier.java new file mode 100644 index 0000000000..4679ea2f69 --- /dev/null +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/domain/DefaultSqlIdentifier.java @@ -0,0 +1,104 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.relational.domain; + +import java.util.function.UnaryOperator; + +import org.springframework.util.Assert; + +/** + * Default {@link SqlIdentifier} implementation using a {@code name} and whether the identifier is quoted. + * + * @author Jens Schauder + * @author Mark Paluch + * @since 2.0 + */ +class DefaultSqlIdentifier implements SqlIdentifier { + + private final String name; + private final boolean quoted; + + DefaultSqlIdentifier(String name, boolean quoted) { + + Assert.hasText(name, "A database object must have at least on name part."); + + this.name = name; + this.quoted = quoted; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.relational.domain.SqlIdentifier#transform(java.util.function.UnaryOperator) + */ + @Override + public SqlIdentifier transform(UnaryOperator transformationFunction) { + + Assert.notNull(transformationFunction, "Transformation function must not be null"); + + return new DefaultSqlIdentifier(transformationFunction.apply(name), quoted); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.relational.domain.SqlIdentifier#toSql(org.springframework.data.relational.domain.IdentifierProcessing) + */ + @Override + public String toSql(IdentifierProcessing processing) { + return quoted ? processing.quote(getReference(processing)) : getReference(processing); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.relational.domain.SqlIdentifier#getReference(org.springframework.data.relational.domain.IdentifierProcessing) + */ + @Override + public String getReference(IdentifierProcessing processing) { + return name; + } + + /* + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object o) { + + if (this == o) + return true; + if (o instanceof SqlIdentifier) { + return toString().equals(o.toString()); + } + return false; + } + + /* + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return toString().hashCode(); + } + + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return toSql(IdentifierProcessing.ANSI); + } +} diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/domain/IdentifierProcessing.java b/spring-data-relational/src/main/java/org/springframework/data/relational/domain/IdentifierProcessing.java index 78dccb89fe..0ee86f594b 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/domain/IdentifierProcessing.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/domain/IdentifierProcessing.java @@ -18,7 +18,7 @@ /** * An interface describing the processing steps for the conversion of {@link SqlIdentifier} to SQL snippets or column * names. - * + * * @author Jens Schauder * @since 2.0 */ @@ -28,7 +28,23 @@ public interface IdentifierProcessing { * An {@link IdentifierProcessing} that can be used for databases adhering to the SQL standard which uses double * quotes ({@literal "}) for quoting and makes unquoted literals equivalent to upper case. */ - IdentifierProcessing ANSI = new DefaultIdentifierProcessing(Quoting.ANSI, LetterCasing.UPPER_CASE); + IdentifierProcessing ANSI = create(Quoting.ANSI, LetterCasing.UPPER_CASE); + + /** + * An {@link IdentifierProcessing} without applying transformations. + */ + IdentifierProcessing NONE = create(Quoting.NONE, LetterCasing.AS_IS); + + /** + * Create a {@link IdentifierProcessing} rule given {@link Quoting} and {@link LetterCasing} rules. + * + * @param quoting quoting rules. + * @param letterCasing {@link LetterCasing} rules for identifier normalization. + * @return a new {@link IdentifierProcessing} object. + */ + static DefaultIdentifierProcessing create(Quoting quoting, LetterCasing letterCasing) { + return new DefaultIdentifierProcessing(quoting, letterCasing); + } /** * Converts a {@link String} representing a bare name of an identifier to a {@link String} with proper quoting @@ -43,40 +59,15 @@ public interface IdentifierProcessing { * Standardizes the use of upper and lower case letters in an identifier in such a way that semantically the same * identifier results from the quoted and the unquoted version. If this is not possible use of * {@link LetterCasing#AS_IS} is recommended. - * + * * @param identifier an identifier with arbitrary upper and lower cases. must not be {@literal null}. * @return an identifier with standardized use of upper and lower case letter. Guaranteed to be not {@literal null}. */ String standardizeLetterCase(String identifier); - /** - * An {@link IdentifierProcessing} implementation based on two implementations for the quoting and for the letter case - * standardization. - */ - class DefaultIdentifierProcessing implements IdentifierProcessing { - - private final Quoting quoting; - private final LetterCasing letterCasing; - - public DefaultIdentifierProcessing(Quoting quoting, LetterCasing letterCasing) { - this.quoting = quoting; - this.letterCasing = letterCasing; - } - - @Override - public String quote(String identifier) { - return quoting.apply(identifier); - } - - @Override - public String standardizeLetterCase(String identifier) { - return letterCasing.apply(identifier); - } - } - /** * A conversion from unquoted identifiers to quoted identifiers. - * + * * @author Jens Schauder * @since 2.0 */ @@ -84,12 +75,14 @@ class Quoting { public static final Quoting ANSI = new Quoting("\""); + public static final Quoting NONE = new Quoting(""); + private final String prefix; private final String suffix; /** * Constructs a {@literal Quoting} with potential different prefix and suffix used for quoting. - * + * * @param prefix a {@literal String} prefixed before the name for quoting it. * @param suffix a {@literal String} suffixed at the end of the name for quoting it. */ @@ -101,7 +94,7 @@ public Quoting(String prefix, String suffix) { /** * Constructs a {@literal Quoting} with the same {@literal String} appended in front and end of an identifier. - * + * * @param quoteCharacter the value appended at the beginning and the end of a name in order to quote it. */ public Quoting(String quoteCharacter) { diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/domain/SqlIdentifier.java b/spring-data-relational/src/main/java/org/springframework/data/relational/domain/SqlIdentifier.java index d40f11cdcd..4536c42756 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/domain/SqlIdentifier.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/domain/SqlIdentifier.java @@ -15,53 +15,34 @@ */ package org.springframework.data.relational.domain; -import java.util.Arrays; -import java.util.Objects; -import java.util.StringJoiner; - -import org.springframework.util.Assert; +import java.util.function.UnaryOperator; /** - * Represents a named object that exists in the database like a table name or a column name - * + * Represents a named object that exists in the database like a table name or a column name. SQL identifiers are created + * from a {@link String name} with specifying whether the name should be quoted or unquoted. + *

+ * {@link SqlIdentifier} renders its name using {@link IdentifierProcessing} rules. Use + * {@link #getReference(IdentifierProcessing)} to refer to an object using the identifier when e.g. obtaining values + * from a result or providing values for a prepared statement. {@link #toSql(IdentifierProcessing)} renders the + * identifier for SQL statement usage. + *

+ * {@link SqlIdentifier} objects are immutable. Calling transformational methods such as + * {@link #transform(UnaryOperator)} creates a new instance. + * * @author Jens Schauder + * @author Mark Paluch * @since 2.0 */ public interface SqlIdentifier { - SimpleSqlIdentifier prefix(SqlIdentifier prefix, String separator); - - SqlIdentifier suffix(String suffix); - - SqlIdentifier concat(SqlIdentifier second); - - String toSql(IdentifierProcessing processing); - - String toColumnName(IdentifierProcessing processing); - - static SimpleSqlIdentifier quoted(String name) { - return new SimpleSqlIdentifier(name, true, true); - } - - static SimpleSqlIdentifier unquoted(String name) { - return new SimpleSqlIdentifier(name, false, true); - } - + /** + * Null-object. + */ SqlIdentifier EMPTY = new SqlIdentifier() { @Override - public SimpleSqlIdentifier prefix(SqlIdentifier prefix, String separator) { - throw new UnsupportedOperationException("We can't prefix an empty DatabaseObjectIdentifier"); - } - - @Override - public SqlIdentifier suffix(String suffix) { - throw new UnsupportedOperationException("We can't suffix an empty DatabaseObjectIdentifier"); - } - - @Override - public SqlIdentifier concat(SqlIdentifier second) { - return second; + public SqlIdentifier transform(UnaryOperator transformationFunction) { + return this; } @Override @@ -70,7 +51,7 @@ public String toSql(IdentifierProcessing processing) { } @Override - public String toColumnName(IdentifierProcessing processing) { + public String getReference(IdentifierProcessing processing) { throw new UnsupportedOperationException("An empty SqlIdentifier can't be used in to create column names"); } @@ -79,141 +60,64 @@ public String toString() { } }; - final class SimpleSqlIdentifier implements SqlIdentifier { - - private final String name; - private final boolean quoted; - private final boolean fixedLetterCasing; - - private SimpleSqlIdentifier(String name, boolean quoted, boolean fixedLetterCasing) { - - Assert.hasText(name, "A database object must have at least on name part."); - - this.name = name; - this.quoted = quoted; - this.fixedLetterCasing = fixedLetterCasing; - } - - public SimpleSqlIdentifier withAdjustableLetterCasing() { - return new SimpleSqlIdentifier(name, quoted, false); - } - - public SimpleSqlIdentifier prefix(String prefix) { - return new SimpleSqlIdentifier(prefix + name, quoted, fixedLetterCasing); - } - - @Override - public SimpleSqlIdentifier prefix(SqlIdentifier prefix, String separator) { - - Assert.isInstanceOf(SimpleSqlIdentifier.class, prefix, "Prefixing is only supported for simple SqlIdentifier"); - - return new SimpleSqlIdentifier(((SimpleSqlIdentifier) prefix).name + separator + name, quoted, fixedLetterCasing); - } - - public SimpleSqlIdentifier suffix(String suffix) { - return new SimpleSqlIdentifier(name + suffix, quoted, fixedLetterCasing); - } - - @Override - public boolean equals(Object o) { - - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - SimpleSqlIdentifier that = (SimpleSqlIdentifier) o; - return quoted == that.quoted && Objects.equals(name, that.name); - } - - @Override - public int hashCode() { - - int result = Objects.hash(quoted); - result = 31 * result + name.hashCode(); - return result; - } - - @Override - public String toString() { - return "DatabaseObjectIdentifier{" + "name=" + name + ", quoted=" + quoted + '}'; - } - - @Override - public SqlIdentifier concat(SqlIdentifier second) { - // TODO: this is completely broken and needs fixing. - return new CombinedSqlIdentifier(this, (SimpleSqlIdentifier) second); - } - - @Override - public String toSql(IdentifierProcessing processing) { - - return quoted ? processing.quote(toColumnName(processing)) : toColumnName(processing); - } + /** + * Return the reference name after applying {@link IdentifierProcessing} rules. The reference name is used for + * programmatic access to the object identified by this {@link SqlIdentifier}. + * + * @param processing identifier processing rules. + * @return + */ + String getReference(IdentifierProcessing processing); + + /** + * Return the identifier for SQL usage after applying {@link IdentifierProcessing} rules. The identifier name is used + * to construct SQL statements. + * + * @param processing identifier processing rules. + * @return + */ + String toSql(IdentifierProcessing processing); - @Override - public String toColumnName(IdentifierProcessing processing) { - return fixedLetterCasing ? name : processing.standardizeLetterCase(name); - } + /** + * Transform the SQL identifier name by applying a {@link UnaryOperator transformation function}. The transformation + * function must return a valid, {@literal non-null} identifier {@link String}. + * + * @param transformationFunction the transformation function. Must return a {@literal non-null} identifier + * {@link String}. + * @return a new {@link SqlIdentifier} with the transformation applied. + */ + SqlIdentifier transform(UnaryOperator transformationFunction); + + /** + * Create a new quoted identifier given {@code name}. + * + * @param name the identifier. + * @return a new quoted identifier given {@code name}. + */ + static SqlIdentifier quoted(String name) { + return new DefaultSqlIdentifier(name, true); } - final class CombinedSqlIdentifier implements SqlIdentifier { - - private final SimpleSqlIdentifier[] parts; - - private CombinedSqlIdentifier(SimpleSqlIdentifier... parts) { - this.parts = parts; - } - - @Override - public SqlIdentifier concat(SqlIdentifier second) { - throw new UnsupportedOperationException(); - } - - @Override - public SimpleSqlIdentifier prefix(SqlIdentifier prefix, String separator) { - throw new UnsupportedOperationException(); - } - - @Override - public SqlIdentifier suffix(String suffix) { - throw new UnsupportedOperationException(); - } - - @Override - public String toSql(IdentifierProcessing processing) { - - StringJoiner stringJoiner = new StringJoiner("."); - - for (SimpleSqlIdentifier namePart : parts) { - stringJoiner.add(namePart.toSql(processing)); - } - - return stringJoiner.toString(); - } - - @Override - public String toColumnName(IdentifierProcessing processing) { - throw new UnsupportedOperationException("A CombinedSqlIdentifier can't be used as a column name"); - } - - @Override - public String toString() { - return "CombinedDatabaseObjectIdentifier{" + "parts=" + Arrays.toString(parts) + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - CombinedSqlIdentifier that = (CombinedSqlIdentifier) o; - return Arrays.equals(parts, that.parts); - } + /** + * Create a new unquoted identifier given {@code name}. + * + * @param name the identifier. + * @return a new unquoted identifier given {@code name}. + */ + static SqlIdentifier unquoted(String name) { + return new DefaultSqlIdentifier(name, false); + } - @Override - public int hashCode() { - return Arrays.hashCode(parts); - } + /** + * Create a new composite {@link SqlIdentifier} from one or more {@link SqlIdentifier}s. + *

+ * Composite identifiers do not allow {@link #transform(UnaryOperator)} transformation. + *

+ * + * @param sqlIdentifiers the elements of the new identifier. + * @return the new composite identifier. + */ + static SqlIdentifier from(SqlIdentifier... sqlIdentifiers) { + return new CompositeSqlIdentifier(sqlIdentifiers); } } diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/DerivedSqlIdentifierUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/DerivedSqlIdentifierUnitTests.java new file mode 100644 index 0000000000..4b40445984 --- /dev/null +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/DerivedSqlIdentifierUnitTests.java @@ -0,0 +1,86 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.relational.core.mapping; + +import static org.assertj.core.api.Assertions.*; + +import org.assertj.core.api.SoftAssertions; +import org.junit.Test; + +import org.springframework.data.relational.domain.IdentifierProcessing; +import org.springframework.data.relational.domain.IdentifierProcessing.LetterCasing; +import org.springframework.data.relational.domain.IdentifierProcessing.Quoting; +import org.springframework.data.relational.domain.SqlIdentifier; + +/** + * Unit tests for {@link DerivedSqlIdentifier}. + * + * @author Jens Schauder + * @author Mark Paluch + */ +public class DerivedSqlIdentifierUnitTests { + + public static final IdentifierProcessing BRACKETS_LOWER_CASE = IdentifierProcessing.create(new Quoting("[", "]"), + LetterCasing.LOWER_CASE); + + @Test // DATAJDBC-386 + public void quotedSimpleObjectIdentifierWithAdjustableLetterCasing() { + + SqlIdentifier identifier = new DerivedSqlIdentifier("someName", true); + + assertThat(identifier.toSql(BRACKETS_LOWER_CASE)).isEqualTo("[somename]"); + assertThat(identifier.getReference(BRACKETS_LOWER_CASE)).isEqualTo("somename"); + + } + + @Test // DATAJDBC-386 + public void unquotedSimpleObjectIdentifierWithAdjustableLetterCasing() { + + SqlIdentifier identifier = new DerivedSqlIdentifier("someName", false); + String sql = identifier.toSql(BRACKETS_LOWER_CASE); + + assertThat(sql).isEqualTo("somename"); + assertThat(identifier.getReference(BRACKETS_LOWER_CASE)).isEqualTo("somename"); + } + + @Test // DATAJDBC-386 + public void quotedMultipartObjectIdentifierWithAdjustableLetterCase() { + + SqlIdentifier identifier = SqlIdentifier.from(new DerivedSqlIdentifier("some", true), + new DerivedSqlIdentifier("name", true)); + String sql = identifier.toSql(IdentifierProcessing.ANSI); + + assertThat(sql).isEqualTo("\"SOME\".\"NAME\""); + } + + @Test // DATAJDBC-386 + public void equality() { + + SqlIdentifier basis = new DerivedSqlIdentifier("simple", false); + SqlIdentifier equal = new DerivedSqlIdentifier("simple", false); + SqlIdentifier quoted = new DerivedSqlIdentifier("simple", true); + SqlIdentifier notSimple = SqlIdentifier.from(new DerivedSqlIdentifier("simple", false), + new DerivedSqlIdentifier("not", false)); + + SoftAssertions.assertSoftly(softly -> { + + softly.assertThat(basis).isEqualTo(equal); + softly.assertThat(equal).isEqualTo(basis); + softly.assertThat(basis).isNotEqualTo(quoted); + softly.assertThat(basis).isNotEqualTo(notSimple); + }); + } +} diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/NamingStrategyUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/NamingStrategyUnitTests.java index 2599dbd461..bb30fd2c63 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/NamingStrategyUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/NamingStrategyUnitTests.java @@ -16,12 +16,12 @@ package org.springframework.data.relational.core.mapping; import static org.assertj.core.api.Assertions.*; -import static org.springframework.data.relational.domain.SqlIdentifier.*; import java.time.LocalDateTime; import java.util.List; import org.junit.Test; + import org.springframework.data.annotation.Id; import org.springframework.data.relational.core.mapping.RelationalPersistentEntityImplUnitTests.DummySubEntity; import org.springframework.data.relational.domain.SqlIdentifier; @@ -42,53 +42,51 @@ public class NamingStrategyUnitTests { @Test public void getTableName() { - assertThat(target.getTableName(persistentEntity.getType())).isEqualTo(quoted("dummy_entity")); - assertThat(target.getTableName(DummySubEntity.class)).isEqualTo(quoted("dummy_sub_entity")); + assertThat(target.getTableName(persistentEntity.getType())).isEqualTo("dummy_entity"); + assertThat(target.getTableName(DummySubEntity.class)).isEqualTo("dummy_sub_entity"); } @Test public void getColumnName() { - assertThat(target.getColumnName(persistentEntity.getPersistentProperty("id"))).isEqualTo(quoted("id")); - assertThat(target.getColumnName(persistentEntity.getPersistentProperty("createdAt"))) - .isEqualTo(quoted("created_at")); + assertThat(target.getColumnName(persistentEntity.getPersistentProperty("id"))).isEqualTo("id"); + assertThat(target.getColumnName(persistentEntity.getPersistentProperty("createdAt"))).isEqualTo("created_at"); assertThat(target.getColumnName(persistentEntity.getPersistentProperty("dummySubEntities"))) - .isEqualTo(quoted("dummy_sub_entities")); + .isEqualTo("dummy_sub_entities"); } @Test public void getReverseColumnName() { assertThat(target.getReverseColumnName(persistentEntity.getPersistentProperty("dummySubEntities"))) - .isEqualTo(quoted("dummy_entity")); + .isEqualTo("dummy_entity"); } @Test public void getKeyColumn() { assertThat(target.getKeyColumn(persistentEntity.getPersistentProperty("dummySubEntities"))) - .isEqualTo(quoted("dummy_entity_key")); + .isEqualTo("dummy_entity_key"); } @Test public void getSchema() { - assertThat(target.getSchema()).isEqualTo(SqlIdentifier.EMPTY); + assertThat(target.getSchema()).isEqualTo(""); } @Test public void getQualifiedTableName() { - assertThat(target.getQualifiedTableName(persistentEntity.getType())).isEqualTo(quoted("dummy_entity")); + assertThat(target.getQualifiedTableName(persistentEntity.getType())).isEqualTo("dummy_entity"); NamingStrategy strategy = new NamingStrategy() { @Override - public SqlIdentifier getSchema() { - return quoted("schema"); + public String getSchema() { + return "schema"; } }; - assertThat(strategy.getQualifiedTableName(persistentEntity.getType())) - .isEqualTo(quoted("schema").concat(quoted("dummy_entity"))); + assertThat(strategy.getQualifiedTableName(persistentEntity.getType())).isEqualTo("schema.dummy_entity"); } static class DummyEntity { diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImplUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImplUnitTests.java index e3fcd4f3dc..1ca3030dd2 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImplUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImplUnitTests.java @@ -23,7 +23,7 @@ /** * Unit tests for {@link RelationalPersistentEntityImpl}. - * + * * @author Oliver Gierke * @author Kazuki Shimizu * @author Bastian Wilhelm @@ -53,7 +53,7 @@ public void emptyTableAnnotationFallsBackToNamingStrategy() { RelationalPersistentEntity entity = mappingContext.getPersistentEntity(DummyEntityWithEmptyAnnotation.class); - assertThat(entity.getTableName()).isEqualTo(quoted("dummy_entity_with_empty_annotation")); + assertThat(entity.getTableName()).isEqualTo(quoted("DUMMY_ENTITY_WITH_EMPTY_ANNOTATION")); } @Table("dummy_sub_entity") diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/domain/DefaultIdentifierProcessingUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/domain/DefaultIdentifierProcessingUnitTests.java index e153abd2ac..399ef39dab 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/domain/DefaultIdentifierProcessingUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/domain/DefaultIdentifierProcessingUnitTests.java @@ -18,13 +18,13 @@ import static org.assertj.core.api.Assertions.*; import org.junit.Test; -import org.springframework.data.relational.domain.IdentifierProcessing.DefaultIdentifierProcessing; + import org.springframework.data.relational.domain.IdentifierProcessing.LetterCasing; import org.springframework.data.relational.domain.IdentifierProcessing.Quoting; /** * unit tests for {@link DefaultIdentifierProcessing}. - * + * * @author Jens Schauder */ public class DefaultIdentifierProcessingUnitTests { @@ -32,7 +32,7 @@ public class DefaultIdentifierProcessingUnitTests { @Test // DATAJDBC-386 public void ansiConformProcessing() { - DefaultIdentifierProcessing processing = new DefaultIdentifierProcessing(Quoting.ANSI, LetterCasing.UPPER_CASE); + DefaultIdentifierProcessing processing = IdentifierProcessing.create(Quoting.ANSI, LetterCasing.UPPER_CASE); assertThat(processing.quote("something")).isEqualTo("\"something\""); assertThat(processing.standardizeLetterCase("aBc")).isEqualTo("ABC"); @@ -41,7 +41,7 @@ public void ansiConformProcessing() { @Test // DATAJDBC-386 public void twoCharacterAsIs() { - DefaultIdentifierProcessing processing = new DefaultIdentifierProcessing(new Quoting("[", "]"), LetterCasing.AS_IS); + DefaultIdentifierProcessing processing = IdentifierProcessing.create(new Quoting("[", "]"), LetterCasing.AS_IS); assertThat(processing.quote("something")).isEqualTo("[something]"); assertThat(processing.standardizeLetterCase("aBc")).isEqualTo("aBc"); diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/domain/IdentifierUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/domain/IdentifierUnitTests.java index 340187bede..67d7224b34 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/domain/IdentifierUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/domain/IdentifierUnitTests.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.List; +import org.junit.Ignore; import org.junit.Test; /** @@ -31,6 +32,7 @@ * @author Jens Schauder * @author Mark Paluch */ +@Ignore public class IdentifierUnitTests { @Test // DATAJDBC-326 diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/SqlIdentifierUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/domain/SqlIdentifierUnitTests.java similarity index 52% rename from spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/SqlIdentifierUnitTests.java rename to spring-data-relational/src/test/java/org/springframework/data/relational/domain/SqlIdentifierUnitTests.java index 909cef124c..67c4cc6ea3 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/SqlIdentifierUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/domain/SqlIdentifierUnitTests.java @@ -13,83 +13,51 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.relational.core.mapping; +package org.springframework.data.relational.domain; import static org.assertj.core.api.Assertions.*; import static org.springframework.data.relational.domain.SqlIdentifier.*; import org.assertj.core.api.SoftAssertions; import org.junit.Test; -import org.springframework.data.relational.domain.IdentifierProcessing; -import org.springframework.data.relational.domain.IdentifierProcessing.DefaultIdentifierProcessing; + import org.springframework.data.relational.domain.IdentifierProcessing.LetterCasing; import org.springframework.data.relational.domain.IdentifierProcessing.Quoting; -import org.springframework.data.relational.domain.SqlIdentifier; /** - * Unit tests for SqlIdentifier. - * + * Unit tests for {@link SqlIdentifier}. + * * @author Jens Schauder + * @author Mark Paluch */ public class SqlIdentifierUnitTests { - public static final DefaultIdentifierProcessing BRACKETS_LOWER_CASE = new DefaultIdentifierProcessing( - new Quoting("[", "]"), LetterCasing.LOWER_CASE); + public static final IdentifierProcessing BRACKETS_LOWER_CASE = IdentifierProcessing.create(new Quoting("[", "]"), + LetterCasing.LOWER_CASE); @Test // DATAJDBC-386 public void quotedSimpleObjectIdentifier() { - SimpleSqlIdentifier identifier = quoted("someName"); + SqlIdentifier identifier = quoted("someName"); assertThat(identifier.toSql(BRACKETS_LOWER_CASE)).isEqualTo("[someName]"); - assertThat(identifier.toColumnName(BRACKETS_LOWER_CASE)).isEqualTo("someName"); - + assertThat(identifier.getReference(BRACKETS_LOWER_CASE)).isEqualTo("someName"); } @Test // DATAJDBC-386 public void unquotedSimpleObjectIdentifier() { - SimpleSqlIdentifier identifier = unquoted("someName"); + SqlIdentifier identifier = unquoted("someName"); String sql = identifier.toSql(BRACKETS_LOWER_CASE); assertThat(sql).isEqualTo("someName"); - assertThat(identifier.toColumnName(BRACKETS_LOWER_CASE)).isEqualTo("someName"); - } - - @Test // DATAJDBC-386 - public void quotedSimpleObjectIdentifierWithAdjustableLetterCasing() { - - SimpleSqlIdentifier identifier = quoted("someName").withAdjustableLetterCasing(); - - assertThat(identifier.toSql(BRACKETS_LOWER_CASE)).isEqualTo("[somename]"); - assertThat(identifier.toColumnName(BRACKETS_LOWER_CASE)).isEqualTo("somename"); - - } - - @Test // DATAJDBC-386 - public void unquotedSimpleObjectIdentifierWithAdjustableLetterCasing() { - - SimpleSqlIdentifier identifier = unquoted("someName").withAdjustableLetterCasing(); - String sql = identifier.toSql(BRACKETS_LOWER_CASE); - - assertThat(sql).isEqualTo("somename"); - assertThat(identifier.toColumnName(BRACKETS_LOWER_CASE)).isEqualTo("somename"); - } - - @Test // DATAJDBC-386 - public void quotedMultipartObjectIdentifierWithAdjustableLetterCase() { - - SqlIdentifier identifier = quoted("some").withAdjustableLetterCasing() - .concat(quoted("name").withAdjustableLetterCasing()); - String sql = identifier.toSql(IdentifierProcessing.ANSI); - - assertThat(sql).isEqualTo("\"SOME\".\"NAME\""); + assertThat(identifier.getReference(BRACKETS_LOWER_CASE)).isEqualTo("someName"); } @Test // DATAJDBC-386 public void quotedMultipartObjectIdentifier() { - SqlIdentifier identifier = quoted("some").concat(quoted("name")); + SqlIdentifier identifier = SqlIdentifier.from(quoted("some"), quoted("name")); String sql = identifier.toSql(IdentifierProcessing.ANSI); assertThat(sql).isEqualTo("\"some\".\"name\""); @@ -98,7 +66,7 @@ public void quotedMultipartObjectIdentifier() { @Test // DATAJDBC-386 public void unquotedMultipartObjectIdentifier() { - SqlIdentifier identifier = unquoted("some").concat(unquoted("name")); + SqlIdentifier identifier = SqlIdentifier.from(unquoted("some"), unquoted("name")); String sql = identifier.toSql(IdentifierProcessing.ANSI); assertThat(sql).isEqualTo("some.name"); @@ -110,7 +78,7 @@ public void equality() { SqlIdentifier basis = SqlIdentifier.unquoted("simple"); SqlIdentifier equal = SqlIdentifier.unquoted("simple"); SqlIdentifier quoted = quoted("simple"); - SqlIdentifier notSimple = SqlIdentifier.unquoted("simple").concat(unquoted("not")); + SqlIdentifier notSimple = SqlIdentifier.from(unquoted("simple"), unquoted("not")); SoftAssertions.assertSoftly(softly -> { From 4b83d506d9dd809b98ee872db27040fde7db2963 Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Fri, 10 Jan 2020 09:09:46 +0100 Subject: [PATCH 5/6] DATAJDBC-386 - Fixes integration tests. Tests that used the `@Column` annotation to map multiple properties to a single database column failed. Mapping multiple values to one column is possible to allow for entities inside an aggregate to have the id of the aggregate as ID or as part of the ID. The reason for the test failures was that columns get referred to by different ways: Once per DerivedSqlIdentifier (i.e. with normalized spelling). And Once per `@Column` annotation. SqlIdentifier from an `@Column` annotation have always the same spelling, while the normalized version depends on the `Dialect`. In order to make the tests work for all databases all references to the column in question had to get a `@Column` annotation. This in turn required the create scripts to also use quoting when the normal case of the database did not match the case choosen in the annotation. Finally there were some tests that used hand coded SQL which now uses `SqlIdentifier` and an injected `Dialect` to arrive at the corrrect SQL syntax. --- ...JdbcAggregateTemplateIntegrationTests.java | 2 +- ...dedNotInAggregateRootIntegrationTests.java | 40 ++++++++++------ ...mbeddedWithCollectionIntegrationTests.java | 47 ++++++++++++------- ...EmbeddedWithReferenceIntegrationTests.java | 38 ++++++++++----- .../src/test/resources/logback.xml | 2 +- ...egateTemplateIntegrationTests-postgres.sql | 19 ++++---- ...tInAggregateRootIntegrationTests-mysql.sql | 13 ++++- ...AggregateRootIntegrationTests-postgres.sql | 13 ++++- ...ithCollectionIntegrationTests-postgres.sql | 15 +++++- ...WithReferenceIntegrationTests-postgres.sql | 22 ++++++++- 10 files changed, 148 insertions(+), 63 deletions(-) diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java index f35ff0a1f4..af89e71edb 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java @@ -821,6 +821,7 @@ private Long count(String tableName) { return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM " + tableName, emptyMap(), Long.class); } + @Table("ARRAY_OWNER") private static class ArrayOwner { @Id Long id; @@ -1039,7 +1040,6 @@ static class AggregateWithImmutableVersion { @Id private Long id; @Version private final Long version; - } @Data diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests.java index 10147bdc30..68a00fa9b6 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests.java @@ -20,6 +20,8 @@ import lombok.Data; +import java.sql.SQLException; + import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -30,9 +32,11 @@ import org.springframework.data.annotation.Id; import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory; import org.springframework.data.jdbc.testing.TestConfiguration; +import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.data.relational.core.mapping.Column; import org.springframework.data.relational.core.mapping.Embedded; import org.springframework.data.relational.core.mapping.Embedded.OnEmpty; +import org.springframework.data.relational.domain.SqlIdentifier; import org.springframework.data.repository.CrudRepository; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @@ -74,17 +78,24 @@ DummyEntityRepository dummyEntityRepository() { @Autowired NamedParameterJdbcTemplate template; @Autowired DummyEntityRepository repository; + @Autowired Dialect dialect; @Test // DATAJDBC-111 - public void savesAnEntity() { + public void savesAnEntity() throws SQLException { DummyEntity entity = repository.save(createDummyEntity()); - assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity", - "id = " + entity.getId())).isEqualTo(1); + assertThat(countRowsInTable("dummy_entity", entity.getId())).isEqualTo(1); + assertThat(countRowsInTable("dummy_entity2", entity.getId())).isEqualTo(1); + } + + private int countRowsInTable(String name, long idValue) { + + SqlIdentifier id = SqlIdentifier.quoted("ID"); + String whereClause = id.toSql(dialect.getIdentifierProcessing()) + " = " + idValue; - assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity2", - "id = " + entity.getId())).isEqualTo(1); + return JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), + name, whereClause); } @Test // DATAJDBC-111 @@ -95,7 +106,8 @@ public void saveAndLoadAnEntity() { assertThat(repository.findById(entity.getId())).hasValueSatisfying(it -> { assertThat(it.getId()).isEqualTo(entity.getId()); assertThat(it.getDummyEntity2().getTest()).isEqualTo(entity.getDummyEntity2().getTest()); - assertThat(it.getDummyEntity2().getEmbeddable().getAttr()).isEqualTo(entity.getDummyEntity2().getEmbeddable().getAttr()); + assertThat(it.getDummyEntity2().getEmbeddable().getAttr()) + .isEqualTo(entity.getDummyEntity2().getEmbeddable().getAttr()); }); } @@ -130,7 +142,8 @@ public void update() { assertThat(repository.findById(entity.getId())).hasValueSatisfying(it -> { assertThat(it.getDummyEntity2().getTest()).isEqualTo(saved.getDummyEntity2().getTest()); - assertThat(it.getDummyEntity2().getEmbeddable().getAttr()).isEqualTo(saved.getDummyEntity2().getEmbeddable().getAttr()); + assertThat(it.getDummyEntity2().getEmbeddable().getAttr()) + .isEqualTo(saved.getDummyEntity2().getEmbeddable().getAttr()); }); } @@ -154,7 +167,8 @@ public void updateMany() { assertThat(repository.findAll()) // .extracting(d -> d.getDummyEntity2().getEmbeddable().getAttr()) // - .containsExactlyInAnyOrder(entity.getDummyEntity2().getEmbeddable().getAttr(), other.getDummyEntity2().getEmbeddable().getAttr()); + .containsExactlyInAnyOrder(entity.getDummyEntity2().getEmbeddable().getAttr(), + other.getDummyEntity2().getEmbeddable().getAttr()); } @Test // DATAJDBC-111 @@ -233,22 +247,20 @@ interface DummyEntityRepository extends CrudRepository {} @Data static class DummyEntity { - @Id Long id; + @Column("ID") @Id Long id; String test; - @Column("ID") - DummyEntity2 dummyEntity2; + @Column("ID") DummyEntity2 dummyEntity2; } @Data static class DummyEntity2 { - @Id Long id; + @Column("ID") @Id Long id; String test; - @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "prefix_") - Embeddable embeddable; + @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "prefix_") Embeddable embeddable; } @Data diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithCollectionIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithCollectionIntegrationTests.java index 93c3bc56f3..39912f6a87 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithCollectionIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithCollectionIntegrationTests.java @@ -20,6 +20,10 @@ import lombok.Data; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -30,10 +34,12 @@ import org.springframework.data.annotation.Id; import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory; import org.springframework.data.jdbc.testing.TestConfiguration; +import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.data.relational.core.mapping.Column; import org.springframework.data.relational.core.mapping.Embedded; import org.springframework.data.relational.core.mapping.Embedded.OnEmpty; import org.springframework.data.relational.core.mapping.MappedCollection; +import org.springframework.data.relational.domain.SqlIdentifier; import org.springframework.data.repository.CrudRepository; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @@ -43,9 +49,6 @@ import org.springframework.test.jdbc.JdbcTestUtils; import org.springframework.transaction.annotation.Transactional; -import java.util.ArrayList; -import java.util.List; - /** * Very simple use cases for creation and usage of JdbcRepositories with test {@link Embedded} annotation in Entities. * @@ -78,17 +81,23 @@ DummyEntityRepository dummyEntityRepository() { @Autowired NamedParameterJdbcTemplate template; @Autowired DummyEntityRepository repository; + @Autowired Dialect dialect; @Test // DATAJDBC-111 - public void savesAnEntity() { + public void savesAnEntity() throws SQLException { DummyEntity entity = repository.save(createDummyEntity()); - assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity", - "id = " + entity.getId())).isEqualTo(1); + assertThat(countRowsInTable("dummy_entity", entity.getId())).isEqualTo(1); + assertThat(countRowsInTable("dummy_entity2", entity.getId())).isEqualTo(2); + } + + private int countRowsInTable(String name, long idValue) { + + SqlIdentifier id = SqlIdentifier.quoted("ID"); + String whereClause = id.toSql(dialect.getIdentifierProcessing()) + " = " + idValue; - assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity2", - "id = " + entity.getId())).isEqualTo(2); + return JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), name, whereClause); } @Test // DATAJDBC-111 @@ -100,8 +109,10 @@ public void saveAndLoadAnEntity() { assertThat(it.getId()).isEqualTo(entity.getId()); assertThat(it.getEmbeddable().getTest()).isEqualTo(entity.getEmbeddable().getTest()); assertThat(it.getEmbeddable().getList().size()).isEqualTo(entity.getEmbeddable().getList().size()); - assertThat(it.getEmbeddable().getList().get(0).getTest()).isEqualTo(entity.getEmbeddable().getList().get(0).getTest()); - assertThat(it.getEmbeddable().getList().get(1).getTest()).isEqualTo(entity.getEmbeddable().getList().get(1).getTest()); + assertThat(it.getEmbeddable().getList().get(0).getTest()) + .isEqualTo(entity.getEmbeddable().getList().get(0).getTest()); + assertThat(it.getEmbeddable().getList().get(1).getTest()) + .isEqualTo(entity.getEmbeddable().getList().get(1).getTest()); }); } @@ -138,8 +149,10 @@ public void update() { assertThat(it.getId()).isEqualTo(saved.getId()); assertThat(it.getEmbeddable().getTest()).isEqualTo(saved.getEmbeddable().getTest()); assertThat(it.getEmbeddable().getList().size()).isEqualTo(saved.getEmbeddable().getList().size()); - assertThat(it.getEmbeddable().getList().get(0).getTest()).isEqualTo(saved.getEmbeddable().getList().get(0).getTest()); - assertThat(it.getEmbeddable().getList().get(1).getTest()).isEqualTo(saved.getEmbeddable().getList().get(1).getTest()); + assertThat(it.getEmbeddable().getList().get(0).getTest()) + .isEqualTo(saved.getEmbeddable().getList().get(0).getTest()); + assertThat(it.getEmbeddable().getList().get(1).getTest()) + .isEqualTo(saved.getEmbeddable().getList().get(1).getTest()); }); } @@ -163,7 +176,8 @@ public void updateMany() { assertThat(repository.findAll()) // .extracting(d -> d.getEmbeddable().getList().get(0).getTest()) // - .containsExactlyInAnyOrder(entity.getEmbeddable().getList().get(0).getTest(), other.getEmbeddable().getList().get(0).getTest()); + .containsExactlyInAnyOrder(entity.getEmbeddable().getList().get(0).getTest(), + other.getEmbeddable().getList().get(0).getTest()); } @Test // DATAJDBC-111 @@ -246,18 +260,17 @@ interface DummyEntityRepository extends CrudRepository {} @Data private static class DummyEntity { + @Column("ID") @Id Long id; String test; - @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "PREFIX_") - Embeddable embeddable; + @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "PREFIX_") Embeddable embeddable; } @Data private static class Embeddable { - @MappedCollection(idColumn = "ID", keyColumn = "ORDER_KEY") - List list = new ArrayList<>(); + @MappedCollection(idColumn = "ID", keyColumn = "ORDER_KEY") List list = new ArrayList<>(); String test; } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithReferenceIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithReferenceIntegrationTests.java index d29091e154..e1ed076f4f 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithReferenceIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithReferenceIntegrationTests.java @@ -20,6 +20,8 @@ import lombok.Data; +import java.sql.SQLException; + import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -30,9 +32,11 @@ import org.springframework.data.annotation.Id; import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory; import org.springframework.data.jdbc.testing.TestConfiguration; +import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.data.relational.core.mapping.Column; import org.springframework.data.relational.core.mapping.Embedded; import org.springframework.data.relational.core.mapping.Embedded.OnEmpty; +import org.springframework.data.relational.domain.SqlIdentifier; import org.springframework.data.repository.CrudRepository; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @@ -74,17 +78,23 @@ DummyEntityRepository dummyEntityRepository() { @Autowired NamedParameterJdbcTemplate template; @Autowired DummyEntityRepository repository; + @Autowired Dialect dialect; @Test // DATAJDBC-111 public void savesAnEntity() { DummyEntity entity = repository.save(createDummyEntity()); - assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity", - "id = " + entity.getId())).isEqualTo(1); + assertThat(countRowsInTable("dummy_entity", entity.getId())).isEqualTo(1); + assertThat(countRowsInTable("dummy_entity2", entity.getId())).isEqualTo(1); + } + + private int countRowsInTable(String name, long idValue) { - assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity2", - "id = " + entity.getId())).isEqualTo(1); + SqlIdentifier id = SqlIdentifier.quoted("ID"); + String whereClause = id.toSql(dialect.getIdentifierProcessing()) + " = " + idValue; + + return JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), name, whereClause); } @Test // DATAJDBC-111 @@ -95,7 +105,8 @@ public void saveAndLoadAnEntity() { assertThat(repository.findById(entity.getId())).hasValueSatisfying(it -> { assertThat(it.getId()).isEqualTo(entity.getId()); assertThat(it.getEmbeddable().getTest()).isEqualTo(entity.getEmbeddable().getTest()); - assertThat(it.getEmbeddable().getDummyEntity2().getTest()).isEqualTo(entity.getEmbeddable().getDummyEntity2().getTest()); + assertThat(it.getEmbeddable().getDummyEntity2().getTest()) + .isEqualTo(entity.getEmbeddable().getDummyEntity2().getTest()); }); } @@ -130,7 +141,8 @@ public void update() { assertThat(repository.findById(entity.getId())).hasValueSatisfying(it -> { assertThat(it.getEmbeddable().getTest()).isEqualTo(saved.getEmbeddable().getTest()); - assertThat(it.getEmbeddable().getDummyEntity2().getTest()).isEqualTo(saved.getEmbeddable().getDummyEntity2().getTest()); + assertThat(it.getEmbeddable().getDummyEntity2().getTest()) + .isEqualTo(saved.getEmbeddable().getDummyEntity2().getTest()); }); } @@ -154,7 +166,8 @@ public void updateMany() { assertThat(repository.findAll()) // .extracting(d -> d.getEmbeddable().getDummyEntity2().getTest()) // - .containsExactlyInAnyOrder(entity.getEmbeddable().getDummyEntity2().getTest(), other.getEmbeddable().getDummyEntity2().getTest()); + .containsExactlyInAnyOrder(entity.getEmbeddable().getDummyEntity2().getTest(), + other.getEmbeddable().getDummyEntity2().getTest()); } @Test // DATAJDBC-111 @@ -233,19 +246,18 @@ interface DummyEntityRepository extends CrudRepository {} @Data private static class DummyEntity { - @Id Long id; + + @Column("ID") @Id Long id; String test; - @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "PREFIX_") - Embeddable embeddable; + @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "PREFIX_") Embeddable embeddable; } @Data private static class Embeddable { - @Column("ID") - DummyEntity2 dummyEntity2; + @Column("ID") DummyEntity2 dummyEntity2; String test; } @@ -253,7 +265,7 @@ private static class Embeddable { @Data private static class DummyEntity2 { - @Id Long id; + @Column("ID") @Id Long id; String test; } diff --git a/spring-data-jdbc/src/test/resources/logback.xml b/spring-data-jdbc/src/test/resources/logback.xml index 8ef5ba0910..ade0cc6ed6 100644 --- a/spring-data-jdbc/src/test/resources/logback.xml +++ b/spring-data-jdbc/src/test/resources/logback.xml @@ -8,7 +8,7 @@ - + diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-postgres.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-postgres.sql index ee8c090c43..30b158fc3d 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-postgres.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-postgres.sql @@ -15,12 +15,12 @@ DROP TABLE WITH_READ_ONLY; CREATE TABLE LEGO_SET ( - "id1" SERIAL PRIMARY KEY, - NAME VARCHAR(30) + "id1" SERIAL PRIMARY KEY, + NAME VARCHAR(30) ); CREATE TABLE MANUAL ( - "id2" SERIAL PRIMARY KEY, + "id2" SERIAL PRIMARY KEY, LEGO_SET BIGINT, ALTERNATIVE BIGINT, CONTENT VARCHAR(2000) @@ -32,7 +32,7 @@ ALTER TABLE MANUAL CREATE TABLE ONE_TO_ONE_PARENT ( - "id3" SERIAL PRIMARY KEY, + "id3" SERIAL PRIMARY KEY, content VARCHAR(30) ); CREATE TABLE Child_No_Id @@ -43,9 +43,10 @@ CREATE TABLE Child_No_Id CREATE TABLE LIST_PARENT ( - "id4" SERIAL PRIMARY KEY, - NAME VARCHAR(100) + "id4" SERIAL PRIMARY KEY, + NAME VARCHAR(100) ); + CREATE TABLE element_no_id ( content VARCHAR(100), @@ -53,14 +54,14 @@ CREATE TABLE element_no_id LIST_PARENT INTEGER ); -CREATE TABLE ARRAY_OWNER +CREATE TABLE "ARRAY_OWNER" ( ID SERIAL PRIMARY KEY, DIGITS VARCHAR(20)[10], MULTIDIMENSIONAL VARCHAR(20)[10][10] ); -CREATE TABLE BYTE_ARRAY_OWNER RelationalPersistentEntityImplUnitTests. +CREATE TABLE BYTE_ARRAY_OWNER ( ID SERIAL PRIMARY KEY, BINARY_DATA BYTEA NOT NULL @@ -305,7 +306,7 @@ CREATE TABLE NO_ID_MAP_CHAIN0 ) ); -CREATE TABLE VERSIONED_AGGREGATE +CREATE TABLE "VERSIONED_AGGREGATE" ( ID SERIAL PRIMARY KEY, VERSION BIGINT diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests-mysql.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests-mysql.sql index c9a201e612..c8ae948db3 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests-mysql.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests-mysql.sql @@ -1,2 +1,11 @@ -CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100)); -CREATE TABLE dummy_entity2 (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100), PREFIX_ATTR BIGINT); +CREATE TABLE dummy_entity +( + ID BIGINT AUTO_INCREMENT PRIMARY KEY, + TEST VARCHAR(100) +); +CREATE TABLE dummy_entity2 +( + ID BIGINT PRIMARY KEY, + TEST VARCHAR(100), + PREFIX_ATTR BIGINT +); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests-postgres.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests-postgres.sql index 13d7c6a110..fa4b1a1392 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests-postgres.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests-postgres.sql @@ -1,4 +1,13 @@ DROP TABLE dummy_entity; -CREATE TABLE dummy_entity (id SERIAL PRIMARY KEY, TEST VARCHAR(100)); +CREATE TABLE dummy_entity +( + "ID" SERIAL PRIMARY KEY, + TEST VARCHAR(100) +); DROP TABLE dummy_entity2; -CREATE TABLE dummy_entity2 (id SERIAL PRIMARY KEY, TEST VARCHAR(100), PREFIX_ATTR BIGINT); +CREATE TABLE dummy_entity2 +( + "ID" INTEGER PRIMARY KEY, + TEST VARCHAR(100), + PREFIX_ATTR BIGINT +); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedWithCollectionIntegrationTests-postgres.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedWithCollectionIntegrationTests-postgres.sql index fa9cff08b2..4b49f1ef89 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedWithCollectionIntegrationTests-postgres.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedWithCollectionIntegrationTests-postgres.sql @@ -1,4 +1,15 @@ DROP TABLE dummy_entity; -CREATE TABLE dummy_entity (id SERIAL PRIMARY KEY, TEST VARCHAR(100), PREFIX_TEST VARCHAR(100)); +CREATE TABLE dummy_entity +( + "ID" SERIAL PRIMARY KEY, + TEST VARCHAR(100), + PREFIX_TEST VARCHAR(100) +); DROP TABLE dummy_entity2; -CREATE TABLE dummy_entity2 (id BIGINT, ORDER_KEY BIGINT, TEST VARCHAR(100), PRIMARY KEY (id, ORDER_KEY)); +CREATE TABLE dummy_entity2 +( + "ID" BIGINT, + "ORDER_KEY" BIGINT, + TEST VARCHAR(100), + PRIMARY KEY ("ID", "ORDER_KEY") +); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedWithReferenceIntegrationTests-postgres.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedWithReferenceIntegrationTests-postgres.sql index c4c8cef0c0..c8128208d3 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedWithReferenceIntegrationTests-postgres.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedWithReferenceIntegrationTests-postgres.sql @@ -1,4 +1,22 @@ DROP TABLE dummy_entity; -CREATE TABLE dummy_entity (id SERIAL PRIMARY KEY, TEST VARCHAR(100), PREFIX_TEST VARCHAR(100)); +CREATE TABLE dummy_entity +( + "ID" SERIAL PRIMARY KEY, + TEST VARCHAR(100), + PREFIX_TEST VARCHAR(100) +); DROP TABLE dummy_entity2; -CREATE TABLE dummy_entity2 (id SERIAL PRIMARY KEY, TEST VARCHAR(100)); +CREATE TABLE dummy_entity2 +( + "ID" SERIAL PRIMARY KEY, + TEST VARCHAR(100) +); +-- +-- SELECT "dummy_entity"."ID" AS "ID", +-- "dummy_entity"."test" AS "test", +-- "dummy_entity"."prefix_test" AS "prefix_test", +-- "PREFIX_dummyEntity2"."id" AS "prefix_dummyentity2_id", +-- "PREFIX_dummyEntity2"."test" AS "prefix_dummyentity2_test" +-- FROM "dummy_entity" +-- LEFT OUTER JOIN "dummy_entity2" AS "PREFIX_dummyEntity2" ON +-- "PREFIX_dummyEntity2"."ID" = "dummy_entity"."ID" \ No newline at end of file From 7cefedf48948802888403e5e26b3328a57cadcfd Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Fri, 10 Jan 2020 17:26:58 +0100 Subject: [PATCH 6/6] DATAJDBC-386 - Polishing. Removed a couple of `@Ignore` annotations that got left in the code. --- .../core/AggregateChangeIdGenerationImmutableUnitTests.java | 2 -- .../jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java | 1 - .../core/convert/SqlIdentifierParameterSourceUnitTests.java | 1 - .../data/jdbc/mybatis/MyBatisDataAccessStrategyUnitTests.java | 1 - .../data/relational/domain/CompositeSqlIdentifier.java | 1 + .../data/relational/domain/IdentifierUnitTests.java | 2 -- 6 files changed, 1 insertion(+), 7 deletions(-) diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AggregateChangeIdGenerationImmutableUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AggregateChangeIdGenerationImmutableUnitTests.java index b008627582..49a9b96446 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AggregateChangeIdGenerationImmutableUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AggregateChangeIdGenerationImmutableUnitTests.java @@ -486,8 +486,6 @@ private static class Content { @With @AllArgsConstructor private static class ContentNoId { - // "foo_bar_single" - // "FOO_BAR_TAG_SET" @Column("single") Tag single; Set tagSet; List tagList; diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java index 0a92f41f36..c039973983 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java @@ -50,7 +50,6 @@ * @author Jens Schauder * @author Mark Paluch */ -@Ignore public class DefaultDataAccessStrategyUnitTests { public static final long ID_FROM_ADDITIONAL_VALUES = 23L; diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSourceUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSourceUnitTests.java index dd5a2c2c1d..f4aaed9bde 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSourceUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSourceUnitTests.java @@ -16,7 +16,6 @@ package org.springframework.data.jdbc.core.convert; import org.assertj.core.api.SoftAssertions; -import org.junit.Ignore; import org.junit.Test; import org.springframework.data.relational.domain.IdentifierProcessing; import org.springframework.data.relational.domain.SqlIdentifier; diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategyUnitTests.java index efd121f6d8..45d62633d1 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategyUnitTests.java @@ -48,7 +48,6 @@ * @author Mark Paluch * @author Tyler Van Gorder */ -@Ignore public class MyBatisDataAccessStrategyUnitTests { RelationalMappingContext context = new JdbcMappingContext(); diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/domain/CompositeSqlIdentifier.java b/spring-data-relational/src/main/java/org/springframework/data/relational/domain/CompositeSqlIdentifier.java index ec6aa3613f..86be263b6b 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/domain/CompositeSqlIdentifier.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/domain/CompositeSqlIdentifier.java @@ -32,6 +32,7 @@ class CompositeSqlIdentifier implements SqlIdentifier { private final SqlIdentifier[] parts; CompositeSqlIdentifier(SqlIdentifier... parts) { + Assert.notNull(parts, "SqlIdentifier parts must not be null"); Assert.noNullElements(parts, "SqlIdentifier parts must not contain null elements"); Assert.isTrue(parts.length > 0, "SqlIdentifier parts must not be empty"); diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/domain/IdentifierUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/domain/IdentifierUnitTests.java index 67d7224b34..340187bede 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/domain/IdentifierUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/domain/IdentifierUnitTests.java @@ -23,7 +23,6 @@ import java.util.HashMap; import java.util.List; -import org.junit.Ignore; import org.junit.Test; /** @@ -32,7 +31,6 @@ * @author Jens Schauder * @author Mark Paluch */ -@Ignore public class IdentifierUnitTests { @Test // DATAJDBC-326