DATAJDBC-324 - Add support of read-only columns.
Columns annotated with `ReadOnlyProperty` will be ignored when generating INSERT or UPDATE statements. Original pull request: #112.
This commit is contained in:
committed by
Jens Schauder
parent
8a2382f727
commit
709d6ef4d5
@@ -17,6 +17,7 @@ package org.springframework.data.jdbc.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -24,6 +25,7 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.jdbc.repository.support.SimpleJdbcRepository;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
@@ -41,6 +43,7 @@ import org.springframework.util.Assert;
|
||||
* @author Jens Schauder
|
||||
* @author Yoichi Imai
|
||||
* @author Bastian Wilhelm
|
||||
* @author Oleksandr Kucher
|
||||
*/
|
||||
class SqlGenerator {
|
||||
|
||||
@@ -48,6 +51,7 @@ class SqlGenerator {
|
||||
private final RelationalMappingContext context;
|
||||
private final List<String> columnNames = new ArrayList<>();
|
||||
private final List<String> nonIdColumnNames = new ArrayList<>();
|
||||
private final Set<String> readOnlyColumnNames = new HashSet<>();
|
||||
|
||||
private final Lazy<String> findOneSql = Lazy.of(this::createFindOneSelectSql);
|
||||
private final Lazy<String> findAllSql = Lazy.of(this::createFindAllSql);
|
||||
@@ -93,6 +97,9 @@ class SqlGenerator {
|
||||
if (!entity.isIdProperty(property)) {
|
||||
nonIdColumnNames.add(columnName);
|
||||
}
|
||||
if (property.isAnnotationPresent(ReadOnlyProperty.class)) {
|
||||
readOnlyColumnNames.add(columnName);
|
||||
}
|
||||
}
|
||||
|
||||
private void initEmbeddedColumnNames(RelationalPersistentProperty property, String prefix) {
|
||||
@@ -328,6 +335,7 @@ class SqlGenerator {
|
||||
|
||||
LinkedHashSet<String> columnNamesForInsert = new LinkedHashSet<>(nonIdColumnNames);
|
||||
columnNamesForInsert.addAll(additionalColumns);
|
||||
columnNamesForInsert.removeIf(readOnlyColumnNames::contains);
|
||||
|
||||
String tableColumns = String.join(", ", columnNamesForInsert);
|
||||
|
||||
@@ -344,6 +352,7 @@ class SqlGenerator {
|
||||
|
||||
String setClause = columnNames.stream() //
|
||||
.filter(s -> !s.equals(entity.getIdColumn())) //
|
||||
.filter(s -> !readOnlyColumnNames.contains(s)) //
|
||||
.map(n -> String.format("%s = :%s", n, n)) //
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.jdbc.core.mapping.AggregateReference;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.jdbc.core.mapping.PersistentPropertyPathTestUtils;
|
||||
@@ -40,6 +41,7 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentProp
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Greg Turnquist
|
||||
* @author Oleksandr Kucher
|
||||
*/
|
||||
public class SqlGeneratorUnitTests {
|
||||
|
||||
@@ -226,6 +228,87 @@ public class SqlGeneratorUnitTests {
|
||||
"id1 = :id");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-324
|
||||
public void readOnlyPropertyExcludedFromQuery_when_generateUpdateSql() {
|
||||
|
||||
final SqlGenerator sqlGenerator = createSqlGenerator(EntityWithReadOnlyProperty.class);
|
||||
|
||||
assertThat(sqlGenerator.getUpdate()).isEqualToIgnoringCase( //
|
||||
"UPDATE entity_with_read_only_property " //
|
||||
+ "SET x_name = :x_name " //
|
||||
+ "WHERE x_id = :x_id" //
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-324
|
||||
public void readOnlyPropertyExcludedFromQuery_when_generateInsertSql() {
|
||||
|
||||
final SqlGenerator sqlGenerator = createSqlGenerator(EntityWithReadOnlyProperty.class);
|
||||
|
||||
assertThat(sqlGenerator.getInsert(emptySet())).isEqualToIgnoringCase( //
|
||||
"INSERT INTO entity_with_read_only_property (x_name) " //
|
||||
+ "VALUES (:x_name)" //
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-324
|
||||
public void readOnlyPropertyIncludedIntoQuery_when_generateFindAllSql() {
|
||||
|
||||
final SqlGenerator sqlGenerator = createSqlGenerator(EntityWithReadOnlyProperty.class);
|
||||
|
||||
assertThat(sqlGenerator.getFindAll()).isEqualToIgnoringCase("SELECT "
|
||||
+ "entity_with_read_only_property.x_id AS x_id, " + "entity_with_read_only_property.x_name AS x_name, "
|
||||
+ "entity_with_read_only_property.x_read_only_value AS x_read_only_value "
|
||||
+ "FROM entity_with_read_only_property");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-324
|
||||
public void readOnlyPropertyIncludedIntoQuery_when_generateFindAllByPropertySql() {
|
||||
|
||||
final SqlGenerator sqlGenerator = createSqlGenerator(EntityWithReadOnlyProperty.class);
|
||||
|
||||
assertThat(sqlGenerator.getFindAllByProperty("back-ref", "key-column", true)).isEqualToIgnoringCase( //
|
||||
"SELECT " //
|
||||
+ "entity_with_read_only_property.x_id AS x_id, " //
|
||||
+ "entity_with_read_only_property.x_name AS x_name, " //
|
||||
+ "entity_with_read_only_property.x_read_only_value AS x_read_only_value, " //
|
||||
+ "entity_with_read_only_property.key-column AS key-column " //
|
||||
+ "FROM entity_with_read_only_property " //
|
||||
+ "WHERE back-ref = :back-ref " //
|
||||
+ "ORDER BY key-column" //
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-324
|
||||
public void readOnlyPropertyIncludedIntoQuery_when_generateFindAllInListSql() {
|
||||
|
||||
final SqlGenerator sqlGenerator = createSqlGenerator(EntityWithReadOnlyProperty.class);
|
||||
|
||||
assertThat(sqlGenerator.getFindAllInList()).isEqualToIgnoringCase( //
|
||||
"SELECT " //
|
||||
+ "entity_with_read_only_property.x_id AS x_id, " //
|
||||
+ "entity_with_read_only_property.x_name AS x_name, " //
|
||||
+ "entity_with_read_only_property.x_read_only_value AS x_read_only_value " //
|
||||
+ "FROM entity_with_read_only_property " //
|
||||
+ "WHERE entity_with_read_only_property.x_id in(:ids)" //
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-324
|
||||
public void readOnlyPropertyIncludedIntoQuery_when_generateFindOneSql() {
|
||||
|
||||
final SqlGenerator sqlGenerator = createSqlGenerator(EntityWithReadOnlyProperty.class);
|
||||
|
||||
assertThat(sqlGenerator.getFindOne()).isEqualToIgnoringCase( //
|
||||
"SELECT " //
|
||||
+ "entity_with_read_only_property.x_id AS x_id, " //
|
||||
+ "entity_with_read_only_property.x_name AS x_name, " //
|
||||
+ "entity_with_read_only_property.x_read_only_value AS x_read_only_value " //
|
||||
+ "FROM entity_with_read_only_property " //
|
||||
+ "WHERE entity_with_read_only_property.x_id = :id" //
|
||||
);
|
||||
}
|
||||
|
||||
private PersistentPropertyPath<RelationalPersistentProperty> getPath(String path, Class<?> base) {
|
||||
return PersistentPropertyPathTestUtils.getPath(context, path, base);
|
||||
}
|
||||
@@ -289,4 +372,10 @@ public class SqlGeneratorUnitTests {
|
||||
@Id Long id;
|
||||
}
|
||||
|
||||
static class EntityWithReadOnlyProperty {
|
||||
|
||||
@Id Long id;
|
||||
String name;
|
||||
@ReadOnlyProperty String readOnlyValue;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user