Dataes 716 - Add value mapping to the ElasticsearchMappingConverter.

Original PR: #366
This commit is contained in:
Peter-Josef Meisch
2019-12-28 19:25:25 +01:00
committed by GitHub
parent d2b7df87f4
commit a68c6ba5d7
18 changed files with 820 additions and 245 deletions

View File

@@ -0,0 +1,104 @@
/*
* Copyright 2019 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 java.time.LocalDate;
import java.util.Collections;
import org.json.JSONException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
/**
* Tests for the mapping of {@link CriteriaQuery} by a
* {@link org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter}. In the same package as
* {@link CriteriaQueryProcessor} as this is needed to get the String represenation to assert.
*
* @author Peter-Josef Meisch
*/
public class CriteriaQueryMappingTests {
MappingElasticsearchConverter mappingElasticsearchConverter;
@BeforeEach
void setUp() {
SimpleElasticsearchMappingContext mappingContext = new SimpleElasticsearchMappingContext();
mappingContext.setInitialEntitySet(Collections.singleton(Person.class));
mappingContext.afterPropertiesSet();
mappingElasticsearchConverter = new MappingElasticsearchConverter(mappingContext, new GenericConversionService());
mappingElasticsearchConverter.afterPropertiesSet();
}
@Test
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)));
// mapped field name and converted parameter
String expected = '{' + //
" \"bool\" : {" + //
" \"should\" : [" + //
" {" + //
" \"range\" : {" + //
" \"birth-date\" : {" + //
" \"from\" : \"09.11.1989\"," + //
" \"to\" : \"09.11.1990\"," + //
" \"include_lower\" : true," + //
" \"include_upper\" : true" + //
" }" + //
" }" + //
" }," + //
" {" + //
" \"query_string\" : {" + //
" \"query\" : \"28.12.2019\"," + //
" \"fields\" : [" + //
" \"birth-date^1.0\"" + //
" ]" + //
" }" + //
" }" + //
" ]" + //
" }" + //
'}'; //
mappingElasticsearchConverter.updateQuery(criteriaQuery, Person.class);
String queryString = new CriteriaQueryProcessor().createQueryFromCriteria(criteriaQuery.getCriteria()).toString();
assertEquals(expected, queryString, false);
}
static class Person {
@Id String id;
@Field(name = "first-name") String firstName;
@Field(name = "last-name") String lastName;
@Field(name = "birth-date", type = FieldType.Date, format = DateFormat.custom,
pattern = "dd.MM.yyyy") LocalDate birthDate;
}
}

View File

@@ -0,0 +1,50 @@
package org.springframework.data.elasticsearch.core.convert;
import static org.assertj.core.api.Assertions.*;
import java.time.LocalDate;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.springframework.data.elasticsearch.annotations.DateFormat;
/**
* @author Peter-Josef Meisch
*/
class ElasticsearchDateConverterTests {
@ParameterizedTest
@EnumSource(DateFormat.class)
void shouldCreateConvertersForAllKnownFormats(DateFormat dateFormat) {
if (dateFormat == DateFormat.none) {
return;
}
String pattern = (dateFormat != DateFormat.custom) ? dateFormat.name() : "dd.MM.yyyy";
ElasticsearchDateConverter converter = ElasticsearchDateConverter.of(pattern);
assertThat(converter).isNotNull();
}
@Test
void shouldConvertToString() {
LocalDate localDate = LocalDate.of(2019, 12, 27);
ElasticsearchDateConverter converter = ElasticsearchDateConverter.of(DateFormat.basic_date);
String formatted = converter.format(localDate);
assertThat(formatted).isEqualTo("20191227");
}
@Test
void shouldParseFromString() {
LocalDate localDate = LocalDate.of(2019, 12, 27);
ElasticsearchDateConverter converter = ElasticsearchDateConverter.of(DateFormat.basic_date);
LocalDate parsed = converter.parse("20191227", LocalDate.class);
assertThat(parsed).isEqualTo(localDate);
}
}

View File

