DATAES-771 - Add after-save entity callbacks support.

Original PR: #414
This commit is contained in:
Roman Puchkovskiy
2020-03-29 21:50:56 +04:00
committed by GitHub
parent a7cdfb84b0
commit c73d1973bc
9 changed files with 944 additions and 11 deletions

View File

@@ -0,0 +1,276 @@
/*
* 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.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.core.event.AfterSaveCallback;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.BulkOptions;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.mapping.callback.EntityCallbacks;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
/**
* @author Roman Puchkovskiy
*/
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class ElasticsearchRestTemplateCallbackTests {
private ElasticsearchRestTemplate template;
@Mock
private RestHighLevelClient client;
@Mock
private IndexResponse indexResponse;
@Mock
private BulkResponse bulkResponse;
@Mock
private BulkItemResponse bulkItemResponse;
@BeforeEach
public void setUp() throws Exception {
template = new ElasticsearchRestTemplate(client);
doReturn(indexResponse).when(client).index(any(IndexRequest.class), any(RequestOptions.class));
doReturn("response-id").when(indexResponse).getId();
doReturn(bulkResponse).when(client).bulk(any(BulkRequest.class), any(RequestOptions.class));
doReturn(new BulkItemResponse[] {bulkItemResponse, bulkItemResponse}).when(bulkResponse).getItems();
doReturn("response-id").when(bulkItemResponse).getId();
}
@Test // DATAES-771
void saveOneShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(EntityCallbacks.create(afterSaveCallback));
Person entity = new Person("init", "luke");
Person saved = template.save(entity);
verify(afterSaveCallback).onAfterSave(eq(entity));
assertThat(saved.id).isEqualTo("after-save");
}
@Test // DATAES-771
void saveWithIndexCoordinatesShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(EntityCallbacks.create(afterSaveCallback));
Person entity = new Person("init", "luke");
Person saved = template.save(entity, IndexCoordinates.of("index"));
verify(afterSaveCallback).onAfterSave(eq(entity));
assertThat(saved.id).isEqualTo("after-save");
}
@Test // DATAES-771
void saveArrayShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(EntityCallbacks.create(afterSaveCallback));
Person entity1 = new Person("init1", "luke1");
Person entity2 = new Person("init2", "luke2");
Iterable<Person> saved = template.save(entity1, entity2);
verify(afterSaveCallback, times(2)).onAfterSave(any());
Iterator<Person> savedIterator = saved.iterator();
assertThat(savedIterator.next().getId()).isEqualTo("after-save");
assertThat(savedIterator.next().getId()).isEqualTo("after-save");
}
@Test // DATAES-771
void saveIterableShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(EntityCallbacks.create(afterSaveCallback));
Person entity1 = new Person("init1", "luke1");
Person entity2 = new Person("init2", "luke2");
Iterable<Person> saved = template.save(Arrays.asList(entity1, entity2));
verify(afterSaveCallback, times(2)).onAfterSave(any());
Iterator<Person> savedIterator = saved.iterator();
assertThat(savedIterator.next().getId()).isEqualTo("after-save");
assertThat(savedIterator.next().getId()).isEqualTo("after-save");
}
@Test // DATAES-771
void saveIterableWithIndexCoordinatesShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(EntityCallbacks.create(afterSaveCallback));
Person entity1 = new Person("init1", "luke1");
Person entity2 = new Person("init2", "luke2");
Iterable<Person> saved = template.save(Arrays.asList(entity1, entity2), IndexCoordinates.of("index"));
verify(afterSaveCallback, times(2)).onAfterSave(any());
Iterator<Person> savedIterator = saved.iterator();
assertThat(savedIterator.next().getId()).isEqualTo("after-save");
assertThat(savedIterator.next().getId()).isEqualTo("after-save");
}
@Test // DATAES-771
void indexShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(EntityCallbacks.create(afterSaveCallback));
Person entity = new Person("init", "luke");
IndexQuery indexQuery = indexQueryForEntity(entity);
template.index(indexQuery, IndexCoordinates.of("index"));
verify(afterSaveCallback).onAfterSave(eq(entity));
Person newPerson = (Person) indexQuery.getObject();
assertThat(newPerson.id).isEqualTo("after-save");
}
private IndexQuery indexQueryForEntity(Person entity) {
IndexQuery indexQuery = new IndexQuery();
indexQuery.setObject(entity);
return indexQuery;
}
@Test // DATAES-771
void bulkIndexShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(EntityCallbacks.create(afterSaveCallback));
Person entity1 = new Person("init1", "luke1");
Person entity2 = new Person("init2", "luke2");
IndexQuery query1 = indexQueryForEntity(entity1);
IndexQuery query2 = indexQueryForEntity(entity2);
template.bulkIndex(Arrays.asList(query1, query2), IndexCoordinates.of("index"));
verify(afterSaveCallback, times(2)).onAfterSave(any());
Person savedPerson1 = (Person) query1.getObject();
Person savedPerson2 = (Person) query2.getObject();
assertThat(savedPerson1.getId()).isEqualTo("after-save");
assertThat(savedPerson2.getId()).isEqualTo("after-save");
}
@Test // DATAES-771
void bulkIndexWithOptionsShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(EntityCallbacks.create(afterSaveCallback));
Person entity1 = new Person("init1", "luke1");
Person entity2 = new Person("init2", "luke2");
IndexQuery query1 = indexQueryForEntity(entity1);
IndexQuery query2 = indexQueryForEntity(entity2);
template.bulkIndex(Arrays.asList(query1, query2), BulkOptions.defaultOptions(), IndexCoordinates.of("index"));
verify(afterSaveCallback, times(2)).onAfterSave(any());
Person savedPerson1 = (Person) query1.getObject();
Person savedPerson2 = (Person) query2.getObject();
assertThat(savedPerson1.getId()).isEqualTo("after-save");
assertThat(savedPerson2.getId()).isEqualTo("after-save");
}
@Data
@AllArgsConstructor
@NoArgsConstructor
static class Person {
@Id String id;
String firstname;
}
static class ValueCapturingEntityCallback<T> {
private final List<T> values = new ArrayList<>(1);
protected void capture(T value) {
values.add(value);
}
public List<T> getValues() {
return values;
}
@Nullable
public T getValue() {
return CollectionUtils.lastElement(values);
}
}
static class ValueCapturingAfterSaveCallback extends ValueCapturingEntityCallback<Person>
implements AfterSaveCallback<Person> {
@Override
public Person onAfterSave(Person entity) {
capture(entity);
return new Person() {
{
id = "after-save";
firstname = entity.firstname;
}
};
}
}
}

