Introduce SqlSort.
SqlSort allows the specification of unsafe order-by-expressions. Order-by-expressions that are not declared unsafe are only accepted when they either match a property or consist only of digits, letters, underscore, dot, or parentheses. Closes #1507
This commit is contained in:
@@ -38,6 +38,7 @@ import org.springframework.data.relational.core.query.CriteriaDefinition;
|
||||
import org.springframework.data.relational.core.query.CriteriaDefinition.Comparator;
|
||||
import org.springframework.data.relational.core.query.ValueFunction;
|
||||
import org.springframework.data.relational.core.sql.*;
|
||||
import org.springframework.data.relational.domain.SqlSort;
|
||||
import org.springframework.data.util.Pair;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -56,6 +57,7 @@ import org.springframework.util.ClassUtils;
|
||||
* @author Mark Paluch
|
||||
* @author Roman Chigvintsev
|
||||
* @author Manousos Mathioudakis
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
public class QueryMapper {
|
||||
|
||||
@@ -111,6 +113,8 @@ public class QueryMapper {
|
||||
|
||||
for (Sort.Order order : sort) {
|
||||
|
||||
SqlSort.validate(order);
|
||||
|
||||
Field field = createPropertyField(entity, SqlIdentifier.unquoted(order.getProperty()), this.mappingContext);
|
||||
mappedOrder.add(
|
||||
Sort.Order.by(toSql(field.getMappedColumnName())).with(order.getNullHandling()).with(order.getDirection()));
|
||||
@@ -133,13 +137,22 @@ public class QueryMapper {
|
||||
|
||||
for (Sort.Order order : sort) {
|
||||
|
||||
Field field = createPropertyField(entity, SqlIdentifier.unquoted(order.getProperty()), this.mappingContext);
|
||||
OrderByField orderBy = OrderByField.from(table.column(field.getMappedColumnName()))
|
||||
OrderByField simpleOrderByField = createSimpleOrderByField(table, entity, order);
|
||||
OrderByField orderBy = simpleOrderByField
|
||||
.withNullHandling(order.getNullHandling());
|
||||
mappedOrder.add(order.isAscending() ? orderBy.asc() : orderBy.desc());
|
||||
}
|
||||
|
||||
return mappedOrder;
|
||||
|
||||
}
|
||||
|
||||
private OrderByField createSimpleOrderByField(Table table, RelationalPersistentEntity<?> entity, Sort.Order order) {
|
||||
|
||||
SqlSort.validate(order);
|
||||
|
||||
Field field = createPropertyField(entity, SqlIdentifier.unquoted(order.getProperty()), this.mappingContext);
|
||||
return OrderByField.from(table.column(field.getMappedColumnName()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,6 +20,8 @@ import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.domain.Sort.Order.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
@@ -35,6 +37,7 @@ import org.springframework.data.relational.core.mapping.Column;
|
||||
import org.springframework.data.relational.core.query.Criteria;
|
||||
import org.springframework.data.relational.core.sql.Expression;
|
||||
import org.springframework.data.relational.core.sql.Functions;
|
||||
import org.springframework.data.relational.core.sql.OrderByField;
|
||||
import org.springframework.data.relational.core.sql.Table;
|
||||
import org.springframework.r2dbc.core.Parameter;
|
||||
import org.springframework.r2dbc.core.binding.BindMarkersFactory;
|
||||
@@ -47,6 +50,7 @@ import org.testcontainers.shaded.com.fasterxml.jackson.databind.node.TextNode;
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Mingyuan Wu
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
class QueryMapperUnitTests {
|
||||
|
||||
@@ -423,6 +427,42 @@ class QueryMapperUnitTests {
|
||||
assertThat(mapped.getOrderFor("alternative_name")).isEqualTo(desc("alternative_name"));
|
||||
}
|
||||
|
||||
@Test // GH-1507
|
||||
public void shouldMapSortWithUnknownField() {
|
||||
|
||||
Sort sort = Sort.by(desc("unknownField"));
|
||||
|
||||
List<OrderByField> fields = mapper.getMappedSort(Table.create("tbl"), sort,
|
||||
mapper.getMappingContext().getRequiredPersistentEntity(Person.class));
|
||||
|
||||
assertThat(fields) //
|
||||
.extracting(Objects::toString) //
|
||||
.containsExactly("tbl.unknownField DESC");
|
||||
}
|
||||
|
||||
@Test // GH-1507
|
||||
public void shouldMapSortWithAllowedSpecialCharacters() {
|
||||
|
||||
Sort sort = Sort.by(desc("x(._)x"));
|
||||
|
||||
List<OrderByField> fields = mapper.getMappedSort(Table.create("tbl"), sort,
|
||||
mapper.getMappingContext().getRequiredPersistentEntity(Person.class));
|
||||
|
||||
assertThat(fields) //
|
||||
.extracting(Objects::toString) //
|
||||
.containsExactly("tbl.x(._)x DESC");
|
||||
}
|
||||
|
||||
|
||||
@Test // GH-1507
|
||||
public void shouldNotMapSortWithIllegalExpression() {
|
||||
|
||||
Sort sort = Sort.by(desc("unknown Field"));
|
||||
|
||||
assertThatThrownBy(() -> mapper.getMappedSort(Table.create("tbl"), sort,
|
||||
mapper.getMappingContext().getRequiredPersistentEntity(Person.class))).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test // gh-369
|
||||
void mapQueryForPropertyPathInPrimitiveShouldFallBackToColumnName() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user