DATAJDBC-386 - Refactor SqlIdentifier.

Fix bind marker rendering for delete by Id.

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).

Move SqlIdentifier to relational.core.sql package.

Original pull request: #182.
This commit is contained in:
Mark Paluch
2020-01-09 10:22:54 +01:00
parent 558e7386dc
commit b3d5f05258
70 changed files with 1131 additions and 714 deletions

View File

@@ -44,7 +44,7 @@ import org.springframework.data.relational.core.mapping.PersistentPropertyPathEx
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.core.sql.IdentifierProcessing;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
@@ -378,7 +378,7 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
}
Object value = getObjectFromResultSet(
path.extendBy(property).getColumnAlias().toColumnName(identifierProcessing));
path.extendBy(property).getColumnAlias().getReference(identifierProcessing));
return readValue(value, property.getTypeInformation());
}
@@ -433,7 +433,7 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
idValue = newContext.readFrom(idProperty);
} else {
idValue = newContext.getObjectFromResultSet(
path.extendBy(property).getReverseColumnNameAlias().toColumnName(identifierProcessing));
path.extendBy(property).getReverseColumnNameAlias().getReference(identifierProcessing));
}
if (idValue == null) {

View File

@@ -24,7 +24,7 @@ import java.util.function.Function;
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.data.relational.core.sql.SqlIdentifier;
/**
* Delegates each methods to the {@link DataAccessStrategy}s passed to the constructor in turn until the first that does

View File

@@ -22,7 +22,7 @@ import org.springframework.data.jdbc.core.JdbcAggregateOperations;
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.data.relational.core.sql.SqlIdentifier;
import org.springframework.lang.Nullable;
/**

View File

@@ -39,8 +39,8 @@ 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.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
@@ -403,7 +403,7 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
} 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 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
return null;
}
return keys.get(persistentEntity.getIdColumn().toColumnName(getIdentifierProcessing()));
return keys.get(persistentEntity.getIdColumn().getReference(getIdentifierProcessing()));
}
}

View File

@@ -20,7 +20,7 @@ import java.util.Map;
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.data.relational.core.sql.SqlIdentifier;
import org.springframework.util.Assert;
/**

View File

@@ -24,8 +24,8 @@ import java.util.Map;
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.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.lang.NonNull;
@@ -49,7 +49,7 @@ class MapEntityRowMapper<T> implements RowMapper<Map.Entry<Object, T>> {
@Override
public Map.Entry<Object, T> 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));
}

View File

@@ -20,8 +20,8 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentEnti
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;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.SqlIdentifier;
/**
* Utility to get from path to SQL DSL elements.

View File

@@ -17,7 +17,16 @@ package org.springframework.data.jdbc.core.convert;
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;
@@ -33,8 +42,8 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentProp
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.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.data.util.Lazy;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -81,7 +90,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}.
@@ -143,7 +152,7 @@ class SqlGenerator {
}
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 @@ class SqlGenerator {
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,14 +538,15 @@ class SqlGenerator {
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);
}
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.getReference(identifierProcessing))));
}
private String createDeleteByPathAndCriteria(PersistentPropertyPathExtension path,
@@ -666,7 +676,7 @@ class SqlGenerator {
private void initSimpleColumnName(RelationalPersistentProperty property, String prefix) {
SqlIdentifier columnName = property.getColumnName().prefix(prefix);
SqlIdentifier columnName = property.getColumnName().transform(prefix::concat);
columnNames.add(columnName);

View File

@@ -21,7 +21,6 @@ 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;
/**

View File

@@ -21,14 +21,14 @@ 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.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.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
*/
@@ -68,7 +68,7 @@ class SqlIdentifierParameterSource extends AbstractSqlParameterSource {
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 @@ class SqlIdentifierParameterSource extends AbstractSqlParameterSource {
for (SqlIdentifier identifier : others.getIdentifiers()) {
String name = identifier.toColumnName(identifierProcessing);
String name = identifier.getReference(identifierProcessing);
addValue(identifier, others.getValue(name), others.getSqlType(name));
}
}

View File

@@ -38,8 +38,8 @@ 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.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.util.Assert;

View File

@@ -40,6 +40,7 @@ import org.springframework.data.relational.core.conversion.BasicRelationalConver
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 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
List<Content> contentList;
Map<String, Content> contentMap;
List<ContentNoId> contentNoIdList;
@Embedded(onEmpty = Embedded.OnEmpty.USE_NULL) ContentNoId embedded;
@Embedded(onEmpty = Embedded.OnEmpty.USE_NULL, prefix = "fooBar") ContentNoId embedded;
DummyEntity() {
@@ -485,8 +486,9 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
@With
@AllArgsConstructor
private static class ContentNoId {
Tag single;
// "foo_bar_single"
// "FOO_BAR_TAG_SET"
@Column("single") Tag single;
Set<Tag> tagSet;
List<Tag> tagList;
Map<String, Tag> tagMap;

View File

@@ -19,7 +19,7 @@ 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 static org.springframework.data.relational.core.sql.SqlIdentifier.*;
import java.util.List;
@@ -38,6 +38,7 @@ import org.springframework.data.relational.core.conversion.DbAction.UpdateRoot;
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.core.sql.SqlIdentifier;
/**
* Unit tests for {@link DefaultJdbcInterpreter}
@@ -49,7 +50,7 @@ import org.springframework.data.relational.domain.Identifier;
*/
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 class DefaultJdbcInterpreterUnitTests {
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
);
}

View File

@@ -16,7 +16,7 @@
package org.springframework.data.jdbc.core;
import static org.assertj.core.api.SoftAssertions.*;
import static org.springframework.data.relational.domain.SqlIdentifier.*;
import static org.springframework.data.relational.core.sql.SqlIdentifier.*;
import java.util.List;
@@ -99,13 +99,13 @@ public class PersistentPropertyPathExtensionUnitTests {
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 class PersistentPropertyPathExtensionUnitTests {
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 class PersistentPropertyPathExtensionUnitTests {
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"));
});
}

View File

@@ -18,7 +18,7 @@ package org.springframework.data.jdbc.core.convert;
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 static org.springframework.data.relational.core.sql.SqlIdentifier.*;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
@@ -29,6 +29,7 @@ import java.util.HashMap;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.annotation.Id;
import org.springframework.data.convert.ReadingConverter;
@@ -37,7 +38,7 @@ 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.data.relational.core.sql.SqlIdentifier;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
@@ -49,6 +50,7 @@ import org.springframework.jdbc.support.KeyHolder;
* @author Jens Schauder
* @author Mark Paluch
*/
@Ignore
public class DefaultDataAccessStrategyUnitTests {
public static final long ID_FROM_ADDITIONAL_VALUES = 23L;
@@ -104,9 +106,9 @@ public class DefaultDataAccessStrategyUnitTests {
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\" (", "\"ID\"", ") VALUES (", ":id", ")") //
.containsSequence("INSERT INTO \"DUMMY_ENTITY\" (", "reference", ") VALUES (", ":reference", ")");
assertThat(paramSourceCaptor.getValue().getValue("ID")).isEqualTo(ORIGINAL_ID);
assertThat(paramSourceCaptor.getValue().getValue("id")).isEqualTo(ORIGINAL_ID);
}
@Test // DATAJDBC-235
@@ -134,8 +136,8 @@ public class DefaultDataAccessStrategyUnitTests {
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

View File

@@ -60,9 +60,9 @@ 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.SqlIdentifier.SimpleSqlIdentifier;
import org.springframework.data.repository.query.Param;
import org.springframework.util.Assert;
import org.springframework.util.LinkedCaseInsensitiveMap;
/**
* Tests the extraction of entities from a {@link ResultSet} by the {@link EntityRowMapper}.
@@ -81,8 +81,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");
}
};
@@ -728,7 +728,7 @@ public class EntityRowMapperUnitTests {
int index = 0;
while (index < values.length) {
Map<String, Object> row = new HashMap<>();
Map<String, Object> row = new LinkedCaseInsensitiveMap<>();
result.add(row);
for (String column : columns) {

View File

@@ -17,7 +17,7 @@ package org.springframework.data.jdbc.core.convert;
import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.jdbc.core.PropertyPathTestingUtils.*;
import static org.springframework.data.relational.domain.SqlIdentifier.*;
import static org.springframework.data.relational.core.sql.SqlIdentifier.*;
import java.util.List;
import java.util.Map;
@@ -47,7 +47,7 @@ public class JdbcIdentifierBuilderUnitTests {
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 class JdbcIdentifierBuilderUnitTests {
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 class JdbcIdentifierBuilderUnitTests {
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 class JdbcIdentifierBuilderUnitTests {
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 class JdbcIdentifierBuilderUnitTests {
assertThat(identifier.getParts()) //
.extracting("name", "value", "targetType") //
.containsExactly( //
tuple(quoted("dummy_entity"), "parent-eins", UUID.class) //
tuple(quoted("DUMMY_ENTITY"), "parent-eins", UUID.class) //
);
}

View File

@@ -16,7 +16,6 @@
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;
@@ -33,10 +32,9 @@ 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.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;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.IdentifierProcessing.LetterCasing;
import org.springframework.data.relational.core.sql.IdentifierProcessing.Quoting;
/**
* Unit tests to verify a contextual {@link NamingStrategy} implementation that customizes using a user-centric
@@ -56,8 +54,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 +219,7 @@ public class SqlGeneratorContextBasedNamingStrategyUnitTests {
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")

View File

@@ -32,9 +32,9 @@ import org.springframework.data.relational.core.mapping.PersistentPropertyPathEx
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;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.IdentifierProcessing.LetterCasing;
import org.springframework.data.relational.core.sql.IdentifierProcessing.Quoting;
/**
* Unit tests for the {@link SqlGenerator} in a context of the {@link Embedded} annotation.
@@ -54,7 +54,7 @@ public class SqlGeneratorEmbeddedUnitTests {
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

View File

@@ -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.core.sql.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 class SqlGeneratorFixedNamingStrategyUnitTests {
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 class SqlGeneratorFixedNamingStrategyUnitTests {
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 class SqlGeneratorFixedNamingStrategyUnitTests {
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 class SqlGeneratorFixedNamingStrategyUnitTests {
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 class SqlGeneratorFixedNamingStrategyUnitTests {
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 class SqlGeneratorFixedNamingStrategyUnitTests {
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 class SqlGeneratorFixedNamingStrategyUnitTests {
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 class SqlGeneratorFixedNamingStrategyUnitTests {
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<RelationalPersistentProperty> getPath(String path) {

View File

@@ -17,7 +17,7 @@ package org.springframework.data.jdbc.core.convert;
import static java.util.Collections.*;
import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.relational.domain.SqlIdentifier.*;
import static org.springframework.data.relational.core.sql.SqlIdentifier.*;
import java.util.Map;
import java.util.Set;
@@ -25,6 +25,7 @@ import java.util.Set;
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;
@@ -42,11 +43,9 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentProp
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.*;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.IdentifierProcessing.LetterCasing;
import org.springframework.data.relational.core.sql.IdentifierProcessing.Quoting;
/**
* Unit tests for the {@link SqlGenerator}.
@@ -73,7 +72,7 @@ public class SqlGeneratorUnitTests {
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 class SqlGeneratorUnitTests {
"\"VERSIONED_ENTITY\"", //
"SET", //
"WHERE", //
"\"ID1\" = :ID1", //
"\"id1\" = :id1", //
"AND", //
"\"X_VERSION\" = :___oldOptimisticLockingVersion");
}
@@ -276,7 +275,7 @@ public class SqlGeneratorUnitTests {
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 class SqlGeneratorUnitTests {
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 class SqlGeneratorUnitTests {
"\"DUMMY_ENTITY\"", //
"SET", //
"WHERE", //
"\"ID1\" = :ID");
"\"id1\" = :id1");
}
@Test // DATAJDBC-324
@@ -323,8 +322,8 @@ public class SqlGeneratorUnitTests {
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 class SqlGeneratorUnitTests {
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 class SqlGeneratorUnitTests {
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 class SqlGeneratorUnitTests {
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 class SqlGeneratorUnitTests {
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 class SqlGeneratorUnitTests {
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 @@ public class SqlGeneratorUnitTests {
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);
}
}

View File

@@ -16,9 +16,10 @@
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;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.SqlIdentifier;
/**
* Tests for {@link SqlIdentifierParameterSource}.

View File

@@ -16,7 +16,7 @@
package org.springframework.data.jdbc.core.mapping;
import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.relational.domain.SqlIdentifier.*;
import static org.springframework.data.relational.core.sql.SqlIdentifier.*;
import lombok.Data;

View File

@@ -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,11 +23,11 @@ import java.time.LocalDateTime;
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;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
import org.springframework.data.relational.domain.SqlIdentifier;
/**
* Unit tests for the default {@link NamingStrategy}.
@@ -46,42 +45,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

View File

@@ -20,7 +20,7 @@ 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 static org.springframework.data.relational.core.sql.SqlIdentifier.*;
import java.util.Collections;
@@ -38,7 +38,7 @@ import org.springframework.data.mapping.PersistentPropertyPath;
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.core.sql.IdentifierProcessing;
/**
* Unit tests for the {@link MyBatisDataAccessStrategy}, mainly ensuring that the correct statements get's looked up.
@@ -47,6 +47,7 @@ import org.springframework.data.relational.domain.IdentifierProcessing;
* @author Mark Paluch
* @author Tyler Van Gorder
*/
@Ignore
public class MyBatisDataAccessStrategyUnitTests {
RelationalMappingContext context = new JdbcMappingContext();

View File

@@ -100,7 +100,7 @@ public class JdbcRepositoryEmbeddedImmutableIntegrationTests {
@Id Long id;
@Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "prefix_") Embeddable prefixedEmbeddable;
@Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "PREFIX_") Embeddable prefixedEmbeddable;
}
@Value

View File

@@ -251,7 +251,7 @@ public class JdbcRepositoryEmbeddedIntegrationTests {
@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 @@ public class JdbcRepositoryEmbeddedIntegrationTests {
static class CascadedEmbeddable {
String test;
@Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "prefix2_")
@Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "PREFIX2_")
Embeddable embeddable;
}

View File

@@ -33,6 +33,7 @@ import org.springframework.data.jdbc.testing.TestConfiguration;
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.sql.SqlIdentifier;
import org.springframework.data.repository.CrudRepository;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
@@ -237,7 +238,7 @@ public class JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests {
String test;
@Column("id")
@Column("ID")
DummyEntity2 dummyEntity2;
}

View File

@@ -34,6 +34,7 @@ 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.core.sql.SqlIdentifier;
import org.springframework.data.repository.CrudRepository;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
@@ -250,13 +251,13 @@ public class JdbcRepositoryEmbeddedWithCollectionIntegrationTests {
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<DummyEntity2> list = new ArrayList<>();
String test;

View File

@@ -33,6 +33,7 @@ import org.springframework.data.jdbc.testing.TestConfiguration;
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.sql.SqlIdentifier;
import org.springframework.data.repository.CrudRepository;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
@@ -237,14 +238,14 @@ public class JdbcRepositoryEmbeddedWithReferenceIntegrationTests {
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;

View File

@@ -16,7 +16,6 @@
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;
@@ -39,7 +38,6 @@ import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
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;
@@ -167,8 +165,8 @@ public class JdbcRepositoryIdGenerationIntegrationTests {
return new NamingStrategy() {
@Override
public SqlIdentifier getTableName(Class<?> type) {
return unquoted(type.getSimpleName().toUpperCase());
public String getTableName(Class<?> type) {
return type.getSimpleName().toUpperCase();
}
};
}

View File

@@ -16,7 +16,6 @@
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;
@@ -45,7 +44,6 @@ import org.springframework.data.domain.AuditorAware;
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;
@@ -273,8 +271,8 @@ public class EnableJdbcAuditingHsqlIntegrationTests {
return new NamingStrategy() {
public SqlIdentifier getTableName(@NotNull Class<?> type) {
return unquoted("DummyEntity");
public String getTableName(@NotNull Class<?> type) {
return "DummyEntity";
}
};
}

View File

@@ -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
(

View File

@@ -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
);

View File

@@ -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
);
);

View File

@@ -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'
);
);

View File

@@ -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'
);
);

View File

@@ -16,8 +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;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.SqlIdentifier;
/**
* Represents a dialect that is implemented by a particular database. Please note that not all features are supported by
@@ -54,8 +54,9 @@ public interface Dialect {
SelectRenderContext getSelectContext();
/**
* Returns the {@link IdentifierProcessing} used for processing {@link SqlIdentifier} when converting them to SQL snippets or parameter names.
*
* 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
*/

View File

@@ -24,7 +24,7 @@ public class HsqlDbDialect extends AbstractDialect {
public static final HsqlDbDialect INSTANCE = new HsqlDbDialect();
protected HsqlDbDialect() { }
protected HsqlDbDialect() {}
@Override
public LimitClause limit() {
@@ -53,5 +53,4 @@ public class HsqlDbDialect extends AbstractDialect {
return Position.AFTER_ORDER_BY;
}
};
}

View File

@@ -15,10 +15,9 @@
*/
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;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.IdentifierProcessing.LetterCasing;
import org.springframework.data.relational.core.sql.IdentifierProcessing.Quoting;
/**
* A SQL dialect for MySQL.
@@ -90,6 +89,6 @@ public class MySqlDialect extends AbstractDialect {
@Override
public IdentifierProcessing getIdentifierProcessing() {
return new DefaultIdentifierProcessing(new Quoting("`"), LetterCasing.LOWER_CASE);
return IdentifierProcessing.create(new Quoting("`"), LetterCasing.LOWER_CASE);
}
}

View File

@@ -17,10 +17,9 @@ package org.springframework.data.relational.core.dialect;
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.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.IdentifierProcessing.LetterCasing;
import org.springframework.data.relational.core.sql.IdentifierProcessing.Quoting;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -125,6 +124,6 @@ public class PostgresDialect extends AbstractDialect {
@Override
public IdentifierProcessing getIdentifierProcessing() {
return new DefaultIdentifierProcessing(Quoting.ANSI, LetterCasing.LOWER_CASE);
return IdentifierProcessing.create(Quoting.ANSI, LetterCasing.LOWER_CASE);
}
}

View File

@@ -30,8 +30,7 @@ import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
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.relational.core.sql.SqlIdentifier;
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<SimpleSqlIdentifier> columnName;
private final Lazy<SqlIdentifier> columnName;
private final Lazy<Optional<SqlIdentifier>> collectionIdColumnName;
private final Lazy<SqlIdentifier> collectionKeyColumnName;
private final Lazy<Boolean> isEmbedded;
private final Lazy<String> embeddedPrefix;
private final Lazy<Class<?>> columnType = Lazy.of(this::doGetColumnType);
private boolean forceQuote = true;
/**
* Creates a new {@link AnnotationBasedPersistentProperty}.
@@ -93,8 +93,8 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent
this.columnName = Lazy.of(() -> 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 class BasicRelationalPersistentProperty extends AnnotationBasedPersistent
.map(Column::value)) //
.filter(StringUtils::hasText) //
.findFirst() //
.map(name -> 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 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent
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 class BasicRelationalPersistentProperty extends AnnotationBasedPersistent
* @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 class BasicRelationalPersistentProperty extends AnnotationBasedPersistent
@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

View File

@@ -18,8 +18,6 @@ package org.springframework.data.relational.core.mapping;
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<RelationalPersistentProperty, SimpleSqlIdentifier> columnNames = new ConcurrentHashMap<>();
private final Map<RelationalPersistentProperty, SqlIdentifier> keyColumns = new ConcurrentHashMap<>();
private final Map<Class<?>, SqlIdentifier> qualifiedTableNames = new ConcurrentReferenceHashMap<>();
private final Map<Class<?>, SqlIdentifier> tableNames = new ConcurrentReferenceHashMap<>();
private final Map<RelationalPersistentProperty, String> columnNames = new ConcurrentHashMap<>();
private final Map<RelationalPersistentProperty, String> keyColumns = new ConcurrentHashMap<>();
private final Map<Class<?>, String> qualifiedTableNames = new ConcurrentReferenceHashMap<>();
private final Map<Class<?>, String> tableNames = new ConcurrentReferenceHashMap<>();
private final Lazy<SqlIdentifier> schema;
private final Lazy<String> 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 @@ class CachingNamingStrategy implements NamingStrategy {
* @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 @@ class CachingNamingStrategy implements NamingStrategy {
* @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 @@ class CachingNamingStrategy implements NamingStrategy {
* @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 @@ class CachingNamingStrategy implements NamingStrategy {
* @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 @@ class CachingNamingStrategy implements NamingStrategy {
* @see org.springframework.data.relational.core.mapping.NamingStrategy#getSchema()
*/
@Override
public SqlIdentifier getSchema() {
public String getSchema() {
return schema.get();
}
@@ -113,7 +111,7 @@ class CachingNamingStrategy implements NamingStrategy {
* @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);
}
}

