DATAES-706 - CriteriaQueryProcessor must handle nested Criteria definitions.

Original PR: #505
This commit is contained in:
Peter-Josef Meisch
2020-08-18 20:59:35 +02:00
committed by GitHub
parent c8c6e7a646
commit 131f0318cc
13 changed files with 1426 additions and 631 deletions

View File

@@ -56,12 +56,15 @@ public class CriteriaQueryMappingTests {
}
@Test
@Test // DATAES-716
void shouldMapNamesAndConvertValuesInCriteriaQuery() throws JSONException {
// use POJO properties and types in the query building
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("birthDate")
.between(LocalDate.of(1989, 11, 9), LocalDate.of(1990, 11, 9)).or("birthDate").is(LocalDate.of(2019, 12, 28)));
CriteriaQuery criteriaQuery = new CriteriaQuery( //
new Criteria("birthDate") //
.between(LocalDate.of(1989, 11, 9), LocalDate.of(1990, 11, 9)) //
.or("birthDate").is(LocalDate.of(2019, 12, 28)) //
);
// mapped field name and converted parameter
String expected = '{' + //
@@ -90,7 +93,60 @@ public class CriteriaQueryMappingTests {
'}'; //
mappingElasticsearchConverter.updateQuery(criteriaQuery, Person.class);
String queryString = new CriteriaQueryProcessor().createQueryFromCriteria(criteriaQuery.getCriteria()).toString();
String queryString = new CriteriaQueryProcessor().createQuery(criteriaQuery.getCriteria()).toString();
assertEquals(expected, queryString, false);
}
@Test // DATAES-706
void shouldMapNamesAndValuesInSubCriteriaQuery() throws JSONException {
CriteriaQuery criteriaQuery = new CriteriaQuery( //
new Criteria("firstName").matches("John") //
.subCriteria(new Criteria("birthDate") //
.between(LocalDate.of(1989, 11, 9), LocalDate.of(1990, 11, 9)) //
.or("birthDate").is(LocalDate.of(2019, 12, 28))));
String expected = "{\n" + //
" \"bool\": {\n" + //
" \"must\": [\n" + //
" {\n" + //
" \"match\": {\n" + //
" \"first-name\": {\n" + //
" \"query\": \"John\"\n" + //
" }\n" + //
" }\n" + //
" },\n" + //
" {\n" + //
" \"bool\": {\n" + //
" \"should\": [\n" + //
" {\n" + //
" \"range\": {\n" + //
" \"birth-date\": {\n" + //
" \"from\": \"09.11.1989\",\n" + //
" \"to\": \"09.11.1990\",\n" + //
" \"include_lower\": true,\n" + //
" \"include_upper\": true\n" + //
" }\n" + //
" }\n" + //
" },\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"28.12.2019\",\n" + //
" \"fields\": [\n" + //
" \"birth-date^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" }\n" + //
" ]\n" + //
" }\n" + //
" }\n" + //
" ]\n" + //
" }\n" + //
"}\n"; //
mappingElasticsearchConverter.updateQuery(criteriaQuery, Person.class);
String queryString = new CriteriaQueryProcessor().createQuery(criteriaQuery.getCriteria()).toString();
assertEquals(expected, queryString, false);
}

View File