View File

@@ -0,0 +1,288 @@
/*
* 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.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.Client;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.core.event.AfterSaveCallback;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.BulkOptions;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.mapping.callback.EntityCallbacks;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
/**
* @author Roman Puchkovskiy
*/
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class ElasticsearchTransportTemplateCallbackTests {
private ElasticsearchTemplate template;
@Mock
private Client client;
@Mock
private IndexRequestBuilder indexRequestBuilder;
@Mock
private ActionFuture<IndexResponse> indexResponseActionFuture;
@Mock
private IndexResponse indexResponse;
@Mock
private BulkRequestBuilder bulkRequestBuilder;
@Mock
private ActionFuture<BulkResponse> bulkResponseActionFuture;
@Mock
private BulkResponse bulkResponse;
@Mock
private BulkItemResponse bulkItemResponse;
@BeforeEach
public void setUp() {
template = new ElasticsearchTemplate(client);
when(client.prepareIndex(anyString(), anyString(), anyString())).thenReturn(indexRequestBuilder);
doReturn(indexResponseActionFuture).when(indexRequestBuilder).execute();
when(indexResponseActionFuture.actionGet()).thenReturn(indexResponse);
doReturn("response-id").when(indexResponse).getId();
when(client.prepareBulk()).thenReturn(bulkRequestBuilder);
doReturn(bulkResponseActionFuture).when(bulkRequestBuilder).execute();
when(bulkResponseActionFuture.actionGet()).thenReturn(bulkResponse);
doReturn(new BulkItemResponse[] {bulkItemResponse, bulkItemResponse}).when(bulkResponse).getItems();
doReturn("response-id").when(bulkItemResponse).getId();
}
@Test // DATAES-771
void saveOneShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(EntityCallbacks.create(afterSaveCallback));
Person entity = new Person("init", "luke");
Person saved = template.save(entity);
verify(afterSaveCallback).onAfterSave(eq(entity));
assertThat(saved.id).isEqualTo("after-save");
}
@Test // DATAES-771
void saveWithIndexCoordinatesShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(EntityCallbacks.create(afterSaveCallback));
Person entity = new Person("init", "luke");
Person saved = template.save(entity, IndexCoordinates.of("index"));
verify(afterSaveCallback).onAfterSave(eq(entity));
assertThat(saved.id).isEqualTo("after-save");
}
@Test // DATAES-771
void saveArrayShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(EntityCallbacks.create(afterSaveCallback));
Person entity1 = new Person("init1", "luke1");
Person entity2 = new Person("init2", "luke2");
Iterable<Person> saved = template.save(entity1, entity2);
verify(afterSaveCallback, times(2)).onAfterSave(any());
Iterator<Person> savedIterator = saved.iterator();
assertThat(savedIterator.next().getId()).isEqualTo("after-save");
assertThat(savedIterator.next().getId()).isEqualTo("after-save");
}
@Test // DATAES-771
void saveIterableShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(EntityCallbacks.create(afterSaveCallback));
Person entity1 = new Person("init1", "luke1");
Person entity2 = new Person("init2", "luke2");
Iterable<Person> saved = template.save(Arrays.asList(entity1, entity2));
verify(afterSaveCallback, times(2)).onAfterSave(any());
Iterator<Person> savedIterator = saved.iterator();
assertThat(savedIterator.next().getId()).isEqualTo("after-save");
assertThat(savedIterator.next().getId()).isEqualTo("after-save");
}
@Test // DATAES-771
void saveIterableWithIndexCoordinatesShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(EntityCallbacks.create(afterSaveCallback));
Person entity1 = new Person("init1", "luke1");
Person entity2 = new Person("init2", "luke2");
Iterable<Person> saved = template.save(Arrays.asList(entity1, entity2), IndexCoordinates.of("index"));
verify(afterSaveCallback, times(2)).onAfterSave(any());
Iterator<Person> savedIterator = saved.iterator();
assertThat(savedIterator.next().getId()).isEqualTo("after-save");
assertThat(savedIterator.next().getId()).isEqualTo("after-save");
}
@Test // DATAES-771
void indexShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(EntityCallbacks.create(afterSaveCallback));
Person entity = new Person("init", "luke");
IndexQuery indexQuery = indexQueryForEntity(entity);
template.index(indexQuery, IndexCoordinates.of("index"));
verify(afterSaveCallback).onAfterSave(eq(entity));
Person savedPerson = (Person) indexQuery.getObject();
assertThat(savedPerson.id).isEqualTo("after-save");
}
private IndexQuery indexQueryForEntity(Person entity) {
IndexQuery indexQuery = new IndexQuery();
indexQuery.setObject(entity);
return indexQuery;
}
@Test // DATAES-771
void bulkIndexShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(EntityCallbacks.create(afterSaveCallback));
Person entity1 = new Person("init1", "luke1");
Person entity2 = new Person("init2", "luke2");
IndexQuery query1 = indexQueryForEntity(entity1);
IndexQuery query2 = indexQueryForEntity(entity2);
template.bulkIndex(Arrays.asList(query1, query2), IndexCoordinates.of("index"));
verify(afterSaveCallback, times(2)).onAfterSave(any());
Person savedPerson1 = (Person) query1.getObject();
Person savedPerson2 = (Person) query2.getObject();
assertThat(savedPerson1.getId()).isEqualTo("after-save");
assertThat(savedPerson2.getId()).isEqualTo("after-save");
}
@Test // DATAES-771
void bulkIndexWithOptionsShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(EntityCallbacks.create(afterSaveCallback));
Person entity1 = new Person("init1", "luke1");
Person entity2 = new Person("init2", "luke2");
IndexQuery query1 = indexQueryForEntity(entity1);
IndexQuery query2 = indexQueryForEntity(entity2);
template.bulkIndex(Arrays.asList(query1, query2), BulkOptions.defaultOptions(), IndexCoordinates.of("index"));
verify(afterSaveCallback, times(2)).onAfterSave(any());
Person savedPerson1 = (Person) query1.getObject();
Person savedPerson2 = (Person) query2.getObject();
assertThat(savedPerson1.getId()).isEqualTo("after-save");
assertThat(savedPerson2.getId()).isEqualTo("after-save");
}
@Data
@AllArgsConstructor
@NoArgsConstructor
static class Person {
@Id String id;
String firstname;
}
static class ValueCapturingEntityCallback<T> {
private final List<T> values = new ArrayList<>(1);
protected void capture(T value) {
values.add(value);
}
public List<T> getValues() {
return values;
}
@Nullable
public T getValue() {
return CollectionUtils.lastElement(values);
}
}
static class ValueCapturingAfterSaveCallback extends ValueCapturingEntityCallback<Person>
implements AfterSaveCallback<Person> {
@Override
public Person onAfterSave(Person entity) {
capture(entity);
return new Person() {
{
id = "after-save";
firstname = entity.firstname;
}
};
}
}
}