View File

@@ -0,0 +1,113 @@
/*
* 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.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.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<String> 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) {
String normalized = processing.standardizeLetterCase(name);
return quoted ? processing.quote(normalized) : normalized;
}
/*
* (non-Javadoc)
* @see org.springframework.data.relational.domain.SqlIdentifier#getReference(org.springframework.data.relational.domain.IdentifierProcessing)
*/
@Override
public String getReference(IdentifierProcessing processing) {
return this.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() {
if (quoted) {
return toSql(IdentifierProcessing.ANSI);
}
return this.name;
}
}

View File

@@ -15,10 +15,7 @@
*/
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.relational.core.sql.IdentifierProcessing;
import org.springframework.data.util.ParsingUtils;
import org.springframework.util.Assert;
@@ -28,7 +25,7 @@ import org.springframework.util.Assert;
* <p>
* 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 +46,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 +82,14 @@ public interface NamingStrategy {
* @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 +97,13 @@ public interface NamingStrategy {
/**
* For a map valued reference A -> Map&gt;X,B&lt; 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";
}
}

View File

@@ -20,8 +20,8 @@ import lombok.EqualsAndHashCode;
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.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.data.util.Lazy;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -394,15 +394,18 @@ public class PersistentPropertyPathExtension {
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 @@ public class PersistentPropertyPathExtension {
String embeddedPrefix = parentLeaf.getEmbeddedPrefix();
return getParentPath().assembleColumnName(suffix.prefix(embeddedPrefix));
return getParentPath().assembleColumnName(suffix.transform(embeddedPrefix::concat));
}
private RelationalPersistentEntity<?> getRequiredLeafEntity() {
@@ -429,7 +432,8 @@ public class PersistentPropertyPathExtension {
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);
}
}

View File

@@ -37,6 +37,7 @@ public class RelationalMappingContext
extends AbstractMappingContext<RelationalPersistentEntity<?>, RelationalPersistentProperty> {
@Getter private final NamingStrategy namingStrategy;
private boolean forceQuote = true;
/**
* Creates a new {@link RelationalMappingContext}.
@@ -59,13 +60,37 @@ public class RelationalMappingContext
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 <T> RelationalPersistentEntity<T> createPersistentEntity(TypeInformation<T> typeInformation) {
return new RelationalPersistentEntityImpl<>(typeInformation, this.namingStrategy);
RelationalPersistentEntityImpl<T> entity = new RelationalPersistentEntityImpl<>(typeInformation,
this.namingStrategy);
entity.setForceQuote(isForceQuote());
return entity;
}
/*
@@ -75,6 +100,11 @@ public class RelationalMappingContext
@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;
}
}

View File

@@ -16,7 +16,7 @@
package org.springframework.data.relational.core.mapping;
import org.springframework.data.mapping.model.MutablePersistentEntity;
import org.springframework.data.relational.domain.SqlIdentifier;
import org.springframework.data.relational.core.sql.SqlIdentifier;
/**
* A {@link org.springframework.data.mapping.PersistentEntity} interface with additional methods for JDBC/RDBMS related

View File

@@ -19,7 +19,7 @@ import java.util.Optional;
import org.springframework.data.mapping.model.BasicPersistentEntity;
import org.springframework.data.mapping.model.PersistentPropertyAccessorFactory;
import org.springframework.data.relational.domain.SqlIdentifier;
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.data.util.Lazy;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.StringUtils;
@@ -36,6 +36,7 @@ class RelationalPersistentEntityImpl<T> extends BasicPersistentEntity<T, Relatio
private final NamingStrategy namingStrategy;
private final Lazy<Optional<SqlIdentifier>> tableName;
private boolean forceQuote = true;
/**
* Creates a new {@link RelationalPersistentEntityImpl} for the given {@link TypeInformation}.
@@ -51,17 +52,33 @@ class RelationalPersistentEntityImpl<T> extends BasicPersistentEntity<T, Relatio
findAnnotation(Table.class)) //
.map(Table::value) //
.filter(StringUtils::hasText) //
.map(name -> 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 @@ class RelationalPersistentEntityImpl<T> extends BasicPersistentEntity<T, Relatio
return String.format("JdbcPersistentEntityImpl<%s>", getType());
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.model.BasicPersistentEntity#setPersistentPropertyAccessorFactory(org.springframework.data.mapping.model.PersistentPropertyAccessorFactory)
*/

View File

@@ -16,8 +16,7 @@
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.data.relational.core.sql.SqlIdentifier;
import org.springframework.lang.Nullable;
/**
@@ -36,7 +35,7 @@ public interface RelationalPersistentProperty extends PersistentProperty<Relatio
*
* @return the name of the column backing this property.
*/
SimpleSqlIdentifier getColumnName();
SqlIdentifier getColumnName();
/**
* The type to be used to store this property in the database. Multidimensional arrays are unwrapped to reflect a

View File

@@ -0,0 +1,108 @@
/*
* 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.sql;
import java.util.StringJoiner;
import java.util.function.UnaryOperator;
import org.springframework.util.Assert;
/**
* Composite {@link SqlIdentifier}.
*
* @author Jens Schauder
* @author Mark Paluch
* @since 2.0
*/
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");
this.parts = parts;
}
/*
* (non-Javadoc)
* @see org.springframework.data.relational.domain.SqlIdentifier#transform(java.util.function.UnaryOperator)
*/
@Override
public SqlIdentifier transform(UnaryOperator<String> 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);
}
}