@@ -0,0 +1,341 @@
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core;
import static org.skyscreamer.jsonassert.JSONAssert.*;
import org.json.JSONException;
import org.junit.jupiter.api.Test;
import org.springframework.data.elasticsearch.core.query.Criteria;
/**
* @author Peter-Josef Meisch
*/
class CriteriaQueryProcessorTests {
private final CriteriaQueryProcessor queryProcessor = new CriteriaQueryProcessor();
@Test // DATAES-706
void shouldProcessTwoCriteriaWithAnd() throws JSONException {
String expected = "{\n" + //
" \"bool\": {\n" + //
" \"must\": [\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"value1\",\n" + //
" \"fields\": [\n" + //
" \"field1^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" },\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"value2\",\n" + //
" \"fields\": [\n" + //
" \"field2^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" }\n" + //
" ]\n" + //
" }\n" + //
"}"; //
Criteria criteria = new Criteria("field1").is("value1").and("field2").is("value2");
String query = queryProcessor.createQuery(criteria).toString();
assertEquals(expected, query, false);
}
@Test // DATAES-706
void shouldProcessTwoCriteriaWithOr() throws JSONException {
String expected = "{\n" + //
" \"bool\": {\n" + //
" \"should\": [\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"value1\",\n" + //
" \"fields\": [\n" + //
" \"field1^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" },\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"value2\",\n" + //
" \"fields\": [\n" + //
" \"field2^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" }\n" + //
" ]\n" + //
" }\n" + //
"}"; //
Criteria criteria = new Criteria("field1").is("value1").or("field2").is("value2");
String query = queryProcessor.createQuery(criteria).toString();
assertEquals(expected, query, false);
}
@Test // DATAES-706
void shouldProcessMixedCriteriaWithOrAnd() throws JSONException {
String expected = "{\n" + //
" \"bool\": {\n" + //
" \"must\": [\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"value1\",\n" + //
" \"fields\": [\n" + //
" \"field1^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" },\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"value3\",\n" + //
" \"fields\": [\n" + //
" \"field3^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" }\n" + //
" ],\n" + //
" \"should\": [\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"value2\",\n" + //
" \"fields\": [\n" + //
" \"field2^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" },\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"value4\",\n" + //
" \"fields\": [\n" + //
" \"field4^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" }\n" + //
" ]\n" + //
" }\n" + //
"}\n"; //
Criteria criteria = new Criteria("field1").is("value1") //
.or("field2").is("value2") //
.and("field3").is("value3") //
.or("field4").is("value4"); //
String query = queryProcessor.createQuery(criteria).toString();
assertEquals(expected, query, false);
}
@Test // DATAES-706
void shouldAddSubQuery() throws JSONException {
String expected = "{\n" + //
" \"bool\": {\n" + //
" \"must\": [\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"Miller\",\n" + //
" \"fields\": [\n" + //
" \"lastName^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" },\n" + //
" {\n" + //
" \"bool\": {\n" + //
" \"should\": [\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"John\",\n" + //
" \"fields\": [\n" + //
" \"firstName^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" },\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"Jack\",\n" + //
" \"fields\": [\n" + //
" \"firstName^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" }\n" + //
" ]\n" + //
" }\n" + //
" }\n" + //
" ]\n" + //
" }\n" + //
"}"; //
Criteria criteria = new Criteria("lastName").is("Miller")
.subCriteria(new Criteria().or("firstName").is("John").or("firstName").is("Jack"));
String query = queryProcessor.createQuery(criteria).toString();
assertEquals(expected, query, false);
}
@Test // DATAES-706
void shouldProcessNestedSubCriteria() throws JSONException {
String expected = "{\n" + //
" \"bool\": {\n" + //
" \"should\": [\n" + //
" {\n" + //
" \"bool\": {\n" + //
" \"must\": [\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"Miller\",\n" + //
" \"fields\": [\n" + //
" \"lastName^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" },\n" + //
" {\n" + //
" \"bool\": {\n" + //
" \"should\": [\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"Jack\",\n" + //
" \"fields\": [\n" + //
" \"firstName^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" },\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"John\",\n" + //
" \"fields\": [\n" + //
" \"firstName^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" }\n" + //
" ]\n" + //
" }\n" + //
" }\n" + //
" ]\n" + //
" }\n" + //
" },\n" + //
" {\n" + //
" \"bool\": {\n" + //
" \"must\": [\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"Smith\",\n" + //
" \"fields\": [\n" + //
" \"lastName^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" },\n" + //
" {\n" + //
" \"bool\": {\n" + //
" \"should\": [\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"Emma\",\n" + //
" \"fields\": [\n" + //
" \"firstName^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" },\n" + //
" {\n" + //
" \"query_string\": {\n" + //
" \"query\": \"Lucy\",\n" + //
" \"fields\": [\n" + //
" \"firstName^1.0\"\n" + //
" ]\n" + //
" }\n" + //
" }\n" + //
" ]\n" + //
" }\n" + //
" }\n" + //
" ]\n" + //
" }\n" + //
" }\n" + //
" ]\n" + //
" }\n" + //
"}"; //
Criteria criteria = Criteria.or()
.subCriteria(new Criteria("lastName").is("Miller")
.subCriteria(new Criteria().or("firstName").is("John").or("firstName").is("Jack")))
.subCriteria(new Criteria("lastName").is("Smith")
.subCriteria(new Criteria().or("firstName").is("Emma").or("firstName").is("Lucy")));
String query = queryProcessor.createQuery(criteria).toString();
assertEquals(expected, query, false);
}
@Test // DATAES-706
void shouldBuildMatchQuery() throws JSONException {
String expected = "{\n" + //
" \"bool\" : {\n" + //
" \"must\" : [\n" + //
" {\n" + //
" \"match\" : {\n" + //
" \"field1\" : {\n" + //
" \"query\" : \"value1 value2\",\n" + //
" \"operator\" : \"OR\"\n" + //
" }\n" + //
" }\n" + //
" }\n" + //
" ]\n" + //
" }\n" + //
"}\n"; //
Criteria criteria = new Criteria("field1").matches("value1 value2");
String query = queryProcessor.createQuery(criteria).toString();
assertEquals(expected, query, false);
}
@Test // DATAES-706
void shouldBuildMatchAllQuery() throws JSONException {
String expected = "{\n" + //
" \"bool\" : {\n" + //
" \"must\" : [\n" + //
" {\n" + //
" \"match\" : {\n" + //
" \"field1\" : {\n" + //
" \"query\" : \"value1 value2\",\n" + //
" \"operator\" : \"AND\"\n" + //
" }\n" + //
" }\n" + //
" }\n" + //
" ]\n" + //
" }\n" + //
"}\n"; //
Criteria criteria = new Criteria("field1").matchesAll("value1 value2");
String query = queryProcessor.createQuery(criteria).toString();
assertEquals(expected, query, false);
}
}

