Skip to content

Commit d7abbc7

Browse files
committed
Fix mapping of property names in sort parameters.
Original Pull Request #3074 Closes #3072 Signed-off-by: Peter-Josef Meisch <[email protected]> (cherry picked from commit 4238362) (cherry picked from commit 88e2e9d)
1 parent bd99c90 commit d7abbc7

File tree

2 files changed

+117
-16
lines changed

2 files changed

+117
-16
lines changed

src/main/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverter.java

+47-16
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.springframework.core.env.EnvironmentCapable;
3939
import org.springframework.core.env.StandardEnvironment;
4040
import org.springframework.data.convert.CustomConversions;
41+
import org.springframework.data.domain.Sort;
4142
import org.springframework.data.elasticsearch.annotations.FieldType;
4243
import org.springframework.data.elasticsearch.annotations.ScriptedField;
4344
import org.springframework.data.elasticsearch.core.document.Document;
@@ -50,6 +51,7 @@
5051
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
5152
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
5253
import org.springframework.data.elasticsearch.core.query.Field;
54+
import org.springframework.data.elasticsearch.core.query.Order;
5355
import org.springframework.data.elasticsearch.core.query.Query;
5456
import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm;
5557
import org.springframework.data.elasticsearch.core.query.SourceFilter;
@@ -1231,7 +1233,7 @@ public void updateQuery(Query query, @Nullable Class<?> domainClass) {
12311233
return;
12321234
}
12331235

1234-
updatePropertiesInFieldsAndSourceFilter(query, domainClass);
1236+
updatePropertiesInFieldsSortAndSourceFilter(query, domainClass);
12351237

12361238
if (query instanceof CriteriaQuery criteriaQuery) {
12371239
updatePropertiesInCriteriaQuery(criteriaQuery, domainClass);
@@ -1242,20 +1244,27 @@ public void updateQuery(Query query, @Nullable Class<?> domainClass) {
12421244
}
12431245
}
12441246