View File

@@ -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.core.sql;
/**
* 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);
}
}

View File

@@ -0,0 +1,109 @@
/*
* 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.sql;
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 name must not be null or empty");
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<String> 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() {
if (quoted) {
return toSql(IdentifierProcessing.ANSI);
}
return this.name;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2019 the original author or authors.
* 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.
@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.relational.domain;
package org.springframework.data.relational.core.sql;
/**
* 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 @@ public interface IdentifierProcessing {
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 interface IdentifierProcessing {
/**
* 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) {

View File

@@ -0,0 +1,123 @@
/*
* 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.sql;
import java.util.function.UnaryOperator;
/**
* 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.
* <p>
* {@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.
* <p>
* {@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 {
/**
* Null-object.
*/
SqlIdentifier EMPTY = new SqlIdentifier() {
@Override
public SqlIdentifier transform(UnaryOperator<String> transformationFunction) {
return this;
}
@Override
public String toSql(IdentifierProcessing processing) {
throw new UnsupportedOperationException("An empty SqlIdentifier can't be used in to create SQL snippets");
}
@Override
public String getReference(IdentifierProcessing processing) {
throw new UnsupportedOperationException("An empty SqlIdentifier can't be used in to create column names");
}
public String toString() {
return "<NULL-IDENTIFIER>";
}
};
/**
* 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);
/**
* 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<String> 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);
}
/**
* 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);
}
/**
* Create a new composite {@link SqlIdentifier} from one or more {@link SqlIdentifier}s.
* <p>
* Composite identifiers do not allow {@link #transform(UnaryOperator)} transformation.
* </p>
*
* @param sqlIdentifiers the elements of the new identifier.
* @return the new composite identifier.
*/
static SqlIdentifier from(SqlIdentifier... sqlIdentifiers) {
return new CompositeSqlIdentifier(sqlIdentifiers);
}
}

