DATACASS-343 - Polish.
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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" })
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 "));
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(",");
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user