Skip to content

Commit 3ea7dea

Browse files
DATAES-552 - Polishing.
Update lookup to replace all matches & add some tests. Original Pull Request: spring-projects#267
1 parent b93bd07 commit 3ea7dea

File tree

4 files changed

+159
-23
lines changed

4 files changed

+159
-23
lines changed

src/main/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchStringQuery.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
import java.util.regex.Pattern;
2020

2121
import org.springframework.core.convert.support.GenericConversionService;
22-
import org.springframework.data.domain.Pageable;
2322
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
2423
import org.springframework.data.elasticsearch.core.convert.DateTimeConverters;
2524
import org.springframework.data.elasticsearch.core.query.StringQuery;
2625
import org.springframework.data.repository.query.ParametersParameterAccessor;
2726
import org.springframework.util.Assert;
27+
import org.springframework.util.NumberUtils;
2828

2929
/**
3030
* ElasticsearchStringQuery
@@ -83,13 +83,14 @@ protected StringQuery createQuery(ParametersParameterAccessor parameterAccessor)
8383
}
8484

8585
private String replacePlaceholders(String input, ParametersParameterAccessor accessor) {
86+
8687
Matcher matcher = PARAMETER_PLACEHOLDER.matcher(input);
8788
String result = input;
8889
while (matcher.find()) {
89-
String group = matcher.group();
90-
group = "\\" + group;
91-
int index = Integer.parseInt(matcher.group(1));
92-
result = result.replaceFirst(group, getParameterWithIndex(accessor, index));
90+
91+
String placeholder = Pattern.quote(matcher.group()) + "(?!\\d+)";
92+
int index = NumberUtils.parseNumber(matcher.group(1), Integer.class);
93+
result = result.replaceAll(placeholder, getParameterWithIndex(accessor, index));
9394
}
9495
return result;
9596
}

src/main/java/org/springframework/data/elasticsearch/repository/query/ReactiveElasticsearchStringQuery.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.springframework.data.elasticsearch.core.query.StringQuery;
2323
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
2424
import org.springframework.expression.spel.standard.SpelExpressionParser;
25+
import org.springframework.util.NumberUtils;
2526
import org.springframework.util.ObjectUtils;
2627

2728
/**
@@ -60,10 +61,10 @@ private String replacePlaceholders(String input, ElasticsearchParameterAccessor
6061
Matcher matcher = PARAMETER_PLACEHOLDER.matcher(input);
6162
String result = input;
6263
while (matcher.find()) {
63-
String group = matcher.group();
64-
group = "\\" + group;
65-
int index = Integer.parseInt(matcher.group(1));
66-
result = result.replaceFirst(group, getParameterWithIndex(accessor, index));
64+
65+
String placeholder = Pattern.quote(matcher.group()) + "(?!\\d+)";
66+
int index = NumberUtils.parseNumber(matcher.group(1), Integer.class);
67+
result = result.replaceAll(placeholder, getParameterWithIndex(accessor, index));
6768
}
6869
return result;
6970
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright 2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.elasticsearch.repository.query;
17+
18+
import static org.assertj.core.api.Assertions.*;
19+
20+
import java.lang.reflect.Method;
21+
import java.util.Arrays;
22+
23+
import org.junit.Before;
24+
import org.junit.Test;
25+
import org.junit.runner.RunWith;
26+
import org.mockito.Mock;
27+
import org.mockito.junit.MockitoJUnitRunner;
28+
import org.springframework.data.elasticsearch.annotations.Query;
29+
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
30+
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
31+
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
32+
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
33+
import org.springframework.data.elasticsearch.core.query.StringQuery;
34+
import org.springframework.data.elasticsearch.entities.Person;
35+
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
36+
import org.springframework.data.repository.Repository;
37+
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
38+
39+
/**
40+
* @author Christoph Strobl
41+
*/
42+
@RunWith(MockitoJUnitRunner.class)
43+
public class ElasticsearchStringQueryUnitTests {
44+
45+
@Mock ElasticsearchOperations operations;
46+
ElasticsearchConverter converter;
47+
48+
@Before
49+
public void setUp() {
50+
converter = new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext());
51+
}
52+
53+
@Test // DATAES-552
54+
public void shouldReplaceParametersCorrectly() throws Exception {
55+
56+
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByName", "Luke");
57+
58+
assertThat(query).isInstanceOf(StringQuery.class);
59+
assertThat(((StringQuery) query).getSource())
60+
.isEqualTo("{ 'bool' : { 'must' : { 'term' : { 'name' : 'Luke' } } } }");
61+
}
62+
63+
@Test // DATAES-552
64+
public void shouldReplaceRepeatedParametersCorrectly() throws Exception {
65+
66+
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findWithRepeatedPlaceholder", "zero",
67+
"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven");
68+
69+
assertThat(query).isInstanceOf(StringQuery.class);
70+
assertThat(((StringQuery) query).getSource())
71+
.isEqualTo("name:(zero, eleven, one, two, three, four, five, six, seven, eight, nine, ten, eleven, zero, one)");
72+
}
73+
74+
private org.springframework.data.elasticsearch.core.query.Query createQuery(String methodName, String... args)
75+
throws NoSuchMethodException {
76+
77+
Class<?>[] argTypes = Arrays.stream(args).map(Object::getClass).toArray(size -> new Class[size]);
78+
ElasticsearchQueryMethod queryMethod = getQueryMethod(methodName, argTypes);
79+
ElasticsearchStringQuery elasticsearchStringQuery = queryForMethod(queryMethod);
80+
return elasticsearchStringQuery.createQuery(new ElasticsearchParametersParameterAccessor(queryMethod, args));
81+
}
82+
83+
private ElasticsearchStringQuery queryForMethod(ElasticsearchQueryMethod queryMethod) {
84+
return new ElasticsearchStringQuery(queryMethod, operations, queryMethod.getAnnotatedQuery());
85+
}
86+
87+
private ElasticsearchQueryMethod getQueryMethod(String name, Class<?>... parameters) throws NoSuchMethodException {
88+
89+
Method method = SampleRepository.class.getMethod(name, parameters);
90+
return new ElasticsearchQueryMethod(method, new DefaultRepositoryMetadata(SampleRepository.class),
91+
new SpelAwareProxyProjectionFactory(), converter.getMappingContext());
92+
}
93+
94+
private interface SampleRepository extends Repository<Person, String> {
95+
96+
@Query("{ 'bool' : { 'must' : { 'term' : { 'name' : '?0' } } } }")
97+
Person findByName(String name);
98+
99+
@Query(value = "name:(?0, ?11, ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?0, ?1)")
100+
Person findWithRepeatedPlaceholder(String arg0, String arg1, String arg2, String arg3, String arg4, String arg5,
101+
String arg6, String arg7, String arg8, String arg9, String arg10, String arg11);
102+
}
103+
}