View File

@@ -28,6 +28,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -204,7 +205,7 @@ public final class Identifier {
/**
* Performs this operation on the given arguments.
*
*
* @param name
* @param value
* @param targetType

View File

@@ -1,219 +0,0 @@
/*
* 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 "<NULL-IDENTIFIER>";
}
};
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);
}
}
}

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.relational.repository.query;
import org.springframework.data.relational.domain.SqlIdentifier;
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.data.repository.core.EntityInformation;
/**

View File

@@ -16,7 +16,7 @@
package org.springframework.data.relational.repository.query;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
import org.springframework.data.relational.domain.SqlIdentifier;
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.data.repository.core.EntityMetadata;
/**

View File

@@ -18,7 +18,7 @@ package org.springframework.data.relational.repository.query;
import lombok.Getter;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
import org.springframework.data.relational.domain.SqlIdentifier;
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.util.Assert;
/**

View File

@@ -16,7 +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.core.sql.SqlIdentifier;
import org.springframework.data.relational.repository.query.RelationalEntityInformation;
import org.springframework.data.repository.core.support.PersistentEntityInformation;
import org.springframework.lang.Nullable;

View File

@@ -16,7 +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 static org.springframework.data.relational.core.sql.SqlIdentifier.*;
import lombok.Data;

View File

@@ -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.core.sql.IdentifierProcessing;
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.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);
});
}
}

View File

@@ -16,15 +16,14 @@
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;
/**
* Unit tests for the {@link NamingStrategy}.
@@ -42,53 +41,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 {

View File

@@ -16,14 +16,14 @@
package org.springframework.data.relational.core.mapping;
import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.relational.domain.SqlIdentifier.*;
import static org.springframework.data.relational.core.sql.SqlIdentifier.*;
import org.junit.Test;
import org.springframework.data.annotation.Id;
/**
* Unit tests for {@link RelationalPersistentEntityImpl}.
*
*
* @author Oliver Gierke
* @author Kazuki Shimizu
* @author Bastian Wilhelm
@@ -53,7 +53,7 @@ public class RelationalPersistentEntityImplUnitTests {
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")

View File

@@ -1,123 +0,0 @@
/*
* 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);
});
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2019 the original author or authors.
* 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.
@@ -13,18 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.relational.domain;
package org.springframework.data.relational.core.sql;
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;
import org.springframework.data.relational.core.sql.DefaultIdentifierProcessing;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.IdentifierProcessing.LetterCasing;
import org.springframework.data.relational.core.sql.IdentifierProcessing.Quoting;
/**
* unit tests for {@link DefaultIdentifierProcessing}.
*
*
* @author Jens Schauder
*/
public class DefaultIdentifierProcessingUnitTests {
@@ -32,7 +34,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 +43,7 @@ public class DefaultIdentifierProcessingUnitTests {
@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");

View File

@@ -0,0 +1,93 @@
/*
* 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.sql;
import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.relational.core.sql.SqlIdentifier.*;
import org.assertj.core.api.SoftAssertions;
import org.junit.Test;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
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.SqlIdentifier;
/**
* Unit tests for {@link SqlIdentifier}.
*
* @author Jens Schauder
* @author Mark Paluch
*/
public class SqlIdentifierUnitTests {
public static final IdentifierProcessing BRACKETS_LOWER_CASE = IdentifierProcessing.create(new Quoting("[", "]"),
LetterCasing.LOWER_CASE);
@Test // DATAJDBC-386
public void quotedSimpleObjectIdentifier() {
SqlIdentifier identifier = quoted("someName");
assertThat(identifier.toSql(BRACKETS_LOWER_CASE)).isEqualTo("[someName]");
assertThat(identifier.getReference(BRACKETS_LOWER_CASE)).isEqualTo("someName");
}
@Test // DATAJDBC-386
public void unquotedSimpleObjectIdentifier() {
SqlIdentifier identifier = unquoted("someName");
String sql = identifier.toSql(BRACKETS_LOWER_CASE);
assertThat(sql).isEqualTo("someName");
assertThat(identifier.getReference(BRACKETS_LOWER_CASE)).isEqualTo("someName");
}
@Test // DATAJDBC-386
public void quotedMultipartObjectIdentifier() {
SqlIdentifier identifier = SqlIdentifier.from(quoted("some"), quoted("name"));
String sql = identifier.toSql(IdentifierProcessing.ANSI);
assertThat(sql).isEqualTo("\"some\".\"name\"");
}
@Test // DATAJDBC-386
public void unquotedMultipartObjectIdentifier() {
SqlIdentifier identifier = SqlIdentifier.from(unquoted("some"), 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.from(unquoted("simple"), 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);
});
}
}

View File

@@ -27,6 +27,7 @@ import org.junit.Test;
* Test package dependencies for violations.
*
* @author Jens Schauder
* @author Mark Paluch
*/
public class DependencyTests {
@@ -49,6 +50,7 @@ public class DependencyTests {
classpath() //
// include only Spring Data related classes (for example no JDK code)
.including("org.springframework.data.**") //
.excluding("org.springframework.data.relational.core.sql.**") //
.filterClasspath(new AbstractFunction1<String, Object>() {
@Override
public Object apply(String s) { //

View File

@@ -16,21 +16,26 @@
package org.springframework.data.relational.domain;
import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.relational.domain.SqlIdentifier.*;
import static org.springframework.data.relational.core.sql.SqlIdentifier.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.SqlIdentifier;
/**
* Unit tests for {@link Identifier}.
*
* @author Jens Schauder
* @author Mark Paluch
*/
@Ignore
public class IdentifierUnitTests {
@Test // DATAJDBC-326