@@ -16,6 +16,7 @@
package org.springframework.data.elasticsearch.core.convert;
import static org.assertj.core.api.Assertions.*;
import static org.skyscreamer.jsonassert.JSONAssert.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -26,16 +27,17 @@ import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import java.io.IOException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.json.JSONException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.core.convert.ConversionService;
@@ -47,10 +49,15 @@ import org.springframework.data.annotation.Transient;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.GeoPointField;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.geo.Box;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Point;
@@ -294,7 +301,7 @@ public class MappingElasticsearchConverterUnitTests {
public void writesNestedEntity() {
Person person = new Person();
person.birthdate = new Date();
person.birthDate = LocalDate.now();
person.gender = Gender.MAN;
person.address = observatoryRoad;
@@ -574,6 +581,45 @@ public class MappingElasticsearchConverterUnitTests {
assertThat(target.address).isEqualTo(bigBunsCafe);
}
@Test // DATAES-716
void shouldWriteLocalDate() throws JSONException {
Person person = new Person();
person.id = "4711";
person.firstName = "John";
person.lastName = "Doe";
person.birthDate = LocalDate.of(2000, 8, 22);
person.gender = Gender.MAN;
String expected = '{' + //
" \"id\": \"4711\"," + //
" \"first-name\": \"John\"," + //
" \"last-name\": \"Doe\"," + //
" \"birth-date\": \"22.08.2000\"," + //
" \"gender\": \"MAN\"" + //
'}';
Document document = Document.create();
mappingElasticsearchConverter.write(person, document);
String json = document.toJson();
assertEquals(expected, json, false);
}
@Test
void shouldReadLocalDate() {
Document document = Document.create();
document.put("id", "4711");
document.put("first-name", "John");
document.put("last-name", "Doe");
document.put("birth-date", "22.08.2000");
document.put("gender", "MAN");
Person person = mappingElasticsearchConverter.read(Person.class, document);
assertThat(person.getId()).isEqualTo("4711");
assertThat(person.getBirthDate()).isEqualTo(LocalDate.of(2000, 8, 22));
assertThat(person.getGender()).isEqualTo(Gender.MAN);
}
private String pointTemplate(String name, Point point) {
return String.format(Locale.ENGLISH, "\"%s\":{\"lat\":%.1f,\"lon\":%.1f}", name, point.getX(), point.getY());
}
@@ -598,7 +644,10 @@ public class MappingElasticsearchConverterUnitTests {
@Id String id;
String name;
Date birthdate;
@Field(name = "first-name") String firstName;
@Field(name = "last-name") String lastName;
@Field(name = "birth-date", type = FieldType.Date, format = DateFormat.custom,
pattern = "dd.MM.yyyy") LocalDate birthDate;
Gender gender;
Address address;
@@ -759,5 +808,4 @@ public class MappingElasticsearchConverterUnitTests {
@GeoPointField private double[] pointD;
}
}

View File

@@ -33,6 +33,7 @@ import java.lang.Boolean;
import java.lang.Double;
import java.lang.Integer;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
@@ -957,7 +958,7 @@ public class MappingBuilderTests extends MappingContextBaseTests {
@Field(copyTo = { "foo", "bar" }) private String copyTo;
@Field(ignoreAbove = 42) private String ignoreAbove;
@Field(type = FieldType.Integer) private String type;
@Field(type = FieldType.Date, format = DateFormat.custom, pattern = "YYYYMMDD") private String date;
@Field(type = FieldType.Date, format = DateFormat.custom, pattern = "YYYYMMDD") private LocalDate date;
@Field(analyzer = "ana", searchAnalyzer = "sana", normalizer = "norma") private String analyzers;
@Field(type = Keyword, docValues = true) private String docValuesTrue;
@Field(type = Keyword, docValues = false) private String docValuesFalse;

View File

@@ -17,8 +17,14 @@ package org.springframework.data.elasticsearch.core.mapping;
import static org.assertj.core.api.Assertions.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import org.junit.jupiter.api.Test;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.Score;
import org.springframework.data.mapping.MappingException;
@@ -62,6 +68,47 @@ public class SimpleElasticsearchPersistentPropertyUnitTests {
assertThat(persistentProperty.getFieldName()).isEqualTo("by-value");
}
@Test
// DATAES-716
void shouldSetPropertyConverters() {
SimpleElasticsearchPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DatesProperty.class);
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getRequiredPersistentProperty("date");
assertThat(persistentProperty.hasPropertyConverter()).isFalse();
persistentProperty = persistentEntity.getRequiredPersistentProperty("localDate");
assertThat(persistentProperty.hasPropertyConverter()).isTrue();
assertThat(persistentProperty.getPropertyConverter()).isNotNull();
persistentProperty = persistentEntity.getRequiredPersistentProperty("localDateTime");
assertThat(persistentProperty.hasPropertyConverter()).isTrue();
assertThat(persistentProperty.getPropertyConverter()).isNotNull();
}
@Test
// DATAES-716
void shouldConvertFromLocalDate() {
SimpleElasticsearchPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DatesProperty.class);
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getRequiredPersistentProperty("localDate");
LocalDate localDate = LocalDate.of(2019, 12, 27);
String converted = persistentProperty.getPropertyConverter().write(localDate);
assertThat(converted).isEqualTo("27.12.2019");
}
@Test
// DATAES-716
void shouldConvertToLocalDate() {
SimpleElasticsearchPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DatesProperty.class);
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getRequiredPersistentProperty("localDate");
Object converted = persistentProperty.getPropertyConverter().read("27.12.2019");
assertThat(converted).isInstanceOf(LocalDate.class);
assertThat(converted).isEqualTo(LocalDate.of(2019, 12, 27));
}
static class InvalidScoreProperty {
@Score String scoreProperty;
}
@@ -73,4 +120,10 @@ public class SimpleElasticsearchPersistentPropertyUnitTests {
static class FieldValueProperty {
@Field(value = "by-value") String fieldProperty;
}
static class DatesProperty {
@Field(type = FieldType.Date, format = DateFormat.basic_date) Date date;
@Field(type = FieldType.Date, format = DateFormat.custom, pattern = "dd.MM.yyyy") LocalDate localDate;
@Field(type = FieldType.Date, format = DateFormat.basic_date_time) LocalDateTime localDateTime;
}
}