DATACASS-343 - Polish.

This commit is contained in:
John Blum
2017-05-15 14:50:22 -07:00
parent 3e4016da42
commit 2f4767d80f
33 changed files with 712 additions and 508 deletions

View File

@@ -34,6 +34,13 @@ import org.springframework.data.util.TypeInformation;
public interface CassandraConverter
extends EntityConverter<CassandraPersistentEntity<?>, CassandraPersistentProperty, Object, Object> {
/**
* Returns the {@link CustomConversions} registered in the {@link CassandraConverter}.
*
* @return the {@link CustomConversions}.
*/
CustomConversions getCustomConversions();
/* (non-Javadoc)
* @see org.springframework.data.convert.EntityConverter#getMappingContext()
*/
@@ -57,6 +64,25 @@ public interface CassandraConverter
*/
Object getId(Object object, CassandraPersistentEntity<?> entity);
/**
* Converts the given object into a value Cassandra will be able to store natively in a column.
*
* @param obj {@link Object} to convert; must not be {@literal null}.
* @return the result of the conversion.
* @since 2.0
*/
<T> Optional<Object> convertToColumnType(Optional<T> obj);
/**
* Converts the given object into a value Cassandra will be able to store natively in a column.
*
* @param obj {@link Object} to convert; must not be {@literal null}.
* @param typeInformation {@link TypeInformation} used to describe the object type; may be {@literal null}.
* @return the result of the conversion.
* @since 1.5
*/
<T> Optional<Object> convertToColumnType(Optional<T> obj, TypeInformation<?> typeInformation);
/**
* Converts and writes a {@code source} object into a {@code sink} using the given {@link CassandraPersistentEntity}.
*
@@ -66,29 +92,4 @@ public interface CassandraConverter
*/
void write(Object source, Object sink, CassandraPersistentEntity<?> entity);
/**
* Converts the given object into one Cassandra will be able to store natively in a column.
*
* @param obj {@link Object} to convert, must not be {@literal null}.
* @return the result of the conversion.
* @since 2.0
*/
<T> Optional<Object> convertToCassandraColumn(Optional<T> obj);
/**
* Converts the given object into one Cassandra will be able to store natively in a column.
*
* @param obj {@link Object} to convert, must not be {@literal null}.
* @param typeInformation {@link TypeInformation} used to describe the object type; may be {@literal null}.
* @return the result of the conversion.
* @since 1.5
*/
<T> Optional<Object> convertToCassandraColumn(Optional<T> obj, TypeInformation<?> typeInformation);
/**
* Returns the {@link CustomConversions} registered in the {@link CassandraConverter}.
*
* @return the {@link CustomConversions}.
*/
CustomConversions getCustomConversions();
}

View File

