Only throw exception for id and cas not projected if needed. (#1395)

Closes #1394.
This commit is contained in:
Michael Reiche
2022-04-18 15:06:56 -07:00
committed by GitHub
parent fd88011f8f
commit d7326e4c19
7 changed files with 33 additions and 38 deletions

View File

@@ -37,6 +37,7 @@ import org.springframework.data.couchbase.core.mapping.event.BeforeConvertCallba
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.support.TemplateUtils;
import org.springframework.data.couchbase.repository.support.MappingCouchbaseEntityInformation;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.callback.EntityCallbacks;
@@ -45,6 +46,8 @@ import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import com.couchbase.client.core.error.CouchbaseException;
/**
* Internal encode/decode support for CouchbaseTemplate.
*
@@ -85,9 +88,7 @@ class CouchbaseTemplateSupport implements ApplicationContextAware, TemplateSuppo
}
@Override
public <T> T decodeEntity(String id, String source, long cas, Class<T> entityClass, String scope, String collection) {
final CouchbaseDocument converted = new CouchbaseDocument(id);
converted.setId(id);
public <T> T decodeEntity(String id, String source, Long cas, Class<T> entityClass, String scope, String collection) {
// this is the entity class defined for the repository. It may not be the class of the document that was read
// we will reset it after reading the document
@@ -107,18 +108,32 @@ class CouchbaseTemplateSupport implements ApplicationContextAware, TemplateSuppo
// to unwrap. This results in List<String[]> being unwrapped past String[] to String, so this may also be a
// Collection (or Array) of entityClass. We have no way of knowing - so just assume it is what we are told.
// if this is a Collection or array, only the first element will be returned.
final CouchbaseDocument converted = new CouchbaseDocument(id);
Set<Map.Entry<String, Object>> set = ((CouchbaseDocument) translationService.decode(source, converted))
.getContent().entrySet();
return (T) set.iterator().next().getValue();
}
if (id == null) {
throw new CouchbaseException(TemplateUtils.SELECT_ID + " was null. Either use #{#n1ql.selectEntity} or project "
+ TemplateUtils.SELECT_ID);
}
final CouchbaseDocument converted = new CouchbaseDocument(id);
// if possible, set the version property in the source so that if the constructor has a long version argument,
// it will have a value an not fail (as null is not a valid argument for a long argument). This possible failure
// it will have a value and not fail (as null is not a valid argument for a long argument). This possible failure
// can be avoid by defining the argument as Long instead of long.
// persistentEntity is still the (possibly abstract) class specified in the repository definition
// it's possible that the abstract class does not have a version property, and this won't be able to set the version
if (cas != 0 && persistentEntity.getVersionProperty() != null) {
converted.put(persistentEntity.getVersionProperty().getName(), cas);
if (persistentEntity.getVersionProperty() != null) {
if (cas == null) {
throw new CouchbaseException("version/cas in the entity but " + TemplateUtils.SELECT_CAS
+ " was not in result. Either use #{#n1ql.selectEntity} or project " + TemplateUtils.SELECT_CAS);
}
if (cas != 0) {
converted.put(persistentEntity.getVersionProperty().getName(), cas);
}
}
// if the constructor has an argument that is long version, then construction will fail if the 'version'

View File

@@ -40,7 +40,7 @@ public class NonReactiveSupportWrapper implements ReactiveTemplateSupport {
}
@Override
public <T> Mono<T> decodeEntity(String id, String source, long cas, Class<T> entityClass, String scope,
public <T> Mono<T> decodeEntity(String id, String source, Long cas, Class<T> entityClass, String scope,
String collection) {
return Mono.fromSupplier(() -> support.decodeEntity(id, source, cas, entityClass, scope, collection));
}

View File

@@ -85,7 +85,7 @@ class ReactiveCouchbaseTemplateSupport implements ApplicationContextAware, React
}
@Override
public <T> Mono<T> decodeEntity(String id, String source, long cas, Class<T> entityClass, String scope,
public <T> Mono<T> decodeEntity(String id, String source, Long cas, Class<T> entityClass, String scope,
String collection) {
return Mono.fromSupplier(() -> {
final CouchbaseDocument converted = new CouchbaseDocument(id);

View File

@@ -22,7 +22,6 @@ import org.springframework.data.couchbase.core.query.AnalyticsQuery;
import org.springframework.data.couchbase.core.support.TemplateUtils;
import org.springframework.util.Assert;
import com.couchbase.client.core.error.CouchbaseException;
import com.couchbase.client.java.analytics.AnalyticsOptions;
import com.couchbase.client.java.analytics.AnalyticsScanConsistency;
import com.couchbase.client.java.analytics.ReactiveAnalyticsResult;
@@ -117,23 +116,13 @@ public class ReactiveFindByAnalyticsOperationSupport implements ReactiveFindByAn
return throwable;
}
}).flatMapMany(ReactiveAnalyticsResult::rowsAsObject).flatMap(row -> {
String id = "";
Long cas = Long.valueOf(0);
if (row.getString(TemplateUtils.SELECT_ID) == null && row.getString(TemplateUtils.SELECT_ID_3x) == null) {
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));
}
String id = null;
Long cas = null;
id = row.getString(TemplateUtils.SELECT_ID);
if (id == null) {
id = row.getString(TemplateUtils.SELECT_ID_3x);
row.removeKey(TemplateUtils.SELECT_ID_3x);
}
if (row.getLong(TemplateUtils.SELECT_CAS) == null && row.getLong(TemplateUtils.SELECT_CAS_3x) == null) {
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));
}
cas = row.getLong(TemplateUtils.SELECT_CAS);
if (cas == null) {
cas = row.getLong(TemplateUtils.SELECT_CAS_3x);

View File

@@ -25,7 +25,6 @@ import org.springframework.data.couchbase.core.support.PseudoArgs;
import org.springframework.data.couchbase.core.support.TemplateUtils;
import org.springframework.util.Assert;
import com.couchbase.client.core.error.CouchbaseException;
import com.couchbase.client.java.query.QueryOptions;
import com.couchbase.client.java.query.QueryScanConsistency;
import com.couchbase.client.java.query.ReactiveQueryResult;
@@ -184,24 +183,17 @@ public class ReactiveFindByQueryOperationSupport implements ReactiveFindByQueryO
return throwable;
}
}).flatMapMany(ReactiveQueryResult::rowsAsObject).flatMap(row -> {
String id = "";
Long cas = Long.valueOf(0);
if (!query.isDistinct() && distinctFields == null) {
if (row.getString(TemplateUtils.SELECT_ID) == null && row.getString(TemplateUtils.SELECT_ID_3x) == null) {
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));
}
String id = null;
Long cas = null;
if (query.isDistinct() || distinctFields != null) {
id = "";
cas = Long.valueOf(0);
} else {
id = row.getString(TemplateUtils.SELECT_ID);
if (id == null) {
id = row.getString(TemplateUtils.SELECT_ID_3x);
row.removeKey(TemplateUtils.SELECT_ID_3x);
}
if (row.getLong(TemplateUtils.SELECT_CAS) == null && row.getLong(TemplateUtils.SELECT_CAS_3x) == null) {
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));
}
cas = row.getLong(TemplateUtils.SELECT_CAS);
if (cas == null) {
cas = row.getLong(TemplateUtils.SELECT_CAS_3x);

View File

@@ -21,14 +21,13 @@ import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
import org.springframework.data.couchbase.core.mapping.event.CouchbaseMappingEvent;
/**
*
* @author Michael Reiche
*/
public interface ReactiveTemplateSupport {
Mono<CouchbaseDocument> encodeEntity(Object entityToEncode);
<T> Mono<T> decodeEntity(String id, String source, long cas, Class<T> entityClass, String scope, String collection);
<T> Mono<T> decodeEntity(String id, String source, Long cas, Class<T> entityClass, String scope, String collection);
<T> Mono<T> applyUpdatedCas(T entity, CouchbaseDocument converted, long cas);

View File

@@ -26,7 +26,7 @@ public interface TemplateSupport {
CouchbaseDocument encodeEntity(Object entityToEncode);
<T> T decodeEntity(String id, String source, long cas, Class<T> entityClass, String scope, String collection);
<T> T decodeEntity(String id, String source, Long cas, Class<T> entityClass, String scope, String collection);
<T> T applyUpdatedCas(T entity, CouchbaseDocument converted, long cas);