src/test/java/org/springframework/data/elasticsearch/repository/query/ReactiveElasticsearchStringQueryUnitTests.java

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import reactor.core.publisher.Mono;
2222

2323
import java.lang.reflect.Method;
24+
import java.util.Arrays;
2425

2526
import org.junit.Before;
2627
import org.junit.Ignore;
@@ -35,7 +36,6 @@
3536
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
3637
import org.springframework.data.elasticsearch.core.query.StringQuery;
3738
import org.springframework.data.elasticsearch.entities.Person;
38-
import org.springframework.data.projection.ProjectionFactory;
3939
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
4040
import org.springframework.data.repository.Repository;
4141
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
@@ -90,27 +90,54 @@ public void bindsExpressionPropertyCorrectly() throws Exception {
9090
@Test // DATAES-552
9191
public void shouldReplaceLotsOfParametersCorrectly() throws Exception {
9292

93-
ReactiveElasticsearchStringQuery elasticsearchStringQuery = createQueryForMethod("findWithQuiteSomeParameters",
94-
String.class, String.class, String.class, String.class, String.class, String.class, String.class, String.class,
95-
String.class, String.class, String.class, String.class);
96-
StubParameterAccessor accesor = new StubParameterAccessor("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
97-
"l");
98-
org.springframework.data.elasticsearch.core.query.Query query = elasticsearchStringQuery.createQuery(accesor);
99-
StringQuery reference = new StringQuery("name:(a, b, c, d, e, f, g, h, i, j, k, l)");
93+
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findWithQuiteSomeParameters", "zero",
94+
"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven");
95+
10096
assertThat(query).isInstanceOf(StringQuery.class);
101-
assertThat(((StringQuery) query).getSource()).isEqualTo(reference.getSource());
97+
assertThat(((StringQuery) query).getSource())
98+
.isEqualTo("name:(zero, one, two, three, four, five, six, seven, eight, nine, ten, eleven)");
10299
}
103100