View File

@@ -83,99 +83,72 @@ public class CriteriaQueryTests {
indexOperations.delete();
}
@Test
public void shouldPerformAndOperation() {
@Test // ,DATAES-706
public void shouldPerformAndOperationOnCriteriaEntries() {
// given
String documentId = nextIdAsString();
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some test message");
sampleEntity.setVersion(System.currentTimeMillis());
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(documentId);
indexQuery.setObject(sampleEntity);
operations.index(indexQuery, index);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(nextIdAsString());
sampleEntity1.setMessage("some test message");
operations.save(sampleEntity1);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(nextIdAsString());
sampleEntity2.setMessage("some other message");
operations.save(sampleEntity2);
indexOperations.refresh();
// when
CriteriaQuery criteriaQuery = new CriteriaQuery(
new Criteria("message").contains("test").and("message").contains("some"));
// when
SearchHit<SampleEntity> sampleEntity1 = operations.searchOne(criteriaQuery, SampleEntity.class, index);
SearchHit<SampleEntity> searchHit = operations.searchOne(criteriaQuery, SampleEntity.class, index);
// then
assertThat(sampleEntity1).isNotNull();
assertThat(searchHit).isNotNull();
assertThat(searchHit.getId()).isEqualTo(sampleEntity1.id);
}
// @Ignore("DATAES-30")
@Test
public void shouldPerformOrOperation() {
@Test // ,DATAES-706
public void shouldPerformOrOperationOnCriteriaEntries() {
// given
List<IndexQuery> indexQueries = new ArrayList<>();
// first document
String documentId = nextIdAsString();
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setMessage("some message");
sampleEntity1.setVersion(System.currentTimeMillis());
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
// second document
String documentId2 = nextIdAsString();
sampleEntity1.setId(nextIdAsString());
sampleEntity1.setMessage("some test message");
operations.save(sampleEntity1);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setMessage("test message");
sampleEntity2.setVersion(System.currentTimeMillis());
IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(documentId2);
indexQuery2.setObject(sampleEntity2);
indexQueries.add(indexQuery2);
operations.bulkIndex(indexQueries, index);
sampleEntity2.setId(nextIdAsString());
sampleEntity2.setMessage("some other message");
operations.save(sampleEntity2);
indexOperations.refresh();
CriteriaQuery criteriaQuery = new CriteriaQuery(
new Criteria("message").contains("some").or("message").contains("test"));
// when
CriteriaQuery criteriaQuery = new CriteriaQuery(
new Criteria("message").contains("test").or("message").contains("other"));
SearchHits<SampleEntity> searchHits = operations.search(criteriaQuery, SampleEntity.class, index);
// then
assertThat(searchHits).isNotNull();
assertThat(searchHits.getTotalHits()).isGreaterThanOrEqualTo(1);
assertThat(searchHits.getSearchHits().stream().map(SearchHit::getId)).containsExactlyInAnyOrder(sampleEntity1.id,
sampleEntity2.id);
}
@Test
@Test // ,DATAES-706
public void shouldPerformAndOperationWithinCriteria() {
// given
List<IndexQuery> indexQueries = new ArrayList<>();
// first document
String documentId = nextIdAsString();
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
sampleEntity.setVersion(System.currentTimeMillis());
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(documentId);
indexQuery.setObject(sampleEntity);
indexQueries.add(indexQuery);
operations.bulkIndex(indexQueries, index);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(nextIdAsString());
sampleEntity1.setMessage("some test message");
operations.save(sampleEntity1);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(nextIdAsString());
sampleEntity2.setMessage("some other message");
operations.save(sampleEntity2);
indexOperations.refresh();
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria().and(new Criteria("message").contains("some")));
// when
CriteriaQuery criteriaQuery = new CriteriaQuery(
new Criteria("message").contains("test").and(new Criteria("message").contains("some")));
SearchHits<SampleEntity> searchHits = operations.search(criteriaQuery, SampleEntity.class, index);
// then
@@ -183,34 +156,29 @@ public class CriteriaQueryTests {
assertThat(searchHits.getTotalHits()).isGreaterThanOrEqualTo(1);
}
@Test
@Test // ,DATAES-706
public void shouldPerformOrOperationWithinCriteria() {
// given
List<IndexQuery> indexQueries = new ArrayList<>();
// first document
String documentId = nextIdAsString();
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
sampleEntity.setVersion(System.currentTimeMillis());
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(documentId);
indexQuery.setObject(sampleEntity);
indexQueries.add(indexQuery);
operations.bulkIndex(indexQueries, index);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(nextIdAsString());
sampleEntity1.setMessage("some test message");
operations.save(sampleEntity1);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(nextIdAsString());
sampleEntity2.setMessage("some other message");
operations.save(sampleEntity2);
indexOperations.refresh();
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria().or(new Criteria("message").contains("some")));
// when
CriteriaQuery criteriaQuery = new CriteriaQuery(
new Criteria("message").contains("test").or(new Criteria("message").contains("other")));
SearchHits<SampleEntity> searchHits = operations.search(criteriaQuery, SampleEntity.class, index);
// then
assertThat(searchHits).isNotNull();
assertThat(searchHits.getTotalHits()).isGreaterThanOrEqualTo(1);
assertThat(searchHits.getSearchHits().stream().map(SearchHit::getId)).containsExactlyInAnyOrder(sampleEntity1.id,
sampleEntity2.id);
}
@Test

View File

@@ -78,9 +78,9 @@ public class ReactiveElasticsearchStringQueryUnitTests {
public void bindsSimplePropertyCorrectly() throws Exception {
ReactiveElasticsearchStringQuery elasticsearchStringQuery = createQueryForMethod("findByName", String.class);
StubParameterAccessor accesor = new StubParameterAccessor("Luke");
StubParameterAccessor accessor = new StubParameterAccessor("Luke");
org.springframework.data.elasticsearch.core.query.Query query = elasticsearchStringQuery.createQuery(accesor);
org.springframework.data.elasticsearch.core.query.Query query = elasticsearchStringQuery.createQuery(accessor);
StringQuery reference = new StringQuery("{ 'bool' : { 'must' : { 'term' : { 'name' : 'Luke' } } } }");
assertThat(query).isInstanceOf(StringQuery.class);
@@ -93,9 +93,9 @@ public class ReactiveElasticsearchStringQueryUnitTests {
ReactiveElasticsearchStringQuery elasticsearchStringQuery = createQueryForMethod("findByNameWithExpression",
String.class);
StubParameterAccessor accesor = new StubParameterAccessor("Luke");
StubParameterAccessor accessor = new StubParameterAccessor("Luke");
org.springframework.data.elasticsearch.core.query.Query query = elasticsearchStringQuery.createQuery(accesor);
org.springframework.data.elasticsearch.core.query.Query query = elasticsearchStringQuery.createQuery(accessor);
StringQuery reference = new StringQuery("{ 'bool' : { 'must' : { 'term' : { 'name' : 'Luke' } } } }");
assertThat(query).isInstanceOf(StringQuery.class);