View File

@@ -0,0 +1,229 @@
/*
* Copyright 2018-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.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import reactor.core.publisher.Mono;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
import org.springframework.data.elasticsearch.core.event.ReactiveAfterSaveCallback;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.mapping.callback.ReactiveEntityCallbacks;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
/**
* @author Roman Puchkovskiy
*/
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class ReactiveElasticsearchTemplateCallbackTests {
private ReactiveElasticsearchTemplate template;
@Mock
private ReactiveElasticsearchClient client;
@Mock
private IndexResponse indexResponse;
@Mock
private BulkResponse bulkResponse;
@Mock
private BulkItemResponse bulkItemResponse;
@Mock
private DocWriteResponse docWriteResponse;
@BeforeEach
public void setUp() {
template = new ReactiveElasticsearchTemplate(client);
when(client.index(any(IndexRequest.class))).thenReturn(Mono.just(indexResponse));
doReturn("response-id").when(indexResponse).getId();
when(client.bulk(any(BulkRequest.class))).thenReturn(Mono.just(bulkResponse));
doReturn(new BulkItemResponse[] {bulkItemResponse, bulkItemResponse}).when(bulkResponse).getItems();
doReturn(docWriteResponse).when(bulkItemResponse).getResponse();
doReturn("response-id").when(docWriteResponse).getId();
}
@Test // DATAES-771
void saveOneShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(ReactiveEntityCallbacks.create(afterSaveCallback));
Person entity = new Person("init", "luke");
Person saved = template.save(entity).block(Duration.ofSeconds(1));
verify(afterSaveCallback).onAfterSave(eq(entity));
assertThat(saved.id).isEqualTo("after-save");
}
@Test // DATAES-771
void saveOneFromPublisherShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(ReactiveEntityCallbacks.create(afterSaveCallback));
Person entity = new Person("init", "luke");
Person saved = template.save(Mono.just(entity)).block(Duration.ofSeconds(1));
verify(afterSaveCallback).onAfterSave(eq(entity));
assertThat(saved.id).isEqualTo("after-save");
}
@Test // DATAES-771
void saveWithIndexCoordinatesShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(ReactiveEntityCallbacks.create(afterSaveCallback));
Person entity = new Person("init", "luke");
Person saved = template.save(entity, IndexCoordinates.of("index")).block(Duration.ofSeconds(1));
verify(afterSaveCallback).onAfterSave(eq(entity));
assertThat(saved.id).isEqualTo("after-save");
}
@Test // DATAES-771
void saveFromPublisherWithIndexCoordinatesShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(ReactiveEntityCallbacks.create(afterSaveCallback));
Person entity = new Person("init", "luke");
Person saved = template.save(Mono.just(entity), IndexCoordinates.of("index")).block(Duration.ofSeconds(1));
verify(afterSaveCallback).onAfterSave(eq(entity));
assertThat(saved.id).isEqualTo("after-save");
}
@Test // DATAES-771
void saveAllShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(ReactiveEntityCallbacks.create(afterSaveCallback));
Person entity1 = new Person("init1", "luke1");
Person entity2 = new Person("init2", "luke2");
List<Person> saved = template.saveAll(Arrays.asList(entity1, entity2), IndexCoordinates.of("index"))
.toStream().collect(Collectors.toList());
verify(afterSaveCallback, times(2)).onAfterSave(any());
assertThat(saved.get(0).getId()).isEqualTo("after-save");
assertThat(saved.get(1).getId()).isEqualTo("after-save");
}
@Test // DATAES-771
void saveFromMonoAllShouldInvokeAfterSaveCallbacks() {
ValueCapturingAfterSaveCallback afterSaveCallback = spy(new ValueCapturingAfterSaveCallback());
template.setEntityCallbacks(ReactiveEntityCallbacks.create(afterSaveCallback));
Person entity1 = new Person("init1", "luke1");
Person entity2 = new Person("init2", "luke2");
List<Person> saved = template.saveAll(Mono.just(Arrays.asList(entity1, entity2)), IndexCoordinates.of("index"))
.toStream().collect(Collectors.toList());
verify(afterSaveCallback, times(2)).onAfterSave(any());
assertThat(saved.get(0).getId()).isEqualTo("after-save");
assertThat(saved.get(1).getId()).isEqualTo("after-save");
}
@Data
@AllArgsConstructor
@NoArgsConstructor
static class Person {
@Id String id;
String firstname;
}
static class ValueCapturingEntityCallback<T> {
private final List<T> values = new ArrayList<>(1);
protected void capture(T value) {
values.add(value);
}
public List<T> getValues() {
return values;
}
@Nullable
public T getValue() {
return CollectionUtils.lastElement(values);
}
}
static class ValueCapturingAfterSaveCallback extends ValueCapturingEntityCallback<Person>
implements ReactiveAfterSaveCallback<Person> {
@Override
public Mono<Person> onAfterSave(Person entity) {
return Mono.defer(() -> {
capture(entity);
Person newPerson = new Person() {
{
id = "after-save";
firstname = entity.firstname;
}
};
return Mono.just(newPerson);
});
}
}
}