104-
private ReactiveElasticsearchStringQuery createQueryForMethod(String name, Class<?>... parameters) throws Exception {
101+
@Test // DATAES-552
102+
public void shouldReplaceRepeatedParametersCorrectly() throws Exception {
105103

106-
Method method = SampleRepository.class.getMethod(name, parameters);
107-
ProjectionFactory factory = new SpelAwareProxyProjectionFactory();
108-
ReactiveElasticsearchQueryMethod queryMethod = new ReactiveElasticsearchQueryMethod(method,
109-
new DefaultRepositoryMetadata(SampleRepository.class), factory, converter.getMappingContext());
104+
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findWithRepeatedPlaceholder", "zero",
105+
"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven");
106+
107+
assertThat(query).isInstanceOf(StringQuery.class);
108+
assertThat(((StringQuery) query).getSource())
109+
.isEqualTo("name:(zero, eleven, one, two, three, four, five, six, seven, eight, nine, ten, eleven, zero, one)");
110+
}
111+
112+
private org.springframework.data.elasticsearch.core.query.Query createQuery(String methodName, String... args)
113+
throws NoSuchMethodException {
114+
115+
Class<?>[] argTypes = Arrays.stream(args).map(Object::getClass).toArray(size -> new Class[size]);
116+
ReactiveElasticsearchQueryMethod queryMethod = getQueryMethod(methodName, argTypes);
117+
ReactiveElasticsearchStringQuery elasticsearchStringQuery = queryForMethod(queryMethod);
118+
119+
return elasticsearchStringQuery.createQuery(new ElasticsearchParametersParameterAccessor(queryMethod, args));
120+
}
121+
122+
private ReactiveElasticsearchStringQuery queryForMethod(ReactiveElasticsearchQueryMethod queryMethod) {
110123
return new ReactiveElasticsearchStringQuery(queryMethod, operations, PARSER,
111124
QueryMethodEvaluationContextProvider.DEFAULT);
112125
}
113126

127+
private ReactiveElasticsearchQueryMethod getQueryMethod(String name, Class<?>... parameters)
128+
throws NoSuchMethodException {
129+
130+
Method method = SampleRepository.class.getMethod(name, parameters);
131+
return new ReactiveElasticsearchQueryMethod(method, new DefaultRepositoryMetadata(SampleRepository.class),
132+
new SpelAwareProxyProjectionFactory(), converter.getMappingContext());
133+
}
134+
135+
private ReactiveElasticsearchStringQuery createQueryForMethod(String name, Class<?>... parameters) throws Exception {
136+
137+
ReactiveElasticsearchQueryMethod queryMethod = getQueryMethod(name, parameters);
138+
return queryForMethod(queryMethod);
139+
}
140+
114141
private interface SampleRepository extends Repository<Person, String> {
115142

116143
@Query("{ 'bool' : { 'must' : { 'term' : { 'name' : '?0' } } } }")
@@ -122,5 +149,9 @@ private interface SampleRepository extends Repository<Person, String> {
122149
@Query(value = "name:(?0, ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11)")
123150
Person findWithQuiteSomeParameters(String arg0, String arg1, String arg2, String arg3, String arg4, String arg5,
124151
String arg6, String arg7, String arg8, String arg9, String arg10, String arg11);
152+
153+
@Query(value = "name:(?0, ?11, ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?0, ?1)")
154+
Person findWithRepeatedPlaceholder(String arg0, String arg1, String arg2, String arg3, String arg4, String arg5,
155+
String arg6, String arg7, String arg8, String arg9, String arg10, String arg11);
125156
}
126157
}

0 commit comments

Comments
 (0)