Skip to content

Commit fa979c6

Browse files
ls-urs-kellersothawo
authored andcommitted
Enable IndexCoordinates a parameter in repository search queries.
Closes #2506 Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
1 parent 2278d07 commit fa979c6

12 files changed

+316
-9
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ public Object execute(Object[] parameters) {
9090

9191
Query query = createQuery(parameters);
9292

93-
IndexCoordinates index = elasticsearchOperations.getIndexCoordinatesFor(clazz);
93+
IndexCoordinates index = parameterAccessor
94+
.getIndexCoordinates(elasticsearchOperations.getIndexCoordinatesFor(clazz));
9495

9596
Object result = null;
9697

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ private Object execute(ElasticsearchParametersParameterAccessor parameterAccesso
110110
evaluationContextProvider);
111111

112112
String indexName = queryMethod.getEntityInformation().getIndexName();
113-
IndexCoordinates index = IndexCoordinates.of(indexName);
113+
IndexCoordinates index = parameterAccessor.getIndexCoordinates(IndexCoordinates.of(indexName));
114114

115115
ReactiveElasticsearchQueryExecution execution = getExecution(parameterAccessor,
116116
new ResultProcessingConverter(processor));

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import org.springframework.core.MethodParameter;
1919
import org.springframework.data.core.TypeInformation;
20+
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
2021
import org.springframework.data.elasticsearch.core.query.RuntimeField;
2122
import org.springframework.data.elasticsearch.core.query.ScriptedField;
2223
import org.springframework.data.repository.query.Parameter;
@@ -42,7 +43,8 @@ public class ElasticsearchParameter extends Parameter {
4243

4344
@Override
4445
public boolean isSpecialParameter() {
45-
return super.isSpecialParameter() || isScriptedFieldParameter() || isRuntimeFieldParameter();
46+
return super.isSpecialParameter() || isScriptedFieldParameter() || isRuntimeFieldParameter()
47+
|| isIndexCoordinatesParameter();
4648
}
4749

4850
public Boolean isScriptedFieldParameter() {
@@ -52,4 +54,8 @@ public Boolean isScriptedFieldParameter() {
5254
public Boolean isRuntimeFieldParameter() {
5355
return RuntimeField.class.isAssignableFrom(getType());
5456
}
57+
58+
public Boolean isIndexCoordinatesParameter() {
59+
return IndexCoordinates.class.isAssignableFrom(getType());
60+
}
5561
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.data.elasticsearch.repository.query;
1717

18+
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
1819
import org.springframework.data.repository.query.ParameterAccessor;
1920

2021
/**
@@ -29,4 +30,11 @@ public interface ElasticsearchParameterAccessor extends ParameterAccessor {
2930
* @return
3031
*/
3132
Object[] getValues();
33+
34+
/**
35+
* If there is a parameter of type IndexCoordinates, this parameter value is returned, otherwise the defaults value
36+
*
37+
* @param defaults default value
38+
*/
39+
IndexCoordinates getIndexCoordinates(IndexCoordinates defaults);
3240
}

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

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,11 @@
2929
* @since 3.2
3030
*/
3131
public class ElasticsearchParameters extends Parameters<ElasticsearchParameters, ElasticsearchParameter> {
32-
3332
private final List<ElasticsearchParameter> scriptedFields = new ArrayList<>();
3433
private final List<ElasticsearchParameter> runtimeFields = new ArrayList<>();
3534

35+
private final int indexCoordinatesIndex;
36+
3637
public ElasticsearchParameters(ParametersSource parametersSource) {
3738

3839
super(parametersSource,
@@ -53,6 +54,23 @@ public ElasticsearchParameters(ParametersSource parametersSource) {
5354
runtimeFields.add(parameter);
5455
}
5556
}
57+
this.indexCoordinatesIndex = initIndexCoordinatesIndex();
58+
}
59+
60+
private int initIndexCoordinatesIndex() {
61+
int indexCoordinatesIndex = -1;
62+
int index = 0;
63+
for (ElasticsearchParameter parameter : this) {
64+
if (parameter.isIndexCoordinatesParameter()) {
65+
if (indexCoordinatesIndex != -1) {
66+
throw new IllegalArgumentException(this + " can only contain at most one IndexCoordinates parameter.");
67+
} else {
68+
indexCoordinatesIndex = index;
69+
}
70+
}
71+
index++;
72+
}
73+
return indexCoordinatesIndex;
5674
}
5775

5876
private ElasticsearchParameter parameterFactory(MethodParameter methodParameter, TypeInformation<?> domainType) {
@@ -61,6 +79,7 @@ private ElasticsearchParameter parameterFactory(MethodParameter methodParameter,
6179

6280
private ElasticsearchParameters(List<ElasticsearchParameter> parameters) {
6381
super(parameters);
82+
this.indexCoordinatesIndex = initIndexCoordinatesIndex();
6483
}
6584

6685
@Override
@@ -75,4 +94,12 @@ List<ElasticsearchParameter> getScriptedFields() {
7594
List<ElasticsearchParameter> getRuntimeFields() {
7695
return runtimeFields;
7796
}
97+
98+
public boolean hasIndexCoordinatesParameter() {
99+
return this.indexCoordinatesIndex != -1;
100+
}
101+
102+
public int getIndexCoordinatesIndex() {
103+
return indexCoordinatesIndex;
104+
}
78105
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.data.elasticsearch.repository.query;
1717

18+
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
1819
import org.springframework.data.repository.query.ParametersParameterAccessor;
1920

2021
/**
@@ -25,6 +26,7 @@ public class ElasticsearchParametersParameterAccessor extends ParametersParamete
2526
implements ElasticsearchParameterAccessor {
2627

2728
private final Object[] values;
29+
private final ElasticsearchParameters eleasticSearchParameters;
2830

2931
/**
3032
* Creates a new {@link ElasticsearchParametersParameterAccessor}.
@@ -36,10 +38,19 @@ public class ElasticsearchParametersParameterAccessor extends ParametersParamete
3638

3739
super(method.getParameters(), values);
3840
this.values = values;
41+
this.eleasticSearchParameters = method.getParameters();
3942
}
4043

4144
@Override
4245
public Object[] getValues() {
4346
return values;
4447
}
48+
49+
@Override
50+
public IndexCoordinates getIndexCoordinates(IndexCoordinates defaults) {
51+
if (!eleasticSearchParameters.hasIndexCoordinatesParameter()) {
52+
return defaults;
53+
}
54+
return (IndexCoordinates) getValues()[eleasticSearchParameters.getIndexCoordinatesIndex()];
55+
}
4556
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,11 @@ private String[] mapParameters(String[] source, ElasticsearchParametersParameter
373373
return fieldNames.toArray(new String[0]);
374374
}
375375

376+
@Override
377+
public ElasticsearchParameters getParameters() {
378+
return (ElasticsearchParameters) super.getParameters();
379+
}
380+
376381
// region Copied from QueryMethod base class
377382
/*
378383
* Copied from the QueryMethod class adding support for collections of SearchHit instances. No static method here.

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,6 @@ public boolean isStreamQuery() {
136136
return true;
137137
}
138138

139-
@Override
140-
public ElasticsearchParameters getParameters() {
141-
return (ElasticsearchParameters) super.getParameters();
142-
}
143-
144139
@Override
145140
protected boolean isAllowedGenericType(ParameterizedType methodGenericReturnType) {
146141
return super.isAllowedGenericType(methodGenericReturnType)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.springframework.data.elasticsearch.repository.query.indexcoordinates;
2+
3+
import org.springframework.context.annotation.Bean;
4+
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.context.annotation.Import;
6+
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration;
7+
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
8+
import org.springframework.data.elasticsearch.utils.IndexNameProvider;
9+
import org.springframework.test.context.ContextConfiguration;
10+
11+
@ContextConfiguration(classes = { IndexCoordinatesParameterELCIntegrationTests.Config.class })
12+
public class IndexCoordinatesParameterELCIntegrationTests extends IndexCoordinatesParameterIntegrationTests {
13+
14+
@Configuration
15+
@Import({ ElasticsearchTemplateConfiguration.class })
16+
@EnableElasticsearchRepositories(considerNestedRepositories = true)
17+
static class Config {
18+
@Bean
19+
IndexNameProvider indexNameProvider() {
20+
return new IndexNameProvider("query-index-coordinates");
21+
}
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package org.springframework.data.elasticsearch.repository.query.indexcoordinates;
2+
3+
import org.jspecify.annotations.Nullable;
4+
import org.junit.jupiter.api.BeforeEach;
5+
import org.junit.jupiter.api.DisplayName;
6+
import org.junit.jupiter.api.Order;
7+
import org.junit.jupiter.api.Test;
8+
import org.springframework.beans.factory.annotation.Autowired;
9+
import org.springframework.data.annotation.Id;
10+
import org.springframework.data.elasticsearch.annotations.Document;
11+
import org.springframework.data.elasticsearch.annotations.Field;
12+
import org.springframework.data.elasticsearch.annotations.FieldType;
13+
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
14+
import org.springframework.data.elasticsearch.core.SearchHits;
15+
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
16+
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
17+
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
18+
import org.springframework.data.elasticsearch.utils.IndexNameProvider;
19+
20+
@SpringIntegrationTest
21+
abstract class IndexCoordinatesParameterIntegrationTests {
22+
@Autowired ElasticsearchOperations operations;
23+
@Autowired IndexNameProvider indexNameProvider;
24+
@Autowired RecordRepository recordRepository;
25+
26+
@BeforeEach
27+
public void before() {
28+
indexNameProvider.increment();
29+
}
30+
31+
@Test
32+
@Order(Integer.MAX_VALUE)
33+
void cleanup() {
34+
operations.indexOps(IndexCoordinates.of(indexNameProvider.getPrefix() + "*")).delete();
35+
}
36+
37+
@Test // #2506
38+
@DisplayName("should use indexcoordinates passes as repository query argument")
39+
void shouldUseIndexCoordinatesPassesAsRepositoryQueryArgument() {
40+
41+
var record1 = new Record("1", "one");
42+
var indexName1 = indexNameProvider.indexName();
43+
var indexCoordinates1 = IndexCoordinates.of(indexName1);
44+
operations.save(record1, indexCoordinates1);
45+
46+
var record2 = new Record("2", "two");
47+
var indexName2 = indexName1 + "second";
48+
var indexCoordinates2 = IndexCoordinates.of(indexName2);
49+
operations.save(record2, indexCoordinates2);
50+
51+
// search for record1
52+
var searchHits = recordRepository.findByText("one");
53+
assert searchHits.getTotalHits() == 1;
54+
searchHits = recordRepository.findByText("one", indexCoordinates2);
55+
assert searchHits.getTotalHits() == 0;
56+
57+
// search for record2
58+
searchHits = recordRepository.findByText("two");
59+
assert searchHits.getTotalHits() == 0;
60+
searchHits = recordRepository.findByText("two", indexCoordinates2);
61+
assert searchHits.getTotalHits() == 1;
62+
}
63+
64+
@Document(indexName = "#{@indexNameProvider.indexName()}")
65+
static class Record {
66+
@Nullable
67+
@Id private String id;
68+
@Nullable
69+
@Field(type = FieldType.Keyword) private String text;
70+
71+
public Record(@Nullable String id, @Nullable String text) {
72+
this.id = id;
73+
this.text = text;
74+
}
75+
76+
public @Nullable String getId() {
77+
return id;
78+
}
79+
80+
public void setId(@Nullable String id) {
81+
this.id = id;
82+
}
83+
84+
public @Nullable String getText() {
85+
return text;
86+
}
87+
88+
public void setText(@Nullable String text) {
89+
this.text = text;
90+
}
91+
}
92+
93+
interface RecordRepository extends ElasticsearchRepository<Record, String> {
94+
SearchHits<Record> findByText(String text);
95+
96+
SearchHits<Record> findByText(String text, IndexCoordinates index);
97+
}
98+
}

0 commit comments

Comments
 (0)