diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateSchemaIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateSchemaIntegrationTests.java new file mode 100644 index 000000000..3ce135e19 --- /dev/null +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateSchemaIntegrationTests.java @@ -0,0 +1,113 @@ +/* + * Copyright 2017-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.jdbc.core; + +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.annotation.Id; +import org.springframework.data.jdbc.core.convert.DataAccessStrategy; +import org.springframework.data.jdbc.core.convert.JdbcConverter; +import org.springframework.data.jdbc.testing.TestConfiguration; +import org.springframework.data.relational.core.mapping.NamingStrategy; +import org.springframework.data.relational.core.mapping.RelationalMappingContext; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.rules.SpringClassRule; +import org.springframework.test.context.junit4.rules.SpringMethodRule; +import org.springframework.transaction.annotation.Transactional; + +import static org.assertj.core.api.Assertions.*; + +/** + * Integration tests for {@link JdbcAggregateTemplate} using an entity mapped with an explicite schema. + * + * @author Jens Schauder + */ +@ContextConfiguration +@Transactional +public class JdbcAggregateTemplateSchemaIntegrationTests { + + @ClassRule public static final SpringClassRule classRule = new SpringClassRule(); + @Rule public SpringMethodRule methodRule = new SpringMethodRule(); + + @Autowired JdbcAggregateOperations template; + @Autowired NamedParameterJdbcOperations jdbcTemplate; + + + @Test + public void insertFindUpdateDelete() { + + DummyEntity entity = new DummyEntity(); + entity.name = "Alfred"; + entity.reference = new Referenced(); + entity.reference.name = "Peter"; + + template.save(entity); + + DummyEntity reloaded = template.findById(entity.id, DummyEntity.class); + + assertThat(reloaded).isNotNull(); + + reloaded.name += " E. Neumann"; + + template.save(reloaded); + + template.deleteById(reloaded.id, DummyEntity.class); + } + + static class DummyEntity { + + @Id Long id; + String name; + Referenced reference; + } + + static class Referenced { + String name; + } + + @Configuration + @Import(TestConfiguration.class) + static class Config { + + @Bean + Class testClass() { + return JdbcAggregateTemplateSchemaIntegrationTests.class; + } + + @Bean + JdbcAggregateOperations operations(ApplicationEventPublisher publisher, RelationalMappingContext context, + DataAccessStrategy dataAccessStrategy, JdbcConverter converter) { + return new JdbcAggregateTemplate(publisher, context, converter, dataAccessStrategy); + } + + @Bean + NamingStrategy namingStrategy() { + return new NamingStrategy() { + @Override + public String getSchema() { + return "other"; + } + }; + } + } +} 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 a0f3a6e07..640b7cd32 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 @@ -51,7 +51,10 @@ class MariaDBDataSourceConfiguration extends DataSourceConfiguration { if (MARIADB_CONTAINER == null) { - MariaDBContainer container = new MariaDBContainer<>().withConfigurationOverride(""); + MariaDBContainer container = new MariaDBContainer<>() + .withUsername("root") + .withPassword("") + .withConfigurationOverride(""); container.start(); MARIADB_CONTAINER = container; 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 d27af0668..2aef78ffd 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 @@ -54,7 +54,11 @@ class MySqlDataSourceConfiguration extends DataSourceConfiguration { if (MYSQL_CONTAINER == null) { - MySQLContainer container = new MySQLContainer<>().withConfigurationOverride(""); + MySQLContainer container = new MySQLContainer<>() + .withUsername("root") + .withPassword("") + .withConfigurationOverride(""); + container.start(); MYSQL_CONTAINER = container; diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateSchemaIntegrationTests-h2.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateSchemaIntegrationTests-h2.sql new file mode 100644 index 000000000..952dd1e34 --- /dev/null +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateSchemaIntegrationTests-h2.sql @@ -0,0 +1,14 @@ +CREATE SCHEMA OTHER; + +CREATE TABLE OTHER.DUMMY_ENTITY +( + ID SERIAL PRIMARY KEY, + NAME VARCHAR(30) +); + +CREATE TABLE OTHER.REFERENCED +( + DUMMY_ENTITY INTEGER, + NAME VARCHAR(30) +); + diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateSchemaIntegrationTests-hsql.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateSchemaIntegrationTests-hsql.sql new file mode 100644 index 000000000..89f780265 --- /dev/null +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateSchemaIntegrationTests-hsql.sql @@ -0,0 +1,15 @@ +CREATE SCHEMA OTHER; + +CREATE TABLE OTHER.DUMMY_ENTITY +( + ID BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY, + NAME VARCHAR(30) +); + + +CREATE TABLE OTHER.REFERENCED +( + DUMMY_ENTITY INTEGER, + NAME VARCHAR(30) +); + diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateSchemaIntegrationTests-mariadb.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateSchemaIntegrationTests-mariadb.sql new file mode 100644 index 000000000..952540639 --- /dev/null +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateSchemaIntegrationTests-mariadb.sql @@ -0,0 +1,15 @@ +CREATE SCHEMA OTHER; + +CREATE TABLE OTHER.DUMMY_ENTITY +( + ID BIGINT AUTO_INCREMENT PRIMARY KEY, + NAME VARCHAR(30) +); + + +CREATE TABLE OTHER.REFERENCED +( + DUMMY_ENTITY INTEGER, + NAME VARCHAR(30) +); + diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateSchemaIntegrationTests-mysql.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateSchemaIntegrationTests-mysql.sql new file mode 100644 index 000000000..952540639 --- /dev/null +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateSchemaIntegrationTests-mysql.sql @@ -0,0 +1,15 @@ +CREATE SCHEMA OTHER; + +CREATE TABLE OTHER.DUMMY_ENTITY +( + ID BIGINT AUTO_INCREMENT PRIMARY KEY, + NAME VARCHAR(30) +); + + +CREATE TABLE OTHER.REFERENCED +( + DUMMY_ENTITY INTEGER, + NAME VARCHAR(30) +); + diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateSchemaIntegrationTests-postgres.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateSchemaIntegrationTests-postgres.sql new file mode 100644 index 000000000..952dd1e34 --- /dev/null +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateSchemaIntegrationTests-postgres.sql @@ -0,0 +1,14 @@ +CREATE SCHEMA OTHER; + +CREATE TABLE OTHER.DUMMY_ENTITY +( + ID SERIAL PRIMARY KEY, + NAME VARCHAR(30) +); + +CREATE TABLE OTHER.REFERENCED +( + DUMMY_ENTITY INTEGER, + NAME VARCHAR(30) +); + 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 226180a81..5db3031fd 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,10 +18,10 @@ package org.springframework.data.relational.core.dialect; import java.util.List; import org.springframework.data.relational.core.sql.IdentifierProcessing; -import org.springframework.data.relational.core.sql.LockOptions; -import org.springframework.data.relational.core.sql.Table; import org.springframework.data.relational.core.sql.IdentifierProcessing.LetterCasing; import org.springframework.data.relational.core.sql.IdentifierProcessing.Quoting; +import org.springframework.data.relational.core.sql.LockOptions; +import org.springframework.data.relational.core.sql.Table; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -30,6 +30,7 @@ import org.springframework.util.ClassUtils; * * @author Mark Paluch * @author Myeonghyeon Lee + * @author Jens Schauder * @since 1.1 */ public class PostgresDialect extends AbstractDialect { @@ -131,7 +132,9 @@ public class PostgresDialect extends AbstractDialect { return ""; } - String tableName = tables.get(0).getName().toSql(this.identifierProcessing); + String tableName = tables.get(0) // get the first table + .getName().getSimpleIdentifier() // without schema + .toSql(this.identifierProcessing); switch (lockOptions.getLockMode()) { diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/CompositeSqlIdentifier.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/CompositeSqlIdentifier.java index 16bc87892..84297b038 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/CompositeSqlIdentifier.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/CompositeSqlIdentifier.java @@ -74,6 +74,11 @@ class CompositeSqlIdentifier implements SqlIdentifier { throw new UnsupportedOperationException("A Composite SQL Identifiers can't be used as a reference name"); } + @Override + public SqlIdentifier getSimpleIdentifier() { + return parts[parts.length - 1]; + } + /* * (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SqlIdentifier.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SqlIdentifier.java index f3d43b0c4..356fef708 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SqlIdentifier.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SqlIdentifier.java @@ -99,6 +99,16 @@ public interface SqlIdentifier { */ SqlIdentifier transform(UnaryOperator transformationFunction); + /** + * Returns the last part of an identifier. For a fully qualified column name {@literal schema.table.column} it will + * just return the column part. If the identifier consists of only a single part, that part is returned. + * + * @return Guaranteed to be not {@literal null}. + */ + default SqlIdentifier getSimpleIdentifier() { + return this; + } + /** * Create a new quoted identifier given {@code name}. *