Add support for reactive auditing and ReactiveEntityCallbacks.
Add support for reactive auditing and ReactiveEntityCallbacks. Also, adapt CouchbaseAuditingRegistrar for support AuditingEntityCallback. Closes #955. Original pull request: #1102. Co-authored-by: Carlos Espinado <carlosemart> Co-authored-by: mikereiche <michael.reiche@couchbase.com>
This commit is contained in:
committed by
mikereiche
parent
5a04711a6d
commit
3f1cea174f
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -24,6 +24,7 @@ package org.springframework.data.couchbase.config;
|
||||
* @author Michael Nitschinger
|
||||
* @author Simon Baslé
|
||||
* @author Michael Reiche
|
||||
* @author Jorge Rodríguez Martín
|
||||
*/
|
||||
public class BeanNames {
|
||||
|
||||
@@ -53,4 +54,9 @@ public class BeanNames {
|
||||
* The name for the bean that will handle audit trail marking of entities.
|
||||
*/
|
||||
public static final String COUCHBASE_AUDITING_HANDLER = "couchbaseAuditingHandler";
|
||||
|
||||
/**
|
||||
* The name for the bean that will handle reactive audit trail marking of entities.
|
||||
*/
|
||||
public static final String REACTIVE_COUCHBASE_AUDITING_HANDLER = "reactiveCouchbaseAuditingHandler";
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -180,4 +180,8 @@ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationContex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TemplateSupport support() {
|
||||
return templateSupport;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
/*
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -45,9 +46,10 @@ import org.slf4j.LoggerFactory;
|
||||
* @author Michael Nitschinger
|
||||
* @author Michael Reiche
|
||||
* @author Jorge Rodriguez Martin
|
||||
* @author Carlos Espinaco
|
||||
* @since 3.0
|
||||
*/
|
||||
class CouchbaseTemplateSupport implements ApplicationContextAware {
|
||||
class CouchbaseTemplateSupport implements ApplicationContextAware, TemplateSupport {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CouchbaseTemplateSupport.class);
|
||||
|
||||
@@ -63,6 +65,7 @@ class CouchbaseTemplateSupport implements ApplicationContextAware {
|
||||
this.translationService = translationService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CouchbaseDocument encodeEntity(final Object entityToEncode) {
|
||||
maybeEmitEvent(new BeforeConvertEvent<>(entityToEncode));
|
||||
Object maybeNewEntity = maybeCallBeforeConvert(entityToEncode, "");
|
||||
@@ -73,6 +76,7 @@ class CouchbaseTemplateSupport implements ApplicationContextAware {
|
||||
return converted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T decodeEntity(String id, String source, long cas, Class<T> entityClass) {
|
||||
final CouchbaseDocument converted = new CouchbaseDocument(id);
|
||||
converted.setId(id);
|
||||
@@ -90,6 +94,7 @@ class CouchbaseTemplateSupport implements ApplicationContextAware {
|
||||
return accessor.getBean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object applyUpdatedCas(final Object entity, final long cas) {
|
||||
final ConvertingPropertyAccessor<Object> accessor = getPropertyAccessor(entity);
|
||||
final CouchbasePersistentEntity<?> persistentEntity = mappingContext.getRequiredPersistentEntity(entity.getClass());
|
||||
@@ -102,6 +107,7 @@ class CouchbaseTemplateSupport implements ApplicationContextAware {
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object applyUpdatedId(final Object entity, Object id) {
|
||||
final ConvertingPropertyAccessor<Object> accessor = getPropertyAccessor(entity);
|
||||
final CouchbasePersistentEntity<?> persistentEntity = mappingContext.getRequiredPersistentEntity(entity.getClass());
|
||||
@@ -114,6 +120,7 @@ class CouchbaseTemplateSupport implements ApplicationContextAware {
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCas(final Object entity) {
|
||||
final ConvertingPropertyAccessor<Object> accessor = getPropertyAccessor(entity);
|
||||
final CouchbasePersistentEntity<?> persistentEntity = mappingContext.getRequiredPersistentEntity(entity.getClass());
|
||||
@@ -129,6 +136,7 @@ class CouchbaseTemplateSupport implements ApplicationContextAware {
|
||||
return cas;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJavaNameForEntity(final Class<?> clazz) {
|
||||
final CouchbasePersistentEntity<?> persistentEntity = mappingContext.getRequiredPersistentEntity(clazz);
|
||||
MappingCouchbaseEntityInformation<?, Object> info = new MappingCouchbaseEntityInformation<>(persistentEntity);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -53,7 +53,7 @@ public class ExecutableFindByAnalyticsOperationSupport implements ExecutableFind
|
||||
this.domainType = domainType;
|
||||
this.query = query;
|
||||
this.reactiveSupport = new ReactiveFindByAnalyticsSupport<>(template.reactive(), domainType, query,
|
||||
scanConsistency);
|
||||
scanConsistency, new NonReactiveSupportWrapper(template.support()));
|
||||
this.scanConsistency = scanConsistency;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -48,7 +48,7 @@ public class ExecutableFindByIdOperationSupport implements ExecutableFindByIdOpe
|
||||
this.domainType = domainType;
|
||||
this.collection = collection;
|
||||
this.fields = fields;
|
||||
this.reactiveSupport = new ReactiveFindByIdSupport<>(template.reactive(), domainType, collection, fields);
|
||||
this.reactiveSupport = new ReactiveFindByIdSupport<>(template.reactive(), domainType, collection, fields, new NonReactiveSupportWrapper(template.support()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -65,7 +65,7 @@ public class ExecutableFindByQueryOperationSupport implements ExecutableFindByQu
|
||||
this.returnType = returnType;
|
||||
this.query = query;
|
||||
this.reactiveSupport = new ReactiveFindByQuerySupport<T>(template.reactive(), domainType, returnType, query,
|
||||
scanConsistency, collection, distinctFields);
|
||||
scanConsistency, collection, distinctFields, new NonReactiveSupportWrapper(template.support()));
|
||||
this.scanConsistency = scanConsistency;
|
||||
this.collection = collection;
|
||||
this.distinctFields = distinctFields;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -48,7 +48,7 @@ public class ExecutableFindFromReplicasByIdOperationSupport implements Executabl
|
||||
this.collection = collection;
|
||||
this.returnType = returnType;
|
||||
this.reactiveSupport = new ReactiveFindFromReplicasByIdSupport<>(template.reactive(), domainType, returnType,
|
||||
collection);
|
||||
collection, new NonReactiveSupportWrapper(template.support()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -62,7 +62,7 @@ public class ExecutableInsertByIdOperationSupport implements ExecutableInsertByI
|
||||
this.durabilityLevel = durabilityLevel;
|
||||
this.expiry = expiry;
|
||||
this.reactiveSupport = new ReactiveInsertByIdSupport<>(template.reactive(), domainType, collection, persistTo,
|
||||
replicateTo, durabilityLevel, expiry);
|
||||
replicateTo, durabilityLevel, expiry, new NonReactiveSupportWrapper(template.support()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -62,7 +62,7 @@ public class ExecutableReplaceByIdOperationSupport implements ExecutableReplaceB
|
||||
this.durabilityLevel = durabilityLevel;
|
||||
this.expiry = expiry;
|
||||
this.reactiveSupport = new ReactiveReplaceByIdSupport<>(template.reactive(),
|
||||
domainType, collection, persistTo, replicateTo, durabilityLevel, expiry);
|
||||
domainType, collection, persistTo, replicateTo, durabilityLevel, expiry, new NonReactiveSupportWrapper(template.support()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -62,7 +62,7 @@ public class ExecutableUpsertByIdOperationSupport implements ExecutableUpsertByI
|
||||
this.durabilityLevel = durabilityLevel;
|
||||
this.expiry = expiry;
|
||||
this.reactiveSupport = new ReactiveUpsertByIdSupport<>(template.reactive(),
|
||||
domainType, collection, persistTo, replicateTo, durabilityLevel, expiry);
|
||||
domainType, collection, persistTo, replicateTo, durabilityLevel, expiry, new NonReactiveSupportWrapper(template.support()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2021 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.couchbase.core;
|
||||
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Wrapper of {@link TemplateSupport} methods to adapt them to {@link ReactiveTemplateSupport}.
|
||||
*
|
||||
* @author Carlos Espinaco
|
||||
* @since 4.2
|
||||
*/
|
||||
public class NonReactiveSupportWrapper implements ReactiveTemplateSupport {
|
||||
|
||||
private final TemplateSupport support;
|
||||
|
||||
public NonReactiveSupportWrapper(TemplateSupport support) {
|
||||
this.support = support;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<CouchbaseDocument> encodeEntity(Object entityToEncode) {
|
||||
return Mono.fromSupplier(() -> support.encodeEntity(entityToEncode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<T> decodeEntity(String id, String source, long cas, Class<T> entityClass) {
|
||||
return Mono.fromSupplier(() -> support.decodeEntity(id, source, cas, entityClass));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Object> applyUpdatedCas(Object entity, long cas) {
|
||||
return Mono.fromSupplier(() -> support.applyUpdatedCas(entity, cas));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Object> applyUpdatedId(Object entity, Object id) {
|
||||
return Mono.fromSupplier(() -> support.applyUpdatedId(entity, id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getCas(Object entity) {
|
||||
return support.getCas(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJavaNameForEntity(Class<?> clazz) {
|
||||
return support.getJavaNameForEntity(clazz);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -34,13 +34,14 @@ import com.couchbase.client.java.Collection;
|
||||
* @author Michael Nitschinger
|
||||
* @author Michael Reiche
|
||||
* @author Jorge Rodriguez Martin
|
||||
* @author Carlos Espinaco
|
||||
*/
|
||||
public class ReactiveCouchbaseTemplate implements ReactiveCouchbaseOperations, ApplicationContextAware {
|
||||
|
||||
private final CouchbaseClientFactory clientFactory;
|
||||
private final CouchbaseConverter converter;
|
||||
private final PersistenceExceptionTranslator exceptionTranslator;
|
||||
private final CouchbaseTemplateSupport templateSupport;
|
||||
private final ReactiveCouchbaseTemplateSupport templateSupport;
|
||||
|
||||
public ReactiveCouchbaseTemplate(final CouchbaseClientFactory clientFactory, final CouchbaseConverter converter) {
|
||||
this(clientFactory, converter, new JacksonTranslationService());
|
||||
@@ -51,7 +52,7 @@ public class ReactiveCouchbaseTemplate implements ReactiveCouchbaseOperations, A
|
||||
this.clientFactory = clientFactory;
|
||||
this.converter = converter;
|
||||
this.exceptionTranslator = clientFactory.getExceptionTranslator();
|
||||
this.templateSupport = new CouchbaseTemplateSupport(converter, translationService);
|
||||
this.templateSupport = new ReactiveCouchbaseTemplateSupport(converter, translationService);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -134,7 +135,7 @@ public class ReactiveCouchbaseTemplate implements ReactiveCouchbaseOperations, A
|
||||
return converter;
|
||||
}
|
||||
|
||||
CouchbaseTemplateSupport support() {
|
||||
ReactiveTemplateSupport support() {
|
||||
return templateSupport;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.couchbase.core;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
|
||||
import org.springframework.data.couchbase.core.convert.translation.TranslationService;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
|
||||
import org.springframework.data.couchbase.core.mapping.event.BeforeConvertEvent;
|
||||
import org.springframework.data.couchbase.core.mapping.event.BeforeSaveEvent;
|
||||
import org.springframework.data.couchbase.core.mapping.event.CouchbaseMappingEvent;
|
||||
import org.springframework.data.couchbase.core.mapping.event.ReactiveAfterConvertCallback;
|
||||
import org.springframework.data.couchbase.core.mapping.event.ReactiveBeforeConvertCallback;
|
||||
import org.springframework.data.couchbase.repository.support.MappingCouchbaseEntityInformation;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.callback.EntityCallbacks;
|
||||
import org.springframework.data.mapping.callback.ReactiveEntityCallbacks;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
||||
import org.springframework.util.Assert;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Internal encode/decode support for {@link ReactiveCouchbaseTemplate}.
|
||||
*
|
||||
* @author Carlos Espinaco
|
||||
* @since 4.2
|
||||
*/
|
||||
class ReactiveCouchbaseTemplateSupport implements ApplicationContextAware, ReactiveTemplateSupport {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ReactiveCouchbaseTemplateSupport.class);
|
||||
|
||||
private final CouchbaseConverter converter;
|
||||
private final MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext;
|
||||
private final TranslationService translationService;
|
||||
private ReactiveEntityCallbacks reactiveEntityCallbacks;
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
public ReactiveCouchbaseTemplateSupport(final CouchbaseConverter converter,
|
||||
final TranslationService translationService) {
|
||||
this.converter = converter;
|
||||
this.mappingContext = converter.getMappingContext();
|
||||
this.translationService = translationService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<CouchbaseDocument> encodeEntity(final Object entityToEncode) {
|
||||
return Mono.just(entityToEncode)
|
||||
.doOnNext(entity -> maybeEmitEvent(new BeforeConvertEvent<>(entity)))
|
||||
.flatMap(entity -> maybeCallBeforeConvert(entity, ""))
|
||||
.map(maybeNewEntity -> {
|
||||
final CouchbaseDocument converted = new CouchbaseDocument();
|
||||
converter.write(maybeNewEntity, converted);
|
||||
return converted;
|
||||
})
|
||||
.flatMap(converted -> maybeCallAfterConvert(entityToEncode, converted, "").thenReturn(converted))
|
||||
.doOnNext(converted -> maybeEmitEvent(new BeforeSaveEvent<>(entityToEncode, converted)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<T> decodeEntity(String id, String source, long cas, Class<T> entityClass) {
|
||||
return Mono.fromSupplier(() -> {
|
||||
final CouchbaseDocument converted = new CouchbaseDocument(id);
|
||||
converted.setId(id);
|
||||
CouchbasePersistentEntity<?> persistentEntity = mappingContext.getRequiredPersistentEntity(entityClass);
|
||||
if (cas != 0 && persistentEntity.getVersionProperty() != null) {
|
||||
converted.put(persistentEntity.getVersionProperty().getName(), cas);
|
||||
}
|
||||
|
||||
T readEntity = converter.read(entityClass, (CouchbaseDocument) translationService.decode(source, converted));
|
||||
final ConvertingPropertyAccessor<T> accessor = getPropertyAccessor(readEntity);
|
||||
|
||||
if (persistentEntity.getVersionProperty() != null) {
|
||||
accessor.setProperty(persistentEntity.getVersionProperty(), cas);
|
||||
}
|
||||
return accessor.getBean();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Object> applyUpdatedCas(final Object entity, final long cas) {
|
||||
return Mono.fromSupplier(() -> {
|
||||
final ConvertingPropertyAccessor<Object> accessor = getPropertyAccessor(entity);
|
||||
final CouchbasePersistentEntity<?> persistentEntity = mappingContext.getRequiredPersistentEntity(entity.getClass());
|
||||
final CouchbasePersistentProperty versionProperty = persistentEntity.getVersionProperty();
|
||||
|
||||
if (versionProperty != null) {
|
||||
accessor.setProperty(versionProperty, cas);
|
||||
return accessor.getBean();
|
||||
}
|
||||
return entity;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Object> applyUpdatedId(final Object entity, Object id) {
|
||||
return Mono.fromSupplier(() -> {
|
||||
final ConvertingPropertyAccessor<Object> accessor = getPropertyAccessor(entity);
|
||||
final CouchbasePersistentEntity<?> persistentEntity = mappingContext.getRequiredPersistentEntity(entity.getClass());
|
||||
final CouchbasePersistentProperty idProperty = persistentEntity.getIdProperty();
|
||||
|
||||
if (idProperty != null) {
|
||||
accessor.setProperty(idProperty, id);
|
||||
return accessor.getBean();
|
||||
}
|
||||
return entity;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getCas(final Object entity) {
|
||||
final ConvertingPropertyAccessor<Object> accessor = getPropertyAccessor(entity);
|
||||
final CouchbasePersistentEntity<?> persistentEntity = mappingContext
|
||||
.getRequiredPersistentEntity(entity.getClass());
|
||||
final CouchbasePersistentProperty versionProperty = persistentEntity.getVersionProperty();
|
||||
|
||||
long cas = 0;
|
||||
if (versionProperty != null) {
|
||||
Object casObject = (Number) accessor.getProperty(versionProperty);
|
||||
if (casObject instanceof Number) {
|
||||
cas = ((Number) casObject).longValue();
|
||||
}
|
||||
}
|
||||
return cas;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJavaNameForEntity(final Class<?> clazz) {
|
||||
final CouchbasePersistentEntity<?> persistentEntity = mappingContext.getRequiredPersistentEntity(clazz);
|
||||
MappingCouchbaseEntityInformation<?, Object> info = new MappingCouchbaseEntityInformation<>(persistentEntity);
|
||||
return info.getJavaType().getName();
|
||||
}
|
||||
|
||||
private <T> ConvertingPropertyAccessor<T> getPropertyAccessor(final T source) {
|
||||
CouchbasePersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(source.getClass());
|
||||
PersistentPropertyAccessor<T> accessor = entity.getPropertyAccessor(source);
|
||||
return new ConvertingPropertyAccessor<>(accessor, converter.getConversionService());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
if (reactiveEntityCallbacks == null) {
|
||||
setReactiveEntityCallbacks(ReactiveEntityCallbacks.create(applicationContext));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ReactiveEntityCallbacks} instance to use when invoking {@link
|
||||
* org.springframework.data.mapping.callback.ReactiveEntityCallbacks callbacks} like the {@link
|
||||
* ReactiveBeforeConvertCallback}.
|
||||
* <p/>
|
||||
* Overrides potentially existing {@link EntityCallbacks}.
|
||||
*
|
||||
* @param reactiveEntityCallbacks must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if the given instance is {@literal null}.
|
||||
*/
|
||||
public void setReactiveEntityCallbacks(ReactiveEntityCallbacks reactiveEntityCallbacks) {
|
||||
Assert.notNull(reactiveEntityCallbacks, "EntityCallbacks must not be null!");
|
||||
this.reactiveEntityCallbacks = reactiveEntityCallbacks;
|
||||
}
|
||||
|
||||
void maybeEmitEvent(CouchbaseMappingEvent<?> event) {
|
||||
if (canPublishEvent()) {
|
||||
try {
|
||||
this.applicationContext.publishEvent(event);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
LOG.info("maybeEmitEvent called, but ReactiveCouchbaseTemplate not initialized with applicationContext");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean canPublishEvent() {
|
||||
return this.applicationContext != null;
|
||||
}
|
||||
|
||||
protected <T> Mono<T> maybeCallBeforeConvert(T object, String collection) {
|
||||
if (reactiveEntityCallbacks != null) {
|
||||
try {
|
||||
return reactiveEntityCallbacks.callback(ReactiveBeforeConvertCallback.class, object, collection);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
LOG.info("maybeCallBeforeConvert called, but ReactiveCouchbaseTemplate not initialized with applicationContext");
|
||||
}
|
||||
return Mono.just(object);
|
||||
}
|
||||
|
||||
protected <T> Mono<T> maybeCallAfterConvert(T object, CouchbaseDocument document, String collection) {
|
||||
if (null != reactiveEntityCallbacks) {
|
||||
return reactiveEntityCallbacks.callback(ReactiveAfterConvertCallback.class, object, document, collection);
|
||||
} else {
|
||||
LOG.info("maybeCallAfterConvert called, but ReactiveCouchbaseTemplate not initialized with applicationContext");
|
||||
}
|
||||
return Mono.just(object);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.couchbase.core;
|
||||
|
||||
import com.couchbase.client.java.query.ReactiveQueryResult;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -38,7 +39,8 @@ public class ReactiveFindByAnalyticsOperationSupport implements ReactiveFindByAn
|
||||
|
||||
@Override
|
||||
public <T> ReactiveFindByAnalytics<T> findByAnalytics(final Class<T> domainType) {
|
||||
return new ReactiveFindByAnalyticsSupport<>(template, domainType, ALL_QUERY, AnalyticsScanConsistency.NOT_BOUNDED);
|
||||
return new ReactiveFindByAnalyticsSupport<>(template, domainType, ALL_QUERY, AnalyticsScanConsistency.NOT_BOUNDED,
|
||||
template.support());
|
||||
}
|
||||
|
||||
static class ReactiveFindByAnalyticsSupport<T> implements ReactiveFindByAnalytics<T> {
|
||||
@@ -47,29 +49,31 @@ public class ReactiveFindByAnalyticsOperationSupport implements ReactiveFindByAn
|
||||
private final Class<T> domainType;
|
||||
private final AnalyticsQuery query;
|
||||
private final AnalyticsScanConsistency scanConsistency;
|
||||
private final ReactiveTemplateSupport support;
|
||||
|
||||
ReactiveFindByAnalyticsSupport(final ReactiveCouchbaseTemplate template, final Class<T> domainType,
|
||||
final AnalyticsQuery query, final AnalyticsScanConsistency scanConsistency) {
|
||||
final AnalyticsQuery query, final AnalyticsScanConsistency scanConsistency, ReactiveTemplateSupport support) {
|
||||
this.template = template;
|
||||
this.domainType = domainType;
|
||||
this.query = query;
|
||||
this.scanConsistency = scanConsistency;
|
||||
this.support = support;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TerminatingFindByAnalytics<T> matching(AnalyticsQuery query) {
|
||||
return new ReactiveFindByAnalyticsSupport<>(template, domainType, query, scanConsistency);
|
||||
return new ReactiveFindByAnalyticsSupport<>(template, domainType, query, scanConsistency, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public FindByAnalyticsWithQuery<T> consistentWith(AnalyticsScanConsistency scanConsistency) {
|
||||
return new ReactiveFindByAnalyticsSupport<>(template, domainType, query, scanConsistency);
|
||||
return new ReactiveFindByAnalyticsSupport<>(template, domainType, query, scanConsistency, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FindByAnalyticsWithQuery<T> withConsistency(AnalyticsScanConsistency scanConsistency) {
|
||||
return new ReactiveFindByAnalyticsSupport<>(template, domainType, query, scanConsistency);
|
||||
return new ReactiveFindByAnalyticsSupport<>(template, domainType, query, scanConsistency, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -93,19 +97,19 @@ public class ReactiveFindByAnalyticsOperationSupport implements ReactiveFindByAn
|
||||
} else {
|
||||
return throwable;
|
||||
}
|
||||
}).flatMapMany(ReactiveAnalyticsResult::rowsAsObject).map(row -> {
|
||||
}).flatMapMany(ReactiveAnalyticsResult::rowsAsObject).flatMap(row -> {
|
||||
String id = "";
|
||||
long cas = 0;
|
||||
if (row.getString(TemplateUtils.SELECT_ID) == null) {
|
||||
throw new CouchbaseException("analytics query did not project " + TemplateUtils.SELECT_ID
|
||||
return Flux.error(new CouchbaseException("analytics query did not project " + TemplateUtils.SELECT_ID
|
||||
+ ". Either use #{#n1ql.selectEntity} or project " + TemplateUtils.SELECT_ID + " and "
|
||||
+ TemplateUtils.SELECT_CAS + " : " + statement);
|
||||
+ TemplateUtils.SELECT_CAS + " : " + statement));
|
||||
}
|
||||
id = row.getString(TemplateUtils.SELECT_ID);
|
||||
if (row.getLong(TemplateUtils.SELECT_CAS) == null) {
|
||||
throw new CouchbaseException("analytics query did not project " + TemplateUtils.SELECT_CAS
|
||||
return Flux.error(new CouchbaseException("analytics query did not project " + TemplateUtils.SELECT_CAS
|
||||
+ ". Either use #{#n1ql.selectEntity} or project " + TemplateUtils.SELECT_ID + " and "
|
||||
+ TemplateUtils.SELECT_CAS + " : " + statement);
|
||||
+ TemplateUtils.SELECT_CAS + " : " + statement));
|
||||
}
|
||||
cas = row.getLong(TemplateUtils.SELECT_CAS);
|
||||
row.removeKey(TemplateUtils.SELECT_ID);
|
||||
@@ -145,7 +149,7 @@ public class ReactiveFindByAnalyticsOperationSupport implements ReactiveFindByAn
|
||||
statement.append("meta().id as __id, meta().cas as __cas, ").append(bucket).append(".*");
|
||||
}
|
||||
|
||||
final String dataset = template.support().getJavaNameForEntity(domainType);
|
||||
final String dataset = support.getJavaNameForEntity(domainType);
|
||||
statement.append(" FROM ").append(dataset);
|
||||
|
||||
query.appendSort(statement);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -40,7 +40,7 @@ public class ReactiveFindByIdOperationSupport implements ReactiveFindByIdOperati
|
||||
|
||||
@Override
|
||||
public <T> ReactiveFindById<T> findById(Class<T> domainType) {
|
||||
return new ReactiveFindByIdSupport<>(template, domainType, null, null);
|
||||
return new ReactiveFindByIdSupport<>(template, domainType, null, null, template.support());
|
||||
}
|
||||
|
||||
static class ReactiveFindByIdSupport<T> implements ReactiveFindById<T> {
|
||||
@@ -49,13 +49,15 @@ public class ReactiveFindByIdOperationSupport implements ReactiveFindByIdOperati
|
||||
private final Class<T> domainType;
|
||||
private final String collection;
|
||||
private final List<String> fields;
|
||||
private final ReactiveTemplateSupport support;
|
||||
|
||||
ReactiveFindByIdSupport(ReactiveCouchbaseTemplate template, Class<T> domainType, String collection,
|
||||
List<String> fields) {
|
||||
List<String> fields, ReactiveTemplateSupport support) {
|
||||
this.template = template;
|
||||
this.domainType = domainType;
|
||||
this.collection = collection;
|
||||
this.fields = fields;
|
||||
this.support = support;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,7 +68,7 @@ public class ReactiveFindByIdOperationSupport implements ReactiveFindByIdOperati
|
||||
options.project(fields);
|
||||
}
|
||||
return template.getCollection(collection).reactive().get(docId, options);
|
||||
}).map(result -> template.support().decodeEntity(id, result.contentAs(String.class), result.cas(), domainType))
|
||||
}).flatMap(result -> support.decodeEntity(id, result.contentAs(String.class), result.cas(), domainType))
|
||||
.onErrorResume(throwable -> {
|
||||
if (throwable instanceof RuntimeException) {
|
||||
if (throwable instanceof DocumentNotFoundException) {
|
||||
@@ -91,13 +93,13 @@ public class ReactiveFindByIdOperationSupport implements ReactiveFindByIdOperati
|
||||
@Override
|
||||
public TerminatingFindById<T> inCollection(final String collection) {
|
||||
Assert.hasText(collection, "Collection must not be null nor empty.");
|
||||
return new ReactiveFindByIdSupport<>(template, domainType, collection, fields);
|
||||
return new ReactiveFindByIdSupport<>(template, domainType, collection, fields, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FindByIdWithCollection<T> project(String... fields) {
|
||||
Assert.notEmpty(fields, "Fields must not be null nor empty.");
|
||||
return new ReactiveFindByIdSupport<>(template, domainType, collection, Arrays.asList(fields));
|
||||
return new ReactiveFindByIdSupport<>(template, domainType, collection, Arrays.asList(fields), support);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -45,7 +45,7 @@ public class ReactiveFindByQueryOperationSupport implements ReactiveFindByQueryO
|
||||
@Override
|
||||
public <T> ReactiveFindByQuery<T> findByQuery(final Class<T> domainType) {
|
||||
return new ReactiveFindByQuerySupport<>(template, domainType, domainType, ALL_QUERY,
|
||||
QueryScanConsistency.NOT_BOUNDED, null, null);
|
||||
QueryScanConsistency.NOT_BOUNDED, null, null, template.support());
|
||||
}
|
||||
|
||||
static class ReactiveFindByQuerySupport<T> implements ReactiveFindByQuery<T> {
|
||||
@@ -57,10 +57,12 @@ public class ReactiveFindByQueryOperationSupport implements ReactiveFindByQueryO
|
||||
private final QueryScanConsistency scanConsistency;
|
||||
private final String collection;
|
||||
private final String[] distinctFields;
|
||||
private final ReactiveTemplateSupport support;
|
||||
|
||||
ReactiveFindByQuerySupport(final ReactiveCouchbaseTemplate template, final Class<?> domainType,
|
||||
final Class<T> returnType, final Query query, final QueryScanConsistency scanConsistency,
|
||||
final String collection, final String[] distinctFields) {
|
||||
final String collection, final String[] distinctFields, final ReactiveTemplateSupport support) {
|
||||
this.support = support;
|
||||
Assert.notNull(domainType, "domainType must not be null!");
|
||||
Assert.notNull(returnType, "returnType must not be null!");
|
||||
|
||||
@@ -82,41 +84,41 @@ public class ReactiveFindByQueryOperationSupport implements ReactiveFindByQueryO
|
||||
scanCons = scanConsistency;
|
||||
}
|
||||
return new ReactiveFindByQuerySupport<>(template, domainType, returnType, query, scanCons, collection,
|
||||
distinctFields);
|
||||
distinctFields, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FindByQueryInCollection<T> inCollection(String collection) {
|
||||
Assert.hasText(collection, "Collection must not be null nor empty.");
|
||||
return new ReactiveFindByQuerySupport<>(template, domainType, returnType, query, scanConsistency, collection,
|
||||
distinctFields);
|
||||
distinctFields, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public FindByQueryConsistentWith<T> consistentWith(QueryScanConsistency scanConsistency) {
|
||||
return new ReactiveFindByQuerySupport<>(template, domainType, returnType, query, scanConsistency, collection,
|
||||
distinctFields);
|
||||
distinctFields, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FindByQueryWithConsistency<T> withConsistency(QueryScanConsistency scanConsistency) {
|
||||
return new ReactiveFindByQuerySupport<>(template, domainType, returnType, query, scanConsistency, collection,
|
||||
distinctFields);
|
||||
distinctFields, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> FindByQueryWithConsistency<R> as(Class<R> returnType) {
|
||||
Assert.notNull(returnType, "returnType must not be null!");
|
||||
return new ReactiveFindByQuerySupport<>(template, domainType, returnType, query, scanConsistency, collection,
|
||||
distinctFields);
|
||||
distinctFields, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FindByQueryWithDistinct<T> distinct(String[] distinctFields) {
|
||||
Assert.notNull(distinctFields, "distinctFields must not be null!");
|
||||
return new ReactiveFindByQuerySupport<>(template, domainType, returnType, query, scanConsistency, collection,
|
||||
distinctFields);
|
||||
distinctFields, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -144,26 +146,26 @@ public class ReactiveFindByQueryOperationSupport implements ReactiveFindByQueryO
|
||||
} else {
|
||||
return throwable;
|
||||
}
|
||||
}).flatMapMany(ReactiveQueryResult::rowsAsObject).map(row -> {
|
||||
}).flatMapMany(ReactiveQueryResult::rowsAsObject).flatMap(row -> {
|
||||
String id = "";
|
||||
long cas = 0;
|
||||
if (distinctFields == null) {
|
||||
if (row.getString(TemplateUtils.SELECT_ID) == null) {
|
||||
throw new CouchbaseException(
|
||||
return Flux.error(new CouchbaseException(
|
||||
"query did not project " + TemplateUtils.SELECT_ID + ". Either use #{#n1ql.selectEntity} or project "
|
||||
+ TemplateUtils.SELECT_ID + " and " + TemplateUtils.SELECT_CAS + " : " + statement);
|
||||
+ TemplateUtils.SELECT_ID + " and " + TemplateUtils.SELECT_CAS + " : " + statement));
|
||||
}
|
||||
id = row.getString(TemplateUtils.SELECT_ID);
|
||||
if (row.getLong(TemplateUtils.SELECT_CAS) == null) {
|
||||
throw new CouchbaseException(
|
||||
return Flux.error(new CouchbaseException(
|
||||
"query did not project " + TemplateUtils.SELECT_CAS + ". Either use #{#n1ql.selectEntity} or project "
|
||||
+ TemplateUtils.SELECT_ID + " and " + TemplateUtils.SELECT_CAS + " : " + statement);
|
||||
+ TemplateUtils.SELECT_ID + " and " + TemplateUtils.SELECT_CAS + " : " + statement));
|
||||
}
|
||||
cas = row.getLong(TemplateUtils.SELECT_CAS);
|
||||
row.removeKey(TemplateUtils.SELECT_ID);
|
||||
row.removeKey(TemplateUtils.SELECT_CAS);
|
||||
}
|
||||
return template.support().decodeEntity(id, row.toString(), cas, returnType);
|
||||
return support.decodeEntity(id, row.toString(), cas, returnType);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -37,7 +37,7 @@ public class ReactiveFindFromReplicasByIdOperationSupport implements ReactiveFin
|
||||
|
||||
@Override
|
||||
public <T> ReactiveFindFromReplicasById<T> findFromReplicasById(Class<T> domainType) {
|
||||
return new ReactiveFindFromReplicasByIdSupport<>(template, domainType, domainType, null);
|
||||
return new ReactiveFindFromReplicasByIdSupport<>(template, domainType, domainType, null, template.support());
|
||||
}
|
||||
|
||||
static class ReactiveFindFromReplicasByIdSupport<T> implements ReactiveFindFromReplicasById<T> {
|
||||
@@ -46,13 +46,15 @@ public class ReactiveFindFromReplicasByIdOperationSupport implements ReactiveFin
|
||||
private final Class<?> domainType;
|
||||
private final Class<T> returnType;
|
||||
private final String collection;
|
||||
private final ReactiveTemplateSupport support;
|
||||
|
||||
ReactiveFindFromReplicasByIdSupport(ReactiveCouchbaseTemplate template, Class<?> domainType, Class<T> returnType,
|
||||
String collection) {
|
||||
String collection, ReactiveTemplateSupport support) {
|
||||
this.template = template;
|
||||
this.domainType = domainType;
|
||||
this.returnType = returnType;
|
||||
this.collection = collection;
|
||||
this.support = support;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,7 +62,7 @@ public class ReactiveFindFromReplicasByIdOperationSupport implements ReactiveFin
|
||||
return Mono.just(id).flatMap(docId -> {
|
||||
GetAnyReplicaOptions options = getAnyReplicaOptions().transcoder(RawJsonTranscoder.INSTANCE);
|
||||
return template.getCollection(collection).reactive().getAnyReplica(docId, options);
|
||||
}).map(result -> template.support().decodeEntity(id, result.contentAs(String.class), result.cas(), returnType))
|
||||
}).flatMap(result -> support.decodeEntity(id, result.contentAs(String.class), result.cas(), returnType))
|
||||
.onErrorMap(throwable -> {
|
||||
if (throwable instanceof RuntimeException) {
|
||||
return template.potentiallyConvertRuntimeException((RuntimeException) throwable);
|
||||
@@ -78,7 +80,7 @@ public class ReactiveFindFromReplicasByIdOperationSupport implements ReactiveFin
|
||||
@Override
|
||||
public TerminatingFindFromReplicasById<T> inCollection(final String collection) {
|
||||
Assert.hasText(collection, "Collection must not be null nor empty.");
|
||||
return new ReactiveFindFromReplicasByIdSupport<>(template, domainType, returnType, collection);
|
||||
return new ReactiveFindFromReplicasByIdSupport<>(template, domainType, returnType, collection, support);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -42,7 +42,7 @@ public class ReactiveInsertByIdOperationSupport implements ReactiveInsertByIdOpe
|
||||
public <T> ReactiveInsertById<T> insertById(final Class<T> domainType) {
|
||||
Assert.notNull(domainType, "DomainType must not be null!");
|
||||
return new ReactiveInsertByIdSupport<>(template, domainType, null, PersistTo.NONE, ReplicateTo.NONE,
|
||||
DurabilityLevel.NONE, null);
|
||||
DurabilityLevel.NONE, null, template.support());
|
||||
}
|
||||
|
||||
static class ReactiveInsertByIdSupport<T> implements ReactiveInsertById<T> {
|
||||
@@ -54,10 +54,11 @@ public class ReactiveInsertByIdOperationSupport implements ReactiveInsertByIdOpe
|
||||
private final ReplicateTo replicateTo;
|
||||
private final DurabilityLevel durabilityLevel;
|
||||
private final Duration expiry;
|
||||
private final ReactiveTemplateSupport support;
|
||||
|
||||
ReactiveInsertByIdSupport(final ReactiveCouchbaseTemplate template, final Class<T> domainType,
|
||||
final String collection, final PersistTo persistTo, final ReplicateTo replicateTo,
|
||||
final DurabilityLevel durabilityLevel, Duration expiry) {
|
||||
final DurabilityLevel durabilityLevel, Duration expiry, ReactiveTemplateSupport support) {
|
||||
this.template = template;
|
||||
this.domainType = domainType;
|
||||
this.collection = collection;
|
||||
@@ -65,18 +66,19 @@ public class ReactiveInsertByIdOperationSupport implements ReactiveInsertByIdOpe
|
||||
this.replicateTo = replicateTo;
|
||||
this.durabilityLevel = durabilityLevel;
|
||||
this.expiry = expiry;
|
||||
this.support = support;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<T> one(T object) {
|
||||
return Mono.just(object).flatMap(o -> {
|
||||
CouchbaseDocument converted = template.support().encodeEntity(o);
|
||||
return template.getCollection(collection).reactive()
|
||||
.insert(converted.getId(), converted.export(), buildInsertOptions(converted)).map(result -> {
|
||||
Object updatedObject = template.support().applyUpdatedId(o, converted.getId());
|
||||
return (T) template.support().applyUpdatedCas(updatedObject, result.cas());
|
||||
});
|
||||
}).onErrorMap(throwable -> {
|
||||
return (Mono<T>) Mono.just(object).flatMap(support::encodeEntity).flatMap(converted ->
|
||||
template.getCollection(collection).reactive()
|
||||
.insert(converted.getId(), converted.export(), buildInsertOptions(converted))
|
||||
.flatMap(result ->
|
||||
support.applyUpdatedId(object, converted.getId())
|
||||
.flatMap(
|
||||
updatedObject -> support.applyUpdatedCas(updatedObject, result.cas())))
|
||||
).onErrorMap(throwable -> {
|
||||
if (throwable instanceof RuntimeException) {
|
||||
return template.potentiallyConvertRuntimeException((RuntimeException) throwable);
|
||||
} else {
|
||||
@@ -109,14 +111,14 @@ public class ReactiveInsertByIdOperationSupport implements ReactiveInsertByIdOpe
|
||||
public TerminatingInsertById<T> inCollection(final String collection) {
|
||||
Assert.hasText(collection, "Collection must not be null nor empty.");
|
||||
return new ReactiveInsertByIdSupport<>(template, domainType, collection, persistTo, replicateTo, durabilityLevel,
|
||||
expiry);
|
||||
expiry, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InsertByIdWithCollection<T> withDurability(final DurabilityLevel durabilityLevel) {
|
||||
Assert.notNull(durabilityLevel, "Durability Level must not be null.");
|
||||
return new ReactiveInsertByIdSupport<>(template, domainType, collection, persistTo, replicateTo, durabilityLevel,
|
||||
expiry);
|
||||
expiry, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -124,14 +126,14 @@ public class ReactiveInsertByIdOperationSupport implements ReactiveInsertByIdOpe
|
||||
Assert.notNull(persistTo, "PersistTo must not be null.");
|
||||
Assert.notNull(replicateTo, "ReplicateTo must not be null.");
|
||||
return new ReactiveInsertByIdSupport<>(template, domainType, collection, persistTo, replicateTo, durabilityLevel,
|
||||
expiry);
|
||||
expiry, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InsertByIdWithDurability<T> withExpiry(final Duration expiry) {
|
||||
Assert.notNull(expiry, "expiry must not be null.");
|
||||
return new ReactiveInsertByIdSupport<>(template, domainType, collection, persistTo, replicateTo, durabilityLevel,
|
||||
expiry);
|
||||
expiry, support);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -41,7 +41,7 @@ public class ReactiveReplaceByIdOperationSupport implements ReactiveReplaceByIdO
|
||||
public <T> ReactiveReplaceById<T> replaceById(final Class<T> domainType) {
|
||||
Assert.notNull(domainType, "DomainType must not be null!");
|
||||
return new ReactiveReplaceByIdSupport<>(template, domainType, null, PersistTo.NONE, ReplicateTo.NONE,
|
||||
DurabilityLevel.NONE, null);
|
||||
DurabilityLevel.NONE, null, template.support());
|
||||
}
|
||||
|
||||
static class ReactiveReplaceByIdSupport<T> implements ReactiveReplaceById<T> {
|
||||
@@ -53,10 +53,11 @@ public class ReactiveReplaceByIdOperationSupport implements ReactiveReplaceByIdO
|
||||
private final ReplicateTo replicateTo;
|
||||
private final DurabilityLevel durabilityLevel;
|
||||
private final Duration expiry;
|
||||
private final ReactiveTemplateSupport support;
|
||||
|
||||
ReactiveReplaceByIdSupport(final ReactiveCouchbaseTemplate template, final Class<T> domainType,
|
||||
final String collection, final PersistTo persistTo, final ReplicateTo replicateTo,
|
||||
final DurabilityLevel durabilityLevel, final Duration expiry) {
|
||||
final DurabilityLevel durabilityLevel, final Duration expiry, ReactiveTemplateSupport support) {
|
||||
this.template = template;
|
||||
this.domainType = domainType;
|
||||
this.collection = collection;
|
||||
@@ -64,15 +65,15 @@ public class ReactiveReplaceByIdOperationSupport implements ReactiveReplaceByIdO
|
||||
this.replicateTo = replicateTo;
|
||||
this.durabilityLevel = durabilityLevel;
|
||||
this.expiry = expiry;
|
||||
this.support = support;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<T> one(T object) {
|
||||
return Mono.just(object).flatMap(o -> {
|
||||
CouchbaseDocument converted = template.support().encodeEntity(o);
|
||||
return (Mono<T>) Mono.just(object).flatMap(support::encodeEntity).flatMap(converted -> {
|
||||
return template.getCollection(collection).reactive()
|
||||
.replace(converted.getId(), converted.export(), buildReplaceOptions(o, converted))
|
||||
.map(result -> (T) template.support().applyUpdatedCas(o, result.cas()));
|
||||
.replace(converted.getId(), converted.export(), buildReplaceOptions(object, converted))
|
||||
.flatMap(result -> support.applyUpdatedCas(object, result.cas()));
|
||||
}).onErrorMap(throwable -> {
|
||||
if (throwable instanceof RuntimeException) {
|
||||
return template.potentiallyConvertRuntimeException((RuntimeException) throwable);
|
||||
@@ -99,7 +100,7 @@ public class ReactiveReplaceByIdOperationSupport implements ReactiveReplaceByIdO
|
||||
} else if (doc.getExpiration() != 0) {
|
||||
options.expiry(Duration.ofSeconds(doc.getExpiration()));
|
||||
}
|
||||
long cas = template.support().getCas(object);
|
||||
long cas = support.getCas(object);
|
||||
options.cas(cas);
|
||||
return options;
|
||||
}
|
||||
@@ -108,14 +109,14 @@ public class ReactiveReplaceByIdOperationSupport implements ReactiveReplaceByIdO
|
||||
public TerminatingReplaceById<T> inCollection(final String collection) {
|
||||
Assert.hasText(collection, "Collection must not be null nor empty.");
|
||||
return new ReactiveReplaceByIdSupport<>(template, domainType, collection, persistTo, replicateTo, durabilityLevel,
|
||||
expiry);
|
||||
expiry, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplaceByIdWithCollection<T> withDurability(final DurabilityLevel durabilityLevel) {
|
||||
Assert.notNull(durabilityLevel, "Durability Level must not be null.");
|
||||
return new ReactiveReplaceByIdSupport<>(template, domainType, collection, persistTo, replicateTo, durabilityLevel,
|
||||
expiry);
|
||||
expiry, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,14 +124,14 @@ public class ReactiveReplaceByIdOperationSupport implements ReactiveReplaceByIdO
|
||||
Assert.notNull(persistTo, "PersistTo must not be null.");
|
||||
Assert.notNull(replicateTo, "ReplicateTo must not be null.");
|
||||
return new ReactiveReplaceByIdSupport<>(template, domainType, collection, persistTo, replicateTo, durabilityLevel,
|
||||
expiry);
|
||||
expiry, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplaceByIdWithDurability<T> withExpiry(final Duration expiry) {
|
||||
Assert.notNull(expiry, "expiry must not be null.");
|
||||
return new ReactiveReplaceByIdSupport<>(template, domainType, collection, persistTo, replicateTo, durabilityLevel,
|
||||
expiry);
|
||||
expiry, support);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2021 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.couchbase.core;
|
||||
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface ReactiveTemplateSupport {
|
||||
|
||||
Mono<CouchbaseDocument> encodeEntity(Object entityToEncode);
|
||||
|
||||
<T> Mono<T> decodeEntity(String id, String source, long cas, Class<T> entityClass);
|
||||
|
||||
Mono<Object> applyUpdatedCas(Object entity, long cas);
|
||||
|
||||
Mono<Object> applyUpdatedId(Object entity, Object id);
|
||||
|
||||
Long getCas(Object entity);
|
||||
|
||||
String getJavaNameForEntity(Class<?> clazz);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -41,7 +41,7 @@ public class ReactiveUpsertByIdOperationSupport implements ReactiveUpsertByIdOpe
|
||||
public <T> ReactiveUpsertById<T> upsertById(final Class<T> domainType) {
|
||||
Assert.notNull(domainType, "DomainType must not be null!");
|
||||
return new ReactiveUpsertByIdSupport<>(template, domainType, null, PersistTo.NONE, ReplicateTo.NONE,
|
||||
DurabilityLevel.NONE, null);
|
||||
DurabilityLevel.NONE, null, template.support());
|
||||
}
|
||||
|
||||
static class ReactiveUpsertByIdSupport<T> implements ReactiveUpsertById<T> {
|
||||
@@ -53,10 +53,11 @@ public class ReactiveUpsertByIdOperationSupport implements ReactiveUpsertByIdOpe
|
||||
private final ReplicateTo replicateTo;
|
||||
private final DurabilityLevel durabilityLevel;
|
||||
private final Duration expiry;
|
||||
private final ReactiveTemplateSupport support;
|
||||
|
||||
ReactiveUpsertByIdSupport(final ReactiveCouchbaseTemplate template, final Class<T> domainType,
|
||||
final String collection, final PersistTo persistTo, final ReplicateTo replicateTo,
|
||||
final DurabilityLevel durabilityLevel, final Duration expiry) {
|
||||
final DurabilityLevel durabilityLevel, final Duration expiry, ReactiveTemplateSupport support) {
|
||||
this.template = template;
|
||||
this.domainType = domainType;
|
||||
this.collection = collection;
|
||||
@@ -64,18 +65,17 @@ public class ReactiveUpsertByIdOperationSupport implements ReactiveUpsertByIdOpe
|
||||
this.replicateTo = replicateTo;
|
||||
this.durabilityLevel = durabilityLevel;
|
||||
this.expiry = expiry;
|
||||
this.support = support;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<T> one(T object) {
|
||||
return Mono.just(object).flatMap(o -> {
|
||||
CouchbaseDocument converted = template.support().encodeEntity(o);
|
||||
return template.getCollection(collection).reactive()
|
||||
.upsert(converted.getId(), converted.export(), buildUpsertOptions(converted)).map(result -> {
|
||||
Object updatedObject = template.support().applyUpdatedId(o, converted.getId());
|
||||
return (T) template.support().applyUpdatedCas(updatedObject, result.cas());
|
||||
});
|
||||
}).onErrorMap(throwable -> {
|
||||
return (Mono<T>) Mono.just(object).flatMap(support::encodeEntity).flatMap(converted ->
|
||||
template.getCollection(collection).reactive()
|
||||
.upsert(converted.getId(), converted.export(), buildUpsertOptions(converted)).flatMap(result ->
|
||||
support.applyUpdatedId(object, converted.getId())
|
||||
.flatMap(updatedObject -> support.applyUpdatedCas(updatedObject, result.cas())))
|
||||
).onErrorMap(throwable -> {
|
||||
if (throwable instanceof RuntimeException) {
|
||||
return template.potentiallyConvertRuntimeException((RuntimeException) throwable);
|
||||
} else {
|
||||
@@ -108,14 +108,14 @@ public class ReactiveUpsertByIdOperationSupport implements ReactiveUpsertByIdOpe
|
||||
public TerminatingUpsertById<T> inCollection(final String collection) {
|
||||
Assert.hasText(collection, "Collection must not be null nor empty.");
|
||||
return new ReactiveUpsertByIdSupport<>(template, domainType, collection, persistTo, replicateTo, durabilityLevel,
|
||||
expiry);
|
||||
expiry, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpsertByIdWithCollection<T> withDurability(final DurabilityLevel durabilityLevel) {
|
||||
Assert.notNull(durabilityLevel, "Durability Level must not be null.");
|
||||
return new ReactiveUpsertByIdSupport<>(template, domainType, collection, persistTo, replicateTo, durabilityLevel,
|
||||
expiry);
|
||||
expiry, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,14 +123,14 @@ public class ReactiveUpsertByIdOperationSupport implements ReactiveUpsertByIdOpe
|
||||
Assert.notNull(persistTo, "PersistTo must not be null.");
|
||||
Assert.notNull(replicateTo, "ReplicateTo must not be null.");
|
||||
return new ReactiveUpsertByIdSupport<>(template, domainType, collection, persistTo, replicateTo, durabilityLevel,
|
||||
expiry);
|
||||
expiry, support);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpsertByIdWithDurability<T> withExpiry(final Duration expiry) {
|
||||
Assert.notNull(expiry, "expiry must not be null.");
|
||||
return new ReactiveUpsertByIdSupport<>(template, domainType, collection, persistTo, replicateTo, durabilityLevel,
|
||||
expiry);
|
||||
expiry, support);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2021 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.couchbase.core;
|
||||
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
|
||||
|
||||
public interface TemplateSupport {
|
||||
|
||||
CouchbaseDocument encodeEntity(Object entityToEncode);
|
||||
|
||||
<T> T decodeEntity(String id, String source, long cas, Class<T> entityClass);
|
||||
|
||||
Object applyUpdatedCas(Object entity, long cas);
|
||||
|
||||
Object applyUpdatedId(Object entity, Object id);
|
||||
|
||||
long getCas(Object entity);
|
||||
|
||||
String getJavaNameForEntity(Class<?> clazz);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.couchbase.core.mapping.event;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.data.auditing.AuditingHandler;
|
||||
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
|
||||
import org.springframework.data.mapping.callback.EntityCallback;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* {@link EntityCallback} to populate auditing related fields on an entity about to be saved.
|
||||
*
|
||||
* @author Jorge Rodríguez Martín
|
||||
* @since 4.2
|
||||
*/
|
||||
public class AuditingEntityCallback implements BeforeConvertCallback<Object>, Ordered {
|
||||
|
||||
private final ObjectFactory<IsNewAwareAuditingHandler> auditingHandlerFactory;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AuditingEntityCallback} using the given {@link MappingContext} and {@link AuditingHandler}
|
||||
* provided by the given {@link ObjectFactory}.
|
||||
*
|
||||
* @param auditingHandlerFactory must not be {@literal null}.
|
||||
*/
|
||||
public AuditingEntityCallback(ObjectFactory<IsNewAwareAuditingHandler> auditingHandlerFactory) {
|
||||
|
||||
Assert.notNull(auditingHandlerFactory, "IsNewAwareAuditingHandler must not be null!");
|
||||
this.auditingHandlerFactory = auditingHandlerFactory;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.couchbase.core.mapping.event.BeforeConvertCallback#onBeforeConvert(java.lang.Object, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Object onBeforeConvert(Object entity, String collection) {
|
||||
return auditingHandlerFactory.getObject().markAudited(entity);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.Ordered#getOrder()
|
||||
*/
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 100;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2021 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.couchbase.core.mapping.event;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
|
||||
import org.springframework.data.mapping.callback.EntityCallback;
|
||||
|
||||
/**
|
||||
* Callback being invoked after a domain object is materialized from a {@link org.springframework.data.couchbase.core.mapping.CouchbaseDocument} when reading results.
|
||||
*
|
||||
* @author Jorge Rodríguez Martín
|
||||
* @see org.springframework.data.mapping.callback.EntityCallbacks
|
||||
* @since 4.2
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ReactiveAfterConvertCallback<T> extends EntityCallback<T> {
|
||||
|
||||
/**
|
||||
* Entity callback method invoked after a domain object is converted to be persisted. Can return
|
||||
* either the same of a modified instance of the domain object.
|
||||
* @param entity the domain object to save.
|
||||
* @param collection name of the collection.
|
||||
* @return a {@link Publisher} emitting the domain object to be persisted.
|
||||
*/
|
||||
Publisher<T> onAfterConvert(T entity, CouchbaseDocument document, String collection);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2021 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.couchbase.core.mapping.event;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.data.auditing.AuditingHandler;
|
||||
import org.springframework.data.auditing.ReactiveIsNewAwareAuditingHandler;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
import org.springframework.data.mapping.callback.EntityCallback;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Reactive {@link EntityCallback} to populate auditing related fields on an entity about to be
|
||||
* saved. Based on <a href="https://github.com/spring-projects/spring-data-mongodb/blob/3.1.6/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/ReactiveAfterConvertCallback.java">ReactiveAfterConvertCallback</a>
|
||||
*
|
||||
* @author Jorge Rodríguez Martín
|
||||
* @since 4.2
|
||||
*/
|
||||
public class ReactiveAuditingEntityCallback implements ReactiveBeforeConvertCallback<Object>, Ordered {
|
||||
|
||||
private final ObjectFactory<ReactiveIsNewAwareAuditingHandler> auditingHandlerFactory;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ReactiveAuditingEntityCallback} using the given {@link MappingContext} and
|
||||
* {@link AuditingHandler} provided by the given {@link ObjectFactory}.
|
||||
*
|
||||
* @param auditingHandlerFactory must not be {@literal null}.
|
||||
*/
|
||||
public ReactiveAuditingEntityCallback(final ObjectFactory<ReactiveIsNewAwareAuditingHandler> auditingHandlerFactory) {
|
||||
Assert.notNull(auditingHandlerFactory, "IsNewAwareAuditingHandler must not be null!");
|
||||
this.auditingHandlerFactory = auditingHandlerFactory;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.data.couchbase.core.mapping.event.ReactiveBeforeConvertCallback#onBeforeConvert
|
||||
* (java.lang.Object, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Publisher<Object> onBeforeConvert(final Object entity, final String collection) {
|
||||
return this.auditingHandlerFactory.getObject().markAudited(entity);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.core.Ordered#getOrder()
|
||||
*/
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 100;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2021 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.couchbase.core.mapping.event;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.data.mapping.callback.EntityCallback;
|
||||
|
||||
/**
|
||||
* Callback being invoked before a domain object is converted to be persisted.
|
||||
*
|
||||
* @author Jorge Rodríguez Martín
|
||||
* @see org.springframework.data.mapping.callback.ReactiveEntityCallbacks
|
||||
* @since 4.2
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ReactiveBeforeConvertCallback<T> extends EntityCallback<T> {
|
||||
|
||||
/**
|
||||
* Entity callback method invoked before a domain object is converted to be persisted. Can return
|
||||
* either the same of a modified instance of the domain object.
|
||||
*
|
||||
* @param entity the domain object to save.
|
||||
* @param collection name of the collection.
|
||||
* @return a {@link Publisher} emitting the domain object to be persisted.
|
||||
*/
|
||||
Publisher<T> onBeforeConvert(T entity, String collection);
|
||||
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import org.springframework.data.auditing.config.AuditingConfiguration;
|
||||
import org.springframework.data.config.ParsingUtils;
|
||||
import org.springframework.data.couchbase.config.BeanNames;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
|
||||
import org.springframework.data.couchbase.core.mapping.event.AuditingEntityCallback;
|
||||
import org.springframework.data.couchbase.core.mapping.event.AuditingEventListener;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -41,6 +42,7 @@ import org.springframework.util.Assert;
|
||||
* @author Oliver Gierke
|
||||
* @author Simon Baslé
|
||||
* @author Michael Reiche
|
||||
* @author Jorge Rodríguez Martín
|
||||
*/
|
||||
public class CouchbaseAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
||||
|
||||
@@ -84,7 +86,7 @@ public class CouchbaseAuditingRegistrar extends AuditingBeanDefinitionRegistrarS
|
||||
.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(getAuditingHandlerBeanName(), registry));
|
||||
|
||||
registerInfrastructureBeanWithId(listenerBeanDefinitionBuilder.getBeanDefinition(),
|
||||
AuditingEventListener.class.getName(), registry);
|
||||
AuditingEntityCallback.class.getName(), registry);
|
||||
}
|
||||
|
||||
private void ensureMappingContext(BeanDefinitionRegistry registry, Object source) {
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2021 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.couchbase.repository.auditing;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.auditing.DateTimeProvider;
|
||||
import org.springframework.data.domain.ReactiveAuditorAware;
|
||||
|
||||
/**
|
||||
* Annotation to enable auditing in Couchbase using reactive infrastructure via annotation
|
||||
* configuration.
|
||||
*
|
||||
* @author Jorge Rodríguez Martín
|
||||
* @since 4.2
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Import(ReactiveCouchbaseAuditingRegistrar.class)
|
||||
public @interface EnableReactiveCouchbaseAuditing {
|
||||
|
||||
/**
|
||||
* Configures the {@link ReactiveAuditorAware} bean to be used to lookup the current principal.
|
||||
*
|
||||
* @return empty {@link String} by default.
|
||||
*/
|
||||
String auditorAwareRef() default "";
|
||||
|
||||
/**
|
||||
* Configures whether the creation and modification dates are set. Defaults to {@literal true}.
|
||||
*
|
||||
* @return {@literal true} by default.
|
||||
*/
|
||||
boolean setDates() default true;
|
||||
|
||||
/**
|
||||
* Configures whether the entity shall be marked as modified on creation. Defaults to {@literal
|
||||
* true}.
|
||||
*
|
||||
* @return {@literal true} by default.
|
||||
*/
|
||||
boolean modifyOnCreate() default true;
|
||||
|
||||
/**
|
||||
* Configures a {@link DateTimeProvider} bean name that allows customizing the timestamp to be
|
||||
* used for setting creation and modification dates.
|
||||
*
|
||||
* @return empty {@link String} by default.
|
||||
*/
|
||||
String dateTimeProviderRef() default "";
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2021 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.couchbase.repository.auditing;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
|
||||
/**
|
||||
* Simple helper to be able to wire the {@link PersistentEntities} from a {@link
|
||||
* MappingCouchbaseConverter} bean available in the application context.
|
||||
*
|
||||
* @author Jorge Rodríguez Martín
|
||||
* @since 4.2
|
||||
*/
|
||||
class PersistentEntitiesFactoryBean implements FactoryBean<PersistentEntities> {
|
||||
|
||||
private final MappingCouchbaseConverter converter;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PersistentEntitiesFactoryBean} for the given {@link
|
||||
* MappingCouchbaseConverter}.
|
||||
*
|
||||
* @param converter must not be {@literal null}.
|
||||
*/
|
||||
public PersistentEntitiesFactoryBean(final MappingCouchbaseConverter converter) {
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObject()
|
||||
*/
|
||||
@Override
|
||||
public PersistentEntities getObject() {
|
||||
return PersistentEntities.of(this.converter.getMappingContext());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return PersistentEntities.class;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package org.springframework.data.couchbase.repository.auditing;
|
||||
|
||||
import static org.springframework.data.couchbase.config.BeanNames.*;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.data.auditing.ReactiveIsNewAwareAuditingHandler;
|
||||
import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport;
|
||||
import org.springframework.data.auditing.config.AuditingConfiguration;
|
||||
import org.springframework.data.config.ParsingUtils;
|
||||
import org.springframework.data.couchbase.core.mapping.event.ReactiveAuditingEntityCallback;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* A support registrar that allows to set up reactive auditing for Couchbase (including {@link org.springframework.data.auditing.ReactiveAuditingHandler} and {
|
||||
* IsNewStrategyFactory} set up). See {@link EnableReactiveCouchbaseAuditing} for the associated annotation.
|
||||
*
|
||||
* @author Jorge Rodríguez Martín
|
||||
* @since 4.2
|
||||
*/
|
||||
class ReactiveCouchbaseAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAnnotation()
|
||||
*/
|
||||
@Override
|
||||
protected Class<? extends Annotation> getAnnotation() {
|
||||
return EnableReactiveCouchbaseAuditing.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAuditingHandlerBeanName()
|
||||
*/
|
||||
@Override
|
||||
protected String getAuditingHandlerBeanName() {
|
||||
return REACTIVE_COUCHBASE_AUDITING_HANDLER;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAuditHandlerBeanDefinitionBuilder(org.springframework.data.auditing.config.AuditingConfiguration)
|
||||
*/
|
||||
@Override
|
||||
protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) {
|
||||
Assert.notNull(configuration, "AuditingConfiguration must not be null!");
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ReactiveIsNewAwareAuditingHandler.class);
|
||||
|
||||
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(PersistentEntitiesFactoryBean.class);
|
||||
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
|
||||
|
||||
builder.addConstructorArgValue(definition.getBeanDefinition());
|
||||
return configureDefaultAuditHandlerAttributes(configuration, builder);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#registerAuditListener(org.springframework.beans.factory.config.BeanDefinition, org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
||||
*/
|
||||
@Override
|
||||
protected void registerAuditListenerBeanDefinition(BeanDefinition auditingHandlerDefinition,
|
||||
BeanDefinitionRegistry registry) {
|
||||
Assert.notNull(auditingHandlerDefinition, "BeanDefinition must not be null!");
|
||||
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ReactiveAuditingEntityCallback.class);
|
||||
|
||||
builder.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(getAuditingHandlerBeanName(), registry));
|
||||
builder.getRawBeanDefinition().setSource(auditingHandlerDefinition.getSource());
|
||||
|
||||
registerInfrastructureBeanWithId(builder.getBeanDefinition(),
|
||||
ReactiveAuditingEntityCallback.class.getName(), registry);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,8 +16,10 @@
|
||||
|
||||
package org.springframework.data.couchbase.domain;
|
||||
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.annotation.TypeAlias;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
|
||||
@@ -36,6 +38,11 @@ public class Airport extends ComparableEntity {
|
||||
|
||||
String icao;
|
||||
|
||||
@CreatedBy private String createdBy;
|
||||
|
||||
@Version long version;
|
||||
|
||||
|
||||
@PersistenceConstructor
|
||||
public Airport(String id, String iata, String icao) {
|
||||
this.id = id;
|
||||
@@ -55,4 +62,7 @@ public class Airport extends ComparableEntity {
|
||||
return icao;
|
||||
}
|
||||
|
||||
public String getCreatedBy() {
|
||||
return createdBy;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.couchbase.domain;
|
||||
|
||||
import org.springframework.data.domain.ReactiveAuditorAware;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
|
||||
/**
|
||||
* This class returns a string that represents the current user
|
||||
*
|
||||
* @author Jorge Rodríguez Martín
|
||||
* @since 4.2
|
||||
*/
|
||||
public class ReactiveNaiveAuditorAware implements ReactiveAuditorAware<String> {
|
||||
|
||||
@Override
|
||||
public Mono<String> getCurrentAuditor() {
|
||||
return Mono.just("auditor");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -38,8 +38,10 @@ import java.util.stream.Collectors;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.data.auditing.DateTimeProvider;
|
||||
import org.springframework.data.couchbase.CouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
|
||||
import org.springframework.data.couchbase.core.CouchbaseTemplate;
|
||||
@@ -50,10 +52,13 @@ import org.springframework.data.couchbase.domain.Address;
|
||||
import org.springframework.data.couchbase.domain.Airport;
|
||||
import org.springframework.data.couchbase.domain.AirportRepository;
|
||||
import org.springframework.data.couchbase.domain.Iata;
|
||||
import org.springframework.data.couchbase.domain.NaiveAuditorAware;
|
||||
import org.springframework.data.couchbase.domain.Person;
|
||||
import org.springframework.data.couchbase.domain.PersonRepository;
|
||||
import org.springframework.data.couchbase.domain.User;
|
||||
import org.springframework.data.couchbase.domain.UserRepository;
|
||||
import org.springframework.data.couchbase.domain.time.AuditingDateTimeProvider;
|
||||
import org.springframework.data.couchbase.repository.auditing.EnableCouchbaseAuditing;
|
||||
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
|
||||
import org.springframework.data.couchbase.repository.query.CouchbaseQueryMethod;
|
||||
import org.springframework.data.couchbase.repository.query.CouchbaseRepositoryQuery;
|
||||
@@ -378,6 +383,21 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
|
||||
assertEquals(user, users.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void findBySimplePropertyAudited() {
|
||||
Airport vie = null;
|
||||
try {
|
||||
vie = new Airport("airports::vie", "vie", "low2");
|
||||
Airport saved = airportRepository.save(vie);
|
||||
List<Airport> airports1 = airportRepository.findAllByIata("vie");
|
||||
assertEquals(saved, airports1.get(0));
|
||||
assertEquals(saved.getCreatedBy(), "auditor"); // NaiveAuditorAware will provide this
|
||||
} finally {
|
||||
airportRepository.delete(vie);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void sleep(int millis) {
|
||||
try {
|
||||
Thread.sleep(millis); // so they are executed out-of-order
|
||||
@@ -386,6 +406,7 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
|
||||
|
||||
@Configuration
|
||||
@EnableCouchbaseRepositories("org.springframework.data.couchbase")
|
||||
@EnableCouchbaseAuditing(auditorAwareRef = "auditorAwareRef", dateTimeProviderRef = "dateTimeProviderRef")
|
||||
static class Config extends AbstractCouchbaseConfiguration {
|
||||
|
||||
@Override
|
||||
@@ -408,6 +429,15 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
|
||||
return bucketName();
|
||||
}
|
||||
|
||||
@Bean(name = "auditorAwareRef")
|
||||
public NaiveAuditorAware testAuditorAware() {
|
||||
return new NaiveAuditorAware();
|
||||
}
|
||||
|
||||
@Bean(name = "dateTimeProviderRef")
|
||||
public DateTimeProvider testDateTimeProvider() {
|
||||
return new AuditingDateTimeProvider();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,15 +18,22 @@ package org.springframework.data.couchbase.repository;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.auditing.DateTimeProvider;
|
||||
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
|
||||
import org.springframework.data.couchbase.domain.Airport;
|
||||
import org.springframework.data.couchbase.domain.ReactiveAirportRepository;
|
||||
import org.springframework.data.couchbase.domain.ReactiveNaiveAuditorAware;
|
||||
import org.springframework.data.couchbase.domain.ReactiveUserRepository;
|
||||
import org.springframework.data.couchbase.domain.User;
|
||||
import org.springframework.data.couchbase.domain.time.AuditingDateTimeProvider;
|
||||
import org.springframework.data.couchbase.repository.auditing.EnableReactiveCouchbaseAuditing;
|
||||
import org.springframework.data.couchbase.repository.config.EnableReactiveCouchbaseRepositories;
|
||||
import org.springframework.data.couchbase.util.ClusterAwareIntegrationTests;
|
||||
import org.springframework.data.couchbase.util.ClusterType;
|
||||
@@ -39,23 +46,40 @@ public class ReactiveCouchbaseRepositoryKeyValueIntegrationTests extends Cluster
|
||||
|
||||
@Autowired ReactiveUserRepository userRepository;
|
||||
|
||||
@Autowired ReactiveAirportRepository airportRepository;
|
||||
|
||||
@Test
|
||||
void saveAndFindById() {
|
||||
User user = new User(UUID.randomUUID().toString(), "f", "l");
|
||||
|
||||
assertFalse(userRepository.existsById(user.getId()).block());
|
||||
|
||||
userRepository.save(user).block();
|
||||
final User save = userRepository.save(user).block();
|
||||
|
||||
Optional<User> found = userRepository.findById(user.getId()).blockOptional();
|
||||
assertTrue(found.isPresent());
|
||||
found.ifPresent(u -> assertEquals(user, u));
|
||||
found.ifPresent(u -> assertEquals(save, u));
|
||||
|
||||
assertTrue(userRepository.existsById(user.getId()).block());
|
||||
}
|
||||
|
||||
@Test
|
||||
void findBySimplePropertyAudited() {
|
||||
Airport vie = null;
|
||||
try {
|
||||
vie = new Airport("airports::vie", "vie", "low2");
|
||||
Airport saved = airportRepository.save(vie).block();
|
||||
List<Airport> airports1 = airportRepository.findAllByIata("vie").collectList().block();
|
||||
assertEquals(saved, airports1.get(0));
|
||||
assertEquals(saved.getCreatedBy(), "auditor"); // NaiveAuditorAware will provide this
|
||||
} finally {
|
||||
airportRepository.delete(vie).block();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableReactiveCouchbaseRepositories("org.springframework.data.couchbase")
|
||||
@EnableReactiveCouchbaseAuditing
|
||||
static class Config extends AbstractCouchbaseConfiguration {
|
||||
|
||||
@Override
|
||||
@@ -78,6 +102,16 @@ public class ReactiveCouchbaseRepositoryKeyValueIntegrationTests extends Cluster
|
||||
return bucketName();
|
||||
}
|
||||
|
||||
@Bean(name = "auditorAwareRef")
|
||||
public ReactiveNaiveAuditorAware testAuditorAware() {
|
||||
return new ReactiveNaiveAuditorAware();
|
||||
}
|
||||
|
||||
@Bean(name = "dateTimeProviderRef")
|
||||
public DateTimeProvider testDateTimeProvider() {
|
||||
return new AuditingDateTimeProvider();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user