1245-
private void updatePropertiesInFieldsAndSourceFilter(Query query, Class<?> domainClass) {
1247+
/**
1248+
* replaces the names of fields in the query, the sort or soucre filters with the field names used in Elasticsearch
1249+
* when they are defined on the ElasticsearchProperties
1250+
*
1251+
* @param query the query to process
1252+
* @param domainClass the domain class (persistent entity)
1253+
*/
1254+
private void updatePropertiesInFieldsSortAndSourceFilter(Query query, Class<?> domainClass) {
12461255

12471256
ElasticsearchPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(domainClass);
12481257

12491258
if (persistentEntity != null) {
12501259
List<String> fields = query.getFields();
12511260

12521261
if (!fields.isEmpty()) {
1253-
query.setFields(updateFieldNames(fields, persistentEntity));
1262+
query.setFields(propertyToFieldNames(fields, persistentEntity));
12541263
}
12551264

12561265
List<String> storedFields = query.getStoredFields();
12571266
if (!CollectionUtils.isEmpty(storedFields)) {
1258-
query.setStoredFields(updateFieldNames(storedFields, persistentEntity));
1267+
query.setStoredFields(propertyToFieldNames(storedFields, persistentEntity));
12591268
}
12601269

12611270
SourceFilter sourceFilter = query.getSourceFilter();
@@ -1266,37 +1275,60 @@ private void updatePropertiesInFieldsAndSourceFilter(Query query, Class<?> domai
12661275
String[] excludes = null;
12671276

12681277
if (sourceFilter.getIncludes() != null) {
1269-
includes = updateFieldNames(Arrays.asList(sourceFilter.getIncludes()), persistentEntity)
1278+
includes = propertyToFieldNames(Arrays.asList(sourceFilter.getIncludes()), persistentEntity)
12701279
.toArray(new String[] {});
12711280
}
12721281

12731282
if (sourceFilter.getExcludes() != null) {
1274-
excludes = updateFieldNames(Arrays.asList(sourceFilter.getExcludes()), persistentEntity)
1283+
excludes = propertyToFieldNames(Arrays.asList(sourceFilter.getExcludes()), persistentEntity)
12751284
.toArray(new String[] {});
12761285
}
12771286

12781287
query.addSourceFilter(new FetchSourceFilter(includes, excludes));
12791288
}
1289+
1290+
if (query.getSort() != null) {
1291+
var sort = query.getSort();
1292+
// stream the orders and map them to a new order with the changed names,
1293+
// then replace the existing sort with a new sort containing the new orders.
1294+
var newOrders = sort.stream().map(order -> {
1295+
var fieldNames = updateFieldNames(order.getProperty(), persistentEntity);
1296+
1297+
if (order instanceof Order springDataElasticsearchOrder) {
1298+
return springDataElasticsearchOrder.withProperty(fieldNames);
1299+
} else {
1300+
return new Sort.Order(order.getDirection(),
1301+
fieldNames,
1302+
order.isIgnoreCase(),
1303+
order.getNullHandling());
1304+
}
1305+
}).toList();
1306+
1307+
if (query instanceof BaseQuery baseQuery) {
1308+
baseQuery.setSort(Sort.by(newOrders));
1309+
}
1310+
}
12801311
}
12811312
}
12821313

12831314
/**
1284-
* relaces the fieldName with the property name of a property of the persistentEntity with the corresponding
1285-
* fieldname. If no such property exists, the original fieldName is kept.
1315+
* replaces property name of a property of the persistentEntity with the corresponding fieldname. If no such property
1316+
* exists, the original fieldName is kept.
12861317
*
1287-
* @param fieldNames list of fieldnames
1318+
* @param propertyNames list of fieldnames
12881319
* @param persistentEntity the persistent entity to check
12891320
* @return an updated list of field names
12901321
*/
1291-
private List<String> updateFieldNames(List<String> fieldNames, ElasticsearchPersistentEntity<?> persistentEntity) {
1292-
return fieldNames.stream().map(fieldName -> updateFieldName(persistentEntity, fieldName))
1322+
private List<String> propertyToFieldNames(List<String> propertyNames,
1323+
ElasticsearchPersistentEntity<?> persistentEntity) {
1324+
return propertyNames.stream().map(propertyName -> propertyToFieldName(persistentEntity, propertyName))
12931325
.collect(Collectors.toList());
12941326
}
12951327

12961328
@NotNull
1297-
private String updateFieldName(ElasticsearchPersistentEntity<?> persistentEntity, String fieldName) {
1298-
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getPersistentProperty(fieldName);
1299-
return persistentProperty != null ? persistentProperty.getFieldName() : fieldName;
1329+
private String propertyToFieldName(ElasticsearchPersistentEntity<?> persistentEntity, String propertyName) {
1330+
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getPersistentProperty(propertyName);
1331+
return persistentProperty != null ? persistentProperty.getFieldName() : propertyName;
13001332
}
13011333

13021334
private void updatePropertiesInCriteriaQuery(CriteriaQuery criteriaQuery, Class<?> domainClass) {
@@ -1410,7 +1442,7 @@ public String updateFieldNames(String propertyPath, ElasticsearchPersistentEntit
14101442

14111443
if (properties.length > 0) {
14121444
var propertyName = properties[0];
1413-
var fieldName = updateFieldName(persistentEntity, propertyName);
1445+
var fieldName = propertyToFieldName(persistentEntity, propertyName);
14141446

14151447
if (properties.length > 1) {
14161448
var persistentProperty = persistentEntity.getPersistentProperty(propertyName);
@@ -1431,7 +1463,6 @@ public String updateFieldNames(String propertyPath, ElasticsearchPersistentEntit
14311463
}
14321464

14331465
}
1434-
14351466
// endregion
14361467

14371468
@SuppressWarnings("ClassCanBeRecord")

src/test/java/org/springframework/data/elasticsearch/core/query/ElasticsearchPartQueryIntegrationTests.java

+70
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.List;
2424

2525
import org.json.JSONException;
26+
import org.junit.jupiter.api.DisplayName;
2627
import org.junit.jupiter.api.Test;
2728
import org.springframework.beans.factory.annotation.Autowired;
2829
import org.springframework.data.annotation.Id;
@@ -639,6 +640,45 @@ void findByAvailableTrueOrderByNameDesc() throws NoSuchMethodException, JSONExce
639640
assertEquals(expected, query, false);
640641
}
641642

643+
@Test // #3072
644+
@DisplayName("should build sort object with correct field names")
645+
void shouldBuildSortObjectWithCorrectFieldNames() throws NoSuchMethodException, JSONException {
646+
647+
String methodName = "findByNameOrderBySortAuthor_SortName";
648+
Class<?>[] parameterClasses = new Class[] { String.class };
649+
Object[] parameters = new Object[] { BOOK_TITLE };
650+
651+
String query = getQueryString(methodName, parameterClasses, parameters);
652+
653+
String expected = """
654+
655+
{
656+
"query": {
657+
"bool": {
658+
"must": [
659+
{
660+
"query_string": {
661+
"query": "Title",
662+
"fields": [
663+
"name"
664+
]
665+
}
666+
}
667+
]
668+
}
669+
},
670+
"sort": [
671+
{
672+
"sort_author.sort_name": {
673+
"order": "asc"
674+
}
675+
}
676+
]
677+
}""";
678+
679+
assertEquals(expected, query, false);
680+
}
681+
642682
private String getQueryString(String methodName, Class<?>[] parameterClasses, Object[] parameters)
643683
throws NoSuchMethodException {
644684

@@ -726,6 +766,8 @@ private interface SampleRepository extends ElasticsearchRepository<Book, String>
726766

727767
List<Book> findByAvailableTrueOrderByNameDesc();
728768

769+
List<Book> findByNameOrderBySortAuthor_SortName(String name);
770+
729771
}
730772

731773
public static class Book {
@@ -735,6 +777,10 @@ public static class Book {
735777
@Nullable private Integer price;
736778
@Field(type = FieldType.Boolean) private boolean available;
737779

780+
// this is needed for the #3072 test
781+
@Nullable
782+
@Field(name = "sort_author", type = FieldType.Object) private Author sortAuthor;
783+
738784
@Nullable
739785
public String getId() {
740786
return id;
@@ -766,8 +812,32 @@ public Boolean getAvailable() {
766812
return available;
767813
}
768814

815+
@Nullable
816+
public Author getSortAuthor() {
817+
return sortAuthor;
818+
}
819+
820+
public void setSortAuthor(@Nullable Author sortAuthor) {
821+
this.sortAuthor = sortAuthor;
822+
}
823+
769824
public void setAvailable(Boolean available) {
770825
this.available = available;
826+
827+
}
828+
}
829+
830+
public static class Author {
831+
@Nullable
832+
@Field(name = "sort_name", type = FieldType.Keyword) private String sortName;
833+
834+
@Nullable
835+
public String getSortName() {
836+
return sortName;
837+
}
838+
839+
public void setSortName(@Nullable String sortName) {
840+
this.sortName = sortName;
771841
}
772842
}
773843
}

0 commit comments

Comments
 (0)