diff --git a/pom.xml b/pom.xml
index 4ffa5540e7..fbd666d089 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
org.springframework.data
spring-data-jdbc
- 1.0.0.BUILD-SNAPSHOT
+ 1.0.0.DATAJDBC-107-SNAPSHOT
Spring Data JDBC
Spring Data module for JDBC repositories.
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/model/BasicJdbcPersistentProperty.java b/src/main/java/org/springframework/data/jdbc/mapping/model/BasicJdbcPersistentProperty.java
index 015103c461..63868dd27f 100644
--- a/src/main/java/org/springframework/data/jdbc/mapping/model/BasicJdbcPersistentProperty.java
+++ b/src/main/java/org/springframework/data/jdbc/mapping/model/BasicJdbcPersistentProperty.java
@@ -74,7 +74,7 @@ protected Association createAssociation() {
* @see org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty#getColumnName()
*/
public String getColumnName() {
- return getName();
+ return this.context.getNamingStrategy().getColumnName(this);
}
/**
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/model/DefaultNamingStrategy.java b/src/main/java/org/springframework/data/jdbc/mapping/model/DefaultNamingStrategy.java
new file mode 100644
index 0000000000..5bad582468
--- /dev/null
+++ b/src/main/java/org/springframework/data/jdbc/mapping/model/DefaultNamingStrategy.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.jdbc.mapping.model;
+
+/**
+ * Basic implementation of {@link NamingStrategy} with no schema, table based on {@link Class} and
+ * column name based on {@link JdbcPersistentProperty}.
+ *
+ * NOTE: Can also be used as an adapter. Create an anonymous subclass and override any settings to implement
+ * a different strategy on the fly.
+ *
+ * @author Greg Turnquist
+ */
+public class DefaultNamingStrategy implements NamingStrategy {
+
+ /**
+ * No schema at all!
+ */
+ @Override
+ public String getSchema() {
+ return "";
+ }
+
+ /**
+ * Look up the {@link Class}'s simple name.
+ */
+ @Override
+ public String getTableName(Class> type) {
+ return type.getSimpleName();
+ }
+
+
+ /**
+ * Look up the {@link JdbcPersistentProperty}'s name.
+ */
+ @Override
+ public String getColumnName(JdbcPersistentProperty property) {
+ return property.getName();
+ }
+}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/model/JdbcMappingContext.java b/src/main/java/org/springframework/data/jdbc/mapping/model/JdbcMappingContext.java
index d2c074307b..59cc8b0f8e 100644
--- a/src/main/java/org/springframework/data/jdbc/mapping/model/JdbcMappingContext.java
+++ b/src/main/java/org/springframework/data/jdbc/mapping/model/JdbcMappingContext.java
@@ -17,6 +17,8 @@
import static java.util.Arrays.*;
+import lombok.Getter;
+
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.temporal.Temporal;
@@ -46,7 +48,11 @@ public class JdbcMappingContext extends AbstractMappingContext referencedEntities(Class> rootType, PropertyPath pat
*/
@Override
protected JdbcPersistentEntity createPersistentEntity(TypeInformation typeInformation) {
- return new JdbcPersistentEntityImpl<>(typeInformation);
+ return new JdbcPersistentEntityImpl<>(typeInformation, this.namingStrategy);
}
/*
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/model/JdbcPersistentEntityImpl.java b/src/main/java/org/springframework/data/jdbc/mapping/model/JdbcPersistentEntityImpl.java
index 53342792f2..66a6b62206 100644
--- a/src/main/java/org/springframework/data/jdbc/mapping/model/JdbcPersistentEntityImpl.java
+++ b/src/main/java/org/springframework/data/jdbc/mapping/model/JdbcPersistentEntityImpl.java
@@ -29,6 +29,7 @@
class JdbcPersistentEntityImpl extends BasicPersistentEntity
implements JdbcPersistentEntity {
+ private final NamingStrategy namingStrategy;
private final @Getter String tableName;
/**
@@ -36,11 +37,12 @@ class JdbcPersistentEntityImpl extends BasicPersistentEntity information) {
+ JdbcPersistentEntityImpl(TypeInformation information, NamingStrategy namingStrategy) {
super(information);
- tableName = getType().getSimpleName();
+ this.namingStrategy = namingStrategy;
+ this.tableName = this.namingStrategy.getQualifiedTableName(getType());
}
/*
@@ -49,7 +51,7 @@ class JdbcPersistentEntityImpl extends BasicPersistentEntity type);
+
+ String getColumnName(JdbcPersistentProperty property);
+
+ default String getQualifiedTableName(Class> type) {
+ return this.getSchema() + (this.getSchema().equals("") ? "" : ".") + this.getTableName(type);
+ }
+
+}
diff --git a/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java b/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java
index b2b7003fe0..e4f19ae7ae 100644
--- a/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java
+++ b/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java
@@ -15,14 +15,13 @@
*/
package org.springframework.data.jdbc.repository.support;
-import lombok.RequiredArgsConstructor;
-
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.jdbc.core.JdbcEntityTemplate;
import org.springframework.data.jdbc.mapping.model.BasicJdbcPersistentEntityInformation;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntityInformation;
+import org.springframework.data.jdbc.mapping.model.NamingStrategy;
import org.springframework.data.jdbc.repository.SimpleJdbcRepository;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.RepositoryInformation;
@@ -34,13 +33,19 @@
* @author Jens Schauder
* @since 2.0
*/
-@RequiredArgsConstructor
public class JdbcRepositoryFactory extends RepositoryFactorySupport {
- private final JdbcMappingContext context = new JdbcMappingContext();
+ private final JdbcMappingContext context;
private final NamedParameterJdbcOperations jdbcOperations;
private final ApplicationEventPublisher publisher;
+ public JdbcRepositoryFactory(NamedParameterJdbcOperations namedParameterJdbcOperations, ApplicationEventPublisher publisher, NamingStrategy namingStrategy) {
+
+ this.jdbcOperations = namedParameterJdbcOperations;
+ this.publisher = publisher;
+ this.context = new JdbcMappingContext(namingStrategy);
+ }
+
@SuppressWarnings("unchecked")
@Override
public EntityInformation getEntityInformation(Class aClass) {
diff --git a/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java b/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java
index 0e8dc4e6eb..54bed46a6a 100644
--- a/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java
+++ b/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java
@@ -23,6 +23,8 @@
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
+import org.springframework.data.jdbc.mapping.model.NamingStrategy;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport;
@@ -45,9 +47,12 @@ public class JdbcRepositoryFactoryBean, S, ID extend
"No unique NamedParameterJdbcOperation could be found, " //
+ "nor JdbcOperations or DataSource to construct one from.";
+ private static final String NO_NAMING_STRATEGY_ERROR_MESSAGE = "No unique NamingStrategy could be found.";
+
private static final String NAMED_PARAMETER_JDBC_OPERATIONS_BEAN_NAME = "namedParameterJdbcTemplate";
private static final String JDBC_OPERATIONS_BEAN_NAME = "jdbcTemplate";
private static final String DATA_SOURCE_BEAN_NAME = "dataSource";
+ private static final String NAMING_STRATEGY_BEAN_NAME = "namingStrategy";
private final ApplicationEventPublisher applicationEventPublisher;
private final ApplicationContext context;
@@ -62,7 +67,7 @@ public class JdbcRepositoryFactoryBean, S, ID extend
@Override
protected RepositoryFactorySupport doCreateRepositoryFactory() {
- return new JdbcRepositoryFactory(findOrCreateJdbcOperations(), applicationEventPublisher);
+ return new JdbcRepositoryFactory(findOrCreateJdbcOperations(), applicationEventPublisher, findOrCreateNamingStrategy());
}
private NamedParameterJdbcOperations findOrCreateJdbcOperations() {
@@ -75,6 +80,12 @@ private NamedParameterJdbcOperations findOrCreateJdbcOperations() {
.orElseThrow(() -> new IllegalStateException(NO_NAMED_PARAMETER_JDBC_OPERATION_ERROR_MESSAGE));
}
+ private NamingStrategy findOrCreateNamingStrategy() {
+
+ return getNamingStrategy()
+ .orElse(new DefaultNamingStrategy());
+ }
+
private Optional getNamedParameterJdbcOperations() {
return getBean(NamedParameterJdbcOperations.class, NAMED_PARAMETER_JDBC_OPERATIONS_BEAN_NAME);
}
@@ -87,6 +98,10 @@ private Optional getDataSource() {
return getBean(DataSource.class, DATA_SOURCE_BEAN_NAME);
}
+ private Optional getNamingStrategy() {
+ return getBean(NamingStrategy.class, NAMING_STRATEGY_BEAN_NAME);
+ }
+
private Optional getBean(Class type, String name) {
Map beansOfType = context.getBeansOfType(type);
diff --git a/src/test/java/org/springframework/data/jdbc/core/JdbcEntityTemplateIntegrationTests.java b/src/test/java/org/springframework/data/jdbc/core/JdbcEntityTemplateIntegrationTests.java
index 8b0b657fc3..3eb0b81a14 100644
--- a/src/test/java/org/springframework/data/jdbc/core/JdbcEntityTemplateIntegrationTests.java
+++ b/src/test/java/org/springframework/data/jdbc/core/JdbcEntityTemplateIntegrationTests.java
@@ -30,6 +30,7 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.annotation.Id;
+import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.testing.TestConfiguration;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
@@ -253,7 +254,7 @@ Class> testClass() {
JdbcEntityOperations operations(ApplicationEventPublisher publisher,
NamedParameterJdbcOperations namedParameterJdbcOperations) {
- return new JdbcEntityTemplate(publisher, namedParameterJdbcOperations, new JdbcMappingContext());
+ return new JdbcEntityTemplate(publisher, namedParameterJdbcOperations, new JdbcMappingContext(new DefaultNamingStrategy()));
}
}
}
diff --git a/src/test/java/org/springframework/data/jdbc/core/SqlGeneratorContextBasedNamingStrategyUnitTests.java b/src/test/java/org/springframework/data/jdbc/core/SqlGeneratorContextBasedNamingStrategyUnitTests.java
new file mode 100644
index 0000000000..95a6771db9
--- /dev/null
+++ b/src/test/java/org/springframework/data/jdbc/core/SqlGeneratorContextBasedNamingStrategyUnitTests.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.jdbc.core;
+
+import static org.assertj.core.api.Assertions.*;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+import org.assertj.core.api.SoftAssertions;
+import org.junit.Test;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
+import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
+import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
+import org.springframework.data.jdbc.mapping.model.NamingStrategy;
+import org.springframework.data.mapping.PropertyPath;
+
+/**
+ * Unit tests to verify a contextual {@link NamingStrategy} implementation that customizes using a user-centric {@link ThreadLocal}.
+ *
+ * NOTE: Due to the need to verify SQL generation and {@link SqlGenerator}'s package-private status suggests
+ * this unit test exist in this package, not {@literal org.springframework.data.jdbc.mappings.model}.
+ *
+ * @author Greg Turnquist
+ */
+public class SqlGeneratorContextBasedNamingStrategyUnitTests {
+
+ private final ThreadLocal userHandler = new ThreadLocal<>();
+
+ /**
+ * Use a {@link DefaultNamingStrategy}, but override the schema with a {@link ThreadLocal}-based setting.
+ */
+ private final NamingStrategy contextualNamingStrategy = new DefaultNamingStrategy() {
+ @Override
+ public String getSchema() {
+ return userHandler.get();
+ }
+ };
+
+ @Test // DATAJDBC-107
+ public void findOne() {
+
+ testAgainstMultipleUsers(user -> {
+
+ SqlGenerator sqlGenerator = configureSqlGenerator(contextualNamingStrategy);
+
+ String sql = sqlGenerator.getFindOne();
+
+ SoftAssertions softAssertions = new SoftAssertions();
+ softAssertions.assertThat(sql) //
+ .startsWith("SELECT") //
+ .contains(user + ".DummyEntity.id AS id,") //
+ .contains(user + ".DummyEntity.name AS name,") //
+ .contains("ref.l1id AS ref_l1id") //
+ .contains("ref.content AS ref_content") //
+ .contains("FROM " + user + ".DummyEntity");
+ softAssertions.assertAll();
+ });
+ }
+
+ @Test // DATAJDBC-107
+ public void cascadingDeleteFirstLevel() {
+
+ testAgainstMultipleUsers(user -> {
+
+ SqlGenerator sqlGenerator = configureSqlGenerator(contextualNamingStrategy);
+
+ String sql = sqlGenerator.createDeleteByPath(PropertyPath.from("ref", DummyEntity.class));
+
+ assertThat(sql).isEqualTo(
+ "DELETE FROM " + user + ".ReferencedEntity WHERE " + user + ".DummyEntity = :rootId");
+ });
+ }
+
+ @Test // DATAJDBC-107
+ public void cascadingDeleteAllSecondLevel() {
+
+ testAgainstMultipleUsers(user -> {
+
+ SqlGenerator sqlGenerator = configureSqlGenerator(contextualNamingStrategy);
+
+ String sql = sqlGenerator.createDeleteByPath(PropertyPath.from("ref.further", DummyEntity.class));
+
+ assertThat(sql).isEqualTo(
+ "DELETE FROM " + user + ".SecondLevelReferencedEntity " +
+ "WHERE " + user + ".ReferencedEntity IN " +
+ "(SELECT l1id FROM " + user + ".ReferencedEntity " +
+ "WHERE " + user + ".DummyEntity = :rootId)");
+ });
+ }
+
+ @Test // DATAJDBC-107
+ public void deleteAll() {
+
+ testAgainstMultipleUsers(user -> {
+
+ SqlGenerator sqlGenerator = configureSqlGenerator(contextualNamingStrategy);
+
+ String sql = sqlGenerator.createDeleteAllSql(null);
+
+ assertThat(sql).isEqualTo("DELETE FROM " + user + ".DummyEntity");
+ });
+ }
+
+ @Test // DATAJDBC-107
+ public void cascadingDeleteAllFirstLevel() {
+
+ testAgainstMultipleUsers(user -> {
+
+ SqlGenerator sqlGenerator = configureSqlGenerator(contextualNamingStrategy);
+
+ String sql = sqlGenerator.createDeleteAllSql(PropertyPath.from("ref", DummyEntity.class));
+
+ assertThat(sql).isEqualTo(
+ "DELETE FROM " + user + ".ReferencedEntity WHERE " + user + ".DummyEntity IS NOT NULL");
+ });
+ }
+
+ @Test // DATAJDBC-107
+ public void cascadingDeleteSecondLevel() {
+
+ testAgainstMultipleUsers(user -> {
+
+ SqlGenerator sqlGenerator = configureSqlGenerator(contextualNamingStrategy);
+
+ String sql = sqlGenerator.createDeleteAllSql(PropertyPath.from("ref.further", DummyEntity.class));
+
+ assertThat(sql).isEqualTo(
+ "DELETE FROM " + user + ".SecondLevelReferencedEntity " +
+ "WHERE " + user + ".ReferencedEntity IN " +
+ "(SELECT l1id FROM " + user + ".ReferencedEntity " +
+ "WHERE " + user + ".DummyEntity IS NOT NULL)");
+ });
+ }
+
+ /**
+ * Take a set of user-based assertions and run them against multiple users, in different threads.
+ */
+ private void testAgainstMultipleUsers(Consumer testAssertions) {
+
+ CountDownLatch latch = new CountDownLatch(2);
+
+ threadedTest("User1", latch, testAssertions);
+ threadedTest("User2", latch, testAssertions);
+
+ try {
+ latch.await(10L, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Inside a {@link Runnable}, fetch the {@link ThreadLocal}-based username and execute the provided
+ * set of assertions. Then signal through the provided {@link CountDownLatch}.
+ */
+ private void threadedTest(String user, CountDownLatch latch, Consumer testAssertions) {
+
+ new Thread(() -> {
+ userHandler.set(user);
+
+ testAssertions.accept(user);
+
+ latch.countDown();
+ }).start();
+ }
+
+ /**
+ * Plug in a custom {@link NamingStrategy} for this test case.
+ */
+ private SqlGenerator configureSqlGenerator(NamingStrategy namingStrategy) {
+
+ JdbcMappingContext context = new JdbcMappingContext(namingStrategy);
+ JdbcPersistentEntity> persistentEntity = context.getRequiredPersistentEntity(DummyEntity.class);
+
+ return new SqlGenerator(context, persistentEntity, new SqlGeneratorSource(context));
+ }
+
+ static class DummyEntity {
+
+ @Id Long id;
+ String name;
+ ReferencedEntity ref;
+ }
+
+ static class ReferencedEntity {
+
+ @Id Long l1id;
+ String content;
+ SecondLevelReferencedEntity further;
+ }
+
+ static class SecondLevelReferencedEntity {
+
+ @Id Long l2id;
+ String something;
+ }
+
+}
diff --git a/src/test/java/org/springframework/data/jdbc/core/SqlGeneratorFixedNamingStrategyUnitTests.java b/src/test/java/org/springframework/data/jdbc/core/SqlGeneratorFixedNamingStrategyUnitTests.java
new file mode 100644
index 0000000000..29cecf745e
--- /dev/null
+++ b/src/test/java/org/springframework/data/jdbc/core/SqlGeneratorFixedNamingStrategyUnitTests.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.jdbc.core;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.assertj.core.api.SoftAssertions;
+import org.junit.Test;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
+import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
+import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
+import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
+import org.springframework.data.jdbc.mapping.model.NamingStrategy;
+import org.springframework.data.mapping.PropertyPath;
+
+/**
+ * Unit tests to a fixed {@link NamingStrategy} implementation containing a hard wired schema, table, and property prefix.
+ *
+ * NOTE: Due to the need to verify SQL generation and {@link SqlGenerator}'s package-private status suggests
+ * this unit test exist in this package, not {@literal org.springframework.data.jdbc.mappings.model}.
+ *
+ * @author Greg Turnquist
+ */
+public class SqlGeneratorFixedNamingStrategyUnitTests {
+
+ final NamingStrategy fixedCustomTablePrefixStrategy = new DefaultNamingStrategy() {
+
+ @Override
+ public String getSchema() {
+ return "FixedCustomSchema";
+ }
+
+ @Override
+ public String getTableName(Class> type) {
+ return "FixedCustomTablePrefix_" + type.getSimpleName();
+ }
+
+ @Override
+ public String getColumnName(JdbcPersistentProperty property) {
+ return "FixedCustomPropertyPrefix_" + property.getName();
+ }
+ };
+
+ final NamingStrategy upperCaseLowerCaseStrategy = new DefaultNamingStrategy() {
+
+ @Override
+ public String getTableName(Class> type) {
+ return type.getSimpleName().toUpperCase();
+ }
+
+ @Override
+ public String getColumnName(JdbcPersistentProperty property) {
+ return property.getName().toLowerCase();
+ }
+ };
+
+ @Test // DATAJDBC-107
+ public void findOneWithOverriddenFixedTableName() {
+
+ SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);
+
+ String sql = sqlGenerator.getFindOne();
+
+ 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");
+ softAssertions.assertAll();
+ }
+
+ @Test // DATAJDBC-107
+ public void findOneWithUppercasedTablesAndLowercasedColumns() {
+
+ SqlGenerator sqlGenerator = configureSqlGenerator(upperCaseLowerCaseStrategy);
+
+ String sql = sqlGenerator.getFindOne();
+
+ 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");
+ softAssertions.assertAll();
+ }
+
+ @Test // DATAJDBC-107
+ public void cascadingDeleteFirstLevel() {
+
+ SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);
+
+ String sql = sqlGenerator.createDeleteByPath(PropertyPath.from("ref", DummyEntity.class));
+
+ assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity " +
+ "WHERE FixedCustomSchema.FixedCustomTablePrefix_DummyEntity = :rootId");
+ }
+
+ @Test // DATAJDBC-107
+ public void cascadingDeleteAllSecondLevel() {
+
+ SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);
+
+ String sql = sqlGenerator.createDeleteByPath(PropertyPath.from("ref.further", DummyEntity.class));
+
+ assertThat(sql).isEqualTo(
+ "DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_SecondLevelReferencedEntity " +
+ "WHERE FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity IN " +
+ "(SELECT FixedCustomPropertyPrefix_l1id " +
+ "FROM FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity " +
+ "WHERE FixedCustomSchema.FixedCustomTablePrefix_DummyEntity = :rootId)");
+ }
+
+ @Test // DATAJDBC-107
+ public void deleteAll() {
+
+ SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);
+
+ String sql = sqlGenerator.createDeleteAllSql(null);
+
+ assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_DummyEntity");
+ }
+
+ @Test // DATAJDBC-107
+ public void cascadingDeleteAllFirstLevel() {
+
+ SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);
+
+ String sql = sqlGenerator.createDeleteAllSql(PropertyPath.from("ref", DummyEntity.class));
+
+ assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity " +
+ "WHERE FixedCustomSchema.FixedCustomTablePrefix_DummyEntity IS NOT NULL");
+ }
+
+ @Test // DATAJDBC-107
+ public void cascadingDeleteSecondLevel() {
+
+ SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);
+
+ String sql = sqlGenerator.createDeleteAllSql(PropertyPath.from("ref.further", DummyEntity.class));
+
+ assertThat(sql).isEqualTo(
+ "DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_SecondLevelReferencedEntity " +
+ "WHERE FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity IN " +
+ "(SELECT FixedCustomPropertyPrefix_l1id " +
+ "FROM FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity " +
+ "WHERE FixedCustomSchema.FixedCustomTablePrefix_DummyEntity IS NOT NULL)");
+ }
+
+ /**
+ * Plug in a custom {@link NamingStrategy} for this test case.
+ *
+ * @param namingStrategy
+ */
+ private SqlGenerator configureSqlGenerator(NamingStrategy namingStrategy) {
+
+ JdbcMappingContext context = new JdbcMappingContext(namingStrategy);
+ JdbcPersistentEntity> persistentEntity = context.getRequiredPersistentEntity(DummyEntity.class);
+ return new SqlGenerator(context, persistentEntity, new SqlGeneratorSource(context));
+ }
+
+ static class DummyEntity {
+
+ @Id Long id;
+ String name;
+ ReferencedEntity ref;
+ }
+
+ static class ReferencedEntity {
+
+ @Id Long l1id;
+ String content;
+ SecondLevelReferencedEntity further;
+ }
+
+ static class SecondLevelReferencedEntity {
+
+ @Id Long l2id;
+ String something;
+ }
+
+}
diff --git a/src/test/java/org/springframework/data/jdbc/core/SqlGeneratorUnitTests.java b/src/test/java/org/springframework/data/jdbc/core/SqlGeneratorUnitTests.java
index 14b027aec0..0b9238dbf9 100644
--- a/src/test/java/org/springframework/data/jdbc/core/SqlGeneratorUnitTests.java
+++ b/src/test/java/org/springframework/data/jdbc/core/SqlGeneratorUnitTests.java
@@ -18,10 +18,13 @@
import static org.assertj.core.api.Assertions.*;
import org.assertj.core.api.SoftAssertions;
+import org.junit.Before;
import org.junit.Test;
import org.springframework.data.annotation.Id;
+import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
+import org.springframework.data.jdbc.mapping.model.NamingStrategy;
import org.springframework.data.mapping.PropertyPath;
/**
@@ -31,22 +34,33 @@
*/
public class SqlGeneratorUnitTests {
- JdbcMappingContext context = new JdbcMappingContext();
- JdbcPersistentEntity> persistentEntity = context.getRequiredPersistentEntity(DummyEntity.class);
- SqlGenerator sqlGenerator = new SqlGenerator(context, persistentEntity, new SqlGeneratorSource(context));
+ private NamingStrategy namingStrategy;
+ private JdbcMappingContext context;
+ private JdbcPersistentEntity> persistentEntity;
+ private SqlGenerator sqlGenerator;
+
+ @Before
+ public void setUp() {
+
+ this.namingStrategy = new DefaultNamingStrategy();
+ this.context = new JdbcMappingContext(namingStrategy);
+ this.persistentEntity = context.getRequiredPersistentEntity(DummyEntity.class);
+ this.sqlGenerator = new SqlGenerator(context, persistentEntity, new SqlGeneratorSource(context));
+ }
@Test // DATAJDBC-112
public void findOne() {
String sql = sqlGenerator.getFindOne();
- new SoftAssertions().assertThat(sql) //
+ SoftAssertions softAssertions = new SoftAssertions();
+ softAssertions.assertThat(sql) //
.startsWith("SELECT") //
- .contains("DummyEntity.id as id,") //
- .contains("DummyEntity.name as name,") //
- .contains("ref.id AS ref_id") //
+ .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");
- new SoftAssertions().assertAll();
+ softAssertions.assertAll();
}
@Test // DATAJDBC-112
diff --git a/src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityDeleteWriterUnitTests.java b/src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityDeleteWriterUnitTests.java
index f84b23d8b7..4f66b36fd2 100644
--- a/src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityDeleteWriterUnitTests.java
+++ b/src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityDeleteWriterUnitTests.java
@@ -25,6 +25,7 @@
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.conversion.AggregateChange.Kind;
import org.springframework.data.jdbc.core.conversion.DbAction.Delete;
+import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
/**
@@ -35,7 +36,7 @@
@RunWith(MockitoJUnitRunner.class)
public class JdbcEntityDeleteWriterUnitTests {
- JdbcEntityDeleteWriter converter = new JdbcEntityDeleteWriter(new JdbcMappingContext());
+ JdbcEntityDeleteWriter converter = new JdbcEntityDeleteWriter(new JdbcMappingContext(new DefaultNamingStrategy()));
@Test
public void deleteDeletesTheEntityAndReferencedEntities() {
diff --git a/src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriterUnitTests.java b/src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriterUnitTests.java
index 9d1e352310..87ce0441ba 100644
--- a/src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriterUnitTests.java
+++ b/src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriterUnitTests.java
@@ -27,6 +27,7 @@
import org.springframework.data.jdbc.core.conversion.DbAction.Delete;
import org.springframework.data.jdbc.core.conversion.DbAction.Insert;
import org.springframework.data.jdbc.core.conversion.DbAction.Update;
+import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
/**
@@ -37,7 +38,7 @@
@RunWith(MockitoJUnitRunner.class)
public class JdbcEntityWriterUnitTests {
- JdbcEntityWriter converter = new JdbcEntityWriter(new JdbcMappingContext());
+ JdbcEntityWriter converter = new JdbcEntityWriter(new JdbcMappingContext(new DefaultNamingStrategy()));
@Test // DATAJDBC-112
public void newEntityGetsConvertedToOneInsert() {
diff --git a/src/test/java/org/springframework/data/jdbc/mapping/model/BasicJdbcPersistentPropertyUnitTests.java b/src/test/java/org/springframework/data/jdbc/mapping/model/BasicJdbcPersistentPropertyUnitTests.java
index 1df1dedb65..ce9bf881e4 100644
--- a/src/test/java/org/springframework/data/jdbc/mapping/model/BasicJdbcPersistentPropertyUnitTests.java
+++ b/src/test/java/org/springframework/data/jdbc/mapping/model/BasicJdbcPersistentPropertyUnitTests.java
@@ -28,7 +28,7 @@
import org.springframework.data.mapping.PropertyHandler;
/**
- * Unti tests for the {@link BasicJdbcPersistentProperty}.
+ * Unit tests for the {@link BasicJdbcPersistentProperty}.
*
* @author Jens Schauder
*/
@@ -36,7 +36,9 @@ public class BasicJdbcPersistentPropertyUnitTests {
@Test // DATAJDBC-104
public void enumGetsStoredAsString() {
- JdbcPersistentEntity> persistentEntity = new JdbcMappingContext().getRequiredPersistentEntity(DummyEntity.class);
+
+ JdbcPersistentEntity> persistentEntity = new JdbcMappingContext(new DefaultNamingStrategy())
+ .getRequiredPersistentEntity(DummyEntity.class);
persistentEntity.doWithProperties((PropertyHandler) p -> {
switch (p.getName()) {
diff --git a/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java b/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java
index 230ad6d1ab..316a621415 100644
--- a/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java
+++ b/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java
@@ -33,6 +33,8 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.annotation.Id;
+import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
+import org.springframework.data.jdbc.mapping.model.NamingStrategy;
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
import org.springframework.data.repository.CrudRepository;
@@ -128,22 +130,36 @@ Class> testClass() {
return JdbcRepositoryIdGenerationIntegrationTests.class;
}
+ /**
+ * {@link NamingStrategy} that harmlessly uppercases the table name,
+ * demonstrating how to inject one while not breaking existing SQL operations.
+ */
+ @Bean
+ NamingStrategy namingStrategy() {
+ return new DefaultNamingStrategy() {
+ @Override
+ public String getTableName(Class> type) {
+ return type.getSimpleName().toUpperCase();
+ }
+ };
+ }
+
@Bean
NamedParameterJdbcTemplate template(DataSource db) {
return new NamedParameterJdbcTemplate(db);
}
@Bean
- ReadOnlyIdEntityRepository readOnlyIdRepository(DataSource db) {
+ ReadOnlyIdEntityRepository readOnlyIdRepository(DataSource db, NamingStrategy namingStrategy) {
- return new JdbcRepositoryFactory(new NamedParameterJdbcTemplate(db), mock(ApplicationEventPublisher.class))
+ return new JdbcRepositoryFactory(new NamedParameterJdbcTemplate(db), mock(ApplicationEventPublisher.class), namingStrategy)
.getRepository(ReadOnlyIdEntityRepository.class);
}
@Bean
PrimitiveIdEntityRepository primitiveIdRepository(NamedParameterJdbcTemplate template) {
- return new JdbcRepositoryFactory(template, mock(ApplicationEventPublisher.class))
+ return new JdbcRepositoryFactory(template, mock(ApplicationEventPublisher.class), new DefaultNamingStrategy())
.getRepository(PrimitiveIdEntityRepository.class);
}
}
diff --git a/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java b/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java
index 982152d019..af0a6e5e24 100644
--- a/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java
+++ b/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java
@@ -24,6 +24,7 @@
import org.springframework.data.jdbc.mapping.event.BeforeUpdate;
import org.springframework.data.jdbc.mapping.event.Identifier;
import org.springframework.data.jdbc.mapping.event.JdbcEvent;
+import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
import org.springframework.data.repository.CrudRepository;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
@@ -43,7 +44,7 @@ public class SimpleJdbcRepositoryEventsUnitTests {
public void before() {
NamedParameterJdbcOperations operations = createIdGeneratingOperations();
- JdbcRepositoryFactory factory = new JdbcRepositoryFactory(operations, publisher);
+ JdbcRepositoryFactory factory = new JdbcRepositoryFactory(operations, publisher, new DefaultNamingStrategy());
repository = factory.getRepository(DummyEntityRepository.class);
}
diff --git a/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java b/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java
index 0c93cc3f6d..caa1460b28 100644
--- a/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java
+++ b/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java
@@ -22,6 +22,7 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
+import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
@@ -41,7 +42,7 @@ public class TestConfiguration {
@Bean
JdbcRepositoryFactory jdbcRepositoryFactory() {
- return new JdbcRepositoryFactory(namedParameterJdbcTemplate(), publisher);
+ return new JdbcRepositoryFactory(namedParameterJdbcTemplate(), publisher, new DefaultNamingStrategy());
}
@Bean