@@ -69,6 +69,7 @@ abstract class CassandraConverters {
@ReadingConverter
public enum RowToBooleanConverter implements Converter<Row, Boolean> {
INSTANCE;
@Override
@@ -84,6 +85,7 @@ abstract class CassandraConverters {
*/
@ReadingConverter
public enum RowToDateConverter implements Converter<Row, Date> {
INSTANCE;
@Override
@@ -99,6 +101,7 @@ abstract class CassandraConverters {
*/
@ReadingConverter
public enum RowToInetAddressConverter implements Converter<Row, InetAddress> {
INSTANCE;
@Override
@@ -124,11 +127,11 @@ abstract class CassandraConverters {
*/
@ReadingConverter
public enum RowToNumberConverterFactory implements ConverterFactory<Row, Number> {
INSTANCE;
@Override
public <T extends Number> Converter<Row, T> getConverter(Class<T> targetType) {
Assert.notNull(targetType, "Target type must not be null");
return new RowToNumber<>(targetType);
}
@@ -158,6 +161,7 @@ abstract class CassandraConverters {
*/
@ReadingConverter
public enum RowToStringConverter implements Converter<Row, String> {
INSTANCE;
@Override
@@ -173,6 +177,7 @@ abstract class CassandraConverters {
*/
@ReadingConverter
public enum RowToUuidConverter implements Converter<Row, UUID> {
INSTANCE;
@Override
@@ -188,6 +193,7 @@ abstract class CassandraConverters {
*/
@ReadingConverter
public enum RowToCassandraLocalDateConverter implements Converter<Row, LocalDate> {
INSTANCE;
@Override

View File

@@ -38,7 +38,6 @@ public class CassandraCustomConversions extends org.springframework.data.convert
private static final List<Object> STORE_CONVERTERS;
static {
List<Object> converters = new ArrayList<>();
converters.addAll(CassandraConverters.getConvertersToRegister());

View File

@@ -15,9 +15,8 @@
*/
package org.springframework.data.cassandra.convert;
import static org.springframework.data.cassandra.repository.support.BasicMapId.*;
import lombok.AllArgsConstructor;
import static org.springframework.data.cassandra.repository.support.BasicMapId.Entry;
import static org.springframework.data.cassandra.repository.support.BasicMapId.id;
import java.util.ArrayList;
import java.util.Collection;
@@ -25,8 +24,8 @@ import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.context.ApplicationContext;
@@ -56,6 +55,9 @@ import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.CodecRegistry;
import com.datastax.driver.core.DataType;
import com.datastax.driver.core.Row;
@@ -118,6 +120,15 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
this.spELContext = new SpELContext(RowReaderPropertyAccessor.INSTANCE);
}
/* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
this.spELContext = new SpELContext(this.spELContext, applicationContext);
}
@SuppressWarnings("unchecked")
public <R> R readRow(Class<R> type, Row row) {
@@ -139,32 +150,24 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
return getConversionService().convert(row, type);
}
CassandraPersistentEntity<R> persistentEntity = (CassandraPersistentEntity<R>) getMappingContext()
.getRequiredPersistentEntity(typeInfo);
CassandraPersistentEntity<R> persistentEntity =
(CassandraPersistentEntity<R>) getMappingContext().getRequiredPersistentEntity(typeInfo);
return readEntityFromRow(persistentEntity, row);
}
/* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
this.spELContext = new SpELContext(this.spELContext, applicationContext);
}
protected <S> S readEntityFromRow(final CassandraPersistentEntity<S> entity, final Row row) {
protected <S> S readEntityFromRow(CassandraPersistentEntity<S> entity, Row row) {
DefaultSpELExpressionEvaluator expressionEvaluator = new DefaultSpELExpressionEvaluator(row, spELContext);
BasicCassandraRowValueProvider rowValueProvider = new BasicCassandraRowValueProvider(row, expressionEvaluator);
PersistentEntityParameterValueProvider<CassandraPersistentProperty> parameterProvider = new PersistentEntityParameterValueProvider<>(
entity, new MappingAndConvertingValueProvider(rowValueProvider), Optional.empty());
PersistentEntityParameterValueProvider<CassandraPersistentProperty> parameterValueProvider =
new PersistentEntityParameterValueProvider<>(entity,
new MappingAndConvertingValueProvider(rowValueProvider), Optional.empty());
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
S instance = instantiator.createInstance(entity, parameterProvider);
S instance = instantiator.createInstance(entity, parameterValueProvider);
readPropertiesFromRow(entity, rowValueProvider, getConvertingAccessor(instance, entity));
@@ -175,14 +178,15 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
DefaultSpELExpressionEvaluator expressionEvaluator = new DefaultSpELExpressionEvaluator(udtValue, spELContext);
CassandraUDTValueProvider valueProvider = new CassandraUDTValueProvider(udtValue, CodecRegistry.DEFAULT_INSTANCE,
expressionEvaluator);
CassandraUDTValueProvider valueProvider =
new CassandraUDTValueProvider(udtValue, CodecRegistry.DEFAULT_INSTANCE, expressionEvaluator);
PersistentEntityParameterValueProvider<CassandraPersistentProperty> parameterProvider = new PersistentEntityParameterValueProvider(
entity, new MappingAndConvertingValueProvider(valueProvider), Optional.empty());
PersistentEntityParameterValueProvider<CassandraPersistentProperty> parameterValueProvider =
new PersistentEntityParameterValueProvider<>(entity,
new MappingAndConvertingValueProvider(valueProvider), Optional.empty());
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
S instance = instantiator.createInstance(entity, parameterProvider);
S instance = instantiator.createInstance(entity, parameterValueProvider);
readProperties(entity, valueProvider, getConvertingAccessor(instance, entity));
@@ -195,11 +199,11 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
readProperties(entity, row, propertyAccessor);
}
protected void readProperties(final CassandraPersistentEntity<?> entity, final CassandraValueProvider valueProvider,
final PersistentPropertyAccessor propertyAccessor) {
protected void readProperties(CassandraPersistentEntity<?> entity, CassandraValueProvider valueProvider,
PersistentPropertyAccessor propertyAccessor) {
entity.getPersistentProperties().forEach(
property -> MappingCassandraConverter.this.readProperty(entity, property, valueProvider, propertyAccessor));
entity.getPersistentProperties().forEach(property ->
MappingCassandraConverter.this.readProperty(entity, property, valueProvider, propertyAccessor));
}
protected void readProperty(CassandraPersistentEntity<?> entity, CassandraPersistentProperty property,
@@ -259,30 +263,30 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.convert.CassandraConverter#convertToCassandraColumn(java.util.Optional)
* @see org.springframework.data.cassandra.convert.CassandraConverter#convertToColumnType(java.util.Optional)
*/
@Override
@SuppressWarnings("unchecked")
public <T> Optional<Object> convertToCassandraColumn(Optional<T> obj) {
public <T> Optional<Object> convertToColumnType(Optional<T> obj) {
return convertToCassandraColumn(obj,
obj.map(Object::getClass) //
.map(ClassTypeInformation::from) //
.orElse((ClassTypeInformation) ClassTypeInformation.OBJECT));
return convertToColumnType(obj,
obj.map(Object::getClass)
.map(ClassTypeInformation::from)
.orElse((ClassTypeInformation) ClassTypeInformation.OBJECT));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.convert.CassandraConverter#convertToCassandraColumn(java.util.Optional, org.springframework.data.util.TypeInformation)
* @see org.springframework.data.cassandra.convert.CassandraConverter#convertToColumnType(java.util.Optional, org.springframework.data.util.TypeInformation)
*/
@Override
public <T> Optional<Object> convertToCassandraColumn(Optional<T> obj, TypeInformation<?> typeInformation) {
public <T> Optional<Object> convertToColumnType(Optional<T> obj, TypeInformation<?> typeInformation) {
Assert.notNull(typeInformation, "TypeInformation must not be null!");
Assert.notNull(typeInformation, "TypeInformation must not be null");
return obj.flatMap(t -> {
return obj.flatMap(object -> {
if (t.getClass().isArray()) {
return Optional.of(t);
if (object.getClass().isArray()) {
return Optional.of(object);
}
return getWriteValue(obj, typeInformation);
@@ -654,7 +658,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
* Retrieve the value from {@code value} applying the given {@link TypeInformation} and perform optionally a
* conversion of collection element types.
*
* @param value the value, may be {@literal null}.
* @param optional the value, may be {@literal null}.
* @param typeInformation the type information.
* @return the return value, may be {@literal null}.
*/
@@ -667,26 +671,28 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
I value = optional.get();
if (getCustomConversions().isSimpleType(value.getClass())) {
// Doesn't need conversion
return getPotentiallyConvertedSimpleValue(optional, (Class<O>) typeInformation.getType());
Class<O> requestedTargetType = Optional.ofNullable(typeInformation)
.map(typeInfo -> (Class<O>) typeInfo.getType())
.orElse(null);
if (getCustomConversions().hasCustomWriteTarget(value.getClass(), requestedTargetType)) {
return Optional.ofNullable((O) getConversionService().convert(value,
getCustomConversions().getCustomWriteTarget(value.getClass(), requestedTargetType)
.orElse(requestedTargetType)));
}
if (getCustomConversions().hasCustomWriteTarget(value.getClass())) {
return getCustomConversions().getCustomWriteTarget(value.getClass()).map(it -> {
return getConversionService().convert(value, (Class<O>) it);
});
return Optional.ofNullable((O) getConversionService().convert(value,
getCustomConversions().getCustomWriteTarget(value.getClass()).get()));
}
if (getCustomConversions().isSimpleType(value.getClass())) {
// Doesn't need conversion
return getPotentiallyConvertedSimpleValue(optional,
typeInformation != null ? (Class<O>) typeInformation.getType() : null);
return getPotentiallyConvertedSimpleValue(optional, requestedTargetType);
}
TypeInformation<?> type = (typeInformation != null ? typeInformation : ClassTypeInformation.from(value.getClass()));
TypeInformation<?> type = Optional.ofNullable(typeInformation)
.orElseGet(() -> ClassTypeInformation.from((Class) value.getClass()));
TypeInformation<?> actualType = type.getActualType();
if (value instanceof Collection) {
@@ -694,14 +700,15 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
Collection<Object> original = (Collection<Object>) value;
Collection<Object> converted = CollectionFactory.createCollection(getCollectionType(type), original.size());
original.stream() //
.map(element -> convertToCassandraColumn(Optional.ofNullable(element), actualType).orElse(null))
original.stream()
.map(element -> convertToColumnType(Optional.ofNullable(element), actualType).orElse(null))
.forEach(converted::add);
return Optional.of((O) converted);
}
Optional<CassandraPersistentEntity<?>> optionalUdt = getMappingContext().getPersistentEntity(actualType.getType())
Optional<CassandraPersistentEntity<?>> optionalUdt = getMappingContext()
.getPersistentEntity(actualType.getType())
.filter(CassandraPersistentEntity::isUserDefinedType);
if (optionalUdt.isPresent()) {
@@ -721,8 +728,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
}
/**
* Checks whether we have a custom conversion registered for the given value into an arbitrary simple Cassandra type.
* Returns the converted value if so. If not, we perform special enum handling or simply return the value as is.
* Performs special enum handling or simply returns the value as is.
*
* @param optionalValue may be {@literal null}.
* @param requestedTargetType must not be {@literal null}.
@@ -736,16 +742,8 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
Object value = optionalValue.get();
if (getCustomConversions().hasCustomWriteTarget(value.getClass())) {
return getCustomConversions().getCustomWriteTarget(value.getClass()).map(it -> {
return getConversionService().convert(value, (Class<O>) it);
});
}
// Cassandra has no default enum handling - convert it either to string
// or - if requested - to a different type
// Cassandra has no default enum handling - convert it to either a String
// or, if requested, to a different type
if (Enum.class.isAssignableFrom(value.getClass())) {
if (requestedTargetType != null && !requestedTargetType.isEnum()
&& getConversionService().canConvert(value.getClass(), requestedTargetType)) {
@@ -764,9 +762,9 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
* Checks whether we have a custom conversion for the given simple object. Converts the given value if so, applies
* {@link Enum} handling or returns the value as is.
*
* @param value
* @param value simple value to convert into a value of type {@code target}.
* @param target must not be {@literal null}.
* @return
* @return the converted value.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private Object getPotentiallyConvertedSimpleRead(Object value, Class<?> target) {
@@ -775,15 +773,15 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
return value;
}
if (conversions.hasCustomReadTarget(value.getClass(), target)) {
return conversionService.convert(value, target);
if (getCustomConversions().hasCustomReadTarget(value.getClass(), target)) {
return getConversionService().convert(value, target);
}
if (Enum.class.isAssignableFrom(target)) {
return Enum.valueOf((Class<Enum>) target, value.toString());
}
return conversionService.convert(value, target);
return getConversionService().convert(value, target);
}
private Class<?> getCollectionType(TypeInformation<?> type) {
@@ -825,7 +823,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
return Optional.empty();
}
if (conversions.hasCustomWriteTarget(property.getActualType()) && property.isCollectionLike()) {
if (getCustomConversions().hasCustomWriteTarget(property.getActualType()) && property.isCollectionLike()) {
if (obj.filter(it -> it instanceof Collection).isPresent()) {
@@ -865,7 +863,6 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
*
* @param targetType must not be {@literal null}.
* @param sourceValue must not be {@literal null}.
* @param path must not be {@literal null}.
* @return the converted {@link Collection} or array, will never be {@literal null}.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })

View File

@@ -33,6 +33,7 @@ import org.springframework.data.cassandra.core.query.Criteria;
import org.springframework.data.cassandra.core.query.CriteriaDefinition;
import org.springframework.data.cassandra.core.query.CriteriaDefinition.Predicate;
import org.springframework.data.cassandra.core.query.Filter;
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
import org.springframework.data.domain.Sort;
@@ -51,13 +52,26 @@ import org.springframework.util.Assert;
* Map {@link org.springframework.data.cassandra.core.query.Query} to CQL-specific data types.
*
* @author Mark Paluch
* @see org.springframework.data.cassandra.core.query.ColumnName
* @see org.springframework.data.cassandra.core.query.Columns
* @see org.springframework.data.cassandra.core.query.Criteria
* @see org.springframework.data.cassandra.core.query.Filter
* @see org.springframework.data.cassandra.mapping.CassandraMappingContext
* @see org.springframework.data.cassandra.mapping.CassandraPersistentEntity
* @see org.springframework.data.cassandra.mapping.CassandraPersistentProperty
* @see org.springframework.data.domain.Sort
* @see org.springframework.data.mapping.PersistentProperty
* @see org.springframework.data.mapping.PropertyPath
* @see org.springframework.data.mapping.context.MappingContext
* @see org.springframework.data.mapping.context.PersistentPropertyPath
* @see org.springframework.data.util.TypeInformation
* @since 2.0
*/
public class QueryMapper {
private final CassandraConverter converter;
private final MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext;
private final CassandraMappingContext mappingContext;
/**
* Creates a new {@link QueryMapper} with the given {@link CassandraConverter}.
@@ -73,35 +87,25 @@ public class QueryMapper {
}
/**
* Map a {@link Filter} with a {@link CassandraPersistentEntity type hint}. Filter mapping translates property names
* to column names and maps {@link Predicate} values to simple Cassandra values.
* Returns the configured {@link CassandraConverter} used to convert object values into
* Cassandra column typed values.
*
* @param filter must not be {@literal null}.
* @param entity must not be {@literal null}.
* @return the mapped {@link Filter}.
* @return the configured {@link CassandraConverter}.
* @see org.springframework.data.cassandra.convert.CassandraConverter
*/
public Filter getMappedObject(Filter filter, CassandraPersistentEntity<?> entity) {
protected CassandraConverter getConverter() {
return this.converter;
}
Assert.notNull(filter, "Filter must not be null");
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
List<CriteriaDefinition> result = new ArrayList<>();
for (CriteriaDefinition criteriaDefinition : filter) {
Field field = createPropertyField(entity, criteriaDefinition.getColumnName());
Predicate predicate = criteriaDefinition.getPredicate();
Optional<Object> value = Optional.ofNullable(predicate.getValue());
TypeInformation<?> typeInformation = getTypeInformation(field, value);
Optional<Object> mappedValue = converter.convertToCassandraColumn(value, typeInformation);
Predicate mappedPredicate = new Predicate(predicate.getOperator(), mappedValue.orElse(null));
result.add(Criteria.of(field.getMappedKey(), mappedPredicate));
}
return Filter.from(result);
/**
* Returns the configured {@link CassandraMappingContext} containing mapping meta-data (persistent entities
* and properties) used to store (map) objects to Cassandra tables (rows/columns).
*
* @return the configured {@link CassandraMappingContext}.
* @see org.springframework.data.cassandra.mapping.CassandraMappingContext
*/
protected CassandraMappingContext getMappingContext() {
return this.mappingContext;
}
/**
@@ -113,8 +117,41 @@ public class QueryMapper {
public List<Selector> getColumns(CassandraPersistentEntity<?> entity) {
return entity.getPersistentProperties() //
.flatMap(p -> p.getColumnNames().stream()).map(ColumnSelector::from) //
.collect(Collectors.toList());
.flatMap(p -> p.getColumnNames().stream()).map(ColumnSelector::from) //
.collect(Collectors.toList());
}
/**
* Map a {@link Filter} with a {@link CassandraPersistentEntity type hint}. Filter mapping translates property names
* to column names and maps {@link Predicate} values to simple Cassandra values.
*
* @param filter must not be {@literal null}.
* @param entity must not be {@literal null}.
* @return the mapped {@link Filter}.
*/
public Filter getMappedObject(Filter filter, CassandraPersistentEntity<?> entity) {
Assert.notNull(filter, "Filter must not be null");
Assert.notNull(entity, "Entity must not be null");
List<CriteriaDefinition> result = new ArrayList<>();
for (CriteriaDefinition criteriaDefinition : filter) {
Field field = createPropertyField(entity, criteriaDefinition.getColumnName());
Predicate predicate = criteriaDefinition.getPredicate();
Optional<Object> value = Optional.ofNullable(predicate.getValue());
TypeInformation<?> typeInformation = getTypeInformation(field, value);
Optional<Object> mappedValue = getConverter().convertToColumnType(value, typeInformation);
Predicate mappedPredicate = new Predicate(predicate.getOperator(), mappedValue.orElse(null));
result.add(Criteria.of(field.getMappedKey(), mappedPredicate));
}
return Filter.from(result);
}
/**
@@ -171,8 +208,8 @@ public class QueryMapper {
ColumnSelector mappedColumnSelector = ColumnSelector.from(cqlIdentifier);
return columnSelector.getAlias() //
.map(mappedColumnSelector::as) //
return columnSelector.getAlias()
.map(mappedColumnSelector::as)
.orElse(mappedColumnSelector);
}
@@ -180,23 +217,23 @@ public class QueryMapper {
FunctionCall functionCall = (FunctionCall) selector;
List<Object> mappedParameters = functionCall.getParameters() //
.stream() //
.map(o -> {
if (o instanceof Selector) {
return getMappedSelector((Selector) o, cqlIdentifier);
List<Object> mappedParameters = functionCall.getParameters()
.stream()
.map(obj -> {
if (obj instanceof Selector) {
return getMappedSelector((Selector) obj, cqlIdentifier);
}
return o;
return obj;
}) //
.collect(Collectors.toList());
FunctionCall mappedCall = FunctionCall.from(functionCall.getExpression(), mappedParameters.toArray());
FunctionCall mappedFunctionCall =
FunctionCall.from(functionCall.getExpression(), mappedParameters.toArray());
return functionCall.getAlias() //
.map(mappedCall::as) //
.orElse(mappedCall);
.map(mappedFunctionCall::as) //
.orElse(mappedFunctionCall);
}
throw new IllegalArgumentException(String.format("Selector [%s] not supported", selector));
@@ -232,11 +269,8 @@ public class QueryMapper {
columns.getSelector(column) //
.filter(selector -> selector instanceof ColumnSelector) //
.ifPresent(columnExpression -> {
getCqlIdentifier(column, field) //
.map(CqlIdentifier::toCql) //
.ifPresent(columnNames::add);
.ifPresent(columnSelector -> {
getCqlIdentifier(column, field).map(CqlIdentifier::toCql).ifPresent(columnNames::add);
});
}
@@ -271,20 +305,21 @@ public class QueryMapper {
for (Order order : sort) {
ColumnName columnName = ColumnName.from(order.getProperty());
Field field = createPropertyField(entity, columnName);
Order mappedOrder = getCqlIdentifier(columnName, field)
.map(cqlIdentifier -> new Order(order.getDirection(), cqlIdentifier.toCql())).orElse(order);
mappedOrders.add(mappedOrder);
}
return new Sort(mappedOrders);
return Sort.by(mappedOrders);
}
private Optional<CqlIdentifier> getCqlIdentifier(ColumnName column, Field field) {
try {
if (field.getProperty().isPresent()) {
return field.getProperty().map(CassandraPersistentProperty::getColumnName);
}
@@ -306,19 +341,19 @@ public class QueryMapper {
* @return
*/
protected Field createPropertyField(CassandraPersistentEntity<?> entity, ColumnName key) {
return entity == null ? new Field(key) : new MetadataBackedField(key, entity, mappingContext);
return Optional.ofNullable(entity).<Field>map(e -> new MetadataBackedField(key, e, getMappingContext()))
.orElseGet(() -> new Field(key));
}
@SuppressWarnings("unchecked")
TypeInformation<?> getTypeInformation(Field field, Optional<? extends Object> value) {
return field.getProperty().map(CassandraPersistentProperty::getTypeInformation).orElseGet(() -> {
return value.map(Object::getClass) //
.map(ClassTypeInformation::from) //
.orElse((ClassTypeInformation) ClassTypeInformation.OBJECT);
});
return field.getProperty().map(CassandraPersistentProperty::getTypeInformation)
.orElseGet(() ->
value.map(Object::getClass)
.map(ClassTypeInformation::from)
.orElse((ClassTypeInformation) ClassTypeInformation.OBJECT)
);
}
/**
@@ -336,7 +371,6 @@ public class QueryMapper {
* @param name must not be {@literal null} or empty.
*/
public Field(ColumnName name) {
Assert.notNull(name, "Name must not be null!");
this.name = name;
}
@@ -345,7 +379,7 @@ public class QueryMapper {
* Returns a new {@link Field} with the given name.
*
* @param name must not be {@literal null} or empty.
* @return
* @return a new {@link Field} with the given name.
*/
public Field with(ColumnName name) {
return new Field(name);
@@ -386,16 +420,17 @@ public class QueryMapper {
private final Optional<CassandraPersistentProperty> optionalProperty;
/**
* Creates a new {@link MetadataBackedField} with the given name, {@link MongoPersistentEntity} and
* {@link MappingContext}.
* Creates a new {@link MetadataBackedField} with the given name, {@link CassandraPersistentEntity}
* and {@link MappingContext}.
*
* @param name must not be {@literal null} or empty.
* @param entity must not be {@literal null}.
* @param context must not be {@literal null}.
* @param mappingContext must not be {@literal null}.
*/
public MetadataBackedField(ColumnName name, CassandraPersistentEntity<?> entity,
MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> context) {
this(name, entity, context, null);
MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext) {
this(name, entity, mappingContext, null);
}
/**
@@ -404,19 +439,19 @@ public class QueryMapper {
*
* @param name must not be {@literal null} or empty.
* @param entity must not be {@literal null}.
* @param context must not be {@literal null}.
* @param mappingContext must not be {@literal null}.
* @param property may be {@literal null}.
*/
public MetadataBackedField(ColumnName name, CassandraPersistentEntity<?> entity,
MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> context,
MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext,
CassandraPersistentProperty property) {
super(name);
Assert.notNull(entity, "MongoPersistentEntity must not be null!");
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
this.entity = entity;
this.mappingContext = context;
this.mappingContext = mappingContext;
this.path = getPath(name.toCql());
this.property = path.map(PersistentPropertyPath::getLeafProperty).orElse(property);
this.optionalProperty = Optional.ofNullable(this.property);
@@ -431,11 +466,13 @@ public class QueryMapper {
private Optional<PersistentPropertyPath<CassandraPersistentProperty>> getPath(String pathExpression) {
try {
PropertyPath path = PropertyPath.from(pathExpression.replaceAll("\\.\\d", ""), entity.getTypeInformation());
PersistentPropertyPath<CassandraPersistentProperty> propertyPath = mappingContext
.getPersistentPropertyPath(path);
PropertyPath propertyPath = PropertyPath.from(pathExpression.replaceAll("\\.\\d", ""),
entity.getTypeInformation());
return Optional.of(propertyPath);
PersistentPropertyPath<CassandraPersistentProperty> persistentPropertyPath =
mappingContext.getPersistentPropertyPath(propertyPath);
return Optional.of(persistentPropertyPath);
} catch (PropertyReferenceException e) {
return Optional.empty();
}

View File

@@ -35,7 +35,6 @@ import org.springframework.data.cassandra.core.query.Update.RemoveOp;
import org.springframework.data.cassandra.core.query.Update.SetAtIndexOp;
import org.springframework.data.cassandra.core.query.Update.SetAtKeyOp;
import org.springframework.data.cassandra.core.query.Update.SetOp;
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.util.TypeInformation;
@@ -48,24 +47,22 @@ import com.datastax.driver.core.DataType.Name;
* Map {@link org.springframework.data.cassandra.core.query.Update} to CQL-specific data types.
*
* @author Mark Paluch
* @see org.springframework.data.cassandra.core.query.Filter
* @see org.springframework.data.cassandra.core.query.Update
* @see org.springframework.data.cassandra.mapping.CassandraPersistentEntity
* @see org.springframework.data.mapping.PersistentProperty
* @see org.springframework.data.util.TypeInformation
* @since 2.0
*/
public class UpdateMapper extends QueryMapper {
private final CassandraConverter converter;
private final CassandraMappingContext mappingContext;
/**
* Creates a new {@link UpdateMapper} with the given {@link CassandraConverter}.
*
* @param converter must not be {@literal null}.
*/
public UpdateMapper(CassandraConverter converter) {
super(converter);
this.converter = converter;
this.mappingContext = converter.getMappingContext();
}
/**
@@ -116,30 +113,33 @@ public class UpdateMapper extends QueryMapper {
return getMappedUpdateOperation(field, (AddToMapOp) assignmentOp);
}
throw new IllegalArgumentException(String.format("UpdateOp %s not supported", assignmentOp));
throw new IllegalArgumentException(String.format("UpdateOp [%s] not supported", assignmentOp));
}
private AssignmentOp getMappedUpdateOperation(Field field, SetOp updateOp) {
Optional<Object> value = Optional.ofNullable(updateOp.getValue());
Object rawValue = updateOp.getValue();
Optional<Object> value = Optional.ofNullable(rawValue);
if (updateOp instanceof SetAtKeyOp) {
SetAtKeyOp op = (SetAtKeyOp) updateOp;
Optional<? extends TypeInformation<?>> typeInformation = field.getProperty()
.map(PersistentProperty::getTypeInformation);
Optional<? extends TypeInformation<?>> typeInformation =
field.getProperty().map(PersistentProperty::getTypeInformation);
Optional<TypeInformation<?>> keyType = typeInformation.map(TypeInformation::getActualType);
Optional<TypeInformation<?>> valueType = typeInformation.flatMap(TypeInformation::getMapValueType);
Optional<Object> k = Optional.ofNullable(op.getKey());
Optional<Object> v = Optional.ofNullable(op.getValue());
Optional<Object> key = Optional.ofNullable(op.getKey());
Optional<Object> val = Optional.ofNullable(op.getValue());
Optional<Object> mappedKey = keyType.map(it -> converter.convertToCassandraColumn(k, it))
.orElseGet(() -> converter.convertToCassandraColumn(k));
Optional<Object> mappedKey = keyType.map(typeInfo -> getConverter().convertToColumnType(key, typeInfo))
.orElseGet(() -> getConverter().convertToColumnType(key));
Optional<Object> mappedValue = valueType.map(it -> converter.convertToCassandraColumn(v, it))
.orElseGet(() -> converter.convertToCassandraColumn(v));
Optional<Object> mappedValue = valueType.map(typeInfo -> getConverter().convertToColumnType(val, typeInfo))
.orElseGet(() -> getConverter().convertToColumnType(val));
return new SetAtKeyOp(field.getMappedKey(), mappedKey.orElse(null), mappedValue.orElse(null));
}
@@ -150,20 +150,21 @@ public class UpdateMapper extends QueryMapper {
SetAtIndexOp op = (SetAtIndexOp) updateOp;
Optional<Object> mappedValue = converter.convertToCassandraColumn(Optional.ofNullable(op.getValue()),
typeInformation);
Optional<Object> mappedValue = getConverter().convertToColumnType(
Optional.ofNullable(op.getValue()), typeInformation);
return new SetAtIndexOp(field.getMappedKey(), op.getIndex(), mappedValue.orElse(null));
}
if (updateOp.getValue() instanceof Collection && typeInformation.isCollectionLike()) {
if (rawValue instanceof Collection && typeInformation.isCollectionLike()) {
Collection<?> collection = (Collection) updateOp.getValue();
Collection<?> collection = (Collection) rawValue;
if (collection.isEmpty()) {
DataType.Name dataType = field.getProperty() //
.map(mappingContext::getDataType) //
.map(DataType::getName) //
DataType.Name dataType = field.getProperty()
.map(property -> getMappingContext().getDataType(property))
.map(DataType::getName)
.orElse(Name.LIST);
if (dataType == Name.SET) {
@@ -174,7 +175,8 @@ public class UpdateMapper extends QueryMapper {
}
}
Optional<Object> mappedValue = converter.convertToCassandraColumn(value, typeInformation);
Optional<Object> mappedValue = getConverter().convertToColumnType(value, typeInformation);
return new SetOp(field.getMappedKey(), mappedValue.orElse(null));
}
@@ -182,8 +184,8 @@ public class UpdateMapper extends QueryMapper {
Optional<Object> value = Optional.ofNullable(updateOp.getValue());
TypeInformation<?> typeInformation = getTypeInformation(field, value);
Optional<Object> mappedValue = getConverter().convertToColumnType(value, typeInformation);
Optional<Object> mappedValue = converter.convertToCassandraColumn(value, typeInformation);
return new RemoveOp(field.getMappedKey(), mappedValue.orElse(null));
}
@@ -192,22 +194,20 @@ public class UpdateMapper extends QueryMapper {
Optional<Iterable<Object>> value = Optional.ofNullable(updateOp.getValue());
TypeInformation<?> typeInformation = getTypeInformation(field, value);
Collection<Object> mappedValue = (Collection) converter.convertToCassandraColumn(value, typeInformation)
Collection<Object> mappedValue = (Collection) getConverter().convertToColumnType(value, typeInformation)
.orElse(null);
if (field.getProperty().isPresent()) {
DataType dataType = mappingContext.getDataType(field.getProperty().get());
if (dataType.getName() == Name.SET && !(mappedValue instanceof Set)) {
DataType dataType = getMappingContext().getDataType(field.getProperty().get());
if (dataType.getName() == Name.SET && !(mappedValue instanceof Set)) {
Collection<Object> collection = new HashSet<>();
collection.addAll(mappedValue);
mappedValue = collection;
}
if (dataType.getName() == Name.LIST && !(mappedValue instanceof List)) {
Collection<Object> collection = new ArrayList<>();
collection.addAll(mappedValue);
mappedValue = collection;
@@ -219,8 +219,9 @@ public class UpdateMapper extends QueryMapper {
private AssignmentOp getMappedUpdateOperation(Field field, AddToMapOp updateOp) {
Optional<? extends TypeInformation<?>> typeInformation = field.getProperty()
.map(PersistentProperty::getTypeInformation);
Optional<? extends TypeInformation<?>> typeInformation =
field.getProperty().map(PersistentProperty::getTypeInformation);
Optional<TypeInformation<?>> keyType = typeInformation.map(TypeInformation::getActualType);
Optional<TypeInformation<?>> valueType = typeInformation.flatMap(TypeInformation::getMapValueType);
@@ -231,11 +232,11 @@ public class UpdateMapper extends QueryMapper {
Optional<Object> key = Optional.ofNullable(k);
Optional<Object> value = Optional.ofNullable(v);
Optional<Object> mappedKey = keyType.map(it -> converter.convertToCassandraColumn(key, it))
.orElseGet(() -> converter.convertToCassandraColumn(key));
Optional<Object> mappedKey = keyType.map(typeInfo -> getConverter().convertToColumnType(key, typeInfo))
.orElseGet(() -> getConverter().convertToColumnType(key));
Optional<Object> mappedValue = valueType.map(it -> converter.convertToCassandraColumn(value, it))
.orElseGet(() -> converter.convertToCassandraColumn(value));
Optional<Object> mappedValue = valueType.map(typeInfo -> getConverter().convertToColumnType(value, typeInfo))
.orElseGet(() -> getConverter().convertToColumnType(value));
result.put(mappedKey.orElse(null), mappedValue.orElse(null));
});

View File

@@ -69,6 +69,14 @@ import com.datastax.driver.core.querybuilder.Update;
*
* @author Mark Paluch
* @author John Blum
* @see org.springframework.cassandra.core.AsyncCqlOperations
* @see org.springframework.data.cassandra.core.AsyncCassandraOperations
* @see com.datastax.driver.core.querybuilder.Delete
* @see com.datastax.driver.core.querybuilder.Insert
* @see com.datastax.driver.core.querybuilder.QueryBuilder
* @see com.datastax.driver.core.querybuilder.Select
* @see com.datastax.driver.core.querybuilder.Truncate
* @see com.datastax.driver.core.querybuilder.Update
* @since 2.0
*/
public class AsyncCassandraTemplate implements AsyncCassandraOperations {
@@ -321,8 +329,8 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
Assert.notNull(query, "Query must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
return selectOne(getStatementFactory().select(query, getMappingContext().getRequiredPersistentEntity(entityClass)),
entityClass);
return selectOne(getStatementFactory().select(query,
getMappingContext().getRequiredPersistentEntity(entityClass)), entityClass);
}
/* (non-Javadoc)
@@ -511,8 +519,8 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
Assert.notNull(entityClass, "Entity type must not be null");
Truncate truncate = QueryBuilder.truncate(
getMappingContext().getRequiredPersistentEntity(entityClass).getTableName().toCql());
Truncate truncate =
QueryBuilder.truncate(getMappingContext().getRequiredPersistentEntity(entityClass).getTableName().toCql());
return new MappingListenableFutureAdapter<>(getAsyncCqlOperations().execute(truncate), aBoolean -> null);
}

View File

@@ -142,6 +142,15 @@ public class CassandraTemplate implements CassandraOperations {
this.statementFactory = new StatementFactory(new QueryMapper(converter), new UpdateMapper(converter));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#getConverter()
*/
@Override
public CassandraConverter getConverter() {
return this.converter;
}
/* (non-Javadoc) */
private static MappingCassandraConverter newConverter() {
MappingCassandraConverter converter = new MappingCassandraConverter();
@@ -151,6 +160,36 @@ public class CassandraTemplate implements CassandraOperations {
return converter;
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#CqlOperations()
*/
@Override
public CqlOperations getCqlOperations() {
return this.cqlOperations;
}
/**
* Returns the {@link CassandraMappingContext} used by this template to access mapping meta-data used to
* store (map) object to Cassandra tables.
*
* @return the {@link CassandraMappingContext} used by this template.
* @see org.springframework.data.cassandra.mapping.CassandraMappingContext
*/
protected CassandraMappingContext getMappingContext() {
return this.mappingContext;
}
/**
* Returns the {@link StatementFactory} used by this template to construct and run Cassandra CQL statements.
*
* @return the {@link StatementFactory} used by this template to construct and run Cassandra CQL statements.
* @see org.springframework.data.cassandra.core.StatementFactory
*/
protected StatementFactory getStatementFactory() {
return this.statementFactory;
}
// -------------------------------------------------------------------------
// Methods dealing with static CQL
// -------------------------------------------------------------------------
@@ -206,7 +245,7 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(statement, "Statement must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
return cqlOperations.query(statement, (row, rowNum) -> converter.read(entityClass, row));
return getCqlOperations().query(statement, (row, rowNum) -> getConverter().read(entityClass, row));
}
/* (non-Javadoc)
@@ -218,8 +257,8 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(statement, "Statement must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
return StreamSupport.stream(cqlOperations.queryForResultSet(statement).spliterator(), false)
.map(row -> converter.read(entityClass, row));
return StreamSupport.stream(getCqlOperations().queryForResultSet(statement).spliterator(), false)
.map(row -> getConverter().read(entityClass, row));
}
/*
@@ -228,10 +267,7 @@ public class CassandraTemplate implements CassandraOperations {
*/
@Override
public <T> T selectOne(Statement statement, Class<T> entityClass) {
List<T> result = select(statement, entityClass);
return result.stream().findFirst().orElse(null);
return select(statement, entityClass).stream().findFirst().orElse(null);
}
// -------------------------------------------------------------------------
@@ -247,7 +283,8 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(query, "Query must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
return select(statementFactory.select(query, mappingContext.getRequiredPersistentEntity(entityClass)), entityClass);
return select(getStatementFactory().select(query,
getMappingContext().getRequiredPersistentEntity(entityClass)), entityClass);
}
/* (non-Javadoc)
@@ -259,7 +296,8 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(query, "Query must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
return stream(statementFactory.select(query, mappingContext.getRequiredPersistentEntity(entityClass)), entityClass);
return stream(getStatementFactory().select(query,
getMappingContext().getRequiredPersistentEntity(entityClass)), entityClass);
}
/* (non-Javadoc)
@@ -284,8 +322,8 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(update, "Update must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
return cqlOperations
.execute(statementFactory.update(query, update, mappingContext.getRequiredPersistentEntity(entityClass)));
return getCqlOperations().execute(getStatementFactory().update(query, update,
getMappingContext().getRequiredPersistentEntity(entityClass)));
}
/* (non-Javadoc)
@@ -297,8 +335,8 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(query, "Query must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
return cqlOperations
.execute(statementFactory.delete(query, mappingContext.getRequiredPersistentEntity(entityClass)));
return getCqlOperations().execute(getStatementFactory().delete(query,
getMappingContext().getRequiredPersistentEntity(entityClass)));
}
// -------------------------------------------------------------------------
@@ -315,9 +353,9 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(entityClass, "Entity type must not be null");
Select select = QueryBuilder.select().countAll()
.from(mappingContext.getRequiredPersistentEntity(entityClass).getTableName().toCql());
.from(getMappingContext().getRequiredPersistentEntity(entityClass).getTableName().toCql());
return cqlOperations.queryForObject(select, Long.class);
return getCqlOperations().queryForObject(select, Long.class);
}
/*
@@ -330,13 +368,13 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(id, "Id must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
CassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(entityClass);
CassandraPersistentEntity<?> entity = getMappingContext().getRequiredPersistentEntity(entityClass);
Select select = QueryBuilder.select().from(entity.getTableName().toCql());
converter.write(id, select.where(), entity);
getConverter().write(id, select.where(), entity);
return cqlOperations.queryForResultSet(select).iterator().hasNext();
return getCqlOperations().queryForResultSet(select).iterator().hasNext();
}
/*
@@ -349,11 +387,11 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(id, "Id must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
CassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(entityClass);
CassandraPersistentEntity<?> entity = getMappingContext().getRequiredPersistentEntity(entityClass);
Select select = QueryBuilder.select().all().from(entity.getTableName().toCql());
converter.write(id, select.where(), entity);
getConverter().write(id, select.where(), entity);
return selectOne(select, entityClass);
}
@@ -364,15 +402,17 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(ids, "Ids must not be null");
Assert.notNull(entityClass, "EntityClass must not be null");
CassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(entityClass);
CassandraPersistentEntity<?> entity = getMappingContext().getRequiredPersistentEntity(entityClass);
CassandraPersistentProperty idProperty = entity.getIdProperty().orElseThrow(() -> new IllegalArgumentException(
String.format("Entity class [%s] has no primary key", entityClass.getName())));
CassandraPersistentProperty idProperty = entity.getIdProperty().orElseThrow(() ->
new IllegalArgumentException(String.format("Entity class [%s] has no primary key",
entityClass.getName())));
if (idProperty.isCompositePrimaryKey()) {
String typeName = idProperty.getCompositePrimaryKeyEntity().getType().getName();
throw new IllegalArgumentException(
String.format("Entity class [%s] uses a composite primary key class [%s] which this method can't support",
throw new IllegalArgumentException(String.format(
"Entity class [%s] uses a composite primary key class [%s] which this method can't support",
entityClass.getName(), typeName));
}
@@ -403,7 +443,7 @@ public class CassandraTemplate implements CassandraOperations {
Insert insert = QueryUtils.createInsertQuery(getTableName(entity.getClass()).toCql(), entity, options, converter);
return cqlOperations.execute(new StatementCallback<>(insert, entity));
return getCqlOperations().execute(new StatementCallback<>(insert, entity));
}
/*
@@ -426,7 +466,7 @@ public class CassandraTemplate implements CassandraOperations {
Update update = QueryUtils.createUpdateQuery(getTableName(entity.getClass()).toCql(), entity, options, converter);
return cqlOperations.execute(new StatementCallback<>(update, entity));
return getCqlOperations().execute(new StatementCallback<>(update, entity));
}
/*
@@ -449,7 +489,7 @@ public class CassandraTemplate implements CassandraOperations {
Delete delete = QueryUtils.createDeleteQuery(getTableName(entity.getClass()).toCql(), entity, options, converter);
return cqlOperations.execute(new StatementCallback<>(delete, entity));
return getCqlOperations().execute(new StatementCallback<>(delete, entity));
}
/*
@@ -462,13 +502,13 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(id, "Id must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
CassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(entityClass);
CassandraPersistentEntity<?> entity = getMappingContext().getRequiredPersistentEntity(entityClass);
Delete delete = QueryBuilder.delete().from(entity.getTableName().toCql());
converter.write(id, delete.where(), entity);
getConverter().write(id, delete.where(), entity);
return cqlOperations.execute(delete);
return getCqlOperations().execute(delete);
}
/*
@@ -480,10 +520,10 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(entityClass, "Entity type must not be null");
Truncate truncate = QueryBuilder
.truncate(mappingContext.getRequiredPersistentEntity(entityClass).getTableName().toCql());
Truncate truncate =
QueryBuilder.truncate(getMappingContext().getRequiredPersistentEntity(entityClass).getTableName().toCql());
cqlOperations.execute(truncate);
getCqlOperations().execute(truncate);
}
// -------------------------------------------------------------------------
@@ -491,30 +531,13 @@ public class CassandraTemplate implements CassandraOperations {
// -------------------------------------------------------------------------
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#getConverter()
*/
@Override
public CassandraConverter getConverter() {
return converter;
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#CqlOperations()
*/
@Override
public CqlOperations getCqlOperations() {
return cqlOperations;
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperationsNG#getTableName(java.lang.Class)
*/
@Override
public CqlIdentifier getTableName(Class<?> entityClass) {
return mappingContext.getRequiredPersistentEntity(ClassUtils.getUserClass(entityClass)).getTableName();
return getMappingContext().getRequiredPersistentEntity(ClassUtils.getUserClass(entityClass)).getTableName();
}
/*

View File

@@ -66,6 +66,18 @@ import com.datastax.driver.core.querybuilder.Update;
* first case given to the service directly, in the second case to the prepared template.
*
* @author Mark Paluch
* @author John Blum
* @see org.springframework.cassandra.core.ReactiveCqlOperations
* @see org.springframework.data.cassandra.convert.CassandraConverter
* @see org.springframework.data.cassandra.convert.QueryMapper
* @see org.springframework.data.cassandra.convert.UpdateMapper
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations
* @see com.datastax.driver.core.querybuilder.Delete
* @see com.datastax.driver.core.querybuilder.Insert
* @see com.datastax.driver.core.querybuilder.QueryBuilder
* @see com.datastax.driver.core.querybuilder.Select
* @see com.datastax.driver.core.querybuilder.Truncate
* @see com.datastax.driver.core.querybuilder.Update
* @since 2.0
*/
public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
@@ -147,8 +159,9 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
this.statementFactory = new StatementFactory(new QueryMapper(converter), new UpdateMapper(converter));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#getConverter()
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#getConverter()
*/
@Override
public CassandraConverter getConverter() {
@@ -165,15 +178,6 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
return converter;
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#getReactiveCqlOperations()
*/
@Override
public ReactiveCqlOperations getReactiveCqlOperations() {
return cqlOperations;
}
/**
* Returns the {@link CassandraMappingContext} used by this template to access mapping meta-data used to
* store (map) objects to Cassandra tables.
@@ -185,6 +189,15 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
return this.mappingContext;
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#getReactiveCqlOperations()
*/
@Override
public ReactiveCqlOperations getReactiveCqlOperations() {
return this.cqlOperations;
}
/**
* Returns the {@link StatementFactory} used by this template to construct and run Cassandra CQL statements.
*
@@ -265,7 +278,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
Assert.notNull(entityClass, "Entity type must not be null");
return select(getStatementFactory().select(query,
getMappingContext().getRequiredPersistentEntity(entityClass)), entityClass);
getMappingContext().getRequiredPersistentEntity(entityClass)), entityClass);
}
/* (non-Javadoc)

View File

@@ -17,6 +17,7 @@ package org.springframework.data.cassandra.core;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.springframework.cassandra.core.QueryOptionsUtil;
@@ -62,6 +63,15 @@ import com.google.common.primitives.Ints;
* Statement factory to render {@link Statement} from {@link Query} and {@link Update} objects.
*
* @author Mark Paluch
* @author John Blum
* @see org.springframework.data.cassandra.core.query.Query
* @see org.springframework.data.cassandra.core.query.Update
* @see com.datastax.driver.core.querybuilder.Assignment
* @see com.datastax.driver.core.querybuilder.Clause
* @see com.datastax.driver.core.querybuilder.Delete
* @see com.datastax.driver.core.querybuilder.Ordering
* @see com.datastax.driver.core.querybuilder.QueryBuilder
* @see com.datastax.driver.core.querybuilder.Select
* @since 2.0
*/
public class StatementFactory {
@@ -94,6 +104,26 @@ public class StatementFactory {
this.updateMapper = updateMapper;
}
/**
* Returns the {@link QueryMapper} used to map {@link Query} to CQL-specific data types.
*
* @return the {@link QueryMapper} used to map {@link Query} to CQL-specific data types.
* @see org.springframework.data.cassandra.convert.QueryMapper
*/
protected QueryMapper getQueryMapper() {
return this.queryMapper;
}
/**
* Returns the {@link UpdateMapper} used to map {@link Update} to CQL-specific data types.
*
* @return the {@link UpdateMapper} used to map {@link Update} to CQL-specific data types.
* @see org.springframework.data.cassandra.convert.UpdateMapper
*/
protected UpdateMapper getUpdateMapper() {
return this.updateMapper;
}
/**
* Create a {@literal SELECT} statement by mapping {@link Query} to {@link Select}.
*
@@ -104,12 +134,15 @@ public class StatementFactory {
public RegularStatement select(Query query, CassandraPersistentEntity<?> entity) {
Assert.notNull(query, "Query must not be null");
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
Assert.notNull(entity, "Entity must not be null");
List<Selector> selectors = queryMapper.getMappedSelectors(query.getColumns(), entity);
Filter filter = getQueryMapper().getMappedObject(query, entity);
Filter filter = queryMapper.getMappedObject(query, entity);
Sort sort = query.getSort() != null ? queryMapper.getMappedSort(query.getSort(), entity) : null;
List<Selector> selectors = getQueryMapper().getMappedSelectors(query.getColumns(), entity);
Sort sort = Optional.ofNullable(query.getSort())
.map(querySort -> getQueryMapper().getMappedSort(querySort, entity))
.orElse(null);
Select select = select(selectors, entity.getTableName(), filter, sort);
@@ -135,7 +168,6 @@ public class StatementFactory {
if (selectors.isEmpty()) {
select = QueryBuilder.select().all().from(from.toCql());
} else {
Selection selection = QueryBuilder.select();
selectors.forEach(selector -> {
selector.getAlias().map(CqlIdentifier::toCql).ifPresent(getSelection(selection, selector)::as);
@@ -148,10 +180,9 @@ public class StatementFactory {
}
if (sort != null) {
List<Ordering> orderings = new ArrayList<>();
for (Order order : sort) {
for (Order order : sort) {
if (order.isAscending()) {
orderings.add(QueryBuilder.asc(order.getProperty()));
} else {
@@ -171,13 +202,13 @@ public class StatementFactory {
if (selector instanceof FunctionCall) {
Object[] objects = ((FunctionCall) selector).getParameters().stream().map(o -> {
Object[] objects = ((FunctionCall) selector).getParameters().stream().map(param -> {
if (o instanceof ColumnSelector) {
return QueryBuilder.column(((ColumnSelector) o).getExpression());
if (param instanceof ColumnSelector) {
return QueryBuilder.column(((ColumnSelector) param).getExpression());
}
return o;
return param;
}).toArray();
@@ -197,15 +228,15 @@ public class StatementFactory {
public RegularStatement update(Query query, Update updateObj, CassandraPersistentEntity<?> entity) {
Assert.notNull(query, "Query must not be null");
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
Assert.notNull(entity, "Entity must not be null");
Update mappedUpdate = updateMapper.getMappedObject(updateObj, entity);
Filter filter = queryMapper.getMappedObject(query, entity);
Filter filter = getQueryMapper().getMappedObject(query, entity);
Update mappedUpdate = getUpdateMapper().getMappedObject(updateObj, entity);
com.datastax.driver.core.querybuilder.Update update = update(entity.getTableName(), mappedUpdate, filter);
query.getQueryOptions().ifPresent(queryOptions -> {
if (queryOptions instanceof WriteOptions) {
QueryOptionsUtil.addWriteOptions(update, (WriteOptions) queryOptions);
} else {
@@ -261,24 +292,19 @@ public class StatementFactory {
private static Assignment getAssignment(IncrOp incrOp) {
if (incrOp.getValue().intValue() > 0) {
return QueryBuilder.incr(incrOp.getColumnName().toCql(), Math.abs(incrOp.getValue().intValue()));
}
return QueryBuilder.decr(incrOp.getColumnName().toCql(), Math.abs(incrOp.getValue().intValue()));
return incrOp.getValue().intValue() > 0
? QueryBuilder.incr(incrOp.getColumnName().toCql(), Math.abs(incrOp.getValue().intValue()))
: QueryBuilder.decr(incrOp.getColumnName().toCql(), Math.abs(incrOp.getValue().intValue()));
}
private static Assignment getAssignment(SetOp updateOp) {
if (updateOp instanceof SetAtIndexOp) {
SetAtIndexOp op = (SetAtIndexOp) updateOp;
return QueryBuilder.setIdx(op.getColumnName().toCql(), op.getIndex(), op.getValue());
}
if (updateOp instanceof SetAtKeyOp) {
SetAtKeyOp op = (SetAtKeyOp) updateOp;
return QueryBuilder.put(op.getColumnName().toCql(), op.getKey(), op.getValue());
}
@@ -306,11 +332,9 @@ public class StatementFactory {
return QueryBuilder.addAll(updateOp.getColumnName().toCql(), (Set) updateOp.getValue());
}
if (updateOp.getMode() == Mode.PREPEND) {
return QueryBuilder.prependAll(updateOp.getColumnName().toCql(), (List) updateOp.getValue());
}
return QueryBuilder.appendAll(updateOp.getColumnName().toCql(), (List) updateOp.getValue());
return Mode.PREPEND.equals(updateOp.getMode())
? QueryBuilder.prependAll(updateOp.getColumnName().toCql(), (List) updateOp.getValue())
: QueryBuilder.appendAll(updateOp.getColumnName().toCql(), (List) updateOp.getValue());
}
private static Assignment getAssignment(AddToMapOp updateOp) {
@@ -327,10 +351,11 @@ public class StatementFactory {
public RegularStatement delete(Query query, CassandraPersistentEntity<?> entity) {
Assert.notNull(query, "Query must not be null");
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
Assert.notNull(entity, "Entity must not be null");
List<String> columnNames = queryMapper.getMappedColumnNames(query.getColumns(), entity);
Filter filter = queryMapper.getMappedObject(query, entity);
Filter filter = getQueryMapper().getMappedObject(query, entity);
List<String> columnNames = getQueryMapper().getMappedColumnNames(query.getColumns(), entity);
Delete delete = delete(columnNames, entity.getTableName(), filter);
@@ -404,7 +429,7 @@ public class StatementFactory {
return QueryBuilder.containsKey(columnName, predicate.getValue());
}
throw new IllegalArgumentException(
String.format("Criteria %s %s %s not supported", columnName, predicate.getOperator(), predicate.getValue()));
throw new IllegalArgumentException(String.format("Criteria %s %s %s not supported",
columnName, predicate.getOperator(), predicate.getValue()));
}
}

View File

@@ -29,6 +29,7 @@ import org.springframework.util.Assert;
* Implementing classes must provide either {@link #getColumnName()} or {@link #getCqlIdentifier()}.
*
* @author Mark Paluch
* @see org.springframework.cassandra.core.cql.CqlIdentifier
* @since 2.0
*/
public abstract class ColumnName {
@@ -84,14 +85,17 @@ public abstract class ColumnName {
* @see org.springframework.data.cassandra.core.query.Criteria#equals(java.lang.Object)
*/
@Override
public boolean equals(Object o) {
public boolean equals(Object obj) {
if (this == o)
if (this == obj) {
return true;
if (!(o instanceof ColumnName))
return false;
}
ColumnName that = (ColumnName) o;
if (!(obj instanceof ColumnName)) {
return false;
}
ColumnName that = (ColumnName) obj;
return toCql().equals(that.toCql());
}
@@ -101,7 +105,9 @@ public abstract class ColumnName {
*/
@Override
public int hashCode() {
return 31 + toCql().hashCode();
int hashValue = 17;
hashValue = 37 * hashValue + toCql().hashCode();
return hashValue;
}
/**
@@ -117,14 +123,6 @@ public abstract class ColumnName {
this.columnName = columnName;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return columnName;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.query.ColumnName#getColumnName()
*/
@@ -148,6 +146,14 @@ public abstract class ColumnName {
public String toCql() {
return columnName;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return columnName;
}
}
/**
@@ -163,14 +169,6 @@ public abstract class ColumnName {
this.cqlIdentifier = cqlIdentifier;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return cqlIdentifier.toString();
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.query.ColumnName#getColumnName()
*/
@@ -194,5 +192,13 @@ public abstract class ColumnName {
public String toCql() {
return cqlIdentifier.toCql();
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return cqlIdentifier.toString();
}
}
}

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.cassandra.core.query;
import lombok.EqualsAndHashCode;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
@@ -27,6 +25,8 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import lombok.EqualsAndHashCode;
import org.springframework.cassandra.core.cql.CqlIdentifier;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
@@ -37,12 +37,12 @@ import org.springframework.util.StringUtils;
* included using a {@link Selector}.
*
* @author Mark Paluch
* @since 2.0
* @see CqlIdentifier
* @see ColumnName
* @see org.springframework.cassandra.core.cql.CqlIdentifier
* @see org.springframework.data.cassandra.core.query.ColumnName
* @see Selector
* @see ColumnSelector
* @see FunctionCall
* @see ColumnSelector
* @since 2.0
*/
public class Columns implements Iterable<ColumnName> {
@@ -338,14 +338,14 @@ public class Columns implements Iterable<ColumnName> {
* Create a {@link ColumnSelector} given {@link CqlIdentifier}.
*/
public static ColumnSelector from(CqlIdentifier columnName) {
return new ColumnSelector(ColumnName.from(columnName));
return from(ColumnName.from(columnName));
}
/**
* Create a {@link ColumnSelector} given a plain {@code columnName}.
*/
public static ColumnSelector from(String columnName) {
return new ColumnSelector(ColumnName.from(columnName));
return from(ColumnName.from(columnName));
}
/**
@@ -368,14 +368,14 @@ public class Columns implements Iterable<ColumnName> {
return new ColumnSelector(columnName, alias);
}
public String getExpression() {
return columnName.toCql();
}
public Optional<CqlIdentifier> getAlias() {
return alias;
}
public String getExpression() {
return columnName.toCql();
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@@ -454,11 +454,11 @@ public class Columns implements Iterable<ColumnName> {
@Override
public String toString() {
String params = StringUtils.collectionToDelimitedString(getParameters(), ", ");
String parameters = StringUtils.collectionToDelimitedString(getParameters(), ", ");
return getAlias()
.map(cqlIdentifier -> String.format("%s(%s) AS %s", getExpression(), params, cqlIdentifier.toCql()))
.orElseGet(() -> String.format("%s(%s)", getExpression(), params));
.map(cqlIdentifier -> String.format("%s(%s) AS %s", getExpression(), parameters, cqlIdentifier.toCql()))
.orElseGet(() -> String.format("%s(%s)", getExpression(), parameters));
}
}
}

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.cassandra.core.query;
import static org.springframework.util.ObjectUtils.*;
import static org.springframework.util.ObjectUtils.nullSafeHashCode;
import java.util.Arrays;
import java.util.Collection;
@@ -245,7 +245,7 @@ public class Criteria implements CriteriaDefinition {
return true;
}
if (obj == null || !(obj instanceof Criteria)) {
if (!(obj instanceof Criteria)) {
return false;
}

View File

@@ -98,8 +98,15 @@ public interface CriteriaDefinition {
*/
enum Operators implements Operator {
EQ("="), GT(">"), GTE(">="), LT("<"), LTE("<="), IN("IN"), CONTAINS("CONTAINS"), CONTAINS_KEY("CONTAINS KEY"), LIKE(
"LIKE");
EQ("="),
GT(">"),
GTE(">="),
LT("<"),
LTE("<="),
CONTAINS("CONTAINS"),
CONTAINS_KEY("CONTAINS KEY"),
IN("IN"),
LIKE("LIKE");
private final String operator;

View File

@@ -22,6 +22,7 @@ import java.util.stream.StreamSupport;
* Default implementation of {@link Filter}.
*
* @author Mark Paluch
* @see org.springframework.data.cassandra.core.query.Filter
* @since 2.0
*/
class DefaultFilter implements Filter {
@@ -46,7 +47,6 @@ class DefaultFilter implements Filter {
*/
@Override
public String toString() {
return StreamSupport.stream(this.spliterator(), false) //
.map(SerializationUtils::serializeToCqlSafely) //
.collect(Collectors.joining(" AND "));

View File

@@ -15,7 +15,8 @@
*/
package org.springframework.data.cassandra.core.query;
import static org.springframework.util.ObjectUtils.*;
import static org.springframework.util.ObjectUtils.nullSafeEquals;
import static org.springframework.util.ObjectUtils.nullSafeHashCode;
import java.util.ArrayList;
import java.util.Arrays;
@@ -37,6 +38,8 @@ import com.datastax.driver.core.PagingState;
* {@link QueryOptions} for a CQL query. {@link Query} is created with a fluent API creating immutable objects.
*
* @author Mark Paluch
* @see org.springframework.data.cassandra.core.query.Filter
* @see org.springframework.data.domain.Sort
* @since 2.0
*/
public class Query implements Filter {
@@ -119,13 +122,15 @@ public class Query implements Filter {
Assert.notNull(criteriaDefinition, "Criteria must not be null");
List<CriteriaDefinition> criteriaDefinitions = new ArrayList<>(this.criteriaDefinitions.size() + 1);
criteriaDefinitions.addAll(this.criteriaDefinitions);
if (!criteriaDefinitions.contains(criteriaDefinition)) {
criteriaDefinitions.add(criteriaDefinition);
}
return new Query(criteriaDefinitions, columns, sort, pagingState, queryOptions, limit, allowFiltering);
return new Query(criteriaDefinitions, this.columns, this.sort, this.pagingState,
this.queryOptions, this.limit, this.allowFiltering);
}
/* (non-Javadoc)
@@ -147,15 +152,15 @@ public class Query implements Filter {
Assert.notNull(columns, "Columns must not be null");
return new Query(criteriaDefinitions, this.columns.and(columns), sort, pagingState, queryOptions, limit,
allowFiltering);
return new Query(this.criteriaDefinitions, this.columns.and(columns), this.sort, this.pagingState,
this.queryOptions, this.limit, this.allowFiltering);
}
/**
* @return the query {@link Columns}.
*/
public Columns getColumns() {
return columns;
return this.columns;
}
/**
@@ -170,20 +175,20 @@ public class Query implements Filter {
for (Order order : sort) {
if (order.isIgnoreCase()) {
throw new IllegalArgumentException(String.format("Given sort contained an Order for %s with ignore case! "
+ "Apache Cassandra does not support sorting ignoring case currently!", order.getProperty()));
throw new IllegalArgumentException(String.format("Given sort contained an Order for %s with ignore case; "
+ "Apache Cassandra does not support sorting ignoring case currently", order.getProperty()));
}
}
return new Query(criteriaDefinitions, columns, this.sort.and(sort), pagingState, queryOptions, limit,
allowFiltering);
return new Query(this.criteriaDefinitions, this.columns, this.sort.and(sort), this.pagingState,
this.queryOptions, this.limit, this.allowFiltering);
}
/**
* @return the query {@link Sort} object.
*/
public Sort getSort() {
return sort;
return this.sort;
}
/**
@@ -196,14 +201,15 @@ public class Query implements Filter {
Assert.notNull(pagingState, "PagingState must not be null");
return new Query(criteriaDefinitions, columns, sort, Optional.of(pagingState), queryOptions, limit, allowFiltering);
return new Query(this.criteriaDefinitions, this.columns, this.sort, Optional.of(pagingState),
this.queryOptions, this.limit, this.allowFiltering);
}
/**
* @return the optional {@link PagingState}.
*/
public Optional<PagingState> getPagingState() {
return pagingState;
return this.pagingState;
}
/**
@@ -216,14 +222,15 @@ public class Query implements Filter {
Assert.notNull(queryOptions, "QueryOptions must not be null");
return new Query(criteriaDefinitions, columns, sort, pagingState, Optional.of(queryOptions), limit, allowFiltering);
return new Query(this.criteriaDefinitions, this.columns, this.sort, this.pagingState,
Optional.of(queryOptions), this.limit, this.allowFiltering);
}
/**
* @return the optional {@link QueryOptions}.
*/
public Optional<QueryOptions> getQueryOptions() {
return queryOptions;
return this.queryOptions;
}
/**
@@ -233,7 +240,8 @@ public class Query implements Filter {
* @return a new {@link Query} object containing the former settings with {@code limit} applied.
*/
public Query limit(long limit) {
return new Query(criteriaDefinitions, columns, sort, pagingState, queryOptions, Optional.of(limit), allowFiltering);
return new Query(this.criteriaDefinitions, this.columns, this.sort, this.pagingState,
this.queryOptions, Optional.of(limit), this.allowFiltering);
}
/**
@@ -249,15 +257,15 @@ public class Query implements Filter {
* @return a new {@link Query} object containing the former settings with {@code allowFiltering} applied.
*/
public Query withAllowFiltering() {
return new Query(criteriaDefinitions, columns, sort, pagingState, queryOptions, limit, true);
return new Query(this.criteriaDefinitions, this.columns, this.sort, this.pagingState,
this.queryOptions, this.limit, true);
}
/**
* @return {@literal true} to allow filtering.
*/
public boolean isAllowFiltering() {
return allowFiltering;
return this.allowFiltering;
}
/* (non-Javadoc)

View File

@@ -30,6 +30,9 @@ import com.datastax.driver.core.TypeCodec;
* Utility methods for CQL serialization.
*
* @author Mark Paluch
* @see org.springframework.core.convert.converter.Converter
* @see com.datastax.driver.core.CodecRegistry
* @see com.datastax.driver.core.TypeCodec
* @since 2.0
*/
abstract class SerializationUtils {
@@ -51,7 +54,8 @@ abstract class SerializationUtils {
}
CriteriaDefinition.Predicate predicate = criteria.getPredicate();
return serialize(criteria.getColumnName(), criteria.getPredicate().getOperator())
return serialize(criteria.getColumnName(), predicate.getOperator())
.append(serializeToCqlSafely(predicate.getValue())).toString();
}
@@ -61,8 +65,8 @@ abstract class SerializationUtils {
* but falling back to the given object's {@link Object#toString()} method if it's not serializable. Useful for
* printing raw {@link Criteria}s containing complex values before actually converting them into Mongo native types.
*
* @param criteria
* @return
* @param value value to serialize to CQL.
* @return the value as a serialized CQL {@link String}.
*/
public static String serializeToCqlSafely(Object value) {
@@ -92,6 +96,7 @@ abstract class SerializationUtils {
}
TypeCodec<Object> codec = CodecRegistry.DEFAULT_INSTANCE.codecFor(value);
return codec.format(value);
}
@@ -103,7 +108,6 @@ abstract class SerializationUtils {
}
private static String toString(Map<?, ?> source) {
return iterableToDelimitedString(source.entrySet(), "{ ", " }",
s -> String.format("%s : %s", serialize(s.getKey()), serialize(s.getValue())));
}
@@ -119,9 +123,9 @@ abstract class SerializationUtils {
}
/**
* Creates a string representation from the given {@link Iterable} prepending the prefix, applying the given
* {@link Converter} to each element before adding it to the result {@link String}, concatenating each element with
* {@literal ,} and applying the postfix.
* Creates a {@link String} representation from the given {@link Iterable} prepending the {@code prefix},
* applying the given {@link Converter} to each element before adding it to the result {@link String},
* concatenating each element with {@literal ,} and applying the {@code postfix}.
*/
private static <T> String iterableToDelimitedString(Iterable<T> source, String prefix, String postfix,
Converter<? super T, Object> transformer) {
@@ -131,6 +135,7 @@ abstract class SerializationUtils {
while (iterator.hasNext()) {
builder.append(transformer.convert(iterator.next()));
if (iterator.hasNext()) {
builder.append(",");
}

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.cassandra.core.query;
import static org.springframework.data.cassandra.core.query.SerializationUtils.*;
import static org.springframework.data.cassandra.core.query.SerializationUtils.serializeToCqlSafely;
import java.util.Arrays;
import java.util.Collection;
@@ -55,15 +55,6 @@ public class Update {
return new Update(Collections.emptyMap());
}
/**
* Set the {@code columnName} to {@code value}.
*
* @return a new {@link Update}.
*/
public static Update update(String columnName, Object value) {
return empty().set(columnName, value);
}
/**
* Create a {@link Update} object given a list of {@link AssignmentOp}s.
*
@@ -81,13 +72,22 @@ public class Update {
return new Update(updateOperations);
}
/**
* Set the {@code columnName} to {@code value}.
*
* @return a new {@link Update}.
*/
public static Update update(String columnName, Object value) {
return empty().set(columnName, value);
}
/**
* Set the {@code columnName} to {@code value}.
*
* @param columnName must not be {@literal null}.
* @param value
* @return a new {@link Update} object containing the merge result of the existing assignments and the current
* assignment.
* @param value value to set on column with name.
* @return a new {@link Update} object containing the merge result of the existing assignments
* and the current assignment.
*/
public Update set(String columnName, Object value) {
return add(new SetOp(ColumnName.from(columnName), value));
@@ -180,11 +180,11 @@ public class Update {
*/
public Update decrement(String columnName, Number delta) {
if (delta.doubleValue() > 0) {
return add(new IncrOp(ColumnName.from(columnName), -Math.abs(delta.doubleValue())));
}
double deltaValue = delta.doubleValue();
return add(new IncrOp(ColumnName.from(columnName), delta.doubleValue()));
deltaValue = deltaValue > 0 ? -Math.abs(deltaValue) : deltaValue;
return add(new IncrOp(ColumnName.from(columnName), deltaValue));
}
/**
@@ -312,24 +312,34 @@ public class Update {
return prependAll(Collections.singleton(value));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.query.Update.AddToBuilder#prependAll(java.lang.Object[])
*/
@Override
public Update prependAll(Object... values) {
Assert.notNull(values, "Values must not be null");
return prependAll(Arrays.asList(values));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.query.Update.AddToBuilder#prependAll(java.lang.Iterable)
*/
@Override
public Update prependAll(Iterable<? extends Object> values) {
Assert.notNull(values, "Values must not be null");
return add(new AddToOp(columnName, values, Mode.PREPEND));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.query.Update.AddToBuilder#append(java.lang.Object)
*/
@Override
public Update append(Object value) {
return prependAll(Collections.singleton(value));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.query.Update.AddToBuilder#entry(java.lang.Object, java.lang.Object)
*/
@Override
public Update entry(Object key, Object value) {
Assert.notNull(key, "Key must not be null");
Assert.notNull(value, "Value must not be null");
return addAll(Collections.singletonMap(key, value));
return appendAll(Collections.singleton(value));
}
/* (non-Javadoc)
@@ -355,25 +365,15 @@ public class Update {
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.query.Update.AddToBuilder#prependAll(java.lang.Object[])
* @see org.springframework.data.cassandra.core.query.Update.AddToBuilder#entry(java.lang.Object, java.lang.Object)
*/
@Override
public Update prependAll(Object... values) {
public Update entry(Object key, Object value) {
Assert.notNull(values, "Values must not be null");
Assert.notNull(key, "Key must not be null");
Assert.notNull(value, "Value must not be null");
return prependAll(Arrays.asList(values));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.query.Update.AddToBuilder#prependAll(java.lang.Iterable)
*/
@Override
public Update prependAll(Iterable<? extends Object> values) {
Assert.notNull(values, "Values must not be null");
return add(new AddToOp(columnName, values, Mode.PREPEND));
return addAll(Collections.singletonMap(key, value));
}
/* (non-Javadoc)
@@ -446,7 +446,7 @@ public class Update {
*/
@Override
public SetValueBuilder atIndex(int index) {
return value -> add(new SetAtIndexOp(columnName, index, value));
return value -> add(new SetAtIndexOp(this.columnName, index, value));
}
/* (non-Javadoc)
@@ -454,10 +454,7 @@ public class Update {
*/
@Override
public SetValueBuilder atKey(Object key) {
Assert.notNull(key, "Key must not be null");
return value -> add(new SetAtKeyOp(columnName, key, value));
return value -> add(new SetAtKeyOp(this.columnName, key, value));
}
}
@@ -511,11 +508,9 @@ public class Update {
@Override
public String toString() {
if (mode == Mode.PREPEND) {
return String.format("%s = %s + %s", getColumnName(), serializeToCqlSafely(value), getColumnName());
}
return String.format("%s = %s + %s", getColumnName(), getColumnName(), serializeToCqlSafely(value));
return Mode.PREPEND.equals(getMode())
? String.format("%s = %s + %s", getColumnName(), serializeToCqlSafely(value), getColumnName())
: String.format("%s = %s + %s", getColumnName(), getColumnName(), serializeToCqlSafely(value));
}
public enum Mode {

View File

@@ -15,9 +15,9 @@
*/
package org.springframework.data.cassandra.mapping;
import static org.springframework.cassandra.core.cql.CqlIdentifier.*;
import static org.springframework.cassandra.core.keyspace.CreateTableSpecification.*;
import static org.springframework.data.cassandra.mapping.CassandraSimpleTypeHolder.*;
import static org.springframework.cassandra.core.cql.CqlIdentifier.cqlId;
import static org.springframework.cassandra.core.keyspace.CreateTableSpecification.createTable;
import static org.springframework.data.cassandra.mapping.CassandraSimpleTypeHolder.getDataTypeFor;
import java.util.Collection;
import java.util.Collections;

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.cassandra.mapping;
import static org.springframework.cassandra.core.cql.CqlIdentifier.*;
import static org.springframework.cassandra.core.cql.CqlIdentifier.cqlId;
import java.util.ArrayList;
import java.util.Comparator;

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.cassandra.mapping;
import static org.springframework.cassandra.core.cql.CqlIdentifier.*;
import static org.springframework.cassandra.core.cql.CqlIdentifier.cqlId;
import java.util.ArrayList;
import java.util.Collections;

View File

@@ -19,6 +19,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@@ -50,10 +51,10 @@ public class CassandraSimpleTypeHolder extends SimpleTypeHolder {
private static final Map<DataType.Name, DataType> nameToDataType;
static {
CodecRegistry codecRegistry = CodecRegistry.DEFAULT_INSTANCE;
Map<Class<?>, Class<?>> primitiveWrappers = new HashMap<>(8);
primitiveWrappers.put(Boolean.class, boolean.class);
primitiveWrappers.put(Byte.class, byte.class);
primitiveWrappers.put(Character.class, char.class);
@@ -64,11 +65,12 @@ public class CassandraSimpleTypeHolder extends SimpleTypeHolder {
primitiveWrappers.put(Short.class, short.class);
Set<Class<?>> simpleTypes = getCassandraPrimitiveTypes(codecRegistry);
simpleTypes.add(Number.class);
simpleTypes.add(Row.class);
simpleTypes.add(UDTValue.class);
classToDataType = Collections.unmodifiableMap(classToDataType(primitiveWrappers, codecRegistry));
classToDataType = Collections.unmodifiableMap(classToDataType(codecRegistry, primitiveWrappers));
nameToDataType = Collections.unmodifiableMap(nameToDataType());
CASSANDRA_SIMPLE_TYPES = Collections.unmodifiableSet(simpleTypes);
}
@@ -82,40 +84,37 @@ public class CassandraSimpleTypeHolder extends SimpleTypeHolder {
Map<Name, DataType> nameToDataType = new HashMap<>(16);
for (DataType dataType : DataType.allPrimitiveTypes()) {
DataType.allPrimitiveTypes().forEach(dataType -> {
nameToDataType.put(dataType.getName(), dataType);
}
});
return nameToDataType;
}
/**
* @return the map between {@link Class} and {@link DataType}.
* @param primitiveWrappers map of primitive to wrapper type
* @param codecRegistry the Cassandra codec registry
* @param primitiveWrappers map of primitive to wrapper type
*/
private static Map<Class<?>, DataType> classToDataType(Map<Class<?>, Class<?>> primitiveWrappers,
CodecRegistry codecRegistry) {
private static Map<Class<?>, DataType> classToDataType(CodecRegistry codecRegistry,
Map<Class<?>, Class<?>> primitiveWrappers) {
Map<Class<?>, DataType> classToDataType = new HashMap<>(16);
for (DataType dataType : DataType.allPrimitiveTypes()) {
DataType.allPrimitiveTypes().forEach(dataType -> {
Class<?> javaType = codecRegistry.codecFor(dataType).getJavaType().getRawType();
Class<?> javaClass = codecRegistry.codecFor(dataType).getJavaType().getRawType();
classToDataType.put(javaClass, dataType);
classToDataType.put(javaType, dataType);
Class<?> primitiveJavaClass = primitiveWrappers.get(javaClass);
if (primitiveJavaClass != null) {
classToDataType.put(primitiveJavaClass, dataType);
}
}
Optional.ofNullable(primitiveWrappers.get(javaType))
.ifPresent(primitiveType -> classToDataType.put(primitiveType, dataType));
});
// override String to text datatype as String is used multiple times
classToDataType.put(String.class, DataType.text());
// map Long to bigint as counter columns (last type aver multiple overrides)
// are a special use case so map it to a more common type by
// default
// map Long to bigint as counter columns (last type aver multiple overrides) are a special use case
// so map it to a more common type by default
classToDataType.put(Long.class, DataType.bigint());
classToDataType.put(long.class, DataType.bigint());
@@ -130,10 +129,10 @@ public class CassandraSimpleTypeHolder extends SimpleTypeHolder {
*/
private static Set<Class<?>> getCassandraPrimitiveTypes(CodecRegistry codecRegistry) {
return DataType.allPrimitiveTypes().stream() //
.map(codecRegistry::codecFor) //
.map(TypeCodec::getJavaType) //
.map(TypeToken::getRawType) //
return DataType.allPrimitiveTypes().stream()
.map(codecRegistry::codecFor)
.map(TypeCodec::getJavaType)
.map(TypeToken::getRawType)
.collect(Collectors.toSet());
}
@@ -165,15 +164,19 @@ public class CassandraSimpleTypeHolder extends SimpleTypeHolder {
public static DataType.Name[] getDataTypeNamesFrom(List<TypeInformation<?>> arguments) {
DataType.Name[] array = new DataType.Name[arguments.size()];
for (int i = 0; i != array.length; i++) {
TypeInformation<?> typeInfo = arguments.get(i);
DataType dataType = getDataTypeFor(typeInfo.getType());
if (dataType == null) {
throw new InvalidDataAccessApiUsageException(
String.format("Did not find appropriate primitive DataType for type '%s'", typeInfo.getType()));
String.format("Did not find appropriate primitive DataType for type '%s'", typeInfo.getType()));
}
array[i] = dataType.getName();
}
return array;
}

View File

@@ -136,9 +136,8 @@ public abstract class AbstractCassandraQuery implements RepositoryQuery {
Statement statement = createQuery(parameterAccessor);
CassandraQueryExecution queryExecution = getExecution(
new ResultProcessingConverter(resultProcessor, getOperations().getConverter().getMappingContext(),
getEntityInstantiators()));
CassandraQueryExecution queryExecution = getExecution(new ResultProcessingConverter(
resultProcessor, getOperations().getConverter().getMappingContext(), getEntityInstantiators()));
CassandraReturnedType returnedType = new CassandraReturnedType(resultProcessor.getReturnedType(),
getOperations().getConverter().getCustomConversions());

View File

@@ -18,7 +18,6 @@ package org.springframework.data.cassandra.repository.query;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.reactivestreams.Publisher;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.data.cassandra.core.ReactiveCassandraOperations;
@@ -32,6 +31,8 @@ import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.util.Assert;
import org.reactivestreams.Publisher;
import com.datastax.driver.core.Statement;
/**
@@ -65,13 +66,23 @@ public abstract class AbstractReactiveCassandraQuery implements RepositoryQuery
this.instantiators = new EntityInstantiators();
}
/* (non-Javadoc) */
protected EntityInstantiators getEntityInstantiators() {
return this.instantiators;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.RepositoryQuery#getQueryMethod()
*/
@Override
public CassandraQueryMethod getQueryMethod() {
return method;
public ReactiveCassandraQueryMethod getQueryMethod() {
return this.method;
}
/* (non-Javadoc) */
protected ReactiveCassandraOperations getReactiveCassandraOperations() {
return this.operations;
}
/*
@@ -81,14 +92,14 @@ public abstract class AbstractReactiveCassandraQuery implements RepositoryQuery
@Override
public Object execute(Object[] parameters) {
return (method.hasReactiveWrapperParameter() ? executeDeferred(parameters)
: execute(new ReactiveCassandraParameterAccessor(method, parameters)));
return (getQueryMethod().hasReactiveWrapperParameter() ? executeDeferred(parameters)
: execute(new ReactiveCassandraParameterAccessor(getQueryMethod(), parameters)));
}
@SuppressWarnings("unchecked")
private Object executeDeferred(Object[] parameters) {
ReactiveCassandraParameterAccessor accessor = new ReactiveCassandraParameterAccessor(method, parameters);
ReactiveCassandraParameterAccessor accessor = new ReactiveCassandraParameterAccessor(getQueryMethod(), parameters);
return (getQueryMethod().isCollectionQuery() ? Flux.defer(() -> (Publisher<Object>) execute(accessor))
: Mono.defer(() -> (Mono<Object>) execute(accessor)));
@@ -96,18 +107,20 @@ public abstract class AbstractReactiveCassandraQuery implements RepositoryQuery
private Object execute(CassandraParameterAccessor parameterAccessor) {
CassandraParameterAccessor convertingParameterAccessor = new ConvertingParameterAccessor(operations.getConverter(),
parameterAccessor);
CassandraParameterAccessor convertingParameterAccessor =
new ConvertingParameterAccessor(getReactiveCassandraOperations().getConverter(), parameterAccessor);
Statement statement = createQuery(convertingParameterAccessor);
ResultProcessor resultProcessor = method.getResultProcessor().withDynamicProjection(convertingParameterAccessor);
ResultProcessor resultProcessor =
getQueryMethod().getResultProcessor().withDynamicProjection(convertingParameterAccessor);
ReactiveCassandraQueryExecution queryExecution = getExecution(
new ResultProcessingConverter(resultProcessor, operations.getConverter().getMappingContext(), instantiators));
ReactiveCassandraQueryExecution queryExecution = getExecution(new ResultProcessingConverter(
resultProcessor, getReactiveCassandraOperations().getConverter().getMappingContext(),
getEntityInstantiators()));
CassandraReturnedType returnedType = new CassandraReturnedType(resultProcessor.getReturnedType(),
operations.getConverter().getCustomConversions());
getReactiveCassandraOperations().getConverter().getCustomConversions());
Class<?> resultType = (returnedType.isProjecting() ? returnedType.getDomainType() : returnedType.getReturnedType());
@@ -132,6 +145,7 @@ public abstract class AbstractReactiveCassandraQuery implements RepositoryQuery
/* (non-Javadoc) */
private ReactiveCassandraQueryExecution getExecutionToWrap() {
return (method.isCollectionQuery() ? new CollectionExecution(operations) : new SingleEntityExecution(operations));
return (getQueryMethod().isCollectionQuery() ? new CollectionExecution(getReactiveCassandraOperations())
: new SingleEntityExecution(getReactiveCassandraOperations()));
}
}

View File

@@ -20,8 +20,6 @@ import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.cassandra.core.query.Criteria;
import org.springframework.data.cassandra.core.query.CriteriaDefinition;
@@ -38,6 +36,9 @@ import org.springframework.data.repository.query.parser.Part.Type;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.util.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.querybuilder.Clause;
/**
@@ -73,14 +74,34 @@ class CassandraQueryCreator extends AbstractQueryCreator<Query, CriteriaDefiniti
this.mappingContext = mappingContext;
}
/**
* Returns the {@link CassandraMappingContext} used by this template to access mapping meta-data used to
* store (map) object to Cassandra tables.
*
* @return the {@link CassandraMappingContext} used by this template.
* @see org.springframework.data.cassandra.mapping.CassandraMappingContext
*/
protected CassandraMappingContext getMappingContext() {
return this.mappingContext;
}
/**
* Returns the {@link QueryBuilder} used to construct Cassandra CQL queries.
*
* @return the {@link QueryBuilder} used to construct Cassandra CQL queries.
*/
protected QueryBuilder getQueryBuilder() {
return this.queryBuilder;
}
/* (non-Javadoc)
* @see org.springframework.data.repository.query.parser.AbstractQueryCreator#create(org.springframework.data.repository.query.parser.Part, java.util.Iterator)
*/
@Override
protected CriteriaDefinition create(Part part, Iterator<Object> iterator) {
PersistentPropertyPath<CassandraPersistentProperty> path = mappingContext
.getPersistentPropertyPath(part.getProperty());
PersistentPropertyPath<CassandraPersistentProperty> path =
getMappingContext().getPersistentPropertyPath(part.getProperty());
CassandraPersistentProperty property = path.getLeafProperty();
@@ -94,10 +115,10 @@ class CassandraQueryCreator extends AbstractQueryCreator<Query, CriteriaDefiniti
protected CriteriaDefinition and(Part part, CriteriaDefinition base, Iterator<Object> iterator) {
if (base == null) {
return queryBuilder.and(create(part, iterator));
return getQueryBuilder().and(create(part, iterator));
}
queryBuilder.and(base);
getQueryBuilder().and(base);
return create(part, iterator);
}
@@ -120,10 +141,10 @@ class CassandraQueryCreator extends AbstractQueryCreator<Query, CriteriaDefiniti
protected Query complete(CriteriaDefinition criteria, Sort sort) {
if (criteria != null) {
queryBuilder.and(criteria);
getQueryBuilder().and(criteria);
}
Query query = queryBuilder.create(sort);
Query query = getQueryBuilder().create(sort);
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("Created query [%s]", query));

View File

@@ -143,7 +143,7 @@ class ConvertingParameterAccessor implements CassandraParameterAccessor {
return bindableValue
.flatMap(
v -> converter.convertToCassandraColumn(bindableValue, findTypeInformation(index, v, Optional.empty())))
v -> converter.convertToColumnType(bindableValue, findTypeInformation(index, v, Optional.empty())))
.orElse(null);
}
@@ -151,7 +151,7 @@ class ConvertingParameterAccessor implements CassandraParameterAccessor {
private Object potentiallyConvert(int index, Optional<Object> bindableValue, CassandraPersistentProperty property) {
return bindableValue.flatMap(
v -> converter.convertToCassandraColumn(bindableValue, findTypeInformation(index, v, Optional.of(property))))
v -> converter.convertToColumnType(bindableValue, findTypeInformation(index, v, Optional.of(property))))
.orElse(null);
}

View File

@@ -37,10 +37,10 @@ import com.datastax.driver.core.Statement;
*/
public class PartTreeCassandraQuery extends AbstractCassandraQuery {
private final PartTree tree;
private final CassandraMappingContext mappingContext;
private final PartTree tree;
private final StatementFactory statementFactory;
/**
@@ -70,9 +70,15 @@ public class PartTreeCassandraQuery extends AbstractCassandraQuery {
}
/**
<<<<<<< 85e5d32f4c6db62b63513c14864f7625d7813060
* Returns the {@link StatementFactory} used by this query to construct and run Cassandra CQL statements.
*
* @return the {@link StatementFactory} used by this query to construct and run Cassandra CQL statements.
=======
* Returns the {@link StatementFactory} used by this template to construct and run Cassandra CQL statements.
*
* @return the {@link StatementFactory} used by this template to construct and run Cassandra CQL statements.
>>>>>>> DATACASS-343 - Polish.
* @see org.springframework.data.cassandra.core.StatementFactory
*/
protected StatementFactory getStatementFactory() {

View File

@@ -35,10 +35,10 @@ import com.datastax.driver.core.Statement;
*/
public class ReactivePartTreeCassandraQuery extends AbstractReactiveCassandraQuery {
private final PartTree tree;
private final CassandraMappingContext mappingContext;
private final PartTree tree;
private final StatementFactory statementFactory;
/**
@@ -70,9 +70,15 @@ public class ReactivePartTreeCassandraQuery extends AbstractReactiveCassandraQue
}
/**
<<<<<<< 85e5d32f4c6db62b63513c14864f7625d7813060
* Returns the {@link StatementFactory} used by this query to construct and run Cassandra CQL statements.
*
* @return the {@link StatementFactory} used by this query to construct and run Cassandra CQL statements.
=======
* Returns the {@link StatementFactory} used by this template to construct and run Cassandra CQL statements.
*
* @return the {@link StatementFactory} used by this template to construct and run Cassandra CQL statements.
>>>>>>> DATACASS-343 - Polish.
* @see org.springframework.data.cassandra.core.StatementFactory
*/
protected StatementFactory getStatementFactory() {

View File

@@ -15,14 +15,15 @@
*/
package org.springframework.data.cassandra.repository.query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.cassandra.core.ReactiveCassandraOperations;
import org.springframework.data.repository.query.EvaluationContextProvider;
import org.springframework.data.repository.query.QueryCreationException;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.util.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.SimpleStatement;
/**
@@ -81,6 +82,11 @@ public class ReactiveStringBasedCassandraQuery extends AbstractReactiveCassandra
new ExpressionEvaluatingParameterBinder(expressionParser, evaluationContextProvider));
}
/* (non-Javadoc) */
protected StringBasedQuery getStringBasedQuery() {
return this.stringBasedQuery;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.repository.query.AbstractCassandraQuery#createQuery(org.springframework.data.cassandra.repository.query.CassandraParameterAccessor)
*/
@@ -88,7 +94,7 @@ public class ReactiveStringBasedCassandraQuery extends AbstractReactiveCassandra
public SimpleStatement createQuery(CassandraParameterAccessor parameterAccessor) {
try {
SimpleStatement boundQuery = stringBasedQuery.bindQuery(parameterAccessor, getQueryMethod());
SimpleStatement boundQuery = getStringBasedQuery().bindQuery(parameterAccessor, getQueryMethod());
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("Created query [%s].", boundQuery));

View File

@@ -15,13 +15,14 @@
*/
package org.springframework.data.cassandra.repository.query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.data.repository.query.EvaluationContextProvider;
import org.springframework.data.repository.query.QueryCreationException;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.SimpleStatement;
/**
@@ -72,10 +73,16 @@ public class StringBasedCassandraQuery extends AbstractCassandraQuery {
SpelExpressionParser expressionParser, EvaluationContextProvider evaluationContextProvider) {
super(queryMethod, operations);
this.stringBasedQuery = new StringBasedQuery(query,
new ExpressionEvaluatingParameterBinder(expressionParser, evaluationContextProvider));
}
/* (non-Javadoc) */
protected StringBasedQuery getStringBasedQuery() {
return this.stringBasedQuery;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.repository.query.AbstractCassandraQuery#createQuery(org.springframework.data.cassandra.repository.query.CassandraParameterAccessor)
*/
@@ -83,8 +90,7 @@ public class StringBasedCassandraQuery extends AbstractCassandraQuery {
public SimpleStatement createQuery(CassandraParameterAccessor parameterAccessor) {
try {
SimpleStatement boundQuery = stringBasedQuery.bindQuery(parameterAccessor, getQueryMethod());
SimpleStatement boundQuery = getStringBasedQuery().bindQuery(parameterAccessor, getQueryMethod());
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("Created query [%s].", boundQuery));

View File

@@ -49,7 +49,6 @@ class StringBasedQuery {
*
* @param query must not be empty.
* @param parameterBinder must not be {@literal null}.
* @param codecRegistry must not be {@literal null}.
*/
public StringBasedQuery(String query, ExpressionEvaluatingParameterBinder parameterBinder) {
@@ -63,6 +62,16 @@ class StringBasedQuery {
}
/* (non-Javadoc) */
protected ExpressionEvaluatingParameterBinder getParameterBinder() {
return this.parameterBinder;
}
/* (non-Javadoc) */
protected String getQuery() {
return this.query;
}
/**
* Bind the query to actual parameters using {@link CassandraParameterAccessor},
*
@@ -75,10 +84,10 @@ class StringBasedQuery {
Assert.notNull(parameterAccessor, "CassandraParameterAccessor must not be null");
Assert.notNull(queryMethod, "CassandraQueryMethod must not be null");
List<Object> arguments = parameterBinder.bind(parameterAccessor,
new BindingContext(queryMethod, queryParameterBindings));
List<Object> arguments = getParameterBinder().bind(parameterAccessor,
new BindingContext(queryMethod, this.queryParameterBindings));
return ParameterBinder.INSTANCE.bind(query, arguments);
return ParameterBinder.INSTANCE.bind(getQuery(), arguments);
}
/**

View File

@@ -25,6 +25,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Currency;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import org.junit.Before;
@@ -77,7 +78,8 @@ public class QueryMapperUnitTests {
@Before
public void before() throws Exception {
CustomConversions customConversions = new CustomConversions(Collections.singletonList(CurrencyConverter.INSTANCE));
CassandraCustomConversions customConversions =
new CassandraCustomConversions(Collections.singletonList(CurrencyConverter.INSTANCE));
mappingContext.setCustomConversions(customConversions);
mappingContext.setUserTypeResolver(userTypeResolver);

View File

@@ -55,7 +55,8 @@ public class UpdateMapperUnitTests {
@Before
public void before() throws Exception {
CustomConversions customConversions = new CustomConversions(Collections.singletonList(CurrencyConverter.INSTANCE));
CassandraCustomConversions customConversions =
new CassandraCustomConversions(Collections.singletonList(CurrencyConverter.INSTANCE));
mappingContext.setCustomConversions(customConversions);
mappingContext.setUserTypeResolver(userTypeResolver);